summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Doxyfile1109
-rw-r--r--LICENSE25
-rw-r--r--arch/alpha/alpha_memory.cc661
-rw-r--r--arch/alpha/alpha_memory.hh126
-rw-r--r--arch/alpha/arguments.cc64
-rw-r--r--arch/alpha/arguments.hh143
-rw-r--r--arch/alpha/ev5.cc571
-rw-r--r--arch/alpha/ev5.hh104
-rw-r--r--arch/alpha/fake_syscall.cc1736
-rw-r--r--arch/alpha/faults.cc61
-rw-r--r--arch/alpha/faults.hh56
-rw-r--r--arch/alpha/isa_desc2427
-rw-r--r--arch/alpha/isa_traits.hh282
-rw-r--r--arch/alpha/osfpal.cc304
-rw-r--r--arch/alpha/osfpal.hh79
-rw-r--r--arch/alpha/vtophys.cc123
-rw-r--r--arch/alpha/vtophys.hh46
-rw-r--r--arch/isa_parser.py1446
-rw-r--r--base/bitfield.hh69
-rw-r--r--base/callback.hh56
-rw-r--r--base/circlebuf.cc187
-rw-r--r--base/circlebuf.hh59
-rw-r--r--base/cprintf.cc277
-rw-r--r--base/cprintf.hh197
-rw-r--r--base/cprintf_formats.hh354
-rw-r--r--base/date.cc29
-rw-r--r--base/dbl_list.hh165
-rw-r--r--base/endian.hh41
-rw-r--r--base/fast_alloc.cc191
-rw-r--r--base/fast_alloc.hh203
-rw-r--r--base/fifo_buffer.cc40
-rw-r--r--base/fifo_buffer.hh93
-rw-r--r--base/hashmap.hh83
-rw-r--r--base/inet.cc161
-rw-r--r--base/inet.hh37
-rw-r--r--base/inifile.cc437
-rw-r--r--base/inifile.hh111
-rw-r--r--base/intmath.cc58
-rw-r--r--base/intmath.h123
-rw-r--r--base/kgdb.h203
-rw-r--r--base/misc.cc97
-rw-r--r--base/misc.hh76
-rw-r--r--base/mod_num.hh201
-rw-r--r--base/object_file.cc173
-rw-r--r--base/object_file.hh92
-rw-r--r--base/pollevent.cc254
-rw-r--r--base/pollevent.hh89
-rw-r--r--base/random.cc79
-rw-r--r--base/random.hh100
-rw-r--r--base/range.hh260
-rw-r--r--base/refcnt.hh122
-rw-r--r--base/remote_gdb.cc1150
-rw-r--r--base/remote_gdb.hh189
-rw-r--r--base/res_list.hh756
-rw-r--r--base/sched_list.hh176
-rw-r--r--base/socket.cc114
-rw-r--r--base/socket.hh49
-rw-r--r--base/statistics.cc823
-rw-r--r--base/statistics.hh1682
-rw-r--r--base/str.cc332
-rw-r--r--base/str.hh127
-rw-r--r--base/symtab.cc133
-rw-r--r--base/symtab.hh59
-rw-r--r--base/trace.cc325
-rw-r--r--base/trace.hh218
-rw-r--r--dev/alpha_access.h79
-rw-r--r--dev/alpha_console.cc273
-rw-r--r--dev/alpha_console.hh108
-rw-r--r--dev/console.cc478
-rw-r--r--dev/console.hh147
-rw-r--r--dev/disk_image.cc427
-rw-r--r--dev/disk_image.hh130
-rw-r--r--dev/etherbus.cc128
-rw-r--r--dev/etherbus.hh79
-rw-r--r--dev/etherdump.cc138
-rw-r--r--dev/etherdump.hh60
-rw-r--r--dev/etherint.cc44
-rw-r--r--dev/etherint.hh63
-rw-r--r--dev/etherlink.cc148
-rw-r--r--dev/etherlink.hh123
-rw-r--r--dev/etherpkt.hh65
-rw-r--r--dev/ethertap.cc295
-rw-r--r--dev/ethertap.hh101
-rw-r--r--dev/pcireg.h175
-rw-r--r--dev/simple_disk.cc108
-rw-r--r--dev/simple_disk.hh60
-rw-r--r--kern/tru64/tru64.hh34
-rw-r--r--kern/tru64/tru64_syscalls.cc438
-rw-r--r--kern/tru64/tru64_syscalls.hh355
-rw-r--r--sim/async.hh49
-rw-r--r--sim/base_cpu.cc158
-rw-r--r--sim/base_cpu.hh122
-rw-r--r--sim/cache/lzss_compression.cc166
-rw-r--r--sim/cache/lzss_compression.hh100
-rw-r--r--sim/cache/null_compression.hh72
-rw-r--r--sim/debug.cc137
-rw-r--r--sim/debug.hh34
-rw-r--r--sim/eventq.cc212
-rw-r--r--sim/eventq.hh351
-rw-r--r--sim/exec_context.cc106
-rw-r--r--sim/exec_context.hh360
-rw-r--r--sim/exetrace.cc190
-rw-r--r--sim/exetrace.hh197
-rw-r--r--sim/host.hh57
-rw-r--r--sim/hybrid_pred.cc275
-rw-r--r--sim/hybrid_pred.hh203
-rw-r--r--sim/intr_control.cc59
-rw-r--r--sim/intr_control.hh61
-rw-r--r--sim/main.cc429
-rw-r--r--sim/memtest.cc324
-rw-r--r--sim/memtest.hh140
-rw-r--r--sim/op_class.hh64
-rw-r--r--sim/param.cc760
-rw-r--r--sim/param.hh757
-rw-r--r--sim/pc_event.cc231
-rw-r--r--sim/pc_event.hh215
-rw-r--r--sim/predictor.hh62
-rw-r--r--sim/prog.cc281
-rw-r--r--sim/prog.hh180
-rw-r--r--sim/sat_counter.cc270
-rw-r--r--sim/sat_counter.hh192
-rw-r--r--sim/serialize.cc353
-rw-r--r--sim/serialize.hh241
-rw-r--r--sim/sim_events.cc271
-rw-r--r--sim/sim_events.hh131
-rw-r--r--sim/sim_exit.hh41
-rw-r--r--sim/sim_object.cc280
-rw-r--r--sim/sim_object.hh261
-rw-r--r--sim/sim_time.cc152
-rw-r--r--sim/sim_time.hh84
-rw-r--r--sim/simple_cpu.cc747
-rw-r--r--sim/simple_cpu.hh280
-rw-r--r--sim/smt.hh64
-rw-r--r--sim/static_inst.cc88
-rw-r--r--sim/static_inst.hh433
-rw-r--r--sim/std_types.hh40
-rw-r--r--sim/system.cc250
-rw-r--r--sim/system.hh113
-rw-r--r--sim/universe.cc58
-rw-r--r--test/Makefile83
-rw-r--r--test/bitvectest.cc66
-rw-r--r--test/circletest.cc72
-rw-r--r--test/cprintftest.cc164
-rw-r--r--test/foo.ini7
-rw-r--r--test/initest.cc117
-rw-r--r--test/initest.ini14
-rw-r--r--test/lru_test.cc82
-rw-r--r--test/nmtest.cc75
-rw-r--r--test/offtest.cc70
-rw-r--r--test/paramtest.cc105
-rw-r--r--test/rangetest.cc104
-rw-r--r--test/sized_test.cc67
-rw-r--r--test/stattest.cc504
-rw-r--r--test/strnumtest.cc74
-rw-r--r--test/symtest.cc77
-rw-r--r--test/tokentest.cc69
-rw-r--r--test/tracetest.cc54
-rw-r--r--util/rundiff511
-rw-r--r--util/tap/Makefile67
-rw-r--r--util/tap/tap.cc415
-rw-r--r--util/term/Makefile45
-rw-r--r--util/term/term.c312
162 files changed, 38124 insertions, 0 deletions
diff --git a/Doxyfile b/Doxyfile
new file mode 100644
index 000000000..3bf57ca71
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,1109 @@
+# Doxyfile 1.3.3
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# General configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = M5
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = docs/doxygen
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch,
+# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en
+# (Japanese with English messages), Korean, Norwegian, Polish, Portuguese,
+# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# This tag can be used to specify the encoding used in the generated output.
+# The encoding is not always determined by the language that is chosen,
+# but also whether or not the output is meant for Windows or non-Windows users.
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES
+# forces the Windows encoding (this is the default for the Windows binary),
+# whereas setting the tag to NO uses a Unix-style encoding (the default for
+# all platforms other than Windows).
+
+USE_WINDOWS_ENCODING = NO
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = YES
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = YES
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited
+# members of a class in the documentation of that class as if those members were
+# ordinary class members. Constructors, destructors and assignment operators of
+# the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. It is allowed to use relative paths in the argument list.
+
+STRIP_FROM_PATH = .
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explict @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# reimplements.
+
+INHERIT_DOCS = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources
+# only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = .
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp
+# *.h++ *.idl *.odl *.cs
+
+FILE_PATTERNS = *.c *.cc *.h *.hh *.doxygen
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE = build configs setup */CVS
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories
+# that are symbolic links (a Unix filesystem feature) are excluded from the input.
+
+EXCLUDE_SYMLINKS = YES
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+
+EXCLUDE_PATTERNS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+
+INPUT_FILTER =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output dir.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimised for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assigments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed.
+
+PREDEFINED = DOXYGEN_SHOULD_SKIP_THIS
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse the
+# parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or
+# super classes. Setting the tag to NO turns the diagrams off. Note that this
+# option is superceded by the HAVE_DOT option below. This is only a fallback. It is
+# recommended to install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = YES
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similiar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found on the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_WIDTH = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes that
+# lay further from the root node will be omitted. Note that setting this option to
+# 1 or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that a graph may be further truncated if the graph's image dimensions are
+# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT).
+# If 0 is used for the depth value (the default), the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
+
+# The CGI_NAME tag should be the name of the CGI script that
+# starts the search engine (doxysearch) with the correct parameters.
+# A script with this name will be generated by doxygen.
+
+CGI_NAME = search.cgi
+
+# The CGI_URL tag should be the absolute URL to the directory where the
+# cgi binaries are located. See the documentation of your http daemon for
+# details.
+
+CGI_URL =
+
+# The DOC_URL tag should be the absolute URL to the directory where the
+# documentation is located. If left blank the absolute path to the
+# documentation, with file:// prepended to it, will be used.
+
+DOC_URL =
+
+# The DOC_ABSPATH tag should be the absolute path to the directory where the
+# documentation is located. If left blank the directory on the local machine
+# will be used.
+
+DOC_ABSPATH =
+
+# The BIN_ABSPATH tag must point to the directory where the doxysearch binary
+# is installed.
+
+BIN_ABSPATH = /usr/local/bin/
+
+# The EXT_DOC_PATHS tag can be used to specify one or more paths to
+# documentation generated for other projects. This allows doxysearch to search
+# the documentation for these projects as well.
+
+EXT_DOC_PATHS =
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 000000000..8ecb95578
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,25 @@
+Copyright (c) 2000-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.
diff --git a/arch/alpha/alpha_memory.cc b/arch/alpha/alpha_memory.cc
new file mode 100644
index 000000000..34c8e7f7d
--- /dev/null
+++ b/arch/alpha/alpha_memory.cc
@@ -0,0 +1,661 @@
+/*
+ * 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.
+ */
+
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "alpha_memory.hh"
+#include "ev5.hh"
+#include "exec_context.hh"
+#include "trace.hh"
+#include "inifile.hh"
+#include "str.hh"
+
+using namespace std;
+
+///////////////////////////////////////////////////////////////////////
+//
+// Alpha TLB
+//
+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
+{
+ DPRINTF(TLB, "lookup %#x\n", vpn);
+
+ PageTable::const_iterator i = lookupTable.find(vpn);
+ if (i == lookupTable.end())
+ return NULL;
+
+ 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))
+ return pte;
+
+ ++i;
+ }
+
+ // not found...
+ return NULL;
+}
+
+
+void
+AlphaTlb::checkCacheability(MemReqPtr req)
+{
+ // in Alpha, cacheability is controlled by upper-level bits of the
+ // physical address
+ if (req->paddr & PA_UNCACHED_BIT) {
+ if (PA_IPR_SPACE(req->paddr)) {
+ // IPR memory space not implemented
+ if (!req->xc->misspeculating())
+ panic("IPR memory space not implemented! PA=%x\n", req->paddr);
+ } else {
+ // mark request as uncacheable
+ req->flags |= UNCACHEABLE;
+ }
+ }
+}
+
+
+// insert a new TLB entry
+void
+AlphaTlb::insert(Addr vaddr, AlphaISA::PTE &pte)
+{
+ 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);
+ }
+
+ Addr vpn = VA_VPN(vaddr);
+ DPRINTF(TLB, "insert @%d: %#x -> %#x\n", nlu, vpn, pte.ppn);
+
+ table[nlu] = pte;
+ table[nlu].tag = vpn;
+ table[nlu].valid = true;
+
+ lookupTable.insert(make_pair(vpn, nlu));
+ nextnlu();
+}
+
+void
+AlphaTlb::flushAll()
+{
+ 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);
+
+ if (!pte->asma) {
+ DPRINTF(TLB, "flush @%d: %#x -> %#x\n", index, pte->tag, pte->ppn);
+ pte->valid = false;
+ lookupTable.erase(i);
+ }
+
+ ++i;
+ }
+}
+
+void
+AlphaTlb::flushAddr(Addr vaddr, uint8_t asn)
+{
+ Addr vpn = VA_VPN(vaddr);
+
+ PageTable::iterator i = lookupTable.find(vpn);
+ if (i == lookupTable.end())
+ return;
+
+ 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)) {
+ DPRINTF(TLB, "flushaddr @%d: %#x -> %#x\n", index, vpn, pte->ppn);
+
+ // invalidate this entry
+ pte->valid = false;
+
+ lookupTable.erase(i);
+ }
+
+ ++i;
+ }
+}
+
+
+void
+AlphaTlb::serialize()
+{
+ nameOut();
+
+ paramOut("size", size);
+ paramOut("nlu", nlu);
+
+ stringstream buf;
+ for (int i = 0; i < size; i++) {
+ buf.str("");
+ ccprintf(buf, "pte%02d.valid", i);
+ paramOut(buf.str(), table[i].valid);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.tag", i);
+ paramOut(buf.str(), table[i].tag);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.ppn", i);
+ paramOut(buf.str(), table[i].ppn);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.xre", i);
+ paramOut(buf.str(), table[i].xre);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.xwe", i);
+ paramOut(buf.str(), table[i].xwe);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.fonr", i);
+ paramOut(buf.str(), table[i].fonr);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.fonw", i);
+ paramOut(buf.str(), table[i].fonw);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.asma", i);
+ paramOut(buf.str(), table[i].asma);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.asn", i);
+ paramOut(buf.str(), table[i].asn);
+ }
+}
+
+void
+AlphaTlb::unserialize(IniFile &db, const string &category, ConfigNode *node)
+{
+ string data;
+ stringstream buf;
+
+ db.findDefault(category,"size",data);
+ to_number(data,size);
+ db.findDefault(category,"nlu",data);
+ to_number(data,nlu);
+
+ for (int i = 0; i < size; i++) {
+ buf.str("");
+ ccprintf(buf, "pte%02d.valid", i);
+ db.findDefault(category, buf.str(), data);
+ to_number(data, table[i].valid);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.tag", i);
+ db.findDefault(category, buf.str(), data);
+ to_number(data, table[i].tag);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.ppn", i);
+ db.findDefault(category, buf.str(), data);
+ to_number(data, table[i].ppn);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.xre", i);
+ db.findDefault(category, buf.str(), data);
+ to_number(data, table[i].xre);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.xwe", i);
+ db.findDefault(category, buf.str(), data);
+ to_number(data, table[i].xwe);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.fonr", i);
+ db.findDefault(category, buf.str(), data);
+ to_number(data, table[i].fonr);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.fonw", i);
+ db.findDefault(category, buf.str(), data);
+ to_number(data, table[i].fonw);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.asma", i);
+ db.findDefault(category, buf.str(), data);
+ to_number(data, table[i].asma);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.asn", i);
+ db.findDefault(category, buf.str(), data);
+ to_number(data, table[i].asn);
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////
+//
+// 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;
+}
+
+void
+AlphaItb::fault(Addr pc, ExecContext *xc) const
+{
+ uint64_t *ipr = xc->regs.ipr;
+
+ if (!xc->misspeculating()) {
+ ipr[AlphaISA::IPR_ITB_TAG] = pc;
+ ipr[AlphaISA::IPR_IFAULT_VA_FORM] =
+ ipr[AlphaISA::IPR_IVPTBR] | (VA_VPN(pc) << 3);
+ }
+}
+
+
+Fault
+AlphaItb::translate(MemReqPtr req) const
+{
+ InternalProcReg *ipr = req->xc->regs.ipr;
+
+ if (PC_PAL(req->vaddr)) {
+ // strip off PAL PC marker (lsb is 1)
+ req->paddr = (req->vaddr & ~3) & PA_IMPL_MASK;
+ hits++;
+ return No_Fault;
+ }
+
+ // verify that this is a good virtual address
+ if (!validVirtualAddress(req->vaddr)) {
+ fault(req->vaddr, req->xc);
+ acv++;
+ return Itb_Acv_Fault;
+ }
+
+ // Check for "superpage" mapping: when SP<1> is set, and
+ // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13>.
+ if ((MCSR_SP(ipr[AlphaISA::IPR_MCSR]) & 2) &&
+ VA_SPACE(req->vaddr) == 2) {
+ // only valid in kernel mode
+ if (ICM_CM(ipr[AlphaISA::IPR_ICM]) != AlphaISA::mode_kernel) {
+ fault(req->vaddr, req->xc);
+ acv++;
+ return Itb_Acv_Fault;
+ }
+
+ req->flags |= PHYSICAL;
+ }
+
+ if (req->flags & PHYSICAL) {
+ req->paddr = req->vaddr & PA_IMPL_MASK;
+ } else {
+ // not a physical address: need to look up pte
+
+ AlphaISA::PTE *pte = lookup(VA_VPN(req->vaddr),
+ DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]));
+
+ if (!pte) {
+ fault(req->vaddr, req->xc);
+ misses++;
+ return Itb_Fault_Fault;
+ }
+
+ req->paddr = PA_PFN2PA(pte->ppn) + VA_POFS(req->vaddr & ~3);
+
+ // check permissions for this access
+ if (!(pte->xre & (1 << ICM_CM(ipr[AlphaISA::IPR_ICM])))) {
+ // instruction access fault
+ fault(req->vaddr, req->xc);
+ acv++;
+ return Itb_Acv_Fault;
+ }
+ }
+
+ checkCacheability(req);
+
+ hits++;
+ return No_Fault;
+}
+
+///////////////////////////////////////////////////////////////////////
+//
+// 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;
+}
+
+void
+AlphaDtb::fault(Addr vaddr, uint64_t flags, ExecContext *xc) const
+{
+ uint64_t *ipr = xc->regs.ipr;
+
+ // set fault address and flags
+ if (!xc->misspeculating() && !xc->regs.intrlock) {
+ // set VA register with faulting address
+ ipr[AlphaISA::IPR_VA] = vaddr;
+
+ // set MM_STAT register flags
+ ipr[AlphaISA::IPR_MM_STAT] = (((xc->regs.opcode & 0x3f) << 11)
+ | ((xc->regs.ra & 0x1f) << 6)
+ | (flags & 0x3f));
+
+ // set VA_FORM register with faulting formatted address
+ ipr[AlphaISA::IPR_VA_FORM] =
+ ipr[AlphaISA::IPR_MVPTBR] | (VA_VPN(vaddr) << 3);
+
+ // lock these registers until the VA register is read
+ xc->regs.intrlock = true;
+ }
+}
+
+Fault
+AlphaDtb::translate(MemReqPtr req, bool write) const
+{
+ RegFile *regs = &req->xc->regs;
+ Addr pc = regs->pc;
+ InternalProcReg *ipr = regs->ipr;
+
+ if (write)
+ write_accesses++;
+ else
+ read_accesses++;
+
+ AlphaISA::md_mode_type mode =
+ (AlphaISA::md_mode_type)DTB_CM_CM(ipr[AlphaISA::IPR_DTB_CM]);
+
+ if (PC_PAL(pc)) {
+ mode = (req->flags & ALTMODE) ? (AlphaISA::md_mode_type)
+ (ALT_MODE_AM(ipr[AlphaISA::IPR_ALT_MODE]))
+ : AlphaISA::mode_kernel;
+ }
+
+ // verify that this is a good virtual address
+ if (!validVirtualAddress(req->vaddr)) {
+ fault(req->vaddr,
+ ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_BAD_VA_MASK |
+ MM_STAT_ACV_MASK),
+ req->xc);
+
+ if (write) { write_acv++; } else { read_acv++; }
+ return Dtb_Fault_Fault;
+ }
+
+ // Check for "superpage" mapping: when SP<1> is set, and
+ // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13>.
+ if ((MCSR_SP(ipr[AlphaISA::IPR_MCSR]) & 2) && VA_SPACE(req->vaddr) == 2) {
+ // only valid in kernel mode
+ if (DTB_CM_CM(ipr[AlphaISA::IPR_DTB_CM]) != AlphaISA::mode_kernel) {
+ fault(req->vaddr,
+ ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_ACV_MASK),
+ req->xc);
+ if (write) { write_acv++; } else { read_acv++; }
+ return Dtb_Acv_Fault;
+ }
+
+ req->flags |= PHYSICAL;
+ }
+
+ if (req->flags & PHYSICAL) {
+ req->paddr = req->vaddr & PA_IMPL_MASK;
+ } else {
+ // not a physical address: need to look up pte
+
+ AlphaISA::PTE *pte = lookup(VA_VPN(req->vaddr),
+ DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]));
+
+ if (!pte) {
+ // page fault
+ fault(req->vaddr,
+ ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_DTB_MISS_MASK),
+ req->xc);
+ if (write) { write_misses++; } else { read_misses++; }
+ return (req->flags & VPTE) ? Pdtb_Miss_Fault : Ndtb_Miss_Fault;
+ }
+
+ req->paddr = PA_PFN2PA(pte->ppn) | VA_POFS(req->vaddr);
+
+ if (write) {
+ if (!(pte->xwe & MODE2MASK(mode))) {
+ // declare the instruction access fault
+ fault(req->vaddr, MM_STAT_WR_MASK | MM_STAT_ACV_MASK |
+ (pte->fonw ? MM_STAT_FONW_MASK : 0),
+ req->xc);
+ write_acv++;
+ return Dtb_Fault_Fault;
+ }
+ if (pte->fonw) {
+ fault(req->vaddr, MM_STAT_WR_MASK | MM_STAT_FONW_MASK,
+ req->xc);
+ write_acv++;
+ return Dtb_Fault_Fault;
+ }
+ } else {
+ if (!(pte->xre & MODE2MASK(mode))) {
+ fault(req->vaddr,
+ MM_STAT_ACV_MASK | (pte->fonr ? MM_STAT_FONR_MASK : 0),
+ req->xc);
+ read_acv++;
+ return Dtb_Acv_Fault;
+ }
+ if (pte->fonr) {
+ fault(req->vaddr, MM_STAT_FONR_MASK, req->xc);
+ read_acv++;
+ return Dtb_Fault_Fault;
+ }
+ }
+ }
+
+ checkCacheability(req);
+
+ if (write)
+ write_hits++;
+ else
+ read_hits++;
+
+ return No_Fault;
+}
+
+AlphaISA::PTE &
+AlphaTlb::index()
+{
+ AlphaISA::PTE *pte = &table[nlu];
+ nextnlu();
+
+ return *pte;
+}
+
+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/alpha_memory.hh b/arch/alpha/alpha_memory.hh
new file mode 100644
index 000000000..06fea32e4
--- /dev/null
+++ b/arch/alpha/alpha_memory.hh
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+#ifndef __ALPHA_MEMORY_HH__
+#define __ALPHA_MEMORY_HH__
+
+#include <map>
+
+#include "mem_req.hh"
+#include "sim_object.hh"
+#include "statistics.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();
+ 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 & VA_UNIMPL_MASK;
+ return (unimplBits == 0) || (unimplBits == VA_UNIMPL_MASK);
+ }
+
+ static void checkCacheability(MemReqPtr req);
+
+ // Checkpointing
+ virtual void serialize();
+ virtual void unserialize(IniFile &db, const std::string &category,
+ ConfigNode *node);
+
+};
+
+class AlphaItb : public AlphaTlb
+{
+ protected:
+ mutable Statistics::Scalar<> hits;
+ mutable Statistics::Scalar<> misses;
+ mutable Statistics::Scalar<> acv;
+ mutable Statistics::Formula accesses;
+
+ protected:
+ void fault(Addr pc, ExecContext *xc) const;
+
+ public:
+ AlphaItb(const std::string &name, int size);
+ virtual void regStats();
+
+ Fault translate(MemReqPtr req) const;
+};
+
+class AlphaDtb : public AlphaTlb
+{
+ protected:
+ mutable Statistics::Scalar<> read_hits;
+ mutable Statistics::Scalar<> read_misses;
+ mutable Statistics::Scalar<> read_acv;
+ mutable Statistics::Scalar<> read_accesses;
+ mutable Statistics::Scalar<> write_hits;
+ mutable Statistics::Scalar<> write_misses;
+ mutable Statistics::Scalar<> write_acv;
+ mutable Statistics::Scalar<> write_accesses;
+ Statistics::Formula hits;
+ Statistics::Formula misses;
+ Statistics::Formula acv;
+ Statistics::Formula accesses;
+
+ protected:
+ void fault(Addr pc, uint64_t flags, ExecContext *xc) const;
+
+ 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/arguments.cc b/arch/alpha/arguments.cc
new file mode 100644
index 000000000..91e0576f5
--- /dev/null
+++ b/arch/alpha/arguments.cc
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#include "arguments.hh"
+#include "exec_context.hh"
+#include "physical_memory.hh"
+#include "vtophys.hh"
+
+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->regs.floatRegFile.q[16 + number];
+ else
+ return xc->regs.intRegFile[16 + number];
+ } else {
+ Addr sp = xc->regs.intRegFile[30];
+ Addr paddr = vtophys(xc, sp + (number-6) * sizeof(uint64_t));
+ return xc->physmem->phys_read_qword(paddr);
+ }
+}
+
diff --git a/arch/alpha/arguments.hh b/arch/alpha/arguments.hh
new file mode 100644
index 000000000..c5fdb60ad
--- /dev/null
+++ b/arch/alpha/arguments.hh
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+#ifndef __ARGUMENTS_HH__
+#define __ARGUMENTS_HH__
+
+#include <assert.h>
+
+#include "host.hh"
+#include "kernel.hh"
+#include "refcnt.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));
+ Kernel::CopyData(xc, buf, getArg(), sizeof(T));
+ return buf;
+ }
+
+ operator char *() {
+ char *buf = data->alloc(2048);
+ Kernel::CopyString(xc, buf, getArg(), 2048);
+ return buf;
+ }
+};
+
+#endif // __ARGUMENTS_HH__
diff --git a/arch/alpha/ev5.cc b/arch/alpha/ev5.cc
new file mode 100644
index 000000000..c1631872a
--- /dev/null
+++ b/arch/alpha/ev5.cc
@@ -0,0 +1,571 @@
+/* $Id$ */
+
+#include "alpha_memory.hh"
+#include "annotation.hh"
+#ifdef DEBUG
+#include "debug.hh"
+#endif
+#include "exec_context.hh"
+#include "sim_events.hh"
+#include "isa_traits.hh"
+#include "remote_gdb.hh"
+#include "kgdb.h" // for ALPHA_KENTRY_IF
+#include "osfpal.hh"
+
+#ifdef FULL_SYSTEM
+
+#ifndef SYSTEM_EV5
+#error This code is only valid for EV5 systems
+#endif
+
+////////////////////////////////////////////////////////////////////////
+//
+//
+//
+void
+AlphaISA::swap_palshadow(RegFile *regs, bool use_shadow)
+{
+ if (regs->pal_shadow == use_shadow)
+ panic("swap_palshadow: wrong PAL shadow state");
+
+ regs->pal_shadow = use_shadow;
+
+ for (int i = 0; i < NumIntRegs; i++) {
+ if (reg_redir[i]) {
+ IntReg temp = regs->intRegFile[i];
+ regs->intRegFile[i] = regs->palregs[i];
+ regs->palregs[i] = temp;
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// Machine dependent functions
+//
+void
+AlphaISA::init(void *mem, RegFile *regs)
+{
+ ipr_init(mem, regs);
+}
+
+void
+m5_exit()
+{
+ static SimExitEvent event("m5_exit instruction encountered");
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// alpha exceptions - value equals trap address, update with MD_FAULT_TYPE
+//
+Addr
+AlphaISA::fault_addr[Num_Faults] = {
+ 0x0000, /* No_Fault */
+ 0x0001, /* Reset_Fault */
+ 0x0401, /* Machine_Check_Fault */
+ 0x0501, /* Arithmetic_Fault */
+ 0x0101, /* Interrupt_Fault */
+ 0x0201, /* Ndtb_Miss_Fault */
+ 0x0281, /* Pdtb_Miss_Fault */
+ 0x0301, /* Alignment_Fault */
+ 0x0381, /* Dtb_Fault_Fault */
+ 0x0381, /* Dtb_Acv_Fault */
+ 0x0181, /* Itb_Miss_Fault */
+ 0x0181, /* Itb_Fault_Fault */
+ 0x0081, /* Itb_Acv_Fault */
+ 0x0481, /* Unimplemented_Opcode_Fault */
+ 0x0581, /* Fen_Fault */
+ 0x2001, /* Pal_Fault */
+ 0x0501, /* Integer_Overflow_Fault: maps to Arithmetic_Fault */
+};
+
+const int AlphaISA::reg_redir[AlphaISA::NumIntRegs] = {
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 1, 1, 1, 1, 1, 1, 1, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 1, 0, 0, 0, 0, 0, 0 };
+
+////////////////////////////////////////////////////////////////////////
+//
+//
+//
+void
+AlphaISA::ipr_init(void *mem, RegFile *regs)
+{
+ uint64_t *ipr = regs->ipr;
+
+ bzero((char *)ipr, NumInternalProcRegs * sizeof(InternalProcReg));
+ ipr[IPR_PAL_BASE] = PAL_BASE;
+}
+
+
+void
+ExecContext::ev5_trap(Fault fault)
+{
+ assert(!misspeculating());
+ kernelStats.fault(fault);
+
+ if (fault == Arithmetic_Fault)
+ panic("Arithmetic traps are unimplemented!");
+
+ AlphaISA::InternalProcReg *ipr = regs.ipr;
+
+ // exception restart address
+ if (fault != Interrupt_Fault || !PC_PAL(regs.pc))
+ ipr[AlphaISA::IPR_EXC_ADDR] = regs.pc;
+
+ if (fault == Pal_Fault || fault == Arithmetic_Fault /* ||
+ fault == Interrupt_Fault && !PC_PAL(regs.pc) */) {
+ // traps... skip faulting instruction
+ ipr[AlphaISA::IPR_EXC_ADDR] += 4;
+ }
+
+ if (!PC_PAL(regs.pc))
+ AlphaISA::swap_palshadow(&regs, true);
+
+ regs.pc = ipr[AlphaISA::IPR_PAL_BASE] + AlphaISA::fault_addr[fault];
+ regs.npc = regs.pc + sizeof(MachInst);
+
+ Annotate::Ev5Trap(this, fault);
+}
+
+
+void
+AlphaISA::intr_post(RegFile *regs, Fault fault, Addr pc)
+{
+ InternalProcReg *ipr = regs->ipr;
+ bool use_pc = (fault == No_Fault);
+
+ if (fault == Arithmetic_Fault)
+ panic("arithmetic faults NYI...");
+
+ // compute exception restart address
+ if (use_pc || fault == Pal_Fault || fault == Arithmetic_Fault) {
+ // traps... skip faulting instruction
+ ipr[IPR_EXC_ADDR] = regs->pc + 4;
+ } else {
+ // fault, post fault at excepting instruction
+ ipr[IPR_EXC_ADDR] = regs->pc;
+ }
+
+ // jump to expection address (PAL PC bit set here as well...)
+ if (!use_pc)
+ regs->npc = ipr[IPR_PAL_BASE] + fault_addr[fault];
+ else
+ regs->npc = ipr[IPR_PAL_BASE] + pc;
+
+ // that's it! (orders of magnitude less painful than x86)
+}
+
+bool AlphaISA::check_interrupts = false;
+
+Fault
+ExecContext::hwrei()
+{
+ uint64_t *ipr = regs.ipr;
+
+ if (!PC_PAL(regs.pc))
+ return Unimplemented_Opcode_Fault;
+
+ kernelStats.hwrei();
+
+ regs.npc = ipr[AlphaISA::IPR_EXC_ADDR];
+
+ if (!misspeculating()) {
+ if ((ipr[AlphaISA::IPR_EXC_ADDR] & 1) == 0)
+ AlphaISA::swap_palshadow(&regs, false);
+
+ AlphaISA::check_interrupts = true;
+ }
+
+ // FIXME: XXX check for interrupts? XXX
+ return No_Fault;
+}
+
+uint64_t
+ExecContext::readIpr(int idx, Fault &fault)
+{
+ uint64_t *ipr = regs.ipr;
+ 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_VA:
+ // SFX: unlocks interrupt status registers
+ retval = ipr[idx];
+ regs.intrlock = false;
+ 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 = dtb->index();
+
+ 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 = Unimplemented_Opcode_Fault;
+ break;
+
+ default:
+ // invalid IPR
+ fault = Unimplemented_Opcode_Fault;
+ break;
+ }
+
+ return retval;
+}
+
+#ifdef DEBUG
+// Cause the simulator to break when changing to the following IPL
+int break_ipl = -1;
+#endif
+
+Fault
+ExecContext::setIpr(int idx, uint64_t val)
+{
+ uint64_t *ipr = regs.ipr;
+
+ if (misspeculating())
+ return No_Fault;
+
+ 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_CC_CTL:
+ case AlphaISA::IPR_CC:
+ case AlphaISA::IPR_PMCTR:
+ // write entire quad w/ no side-effect
+ ipr[idx] = val;
+ break;
+
+ case AlphaISA::IPR_PALtemp23:
+ // write entire quad w/ no side-effect
+ ipr[idx] = val;
+ kernelStats.context(ipr[idx]);
+ Annotate::Context(this);
+ 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;
+ kernelStats.swpipl(ipr[idx]);
+ Annotate::IPL(this, val & 0x1f);
+ break;
+
+ case AlphaISA::IPR_DTB_CM:
+ Annotate::ChangeMode(this, (val & 0x18) != 0);
+ kernelStats.mode((val & 0x18) != 0);
+
+ 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 Unimplemented_Opcode_Fault;
+
+ 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;
+
+ dtb->flushAll();
+ break;
+
+ case AlphaISA::IPR_DTB_IAP:
+ // really a control write
+ ipr[idx] = 0;
+
+ dtb->flushProcesses();
+ break;
+
+ case AlphaISA::IPR_DTB_IS:
+ // really a control write
+ ipr[idx] = val;
+
+ dtb->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
+ dtb->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
+ itb->insert(ipr[AlphaISA::IPR_ITB_TAG], pte);
+ }
+ break;
+
+ case AlphaISA::IPR_ITB_IA:
+ // really a control write
+ ipr[idx] = 0;
+
+ itb->flushAll();
+ break;
+
+ case AlphaISA::IPR_ITB_IAP:
+ // really a control write
+ ipr[idx] = 0;
+
+ itb->flushProcesses();
+ break;
+
+ case AlphaISA::IPR_ITB_IS:
+ // really a control write
+ ipr[idx] = val;
+
+ itb->flushAddr(val, ITB_ASN_ASN(ipr[AlphaISA::IPR_ITB_ASN]));
+ break;
+
+ default:
+ // invalid IPR
+ return Unimplemented_Opcode_Fault;
+ }
+
+ // no error...
+ return No_Fault;
+}
+
+/**
+ * Check for special simulator handling of specific PAL calls.
+ * If return value is false, actual PAL call will be suppressed.
+ */
+bool
+ExecContext::simPalCheck(int palFunc)
+{
+ kernelStats.callpal(palFunc);
+
+ switch (palFunc) {
+ case PAL::halt:
+ if (!misspeculating()) {
+ setStatus(Halted);
+ if (--System::numSystemsRunning == 0)
+ new SimExitEvent("all cpus halted");
+ }
+ break;
+
+ case PAL::bpt:
+ case PAL::bugchk:
+ if (system->remoteGDB->trap(ALPHA_KENTRY_IF))
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+#endif // FULL_SYSTEM
diff --git a/arch/alpha/ev5.hh b/arch/alpha/ev5.hh
new file mode 100644
index 000000000..c3330bc01
--- /dev/null
+++ b/arch/alpha/ev5.hh
@@ -0,0 +1,104 @@
+/* $Id$ */
+
+#ifndef __EV5_H__
+#define __EV5_H__
+
+#ifndef SYSTEM_EV5
+#error This code is only valid for EV5 systems
+#endif
+
+#include "isa_traits.hh"
+
+void m5_exit();
+
+////////////////////////////////////////////////////////////////////////
+//
+//
+//
+
+////////////////////////////////////////////////////////////////////////
+//
+//
+//
+
+#define MODE2MASK(X) (1 << (X))
+
+// Alpha IPR register accessors
+#define PC_PAL(X) ((X) & 0x1)
+#define MCSR_SP(X) (((X) >> 1) & 0x3)
+
+#define ICSR_SDE(X) (((X) >> 30) & 0x1)
+#define ICSR_SPE(X) (((X) >> 28) & 0x3)
+#define ICSR_FPE(X) (((X) >> 26) & 0x1)
+
+#define ALT_MODE_AM(X) (((X) >> 3) & 0x3)
+
+#define DTB_CM_CM(X) (((X) >> 3) & 0x3)
+#define DTB_ASN_ASN(X) (((X) >> 57) & 0x7f)
+#define DTB_PTE_PPN(X) (((X) >> 32) & 0x07ffffff)
+#define DTB_PTE_XRE(X) (((X) >> 8) & 0xf)
+#define DTB_PTE_XWE(X) (((X) >> 12) & 0xf)
+#define DTB_PTE_FONR(X) (((X) >> 1) & 0x1)
+#define DTB_PTE_FONW(X) (((X) >> 2) & 0x1)
+#define DTB_PTE_GH(X) (((X) >> 5) & 0x3)
+#define DTB_PTE_ASMA(X) (((X) >> 4) & 0x1)
+
+#define ICM_CM(X) (((X) >> 3) & 0x3)
+#define ITB_ASN_ASN(X) (((X) >> 4) & 0x7f)
+#define ITB_PTE_PPN(X) (((X) >> 32) & 0x07ffffff)
+#define ITB_PTE_XRE(X) (((X) >> 8) & 0xf)
+#define ITB_PTE_FONR(X) (((X) >> 1) & 0x1)
+#define ITB_PTE_FONW(X) (((X) >> 2) & 0x1)
+#define ITB_PTE_GH(X) (((X) >> 5) & 0x3)
+#define ITB_PTE_ASMA(X) (((X) >> 4) & 0x1)
+
+#define VA_UNIMPL_MASK ULL(0xfffff80000000000)
+#define VA_IMPL_MASK ULL(0x000007ffffffffff)
+#define VA_IMPL(X) ((X) & VA_IMPL_MASK)
+#define VA_VPN(X) (VA_IMPL(X) >> 13)
+#define VA_SPACE(X) (((X) >> 41) & 0x3)
+#define VA_POFS(X) ((X) & 0x1fff)
+
+#define PA_IMPL_MASK ULL(0xffffffffff)
+#define PA_UNCACHED_BIT ULL(0x8000000000)
+#define PA_IPR_SPACE(X) ((X) >= ULL(0xFFFFF00000))
+
+#define PA_PFN2PA(X) ((X) << 13)
+
+
+#define MM_STAT_BAD_VA_MASK 0x0020
+#define MM_STAT_DTB_MISS_MASK 0x0010
+#define MM_STAT_FONW_MASK 0x0008
+#define MM_STAT_FONR_MASK 0x0004
+#define MM_STAT_ACV_MASK 0x0002
+#define MM_STAT_WR_MASK 0x0001
+
+
+////////////////////////////////////////////////////////////////////////
+//
+//
+//
+
+// VPTE size for HW_LD/HW_ST
+#define HW_VPTE ((inst >> 11) & 0x1)
+
+// QWORD size for HW_LD/HW_ST
+#define HW_QWORD ((inst >> 12) & 0x1)
+
+// ALT mode for HW_LD/HW_ST
+#define HW_ALT (((inst >> 14) & 0x1) ? ALTMODE : 0)
+
+// LOCK/COND mode for HW_LD/HW_ST
+#define HW_LOCK (((inst >> 10) & 0x1) ? LOCKED : 0)
+#define HW_COND (((inst >> 10) & 0x1) ? LOCKED : 0)
+
+// PHY size for HW_LD/HW_ST
+#define HW_PHY (((inst >> 15) & 0x1) ? PHYSICAL : 0)
+
+// OFFSET for HW_LD/HW_ST
+#define HW_OFS (inst & 0x3ff)
+
+
+#define PAL_BASE 0x4000
+
+#endif //__EV5_H__
diff --git a/arch/alpha/fake_syscall.cc b/arch/alpha/fake_syscall.cc
new file mode 100644
index 000000000..ad3c86515
--- /dev/null
+++ b/arch/alpha/fake_syscall.cc
@@ -0,0 +1,1736 @@
+/*
+ * 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.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h> // for memset()
+
+#include "host.hh"
+#include "base_cpu.hh"
+#include "functional_memory.hh"
+#include "prog.hh"
+#include "exec_context.hh"
+#include "fake_syscall.hh"
+#include "sim_events.hh"
+
+#include "osf_syscalls.h"
+#include "universe.hh" // for curTick & ticksPerSecond
+
+#include "trace.hh"
+
+using namespace std;
+
+//
+// System call descriptor
+//
+class SyscallDesc {
+
+ public:
+
+ typedef int (*FuncPtr)(SyscallDesc *, int num,
+ Process *, ExecContext *);
+
+ const char *name;
+ FuncPtr funcPtr;
+ int flags;
+
+ SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0)
+ : name(_name), funcPtr(_funcPtr), flags(_flags)
+ {}
+
+ int doFunc(int num, Process *proc, ExecContext *xc) {
+ return (*funcPtr)(this, num, proc, 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]; }
+};
+
+
+static IntReg
+getArg(ExecContext *xc, int i)
+{
+ return xc->regs.intRegFile[ArgumentReg0 + i];
+}
+
+
+//
+// used to shift args for indirect syscall
+//
+static void
+setArg(ExecContext *xc, int i, IntReg val)
+{
+ xc->regs.intRegFile[ArgumentReg0 + i] = val;
+}
+
+
+static void
+set_return_value(ExecContext *xc, IntReg return_value)
+{
+ // 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).
+ const int RegA3 = 19; // only place this is used
+ if (return_value >= 0) {
+ // no error
+ xc->regs.intRegFile[RegA3] = 0;
+ xc->regs.intRegFile[ReturnValueReg] = return_value;
+ } else {
+ // got an error, return details
+ xc->regs.intRegFile[RegA3] = (IntReg) -1;
+ xc->regs.intRegFile[ReturnValueReg] = -return_value;
+ }
+}
+
+
+int
+getpagesizeFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ return VMPageSize;
+}
+
+
+int
+obreakFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ // change brk addr to first arg
+ process->brk_point = getArg(xc, 0);
+ return process->brk_point;
+}
+
+
+int
+ioctlFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int fd = process->sim_fd(getArg(xc, 0));
+ unsigned req = getArg(xc, 1);
+
+ switch (req) {
+ case OSF::TIOCGETP: {
+ // get tty parameters: the main use of this call is by
+ // isatty(), which really just wants to see whether it
+ // succeeds or returns ENOTTY to determine whether this is
+ // a terminal or not. This call is in turn used by the
+ // stdio library to determine whether to do line buffering
+ // or block buffering on a specific file descriptor.
+ TypedBufferArg<OSF::sgttyb> buf(getArg(xc, 2));
+
+ if (fd < 0) {
+ // bad file descriptor
+ return -EBADF;
+ } else if (0 <= fd < 3) {
+ // stdin/stdout/stderr: make it look like a terminal
+ // so we get line buffering & not block buffering
+ buf->sg_ispeed = 0xf;
+ buf->sg_ospeed = 0xf;
+ buf->sg_erase = 0x7f;
+ buf->sg_kill = 0x15;
+ buf->sg_flags = 0x18;
+ buf.copyOut(xc->mem);
+ return 0;
+ } else {
+ // any other file descriptor: assume it's a file or
+ // pipe and not a terminal
+ return -ENOTTY;
+ }
+ break;
+ }
+
+ case OSF::TIOCISATTY:
+ if (fd < 0) {
+ // bad file descriptor
+ return -EBADF;
+ } else if (0 <= fd < 3) {
+ // stdin/stdout/stderr: make it look like a terminal
+ // so we get line buffering & not block buffering
+ return 0;
+ } else {
+ // any other file descriptor: assume it's a file or
+ // pipe and not a terminal
+ return -ENOTTY;
+ }
+ break;
+
+ default:
+ cerr << "Unsupported ioctl call: ioctl("
+ << fd << ", " << req << ", ...)" << endl;
+ abort();
+ break;
+ }
+}
+
+
+int
+openFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ string path;
+
+ if (xc->mem->readString(path, getArg(xc, 0)) != No_Fault)
+ 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.
+ DCOUT(SyscallWarnings) << "Ignoring open(" << path << ", ...)" << endl;
+ return -ENOENT;
+ }
+
+ int osfFlags = getArg(xc, 1);
+ int mode = getArg(xc, 2);
+ int hostFlags = 0;
+
+ // translate open flags
+ for (int i = 0; i < OSF::NUM_OPEN_FLAGS; i++) {
+ if (osfFlags & OSF::openFlagTable[i].osfFlag) {
+ osfFlags &= ~OSF::openFlagTable[i].osfFlag;
+ hostFlags |= OSF::openFlagTable[i].hostFlag;
+ }
+ }
+
+ // any target flags left?
+ if (osfFlags != 0)
+ cerr << "Syscall: open: cannot decode flags: " << osfFlags << endl;
+
+#ifdef __CYGWIN32__
+ hostFlags |= O_BINARY;
+#endif
+
+ // open the file
+ int fd = open(path.c_str(), hostFlags, mode);
+
+ return (fd == -1) ? -errno : process->open_fd(fd);
+}
+
+
+int
+closeFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int fd = process->sim_fd(getArg(xc, 0));
+ return close(fd);
+}
+
+
+int
+readFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int fd = process->sim_fd(getArg(xc, 0));
+ int nbytes = getArg(xc, 2);
+ BufferArg bufArg(getArg(xc, 1), nbytes);
+
+ int bytes_read = read(fd, bufArg.bufferPtr(), nbytes);
+
+ if (bytes_read != -1)
+ bufArg.copyOut(xc->mem);
+
+ return bytes_read;
+}
+
+int
+writeFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int fd = process->sim_fd(getArg(xc, 0));
+ int nbytes = getArg(xc, 2);
+ BufferArg bufArg(getArg(xc, 1), nbytes);
+
+ bufArg.copyIn(xc->mem);
+
+ int bytes_written = write(fd, bufArg.bufferPtr(), nbytes);
+
+ fsync(fd);
+
+ return bytes_written;
+}
+
+
+int
+lseekFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int fd = process->sim_fd(getArg(xc, 0));
+ uint64_t offs = getArg(xc, 1);
+ int whence = getArg(xc, 2);
+
+ off_t result = lseek(fd, offs, whence);
+
+ return (result == (off_t)-1) ? -errno : result;
+}
+
+static
+void
+copyOutStatBuf(FunctionalMemory *mem, Addr addr, struct stat *host)
+{
+ TypedBufferArg<OSF::F64_stat> tgt(addr);
+
+ tgt->st_dev = host->st_dev;
+ tgt->st_ino = host->st_ino;
+ tgt->st_mode = host->st_mode;
+ tgt->st_nlink = host->st_nlink;
+ tgt->st_uid = host->st_uid;
+ tgt->st_gid = host->st_gid;
+ tgt->st_rdev = host->st_rdev;
+ tgt->st_size = host->st_size;
+ tgt->st_atimeX = host->st_atime;
+ tgt->st_mtimeX = host->st_mtime;
+ tgt->st_ctimeX = host->st_ctime;
+ tgt->st_blksize = host->st_blksize;
+ tgt->st_blocks = host->st_blocks;
+
+ tgt.copyOut(mem);
+}
+
+int
+statFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ string path;
+
+ if (xc->mem->readString(path, getArg(xc, 0)) != No_Fault)
+ return -EFAULT;
+
+ struct stat hostBuf;
+ int result = stat(path.c_str(), &hostBuf);
+
+ if (result < 0)
+ return -errno;
+
+ copyOutStatBuf(xc->mem, getArg(xc, 1), &hostBuf);
+
+ return 0;
+}
+
+
+int
+lstatFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ string path;
+
+ if (xc->mem->readString(path, getArg(xc, 0)) != No_Fault)
+ return -EFAULT;
+
+ struct stat hostBuf;
+ int result = lstat(path.c_str(), &hostBuf);
+
+ if (result < 0)
+ return -errno;
+
+ copyOutStatBuf(xc->mem, getArg(xc, 1), &hostBuf);
+
+ return 0;
+}
+
+int
+fstatFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int fd = process->sim_fd(getArg(xc, 0));
+
+ if (fd < 0)
+ return -EBADF;
+
+ struct stat hostBuf;
+ int result = fstat(fd, &hostBuf);
+
+ if (result < 0)
+ return -errno;
+
+ copyOutStatBuf(xc->mem, getArg(xc, 1), &hostBuf);
+
+ return 0;
+}
+
+
+//
+// We don't handle mmap(). If the target is really mmaping /dev/zero,
+// we can get away with doing nothing (since 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 an mmap to anything else.
+//
+int
+mmapFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ Addr start = getArg(xc, 0);
+ uint64_t length = getArg(xc, 1);
+ int prot = getArg(xc, 2);
+ int flags = getArg(xc, 3);
+ int fd = process->sim_fd(getArg(xc, 4));
+ int offset = getArg(xc, 5);
+
+ cerr << "Warning: ignoring syscall mmap("
+ << start << ", " << length << ", "
+ << prot << ", " << flags << ", "
+ << fd << " " << getArg(xc, 4) << ", "
+ << offset << ")" << endl;
+
+ return start;
+}
+
+
+const char *hostname = "m5.eecs.umich.edu";
+
+int
+unameFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ TypedBufferArg<OSF::utsname> name(getArg(xc, 0));
+
+ strcpy(name->sysname, "OSF1");
+ strcpy(name->nodename, hostname);
+ strcpy(name->release, "V5.1");
+ strcpy(name->version, "732");
+ strcpy(name->machine, "alpha");
+
+ name.copyOut(xc->mem);
+ return 0;
+}
+
+
+int
+gethostnameFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int name_len = getArg(xc, 1);
+ BufferArg name(getArg(xc, 0), name_len);
+
+ strncpy((char *)name.bufferPtr(), hostname, name_len);
+
+ name.copyOut(xc->mem);
+
+ return 0;
+}
+
+
+int
+getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ unsigned op = getArg(xc, 0);
+ unsigned nbytes = getArg(xc, 2);
+
+ switch (op) {
+
+ case OSF::GSI_MAX_CPU: {
+ TypedBufferArg<uint32_t> max_cpu(getArg(xc, 1));
+ *max_cpu = process->numCpus;
+ max_cpu.copyOut(xc->mem);
+ return 1;
+ }
+
+ case OSF::GSI_CPUS_IN_BOX: {
+ TypedBufferArg<uint32_t> cpus_in_box(getArg(xc, 1));
+ *cpus_in_box = process->numCpus;
+ cpus_in_box.copyOut(xc->mem);
+ return 1;
+ }
+
+ case OSF::GSI_PHYSMEM: {
+ TypedBufferArg<uint64_t> physmem(getArg(xc, 1));
+ *physmem = 1024 * 1024; // physical memory in KB
+ physmem.copyOut(xc->mem);
+ return 1;
+ }
+
+ case OSF::GSI_CPU_INFO: {
+ TypedBufferArg<OSF::cpu_info> infop(getArg(xc, 1));
+
+ infop->current_cpu = 0;
+ infop->cpus_in_box = process->numCpus;
+ infop->cpu_type = 57;
+ infop->ncpus = process->numCpus;
+ int cpumask = (1 << process->numCpus) - 1;
+ infop->cpus_present = infop->cpus_running = cpumask;
+ infop->cpu_binding = 0;
+ infop->cpu_ex_binding = 0;
+ infop->mhz = 667;
+
+ infop.copyOut(xc->mem);
+ return 1;
+ }
+
+ case OSF::GSI_PROC_TYPE: {
+ TypedBufferArg<uint64_t> proc_type(getArg(xc, 1));
+ *proc_type = 11;
+ proc_type.copyOut(xc->mem);
+ return 1;
+ }
+
+ case OSF::GSI_PLATFORM_NAME: {
+ BufferArg bufArg(getArg(xc, 1), nbytes);
+ strncpy((char *)bufArg.bufferPtr(),
+ "COMPAQ Professional Workstation XP1000",
+ nbytes);
+ bufArg.copyOut(xc->mem);
+ return 1;
+ }
+
+ case OSF::GSI_CLK_TCK: {
+ TypedBufferArg<uint64_t> clk_hz(getArg(xc, 1));
+ *clk_hz = 1024;
+ clk_hz.copyOut(xc->mem);
+ return 1;
+ }
+
+ default:
+ cerr << "getsysinfo: unknown op " << op << endl;
+ abort();
+ break;
+ }
+
+ return 0;
+}
+
+int
+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.
+ return 100;
+}
+
+int
+getuidFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ // Make up a UID.
+ return 100;
+}
+
+int
+getrlimitFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ unsigned resource = getArg(xc, 0);
+ TypedBufferArg<OSF::rlimit> rlp(getArg(xc, 1));
+
+ switch (resource) {
+ case OSF::RLIMIT_STACK:
+ // max stack size in bytes: make up a number (2MB for now)
+ rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
+ break;
+
+ default:
+ cerr << "getrlimitFunc: unimplemented resource " << resource << endl;
+ abort();
+ break;
+ }
+
+ rlp.copyOut(xc->mem);
+ return 0;
+}
+
+// 1M usecs in 1 sec, for readability
+static const int one_million = 1000000;
+
+// seconds since the epoch (1/1/1970)... about a billion, by my reckoning
+static const unsigned seconds_since_epoch = 1000000000;
+
+//
+// helper function: populate struct timeval with approximation of
+// current elapsed time
+//
+static void
+getElapsedTime(OSF::timeval *tp)
+{
+ int cycles_per_usec = ticksPerSecond / one_million;
+
+ int elapsed_usecs = curTick / cycles_per_usec;
+ tp->tv_sec = elapsed_usecs / one_million;
+ tp->tv_usec = elapsed_usecs % one_million;
+}
+
+
+int
+gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ TypedBufferArg<OSF::timeval> tp(getArg(xc, 0));
+
+ getElapsedTime(tp);
+ tp->tv_sec += seconds_since_epoch;
+
+ tp.copyOut(xc->mem);
+
+ return 0;
+}
+
+
+int
+getrusageFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int who = getArg(xc, 0); // THREAD, SELF, or CHILDREN
+ TypedBufferArg<OSF::rusage> rup(getArg(xc, 1));
+
+ if (who != OSF::RUSAGE_SELF) {
+ // don't really handle THREAD or CHILDREN, but just warn and
+ // plow ahead
+ DCOUT(SyscallWarnings)
+ << "Warning: getrusage() only supports RUSAGE_SELF."
+ << " Parameter " << who << " ignored." << endl;
+ }
+
+ getElapsedTime(&rup->ru_utime);
+ 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->mem);
+
+ return 0;
+}
+
+
+int
+sigreturnFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ RegFile *regs = &xc->regs;
+ TypedBufferArg<OSF::sigcontext> sc(getArg(xc, 0));
+
+ sc.copyIn(xc->mem);
+
+ // restore state from sigcontext structure
+ regs->pc = sc->sc_pc;
+ regs->npc = regs->pc + sizeof(MachInst);
+
+ for (int i = 0; i < 31; ++i) {
+ regs->intRegFile[i] = sc->sc_regs[i];
+ regs->floatRegFile.q[i] = sc->sc_fpregs[i];
+ }
+
+ regs->miscRegs.fpcr = sc->sc_fpcr;
+
+ return 0;
+}
+
+int
+tableFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int id = getArg(xc, 0); // table ID
+ int index = getArg(xc, 1); // index into table
+ // arg 2 is buffer pointer; type depends on table ID
+ int nel = getArg(xc, 3); // number of elements
+ int lel = getArg(xc, 4); // expected element size
+
+ switch (id) {
+ case OSF::TBL_SYSINFO: {
+ if (index != 0 || nel != 1 || lel != sizeof(OSF::tbl_sysinfo))
+ return -EINVAL;
+ TypedBufferArg<OSF::tbl_sysinfo> elp(getArg(xc, 2));
+
+ const int clk_hz = one_million;
+ elp->si_user = curTick / (ticksPerSecond / clk_hz);
+ elp->si_nice = 0;
+ elp->si_sys = 0;
+ elp->si_idle = 0;
+ elp->wait = 0;
+ elp->si_hz = clk_hz;
+ elp->si_phz = clk_hz;
+ elp->si_boottime = seconds_since_epoch; // seconds since epoch?
+ elp->si_max_procs = process->numCpus;
+ elp.copyOut(xc->mem);
+ return 0;
+ }
+
+ default:
+ cerr << "table(): id " << id << " unknown." << endl;
+ return -EINVAL;
+ }
+}
+
+//
+// forward declaration... defined below table
+//
+int
+indirectSyscallFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc);
+
+//
+// Handler for unimplemented syscalls that we haven't thought about.
+//
+int
+unimplementedFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ cerr << "Error: syscall " << desc->name
+ << " (#" << callnum << ") unimplemented.";
+ cerr << " Args: " << getArg(xc, 0) << ", " << getArg(xc, 1)
+ << ", ..." << endl;
+
+ abort();
+}
+
+
+//
+// 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.
+//
+int
+ignoreFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ DCOUT(SyscallWarnings) << "Warning: ignoring syscall " << desc->name
+ << "(" << getArg(xc, 0)
+ << ", " << getArg(xc, 1)
+ << ", ...)" << endl;
+
+ return 0;
+}
+
+
+int
+exitFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ new SimExitEvent("syscall caused exit", getArg(xc, 0) & 0xff);
+
+ return 1;
+}
+
+
+SyscallDesc syscallDescs[] = {
+ /* 0 */ SyscallDesc("syscall (#0)", indirectSyscallFunc),
+ /* 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", unimplementedFunc),
+ /* 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", getpidFunc),
+ /* 21 */ SyscallDesc("mount", unimplementedFunc),
+ /* 22 */ SyscallDesc("unmount", unimplementedFunc),
+ /* 23 */ SyscallDesc("setuid", unimplementedFunc),
+ /* 24 */ SyscallDesc("getuid", getuidFunc),
+ /* 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),
+ /* 46 */ SyscallDesc("obsolete osigaction", unimplementedFunc),
+ /* 47 */ SyscallDesc("getgid", unimplementedFunc),
+ /* 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),
+ /* 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", unimplementedFunc),
+ /* 68 */ SyscallDesc("pre_F64_lstat", unimplementedFunc),
+ /* 69 */ SyscallDesc("sbrk", unimplementedFunc),
+ /* 70 */ SyscallDesc("sstk", unimplementedFunc),
+ /* 71 */ SyscallDesc("mmap", mmapFunc),
+ /* 72 */ SyscallDesc("ovadvise", unimplementedFunc),
+ /* 73 */ SyscallDesc("munmap", unimplementedFunc),
+ /* 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", unimplementedFunc),
+ /* 92 */ SyscallDesc("fcntl", unimplementedFunc),
+ /* 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", sigreturnFunc),
+ /* 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),
+ /* 117 */ SyscallDesc("getrusage", getrusageFunc),
+ /* 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", unimplementedFunc),
+ /* 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("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),
+ /* 145 */ SyscallDesc("setrlimit", unimplementedFunc),
+ /* 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", unimplementedFunc),
+ /* 160 */ SyscallDesc("pre_F64_statfs", unimplementedFunc),
+ /* 161 */ SyscallDesc("pre_F64_fstatfs", unimplementedFunc),
+ /* 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),
+ /* 225 */ SyscallDesc("lstat", lstatFunc),
+ /* 226 */ SyscallDesc("fstat", fstatFunc),
+ /* 227 */ SyscallDesc("statfs", unimplementedFunc),
+ /* 228 */ SyscallDesc("fstatfs", unimplementedFunc),
+ /* 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", unimplementedFunc),
+ /* 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),
+};
+
+const int Num_Syscall_Descs = sizeof(syscallDescs) / sizeof(SyscallDesc);
+
+const int Max_Syscall_Desc = Num_Syscall_Descs - 1;
+
+//
+// Mach syscalls -- identified by negated syscall numbers
+//
+
+// Create a stack region for a thread.
+int
+stack_createFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ TypedBufferArg<OSF::vm_stack> argp(getArg(xc, 0));
+
+ argp.copyIn(xc->mem);
+
+ // if the user chose an address, just let them have it. Otherwise
+ // pick one for them.
+ if (argp->address == 0) {
+ argp->address = process->next_thread_stack_base;
+ int stack_size = (argp->rsize + argp->ysize + argp->gsize);
+ process->next_thread_stack_base -= stack_size;
+ argp.copyOut(xc->mem);
+ }
+
+ return 0;
+}
+
+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.
+//
+int
+nxm_task_initFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ TypedBufferArg<OSF::nxm_task_attr> attrp(getArg(xc, 0));
+ TypedBufferArg<Addr> configptr_ptr(getArg(xc, 1));
+
+ attrp.copyIn(xc->mem);
+
+ if (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 (attrp->flags != OSF::NXM_TASK_INIT_VP) {
+ cerr << "nxm_task_init: bad flag value " << attrp->flags
+ << " (expected " << OSF::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(OSF::nxm_config_info);
+ // next comes the per-cpu state vector
+ Addr slot_state_addr = cur_addr;
+ int slot_state_size = process->numCpus * sizeof(OSF::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(OSF::nxm_shared)
+ + (process->numCpus-1) * sizeof(OSF::nxm_sched_state));
+ cur_addr += rad_state_size;
+
+ // now initialize a config_info struct and copy it out to user space
+ TypedBufferArg<OSF::nxm_config_info> config(config_addr);
+
+ config->nxm_nslots_per_rad = process->numCpus;
+ config->nxm_nrads = 1; // only one RAD in our system!
+ config->nxm_slot_state = slot_state_addr;
+ config->nxm_rad[0] = rad_state_addr;
+
+ config.copyOut(xc->mem);
+
+ // initialize the slot_state array and copy it out
+ TypedBufferArg<OSF::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
+ slot_state[i] = (i == 0) ? OSF::NXM_SLOT_BOUND : OSF::NXM_SLOT_AVAIL;
+ }
+
+ slot_state.copyOut(xc->mem);
+
+ // 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<OSF::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) {
+ OSF::nxm_sched_state *ssp = &rad_state->nxm_ss[i];
+ ssp->nxm_u.sigmask = 0;
+ ssp->nxm_u.sig = 0;
+ ssp->nxm_u.flags = 0;
+ ssp->nxm_u.cancel_state = 0;
+ ssp->nxm_u.nxm_ssig = 0;
+ ssp->nxm_bits = 0;
+ ssp->nxm_quantum = attrp->nxm_quantum;
+ ssp->nxm_set_quantum = attrp->nxm_quantum;
+ ssp->nxm_sysevent = 0;
+
+ if (i == 0) {
+ uint64_t uniq = xc->regs.miscRegs.uniq;
+ ssp->nxm_u.pth_id = uniq + attrp->nxm_uniq_offset;
+ ssp->nxm_u.nxm_active = uniq | 1;
+ }
+ else {
+ ssp->nxm_u.pth_id = 0;
+ ssp->nxm_u.nxm_active = 0;
+ }
+ }
+
+ rad_state.copyOut(xc->mem);
+
+ //
+ // copy pointer to shared config area out to user
+ //
+ *configptr_ptr = config_addr;
+ configptr_ptr.copyOut(xc->mem);
+
+ return 0;
+}
+
+
+static void
+init_exec_context(ExecContext *ec,
+ OSF::nxm_thread_attr *attrp, uint64_t uniq_val)
+{
+ memset(&ec->regs, 0, sizeof(ec->regs));
+
+ ec->regs.intRegFile[ArgumentReg0] = attrp->registers.a0;
+ ec->regs.intRegFile[27/*t12*/] = attrp->registers.pc;
+ ec->regs.intRegFile[StackPointerReg] = attrp->registers.sp;
+ ec->regs.miscRegs.uniq = uniq_val;
+
+ ec->regs.pc = attrp->registers.pc;
+ ec->regs.npc = attrp->registers.pc + sizeof(MachInst);
+
+ ec->setStatus(ExecContext::Active);
+}
+
+int
+nxm_thread_createFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ TypedBufferArg<OSF::nxm_thread_attr> attrp(getArg(xc, 0));
+ TypedBufferArg<uint64_t> kidp(getArg(xc, 1));
+ int thread_index = getArg(xc, 2);
+
+ // get attribute args
+ attrp.copyIn(xc->mem);
+
+ if (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(OSF::nxm_shared) +
+ (process->numCpus-1) * sizeof(OSF::nxm_sched_state));
+
+ TypedBufferArg<OSF::nxm_shared> rad_state(0x14000,
+ rad_state_size);
+ rad_state.copyIn(xc->mem);
+
+ uint64_t uniq_val = attrp->pthid - rad_state->nxm_uniq_offset;
+
+ if (attrp->type == OSF::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 = 99;
+ kidp.copyOut(xc->mem);
+
+ return 0;
+ } else if (attrp->type == OSF::NXM_TYPE_VP) {
+ // A real "virtual processor" kernel thread. Need to fork
+ // this thread on another CPU.
+ OSF::nxm_sched_state *ssp = &rad_state->nxm_ss[thread_index];
+
+ if (ssp->nxm_u.nxm_active != 0)
+ return OSF::KERN_NOT_RECEIVER;
+
+ ssp->nxm_u.pth_id = attrp->pthid;
+ ssp->nxm_u.nxm_active = uniq_val | 1;
+
+ rad_state.copyOut(xc->mem);
+
+ Addr slot_state_addr = 0x12000 + sizeof(OSF::nxm_config_info);
+ int slot_state_size = process->numCpus * sizeof(OSF::nxm_slot_state_t);
+
+ TypedBufferArg<OSF::nxm_slot_state_t> slot_state(slot_state_addr,
+ slot_state_size);
+
+ slot_state.copyIn(xc->mem);
+
+ if (slot_state[thread_index] != OSF::NXM_SLOT_AVAIL) {
+ cerr << "nxm_thread_createFunc: requested VP slot "
+ << thread_index << " not available!" << endl;
+ fatal("");
+ }
+
+ slot_state[thread_index] = OSF::NXM_SLOT_BOUND;
+
+ slot_state.copyOut(xc->mem);
+
+ // Find a free simulator execution context.
+ list<ExecContext *> &ecList = process->execContexts;
+ list<ExecContext *>::iterator i = ecList.begin();
+ list<ExecContext *>::iterator end = ecList.end();
+ for (; i != end; ++i) {
+ ExecContext *xc = *i;
+
+ if (xc->status() == ExecContext::Unallocated) {
+ // 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 = thread_index;
+ kidp.copyOut(xc->mem);
+
+ 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;
+}
+
+
+int
+nxm_idleFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ return 0;
+}
+
+int
+nxm_thread_blockFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ uint64_t tid = getArg(xc, 0);
+ uint64_t secs = getArg(xc, 1);
+ uint64_t flags = getArg(xc, 2);
+ uint64_t action = getArg(xc, 3);
+ uint64_t usecs = getArg(xc, 4);
+
+ cout << xc->cpu->name() << ": nxm_thread_block " << tid << " " << secs
+ << " " << flags << " " << action << " " << usecs << endl;
+
+ return 0;
+}
+
+
+int
+nxm_blockFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ Addr uaddr = getArg(xc, 0);
+ uint64_t val = getArg(xc, 1);
+ uint64_t secs = getArg(xc, 2);
+ uint64_t usecs = getArg(xc, 3);
+ uint64_t flags = getArg(xc, 4);
+
+ BaseCPU *cpu = xc->cpu;
+
+ cout << cpu->name() << ": nxm_block " << hex << uaddr << dec << " " << val
+ << " " << secs << " " << usecs
+ << " " << flags << endl;
+
+ return 0;
+}
+
+
+int
+nxm_unblockFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ Addr uaddr = getArg(xc, 0);
+
+ cout << xc->cpu->name() << ": nxm_unblock "
+ << hex << uaddr << dec << endl;
+
+ return 0;
+}
+
+
+int
+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 false;
+}
+
+
+// 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->setStatus(ExecContext::Active);
+
+ // get rid of this record
+ i = process->waitList.erase(i);
+
+ ++num_activated;
+ } else {
+ ++i;
+ }
+ }
+
+ return num_activated;
+}
+
+
+static void
+m5_lock_mutex(Addr uaddr, Process *process, ExecContext *xc)
+{
+ TypedBufferArg<uint64_t> lockp(uaddr);
+
+ lockp.copyIn(xc->mem);
+
+ if (*lockp == 0) {
+ // lock is free: grab it
+ *lockp = 1;
+ lockp.copyOut(xc->mem);
+ } else {
+ // lock is busy: disable until free
+ process->waitList.push_back(Process::WaitRec(uaddr, xc));
+ xc->setStatus(ExecContext::Suspended);
+ }
+}
+
+static void
+m5_unlock_mutex(Addr uaddr, Process *process, ExecContext *xc)
+{
+ TypedBufferArg<uint64_t> lockp(uaddr);
+
+ lockp.copyIn(xc->mem);
+ 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->mem);
+ }
+}
+
+
+int
+m5_mutex_lockFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ Addr uaddr = getArg(xc, 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;
+}
+
+
+int
+m5_mutex_trylockFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ Addr uaddr = getArg(xc, 0);
+ TypedBufferArg<uint64_t> lockp(uaddr);
+
+ lockp.copyIn(xc->mem);
+
+ if (*lockp == 0) {
+ // lock is free: grab it
+ *lockp = 1;
+ lockp.copyOut(xc->mem);
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+
+int
+m5_mutex_unlockFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ Addr uaddr = getArg(xc, 0);
+
+ m5_unlock_mutex(uaddr, process, xc);
+
+ return 0;
+}
+
+
+int
+m5_cond_signalFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ Addr cond_addr = getArg(xc, 0);
+
+ // Wqake up one process waiting on the condition variable.
+ activate_waiting_context(cond_addr, process);
+
+ return 0;
+}
+
+
+int
+m5_cond_broadcastFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ Addr cond_addr = getArg(xc, 0);
+
+ // Wake up all processes waiting on the condition variable.
+ activate_waiting_context(cond_addr, process, true);
+
+ return 0;
+}
+
+
+int
+m5_cond_waitFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ Addr cond_addr = getArg(xc, 0);
+ Addr lock_addr = getArg(xc, 1);
+ TypedBufferArg<uint64_t> condp(cond_addr);
+ TypedBufferArg<uint64_t> lockp(lock_addr);
+
+ // user is supposed to acquire lock before entering
+ lockp.copyIn(xc->mem);
+ assert(*lockp != 0);
+
+ m5_unlock_mutex(lock_addr, process, xc);
+
+ process->waitList.push_back(Process::WaitRec(cond_addr, xc));
+ xc->setStatus(ExecContext::Suspended);
+
+ return 0;
+}
+
+
+int
+m5_thread_exitFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ assert(xc->status() == ExecContext::Active);
+ xc->setStatus(ExecContext::Unallocated);
+
+ return 0;
+}
+
+
+SyscallDesc machSyscallDescs[] = {
+ /* 0 */ SyscallDesc("kern_invalid", unimplementedFunc),
+ /* 1 */ SyscallDesc("m5_mutex_lock", m5_mutex_lockFunc),
+ /* 2 */ SyscallDesc("m5_mutex_trylock", m5_mutex_trylockFunc),
+ /* 3 */ SyscallDesc("m5_mutex_unlock", m5_mutex_unlockFunc),
+ /* 4 */ SyscallDesc("m5_cond_signal", m5_cond_signalFunc),
+ /* 5 */ SyscallDesc("m5_cond_broadcast", m5_cond_broadcastFunc),
+ /* 6 */ SyscallDesc("m5_cond_wait", m5_cond_waitFunc),
+ /* 7 */ SyscallDesc("m5_thread_exit", 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", nxm_blockFunc),
+ /* 25 */ SyscallDesc("nxm_unblock", 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", nxm_thread_createFunc),
+ /* 33 */ SyscallDesc("nxm_task_init", nxm_task_initFunc),
+ /* 34 */ SyscallDesc("kern_invalid", unimplementedFunc),
+ /* 35 */ SyscallDesc("nxm_idle", 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", 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", 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", 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", 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)
+};
+
+const int Num_Mach_Syscall_Descs =
+ sizeof(machSyscallDescs) / sizeof(SyscallDesc);
+
+const int Max_Mach_Syscall_Desc = Num_Mach_Syscall_Descs - 1;
+
+// Since negated values are used to identify Mach syscalls, the
+// minimum (signed) valid syscall number is the negated max Mach
+// syscall number.
+const int Min_Syscall_Desc = -Max_Mach_Syscall_Desc;
+
+
+//
+// helper function for invoking syscalls
+//
+static
+int
+doSyscall(int callnum, Process *process,
+ ExecContext *xc)
+{
+ if (callnum < Min_Syscall_Desc || callnum > Max_Syscall_Desc) {
+ cerr << "Syscall " << callnum << " out of range" << endl;
+ abort();
+ }
+
+ SyscallDesc *desc =
+ (callnum < 0) ? &machSyscallDescs[-callnum] : &syscallDescs[callnum];
+
+ DCOUT(SyscallVerbose) << xc->cpu->name() << ": syscall " << desc->name
+ << " called @ " << curTick << endl;
+
+ return desc->doFunc(callnum, process, xc);
+}
+
+//
+// Indirect syscall invocation (call #0)
+//
+int
+indirectSyscallFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int new_callnum = getArg(xc, 0);
+
+ for (int i = 0; i < 5; ++i)
+ setArg(xc, i, getArg(xc, i+1));
+
+ return doSyscall(new_callnum, process, xc);
+}
+
+
+void
+fake_syscall(Process *process, ExecContext *xc)
+{
+ int64_t callnum = xc->regs.intRegFile[ReturnValueReg];
+
+ int retval = doSyscall(callnum, process, xc);
+
+ set_return_value(xc, retval);
+}
diff --git a/arch/alpha/faults.cc b/arch/alpha/faults.cc
new file mode 100644
index 000000000..c3c19eb58
--- /dev/null
+++ b/arch/alpha/faults.cc
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#include "faults.hh"
+
+namespace {
+ const char *
+ fault_name[Num_Faults] = {
+ "none",
+ "reset",
+ "mchk",
+ "arith",
+ "interrupt",
+ "dtb_miss_single",
+ "dtb_miss_double",
+ "unalign",
+ "dfault",
+ "dfault",
+ "itbmiss",
+ "itbmiss",
+ "iaccvio",
+ "opdec",
+ "fen",
+ "pal",
+ };
+}
+
+const char *
+FaultName(int index)
+{
+ if (index < 0 || index >= Num_Faults)
+ return 0;
+
+ return fault_name[index];
+}
+
diff --git a/arch/alpha/faults.hh b/arch/alpha/faults.hh
new file mode 100644
index 000000000..bc8a4da0e
--- /dev/null
+++ b/arch/alpha/faults.hh
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#ifndef __FAULTS_HH__
+#define __FAULTS_HH__
+
+enum Fault {
+ No_Fault,
+ Reset_Fault, // processor reset
+ Machine_Check_Fault, // machine check (also internal S/W fault)
+ Arithmetic_Fault, // FP exception
+ Interrupt_Fault, // external interrupt
+ Ndtb_Miss_Fault, // DTB miss
+ Pdtb_Miss_Fault, // nested DTB miss
+ Alignment_Fault, // unaligned access
+ Dtb_Fault_Fault, // DTB page fault
+ Dtb_Acv_Fault, // DTB access violation
+ Itb_Miss_Fault, // ITB miss
+ Itb_Fault_Fault, // ITB page fault
+ Itb_Acv_Fault, // ITB access violation
+ Unimplemented_Opcode_Fault, // invalid/unimplemented instruction
+ Fen_Fault, // FP not-enabled fault
+ Pal_Fault, // call_pal S/W interrupt
+ Integer_Overflow_Fault,
+ Num_Faults // number of faults
+};
+
+const char *
+FaultName(int index);
+
+#endif // __FAULTS_HH__
diff --git a/arch/alpha/isa_desc b/arch/alpha/isa_desc
new file mode 100644
index 000000000..e6ac01f28
--- /dev/null
+++ b/arch/alpha/isa_desc
@@ -0,0 +1,2427 @@
+// -*- mode:c++ -*-
+//
+// Alpha ISA description file.
+//
+
+let {{
+ global rcs_id
+ rcs_id = "$Id$"
+}};
+
+
+#include <sstream>
+#include <iostream>
+#include <iomanip>
+
+#include <math.h>
+#if defined(linux)
+#include <fenv.h>
+#endif
+
+#include "static_inst.hh"
+#include "cprintf.hh"
+#include "misc.hh"
+#include "op_class.hh"
+
+#include "exec_context.hh"
+#include "simple_cpu.hh"
+#include "spec_state.hh"
+#include "cpu.hh"
+#include "exetrace.hh"
+#include "annotation.hh"
+
+#ifdef FULL_SYSTEM
+#include "ev5.hh"
+#endif
+
+namespace AlphaISA;
+
+// Universal (format-independent) fields
+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>;
+
+let {{
+ global operandTypeMap
+ operandTypeMap = {
+ '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)
+ }
+
+ global operandTraitsMap
+ operandTraitsMap = {
+ # 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': IntRegOperandTraits('uq', 'RA', 'IsInteger', 1),
+ 'Rb': IntRegOperandTraits('uq', 'RB', 'IsInteger', 2),
+ 'Rc': IntRegOperandTraits('uq', 'RC', 'IsInteger', 3),
+ 'Fa': FloatRegOperandTraits('df', 'FA', 'IsFloating', 1),
+ 'Fb': FloatRegOperandTraits('df', 'FB', 'IsFloating', 2),
+ 'Fc': FloatRegOperandTraits('df', 'FC', 'IsFloating', 3),
+ 'Mem': MemOperandTraits('uq', None,
+ ('IsMemRef', 'IsLoad', 'IsStore'), 4),
+ 'NPC': NPCOperandTraits('uq', None, ( None, None, 'IsControl' ), 4),
+ 'Runiq': ControlRegOperandTraits('uq', 'Uniq', None, 1),
+ 'FPCR': ControlRegOperandTraits('uq', 'Fpcr', None, 1),
+ # The next two are hacks for non-full-system call-pal emulation
+ 'R0': IntRegOperandTraits('uq', '0', None, 1),
+ 'R16': IntRegOperandTraits('uq', '16', None, 1),
+ }
+
+ defineDerivedOperandVars()
+}};
+
+declare {{
+// just temporary, while comparing with old code for debugging
+// #define SS_COMPATIBLE_DISASSEMBLY
+
+ /// Check "FP enabled" machine status bit. Called when executing any FP
+ /// instruction in full-system mode.
+ /// @retval Full-system mode: No_Fault if FP is enabled, Fen_Fault
+ /// if not. Non-full-system mode: always returns No_Fault.
+#ifdef FULL_SYSTEM
+ inline Fault checkFpEnableFault(ExecContext *xc)
+ {
+ Fault fault = No_Fault; // dummy... this ipr access should not fault
+ if (!ICSR_FPE(xc->readIpr(AlphaISA::IPR_ICSR, fault))) {
+ fault = Fen_Fault;
+ }
+ return fault;
+ }
+#else
+ inline Fault checkFpEnableFault(ExecContext *xc)
+ {
+ return No_Fault;
+ }
+#endif
+
+ /**
+ * Base class for all Alpha static instructions.
+ */
+ class AlphaStaticInst : public StaticInst<AlphaISA>
+ {
+ 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,
+ IPR_Base_DepTag = AlphaISA::IPR_Base_DepTag
+ };
+
+ /// Constructor.
+ AlphaStaticInst(const char *mnem, MachInst _machInst,
+ OpClass __opClass)
+ : StaticInst<AlphaISA>(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)
+ {
+ if (reg < FP_Base_DepTag) {
+ ccprintf(os, "r%d", reg);
+ }
+ else {
+ ccprintf(os, "f%d", reg - FP_Base_DepTag);
+ }
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+ 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();
+ }
+ };
+}};
+
+
+def template BasicDeclare {{
+ /**
+ * Static instruction class for "%(mnemonic)s".
+ */
+ class %(class_name)s : public %(base_class)s
+ {
+ public:
+ /// Constructor.
+ %(class_name)s(MachInst machInst)
+ : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
+ {
+ %(constructor)s;
+ }
+
+ Fault execute(SimpleCPU *cpu, ExecContext *xc,
+ Trace::InstRecord *traceData)
+ {
+ SimpleCPU *memAccessObj __attribute__((unused)) = cpu;
+ Fault fault = No_Fault;
+
+ %(fp_enable_check)s;
+ %(exec_decl)s;
+ %(simple_rd)s;
+ %(code)s;
+
+ if (fault == No_Fault) {
+ %(simple_wb)s;
+ }
+
+ return fault;
+ }
+
+ Fault execute(CPU *cpu, SpecExecContext *xc, DynInst *dynInst,
+ Trace::InstRecord *traceData)
+ {
+ DynInst *memAccessObj __attribute__((unused)) = dynInst;
+ Fault fault = No_Fault;
+
+ %(fp_enable_check)s;
+ %(exec_decl)s;
+ %(dtld_rd)s;
+ %(code)s;
+
+ if (fault == No_Fault) {
+ %(dtld_wb)s;
+ }
+
+ return fault;
+ }
+ };
+}};
+
+def template BasicDecode {{
+ return new %(class_name)s(machInst);
+}};
+
+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)
+ return iop.subst('BasicDeclare', 'BasicDecode')
+}};
+
+
+
+////////////////////////////////////////////////////////////////////
+
+declare {{
+ /**
+ * 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, MachInst _machInst)
+ : AlphaStaticInst("nop", _machInst, No_OpClass),
+ originalDisassembly(_originalDisassembly)
+ {
+ flags[IsNop] = true;
+ }
+
+ ~Nop() { }
+
+ Fault execute(SimpleCPU *cpu, ExecContext *xc,
+ Trace::InstRecord *traceData)
+ {
+ return No_Fault;
+ }
+
+ Fault execute(CPU *cpu, SpecExecContext *xc, DynInst *dynInst,
+ Trace::InstRecord *traceData)
+ {
+ return No_Fault;
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+#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
+ AlphaStaticInst *
+ makeNop(AlphaStaticInst *inst)
+ {
+ AlphaStaticInst *nop = new Nop(inst->disassemble(0), inst->machInst);
+ delete inst;
+ return nop;
+ }
+}};
+
+def format Nop() {{
+ return ('', 'return new Nop("%s", machInst);\n' % name)
+}};
+
+
+// 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)
+ return iop.subst('BasicDeclare', 'OperateNopCheckDecode')
+}};
+
+
+////////////////////////////////////////////////////////////////////
+//
+// Integer operate instructions
+//
+
+declare {{
+ /**
+ * 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, MachInst _machInst, OpClass __opClass)
+ : AlphaStaticInst(mnem, _machInst, __opClass), imm(INTIMM)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+ 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)
+ decls = iop.subst('BasicDeclare')
+
+ if uses_imm:
+ # append declaration for imm version
+ imm_cblk = CodeBlock(imm_code)
+ imm_iop = InstObjParams(name, Name + 'Imm', 'IntegerImm', imm_cblk,
+ opt_flags)
+ decls += imm_iop.subst('BasicDeclare')
+ # decode checks IMM bit to pick correct version
+ decode = iop.subst('RegOrImmDecode')
+ else:
+ # no imm version: just check for nop
+ decode = iop.subst('OperateNopCheckDecode')
+
+ return (decls, decode)
+}};
+
+
+////////////////////////////////////////////////////////////////////
+//
+// Floating-point instructions
+//
+// Note that many FP-type instructions which do not support all the
+// various rounding & trapping modes use the simpler format
+// BasicOperateWithNopCheck.
+//
+
+declare {{
+ /**
+ * 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:
+#if defined(linux)
+ static const int alphaToC99RoundingMode[];
+#endif
+
+ /// 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;
+
+ /// Constructor
+ AlphaFP(const char *mnem, MachInst _machInst, OpClass __opClass)
+ : AlphaStaticInst(mnem, _machInst, __opClass),
+ roundingMode((enum RoundingMode)FP_ROUNDMODE),
+ trappingMode((enum TrappingMode)FP_TRAPMODE)
+ {
+ if (trappingMode != Imprecise) {
+ warn("Warning: precise FP traps unimplemented\n");
+ }
+ }
+
+#if defined(linux)
+ int
+ getC99RoundingMode(ExecContext *xc)
+ {
+ if (roundingMode == Dynamic) {
+ return alphaToC99RoundingMode[bits(xc->readFpcr(), 59, 58)];
+ }
+ else {
+ return alphaToC99RoundingMode[roundingMode];
+ }
+ }
+#endif
+
+ // This differs from the AlphaStaticInst version only in
+ // printing suffixes for non-default rounding & trapping modes.
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+ std::string mnem_str(mnemonic);
+
+ mnem_str += ((_destRegIdx[0] >= FP_Base_DepTag)
+ ? fpTrappingModeSuffix[trappingMode]
+ : intTrappingModeSuffix[trappingMode]);
+ mnem_str += roundingModeSuffix[roundingMode];
+
+ 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();
+ }
+ };
+
+#if defined(linux)
+ const int AlphaFP::alphaToC99RoundingMode[] = {
+ FE_TOWARDZERO, // Chopped
+ FE_DOWNWARD, // Minus_Infinity
+ FE_TONEAREST, // Normal
+ FE_UPWARD // Dynamic in inst, Plus_Infinity in FPCR
+ };
+#endif
+
+ 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" };
+}};
+
+
+def template FloatingPointDeclare {{
+ /**
+ * "Fast" static instruction class for "%(mnemonic)s" (imprecise
+ * trapping mode, normal rounding mode).
+ */
+ class %(class_name)sFast : public %(base_class)s
+ {
+ public:
+ /// Constructor.
+ %(class_name)sFast(MachInst machInst)
+ : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
+ {
+ %(constructor)s;
+ }
+
+ Fault execute(SimpleCPU *cpu, ExecContext *xc,
+ Trace::InstRecord *traceData)
+ {
+ Fault fault = No_Fault;
+
+ %(fp_enable_check)s;
+ %(exec_decl)s;
+ %(simple_rd)s;
+ %(code)s;
+
+ if (fault == No_Fault) {
+ %(simple_wb)s;
+ }
+
+ return fault;
+ }
+
+ Fault execute(CPU *cpu, SpecExecContext *xc, DynInst *dynInst,
+ Trace::InstRecord *traceData)
+ {
+ Fault fault = No_Fault;
+
+ %(fp_enable_check)s;
+ %(exec_decl)s;
+ %(dtld_rd)s;
+ %(code)s;
+
+ if (fault == No_Fault) {
+ %(dtld_wb)s;
+ }
+
+ return fault;
+ }
+ };
+
+ /**
+ * General static instruction class for "%(mnemonic)s". Supports
+ * all the various rounding and trapping modes.
+ */
+ class %(class_name)sGeneral : public %(base_class)s
+ {
+ public:
+ /// Constructor.
+ %(class_name)sGeneral(MachInst machInst)
+ : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
+ {
+ %(constructor)s;
+ }
+
+ Fault execute(SimpleCPU *cpu, ExecContext *xc,
+ Trace::InstRecord *traceData)
+ {
+ Fault fault = No_Fault;
+
+ %(fp_enable_check)s;
+ %(exec_decl)s;
+ %(simple_rd)s;
+
+#if defined(linux)
+ fesetround(getC99RoundingMode(xc));
+#endif
+
+ %(code)s;
+
+#if defined(linux)
+ fesetround(FE_TONEAREST);
+#endif
+
+ if (fault == No_Fault) {
+ %(simple_wb)s;
+ }
+
+ return fault;
+ }
+
+ Fault execute(CPU *cpu, SpecExecContext *xc, DynInst *dynInst,
+ Trace::InstRecord *traceData)
+ {
+ Fault fault = No_Fault;
+
+ %(fp_enable_check)s;
+ %(exec_decl)s;
+ %(dtld_rd)s;
+
+#if defined(linux)
+ fesetround(getC99RoundingMode(xc));
+#endif
+
+ %(code)s;
+
+#if defined(linux)
+ fesetround(FE_TONEAREST);
+#endif
+
+ if (fault == No_Fault) {
+ %(dtld_wb)s;
+ }
+
+ return fault;
+ }
+ };
+}};
+
+def template FloatingPointDecode {{
+ {
+ bool fast = (FP_TRAPMODE == AlphaFP::Imprecise
+ && FP_ROUNDMODE == AlphaFP::Normal);
+ AlphaStaticInst *i =
+ fast ? (AlphaStaticInst *)new %(class_name)sFast(machInst) :
+ (AlphaStaticInst *)new %(class_name)sGeneral(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)
+ return iop.subst('FloatingPointDeclare', 'FloatingPointDecode')
+}};
+
+
+////////////////////////////////////////////////////////////////////
+//
+// Memory-format instructions: LoadAddress, Load, Store
+//
+
+declare {{
+ /**
+ * Base class for general Alpha memory-format instructions.
+ */
+ class Memory : public AlphaStaticInst
+ {
+ protected:
+
+ /// Displacement for EA calculation (signed).
+ int32_t disp;
+ /// Memory request flags. See mem_req_base.hh.
+ unsigned memAccessFlags;
+
+ /// Constructor
+ Memory(const char *mnem, MachInst _machInst, OpClass __opClass)
+ : AlphaStaticInst(mnem, _machInst, __opClass),
+ disp(MEMDISP), memAccessFlags(0)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+ return csprintf("%-10s %c%d,%d(r%d)", mnemonic,
+ flags[IsFloating] ? 'f' : 'r', RA, MEMDISP, RB);
+ }
+ };
+
+ /**
+ * 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 AlphaStaticInst
+ {
+ protected:
+ /// Memory request flags. See mem_req_base.hh.
+ unsigned memAccessFlags;
+
+ /// Constructor
+ MemoryNoDisp(const char *mnem, MachInst _machInst, OpClass __opClass)
+ : AlphaStaticInst(mnem, _machInst, __opClass),
+ memAccessFlags(0)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+ return csprintf("%-10s (r%d)", mnemonic, RB);
+ }
+ };
+
+ /**
+ * Base class for "fake" effective-address computation
+ * instructions returnded by eaCompInst().
+ */
+ class EACompBase : public AlphaStaticInst
+ {
+ public:
+ /// Constructor
+ EACompBase(MachInst machInst)
+ : AlphaStaticInst("(eacomp)", machInst, IntALU)
+ {
+ }
+
+ Fault execute(SimpleCPU *cpu, ExecContext *xc,
+ Trace::InstRecord *traceData)
+ { panic("attempt to execute eacomp"); }
+
+ Fault execute(CPU *cpu, SpecExecContext *xc, DynInst *dynInst,
+ Trace::InstRecord *traceData)
+ { panic("attempt to execute eacomp"); }
+ };
+
+ /**
+ * Base class for "fake" memory-access instructions returnded by
+ * memAccInst().
+ */
+ class MemAccBase : public AlphaStaticInst
+ {
+ public:
+ /// Constructor
+ MemAccBase(MachInst machInst, OpClass __opClass)
+ : AlphaStaticInst("(memacc)", machInst, __opClass)
+ {
+ }
+
+ Fault execute(SimpleCPU *cpu, ExecContext *xc,
+ Trace::InstRecord *traceData)
+ { panic("attempt to execute memacc"); }
+
+ Fault execute(CPU *cpu, SpecExecContext *xc, DynInst *dynInst,
+ Trace::InstRecord *traceData)
+ { panic("attempt to execute memacc"); }
+ };
+
+}};
+
+
+def format LoadAddress(code) {{
+ iop = InstObjParams(name, Name, 'Memory', CodeBlock(code))
+ return iop.subst('BasicDeclare', 'BasicDecode')
+}};
+
+
+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 EACompBase
+ {
+ public:
+ /// Constructor
+ EAComp(MachInst machInst)
+ : EACompBase(machInst)
+ {
+ %(ea_constructor)s;
+ }
+ };
+
+ /**
+ * "Fake" memory access instruction class for "%(mnemonic)s".
+ */
+ class MemAcc : public MemAccBase
+ {
+ public:
+ /// Constructor
+ MemAcc(MachInst machInst)
+ : MemAccBase(machInst, %(op_class)s)
+ {
+ %(memacc_constructor)s;
+ }
+ };
+
+ /// Pointer to EAComp object.
+ StaticInstPtr<AlphaISA> eaCompPtr;
+ /// Pointer to MemAcc object.
+ StaticInstPtr<AlphaISA> memAccPtr;
+
+ public:
+
+ StaticInstPtr<AlphaISA> eaCompInst() { return eaCompPtr; }
+ StaticInstPtr<AlphaISA> memAccInst() { return memAccPtr; }
+
+ /// Constructor.
+ %(class_name)s(MachInst machInst)
+ : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s),
+ eaCompPtr(new EAComp(machInst)), memAccPtr(new MemAcc(machInst))
+ {
+ %(constructor)s;
+ }
+
+ Fault execute(SimpleCPU *cpu, ExecContext *xc,
+ Trace::InstRecord *traceData)
+ {
+ SimpleCPU *memAccessObj = cpu;
+ Addr EA;
+ Fault fault = No_Fault;
+
+ %(fp_enable_check)s;
+ %(exec_decl)s;
+ %(simple_nonmem_rd)s;
+ %(ea_code)s;
+
+ if (fault == No_Fault) {
+ %(simple_mem_rd)s;
+ %(memacc_code)s;
+ }
+
+ if (fault == No_Fault) {
+ %(simple_mem_wb)s;
+ }
+
+ if (fault == No_Fault) {
+ %(postacc_code)s;
+ }
+
+ if (fault == No_Fault) {
+ %(simple_nonmem_wb)s;
+ }
+
+ return fault;
+ }
+
+ Fault execute(CPU *cpu, SpecExecContext *xc, DynInst *dynInst,
+ Trace::InstRecord *traceData)
+ {
+ DynInst *memAccessObj = dynInst;
+ Addr EA;
+ Fault fault = No_Fault;
+
+ %(fp_enable_check)s;
+ %(exec_decl)s;
+ %(dtld_nonmem_rd)s;
+ %(ea_code)s;
+
+ if (fault == No_Fault) {
+ %(dtld_mem_rd)s;
+ %(memacc_code)s;
+ }
+
+ if (fault == No_Fault) {
+ %(dtld_mem_wb)s;
+ }
+
+ if (fault == No_Fault) {
+ %(postacc_code)s;
+ }
+
+ if (fault == No_Fault) {
+ %(dtld_nonmem_wb)s;
+ }
+
+ return fault;
+ }
+ };
+}};
+
+
+def template PrefetchDeclare {{
+ /**
+ * Static instruction class for "%(mnemonic)s".
+ */
+ class %(class_name)s : public %(base_class)s
+ {
+ public:
+ /// Constructor
+ %(class_name)s(MachInst machInst)
+ : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
+ {
+ %(constructor)s;
+ }
+
+ Fault execute(SimpleCPU *cpu, ExecContext *xc,
+ Trace::InstRecord *traceData)
+ {
+ Addr EA;
+ Fault fault = No_Fault;
+
+ %(fp_enable_check)s;
+ %(exec_decl)s;
+ %(simple_nonmem_rd)s;
+ %(ea_code)s;
+
+ if (fault == No_Fault) {
+ cpu->prefetch(EA, memAccessFlags);
+ }
+
+ return No_Fault;
+ }
+
+ Fault execute(CPU *cpu, SpecExecContext *xc, DynInst *dynInst,
+ Trace::InstRecord *traceData)
+ {
+ Addr EA;
+ Fault fault = No_Fault;
+
+ %(fp_enable_check)s;
+ %(exec_decl)s;
+ %(dtld_nonmem_rd)s;
+ %(ea_code)s;
+
+ if (fault == No_Fault) {
+ dynInst->prefetch(EA, memAccessFlags);
+ }
+
+ return No_Fault;
+ }
+ };
+}};
+
+
+// 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 {{
+global LoadStoreBase
+def LoadStoreBase(name, Name, ea_code, memacc_code, postacc_code = '',
+ base_class = 'Memory', flags = [],
+ declare_template = 'LoadStoreDeclare',
+ decode_template = 'BasicDecode'):
+ # Segregate flags into instruction flags (handled by InstObjParams)
+ # and memory access flags (handled here).
+
+ # Would be nice to autogenerate this list, but oh well.
+ valid_mem_flags = ['LOCKED', 'EVICT_NEXT', 'PF_EXCLUSIVE']
+ inst_flags = []
+ mem_flags = []
+ for f in flags:
+ if f in valid_mem_flags:
+ mem_flags.append(f)
+ else:
+ inst_flags.append(f)
+
+ ea_cblk = CodeBlock(ea_code)
+ memacc_cblk = CodeBlock(memacc_code)
+ postacc_cblk = CodeBlock(postacc_code)
+
+ 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
+
+ mem_flags = string.join(mem_flags, '|')
+ if mem_flags != '':
+ iop.constructor += '\n\tmemAccessFlags = ' + mem_flags + ';'
+
+ return iop.subst(declare_template, decode_template)
+}};
+
+
+def format LoadOrNop(ea_code, memacc_code, *flags) {{
+ return LoadStoreBase(name, Name, ea_code, memacc_code,
+ flags = flags,
+ decode_template = 'LoadNopCheckDecode')
+}};
+
+
+// Note that the flags passed in apply only to the prefetch version
+def format LoadOrPrefetch(ea_code, memacc_code, *pf_flags) {{
+ # declare the load instruction object and generate the decode block
+ (decls, decode) = \
+ LoadStoreBase(name, Name, ea_code, memacc_code,
+ decode_template = 'LoadPrefetchCheckDecode')
+
+ # Declare the prefetch instruction object.
+
+ # convert flags from tuple to list to make them mutable
+ pf_flags = list(pf_flags) + ['IsMemRef', 'IsLoad', 'IsDataPrefetch', 'RdPort']
+
+ (pfdecls, pfdecode) = \
+ LoadStoreBase(name, Name + 'Prefetch', ea_code, '',
+ flags = pf_flags,
+ declare_template = 'PrefetchDeclare')
+
+ return (decls + pfdecls, decode)
+}};
+
+
+def format Store(ea_code, memacc_code, *flags) {{
+ return LoadStoreBase(name, Name, ea_code, memacc_code,
+ flags = flags)
+}};
+
+
+def format StoreCond(ea_code, memacc_code, postacc_code, *flags) {{
+ return LoadStoreBase(name, Name, ea_code, memacc_code, postacc_code,
+ flags = flags)
+}};
+
+
+// Use 'MemoryNoDisp' as base: for wh64, fetch, ecb
+def format MiscPrefetch(ea_code, memacc_code, *flags) {{
+ return LoadStoreBase(name, Name, ea_code, memacc_code,
+ flags = flags, base_class = 'MemoryNoDisp')
+}};
+
+
+////////////////////////////////////////////////////////////////////
+
+
+declare {{
+
+ /**
+ * 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
+ Addr cachedPC;
+ /// Cached symbol table pointer from last disassembly
+ const SymbolTable *cachedSymtab;
+
+ /// Constructor
+ PCDependentDisassembly(const char *mnem, MachInst _machInst,
+ OpClass __opClass)
+ : AlphaStaticInst(mnem, _machInst, __opClass),
+ cachedPC(0), cachedSymtab(0)
+ {
+ }
+
+ const std::string &disassemble(Addr pc, const SymbolTable *symtab)
+ {
+ if (!cachedDisassembly ||
+ pc != cachedPC || symtab != cachedSymtab)
+ {
+ if (cachedDisassembly)
+ delete cachedDisassembly;
+
+ cachedDisassembly =
+ new std::string(generateDisassembly(pc, symtab));
+ cachedPC = pc;
+ cachedSymtab = symtab;
+ }
+
+ return *cachedDisassembly;
+ }
+ };
+
+ /**
+ * 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, MachInst _machInst, OpClass __opClass)
+ : PCDependentDisassembly(mnem, _machInst, __opClass),
+ disp(BRDISP << 2)
+ {
+ }
+
+ Addr branchTarget(Addr branchPC)
+ {
+ return branchPC + 4 + disp;
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+ 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();
+ }
+ };
+
+ /**
+ * 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, MachInst _machInst, OpClass __opClass)
+ : PCDependentDisassembly(mnem, _machInst, __opClass),
+ disp(BRDISP)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+ 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<AlphaISA> *)new %(class_name)s(machInst)
+ : (StaticInst<AlphaISA> *)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'))
+ return iop.subst('BasicDeclare', 'BasicDecode')
+}};
+
+let {{
+global UncondCtrlBase
+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)
+ decls = nolink_iop.subst('BasicDeclare')
+
+ # 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)
+ decls += link_iop.subst('BasicDeclare')
+
+ # need to use link_iop for the decode template since it is expecting
+ # the shorter version of class_name (w/o "AndLink")
+ return (decls, nolink_iop.subst('JumpOrBranchDecode'))
+}};
+
+def format UncondBranch(*flags) {{
+ flags += ('IsUncondControl', 'IsDirectControl')
+ return UncondCtrlBase(name, Name, 'Branch', 'NPC + disp', flags)
+}};
+
+def format Jump(*flags) {{
+ flags += ('IsUncondControl', 'IsIndirectControl')
+ return UncondCtrlBase(name, Name, 'Jump', '(Rb & ~3) | (NPC & 1)', flags)
+}};
+
+
+declare {{
+ /**
+ * Base class for emulated call_pal calls (used only in
+ * non-full-system mode).
+ */
+ class EmulatedCallPal : public AlphaStaticInst
+ {
+ protected:
+
+ /// Constructor.
+ EmulatedCallPal(const char *mnem, MachInst _machInst,
+ OpClass __opClass)
+ : AlphaStaticInst(mnem, _machInst, __opClass)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+#ifdef SS_COMPATIBLE_DISASSEMBLY
+ return csprintf("%s %s", "call_pal", mnemonic);
+#else
+ return csprintf("%-10s %s", "call_pal", mnemonic);
+#endif
+ }
+ };
+}};
+
+def format EmulatedCallPal(code) {{
+ iop = InstObjParams(name, Name, 'EmulatedCallPal', CodeBlock(code))
+ return iop.subst('BasicDeclare', 'BasicDecode')
+}};
+
+declare {{
+ /**
+ * 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
+
+ /// Constructor.
+ CallPalBase(const char *mnem, MachInst _machInst,
+ OpClass __opClass)
+ : AlphaStaticInst(mnem, _machInst, __opClass),
+ palFunc(PALFUNC)
+ {
+ int palPriv = ((machInst & 0x80) != 0);
+ int shortPalFunc = (machInst & 0x3f);
+ palOffset = 0x2001 + (palPriv << 12) + (shortPalFunc << 6);
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+ return csprintf("%-10s %#x", "call_pal", palFunc);
+ }
+ };
+}};
+
+
+def format CallPal(code) {{
+ iop = InstObjParams(name, Name, 'CallPalBase', CodeBlock(code))
+ return iop.subst('BasicDeclare', 'BasicDecode')
+}};
+
+//
+// hw_ld, hw_st
+//
+declare {{
+ /**
+ * Base class for hw_ld and hw_st.
+ */
+ class HwLoadStore : public AlphaStaticInst
+ {
+ protected:
+
+ /// Displacement for EA calculation (signed).
+ int16_t disp;
+ /// Memory request flags. See mem_req_base.hh.
+ unsigned memAccessFlags;
+
+ /// Constructor
+ HwLoadStore(const char *mnem, MachInst _machInst, OpClass __opClass)
+ : AlphaStaticInst(mnem, _machInst, __opClass), 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 generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+#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 HwLoadStore(ea_code, memacc_code, class_ext, *flags) {{
+ return LoadStoreBase(name, Name + class_ext, ea_code, memacc_code,
+ flags = flags,
+ base_class = 'HwLoadStore')
+}};
+
+
+def format HwStoreCond(ea_code, memacc_code, postacc_code, class_ext, *flags) {{
+ return LoadStoreBase(name, Name + class_ext,
+ ea_code, memacc_code, postacc_code,
+ flags = flags,
+ base_class = 'HwLoadStore')
+}};
+
+
+declare {{
+ /**
+ * 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, MachInst _machInst, OpClass __opClass)
+ : AlphaStaticInst(mnem, _machInst, __opClass),
+ ipr_index(HW_IPR_IDX)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+ 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) {{
+ iop = InstObjParams(name, Name, 'HwMoveIPR', CodeBlock(code))
+ return iop.subst('BasicDeclare', 'BasicDecode')
+}};
+
+declare {{
+ /**
+ * 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, MachInst _machInst)
+ : AlphaStaticInst(_mnemonic, _machInst, No_OpClass)
+ {
+ }
+
+ Fault execute(SimpleCPU *cpu, ExecContext *xc,
+ Trace::InstRecord *traceData)
+ {
+ panic("attempt to execute unimplemented instruction '%s' "
+ "(inst 0x%08x, opcode 0x%x)", mnemonic, machInst, OPCODE);
+ return Unimplemented_Opcode_Fault;
+ }
+
+ Fault execute(CPU *cpu, SpecExecContext *xc, DynInst *dynInst,
+ Trace::InstRecord *traceData)
+ {
+ // don't panic if this is a misspeculated instruction
+ if (!xc->spec_mode)
+ panic("attempt to execute unimplemented instruction '%s' "
+ "(inst 0x%08x, opcode 0x%x)",
+ mnemonic, machInst, OPCODE);
+ return Unimplemented_Opcode_Fault;
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+ return csprintf("%-10s (unimplemented)", mnemonic);
+ }
+ };
+
+ /**
+ * 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?
+ bool warned;
+
+ public:
+ /// Constructor
+ WarnUnimplemented(const char *_mnemonic, MachInst _machInst)
+ : AlphaStaticInst(_mnemonic, _machInst, No_OpClass), warned(false)
+ {
+ }
+
+ Fault execute(SimpleCPU *cpu, ExecContext *xc,
+ Trace::InstRecord *traceData)
+ {
+ if (!warned) {
+ warn("Warning: instruction '%s' unimplemented\n", mnemonic);
+ warned = true;
+ }
+
+ return No_Fault;
+ }
+
+ Fault execute(CPU *cpu, SpecExecContext *xc, DynInst *dynInst,
+ Trace::InstRecord *traceData)
+ {
+ if (!xc->spec_mode && !warned) {
+ warn("Warning: instruction '%s' unimplemented\n", mnemonic);
+ warned = true;
+ }
+
+ return No_Fault;
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+#ifdef SS_COMPATIBLE_DISASSEMBLY
+ return csprintf("%-10s", mnemonic);
+#else
+ return csprintf("%-10s (unimplemented)", mnemonic);
+#endif
+ }
+ };
+}};
+
+def template WarnUnimplDeclare {{
+ /**
+ * Static instruction class for "%(mnemonic)s".
+ */
+ class %(class_name)s : public %(base_class)s
+ {
+ public:
+ /// Constructor
+ %(class_name)s(MachInst machInst)
+ : %(base_class)s("%(mnemonic)s", machInst)
+ {
+ }
+ };
+}};
+
+
+def format FailUnimpl() {{
+ iop = InstObjParams(name, 'FailUnimplemented')
+ return ('', iop.subst('BasicDecodeWithMnemonic'))
+}};
+
+def format WarnUnimpl() {{
+ iop = InstObjParams(name, Name, 'WarnUnimplemented')
+ return iop.subst('WarnUnimplDeclare', 'BasicDecode')
+}};
+
+declare {{
+ /**
+ * 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(MachInst _machInst)
+ : AlphaStaticInst("unknown", _machInst, No_OpClass)
+ {
+ }
+
+ Fault execute(SimpleCPU *cpu, ExecContext *xc,
+ Trace::InstRecord *traceData)
+ {
+ panic("attempt to execute unknown instruction "
+ "(inst 0x%08x, opcode 0x%x)", machInst, OPCODE);
+ return Unimplemented_Opcode_Fault;
+ }
+
+ Fault execute(CPU *cpu, SpecExecContext *xc, DynInst *dynInst,
+ Trace::InstRecord *traceData)
+ {
+ // don't panic if this is a misspeculated instruction
+ if (!xc->spec_mode)
+ panic("attempt to execute unknown instruction "
+ "(inst 0x%08x, opcode 0x%x)", machInst, OPCODE);
+ return Unimplemented_Opcode_Fault;
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+ return csprintf("%-10s (inst 0x%x, opcode 0x%x)",
+ "unknown", machInst, OPCODE);
+ }
+ };
+}};
+
+def format Unknown() {{
+ return ('', 'return new Unknown(machInst);\n')
+}};
+
+declare {{
+
+ /// 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.
+ 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
+ }
+}};
+
+decode OPCODE default Unknown::unknown() {
+
+ format LoadAddress {
+ 0x08: lda({{ Ra = Rb + disp; }});
+ 0x09: ldah({{ Ra = Rb + (disp << 16); }});
+ }
+
+ format LoadOrNop {
+ 0x0a: ldbu({{ EA = Rb + disp; }}, {{ Ra.uq = Mem.ub; }});
+ 0x0c: ldwu({{ EA = Rb + disp; }}, {{ Ra.uq = Mem.uw; }});
+ 0x0b: ldq_u({{ EA = (Rb + disp) & ~7; }}, {{ Ra = Mem.uq; }});
+ 0x23: ldt({{ EA = Rb + disp; }}, {{ Fa = Mem.df; }});
+ 0x2a: ldl_l({{ EA = Rb + disp; }}, {{ Ra.sl = Mem.sl; }}, LOCKED);
+ 0x2b: ldq_l({{ EA = Rb + disp; }}, {{ Ra.uq = Mem.uq; }}, LOCKED);
+ }
+
+ format LoadOrPrefetch {
+ 0x28: ldl({{ EA = Rb + disp; }}, {{ Ra.sl = Mem.sl; }});
+ 0x29: ldq({{ EA = Rb + disp; }}, {{ Ra.uq = Mem.uq; }}, EVICT_NEXT);
+ 0x22: lds({{ EA = Rb + disp; }}, {{ Fa.uq = s_to_t(Mem.ul); }},
+ PF_EXCLUSIVE);
+ }
+
+ format Store {
+ 0x0e: stb({{ EA = Rb + disp; }}, {{ Mem.ub = Ra<7:0>; }});
+ 0x0d: stw({{ EA = Rb + disp; }}, {{ Mem.uw = Ra<15:0>; }});
+ 0x2c: stl({{ EA = Rb + disp; }}, {{ Mem.ul = Ra<31:0>; }});
+ 0x2d: stq({{ EA = Rb + disp; }}, {{ Mem.uq = Ra.uq; }});
+ 0x0f: stq_u({{ EA = (Rb + disp) & ~7; }}, {{ Mem.uq = Ra.uq; }});
+ 0x26: sts({{ EA = Rb + disp; }}, {{ Mem.ul = t_to_s(Fa.uq); }});
+ 0x27: stt({{ EA = Rb + disp; }}, {{ Mem.df = Fa; }});
+ }
+
+ format StoreCond {
+ 0x2e: stl_c({{ EA = Rb + disp; }}, {{ Mem.ul = Ra<31:0>; }},
+ {{
+ uint64_t tmp = Mem_write_result;
+ Ra = (tmp == 0 || tmp == 1) ? tmp : Ra;
+ }}, LOCKED);
+ 0x2f: stq_c({{ EA = Rb + disp; }}, {{ Mem.uq = Ra; }},
+ {{
+ uint64_t tmp = Mem_write_result;
+ Ra = (tmp == 0 || tmp == 1) ? tmp : Ra;
+ }}, LOCKED);
+ }
+
+ 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 = Integer_Overflow_Fault;
+ 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 = Integer_Overflow_Fault;
+ 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 = Integer_Overflow_Fault;
+ 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 = Integer_Overflow_Fault;
+ 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({{
+#ifdef FULL_SYSTEM
+ Rc = 1;
+#else
+ Rc = 2;
+#endif
+ }});
+ }
+ }
+ }
+
+#ifdef 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; }}, IntMULT);
+ 0x20: mulq({{ Rc = Ra * Rb_or_imm; }}, IntMULT);
+ 0x30: umulh({{
+ uint64_t hi, lo;
+ mul128(Ra, Rb_or_imm, hi, lo);
+ Rc = hi;
+ }}, IntMULT);
+ 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 = Integer_Overflow_Fault;
+ Rc.sl = tmp<31:0>;
+ }}, IntMULT);
+ 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 = Integer_Overflow_Fault;
+ Rc = lo;
+ }}, IntMULT);
+ }
+
+ 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>; }}); }
+
+ format FailUnimpl {
+ 0x30: ctpop();
+ 0x31: perr();
+ 0x32: ctlz();
+ 0x33: cttz();
+ 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; }}, FloatCVT);
+ }
+ 0x78: decode RB {
+ 31: ftois({{ Rc.sl = t_to_s(Fa.uq); }},
+ FloatCVT);
+ }
+ }
+ }
+ }
+
+ // 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);
+ }
+ }
+
+ // IEEE floating point
+ 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); }}, FloatCVT);
+ 0x024: itoft({{ Fc.uq = Ra.uq; }}, FloatCVT);
+ 0x014: FailUnimpl::itoff(); // VAX-format conversion
+ }
+ }
+ }
+
+ // Square root instructions must have FA == 31
+ 0xb: decode FA {
+ 31: decode FP_TYPEFUNC {
+ format FloatingPointOperate {
+#ifdef SS_COMPATIBLE_FP
+ 0x0b: sqrts({{
+ if (Fb < 0.0)
+ fault = Arithmetic_Fault;
+ Fc = sqrt(Fb);
+ }}, FloatSQRT);
+#else
+ 0x0b: sqrts({{
+ if (Fb.sf < 0.0)
+ fault = Arithmetic_Fault;
+ Fc.sf = sqrt(Fb.sf);
+ }}, FloatSQRT);
+#endif
+ 0x2b: sqrtt({{
+ if (Fb < 0.0)
+ fault = Arithmetic_Fault;
+ Fc = sqrt(Fb);
+ }}, FloatSQRT);
+ }
+ }
+ }
+
+ // 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.
+ // 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.
+ 0: decode FP_TYPEFUNC {
+ format FloatingPointOperate {
+#ifdef SS_COMPATIBLE_FP
+ 0x00: adds({{ Fc = Fa + Fb; }});
+ 0x01: subs({{ Fc = Fa - Fb; }});
+ 0x02: muls({{ Fc = Fa * Fb; }}, FloatMULT);
+ 0x03: divs({{ Fc = Fa / Fb; }}, FloatDIV);
+#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; }}, FloatMULT);
+ 0x03: divs({{ Fc.sf = Fa.sf / Fb.sf; }}, FloatDIV);
+#endif
+
+ 0x20: addt({{ Fc = Fa + Fb; }});
+ 0x21: subt({{ Fc = Fa - Fb; }});
+ 0x22: mult({{ Fc = Fa * Fb; }}, FloatMULT);
+ 0x23: divt({{ Fc = Fa / Fb; }}, FloatDIV);
+ }
+ }
+
+ // 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; }},
+ FloatCMP);
+ 0x0a7, 0x5a7: cmptle({{ Fc = (Fa <= Fb) ? 2.0 : 0.0; }},
+ FloatCMP);
+ 0x0a6, 0x5a6: cmptlt({{ Fc = (Fa < Fb) ? 2.0 : 0.0; }},
+ FloatCMP);
+ 0x0a4, 0x5a4: cmptun({{ // unordered
+ Fc = (!(Fa < Fb) && !(Fa == Fb) && !(Fa > Fb)) ? 2.0 : 0.0;
+ }}, FloatCMP);
+ }
+ }
+
+ // 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: cvttq({{ Fc.sq = (int64_t)rint(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 = Integer_Overflow_Fault;
+ 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; }});
+ 0x025: mf_fpcr({{ Fa.uq = FPCR; }});
+ }
+ }
+
+ // miscellaneous mem-format ops
+ 0x18: decode MEMFUNC {
+ format WarnUnimpl {
+ 0x0000: trapb();
+ 0x0400: excb();
+ 0x4000: mb();
+ 0x4400: wmb();
+ 0x8000: fetch();
+ 0xa000: fetch_m();
+ 0xe800: ecb();
+ }
+
+ format MiscPrefetch {
+ 0xf800: wh64({{ EA = Rb; }},
+ {{ memAccessObj->writeHint(EA, 64); }},
+ IsMemRef, IsStore, WrPort);
+ }
+
+ format BasicOperate {
+ 0xc000: rpcc({{ Ra = curTick; }});
+ }
+
+#ifdef FULL_SYSTEM
+ format BasicOperate {
+ 0xe000: rc({{
+ Ra = xc->regs.intrflag;
+ xc->regs.intrflag = 0;
+ }}, No_OpClass);
+ 0xf000: rs({{
+ Ra = xc->regs.intrflag;
+ xc->regs.intrflag = 1;
+ }}, No_OpClass);
+ }
+#else
+ format FailUnimpl {
+ 0xe000: rc();
+ 0xf000: rs();
+ }
+#endif
+ }
+
+#ifdef FULL_SYSTEM
+ 0x00: CallPal::call_pal({{
+ // check to see if simulator wants to do something special
+ // on this PAL call (including maybe suppress it)
+ bool dopal = xc->simPalCheck(palFunc);
+
+ Annotate::Callpal(xc, palFunc);
+
+ if (dopal) {
+ if (!xc->misspeculating()) {
+ AlphaISA::swap_palshadow(&xc->regs, true);
+ }
+ xc->setIpr(AlphaISA::IPR_EXC_ADDR, NPC);
+ NPC = xc->readIpr(AlphaISA::IPR_PAL_BASE, fault) + palOffset;
+ }
+ }});
+#else
+ 0x00: decode PALFUNC {
+ format EmulatedCallPal {
+ 0x83: callsys({{ xc->syscall(); }});
+ // Read uniq reg into ABI return value register (r0)
+ 0x9e: rduniq({{ R0 = Runiq; }});
+ // Write uniq reg with value from ABI arg register (r16)
+ 0x9f: wruniq({{ Runiq = R16; }});
+ }
+ }
+#endif
+
+#ifdef FULL_SYSTEM
+ format HwLoadStore {
+ 0x1b: decode HW_LDST_QUAD {
+ 0: hw_ld({{ EA = (Rb + disp) & ~3; }}, {{ Ra = Mem.ul; }}, L);
+ 1: hw_ld({{ EA = (Rb + disp) & ~7; }}, {{ Ra = Mem.uq; }}, Q);
+ }
+
+ 0x1f: 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();
+ }
+ }
+
+ format BasicOperate {
+ 0x1e: hw_rei({{ xc->hwrei(); }});
+
+ // M5 special opcodes use the reserved 0x01 opcode space
+ 0x01: decode M5FUNC {
+ 0x00: arm({{
+ Annotate::ARM(xc);
+ xc->kernelStats.arm();
+ }});
+ 0x01: quiesce({{
+ Annotate::QUIESCE(xc);
+ xc->setStatus(ExecContext::Suspended);
+ xc->kernelStats.quiesce();
+ }});
+ 0x10: ivlb({{
+ Annotate::BeginInterval(xc);
+ xc->kernelStats.ivlb();
+ }}, No_OpClass);
+ 0x11: ivle({{ Annotate::EndInterval(xc); }}, No_OpClass);
+ 0x20: m5exit({{
+ if (!xc->misspeculating())
+ m5_exit();
+ }}, No_OpClass);
+ }
+ }
+
+ format HwMoveIPR {
+ 0x19: hw_mfpr({{
+ // this instruction is only valid in PAL mode
+ if (!PC_PAL(xc->regs.pc)) {
+ fault = Unimplemented_Opcode_Fault;
+ }
+ else {
+ Ra = xc->readIpr(ipr_index, fault);
+ }
+ }});
+ 0x1d: hw_mtpr({{
+ // this instruction is only valid in PAL mode
+ if (!PC_PAL(xc->regs.pc)) {
+ fault = Unimplemented_Opcode_Fault;
+ }
+ else {
+ xc->setIpr(ipr_index, Ra);
+ if (traceData) { traceData->setData(Ra); }
+ }
+ }});
+ }
+#endif
+}
diff --git a/arch/alpha/isa_traits.hh b/arch/alpha/isa_traits.hh
new file mode 100644
index 000000000..d77505651
--- /dev/null
+++ b/arch/alpha/isa_traits.hh
@@ -0,0 +1,282 @@
+/*
+ * 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.
+ */
+
+#ifndef __ISA_TRAITS_HH__
+#define __ISA_TRAITS_HH__
+
+#include "host.hh"
+#include "faults.hh"
+#include "misc.hh"
+
+class CPU;
+class IniFile;
+
+#define TARGET_ALPHA
+
+template <class ISA> class StaticInst;
+template <class ISA> class StaticInstPtr;
+
+class AlphaISA
+{
+ public:
+
+ typedef uint32_t MachInst;
+ typedef uint64_t Addr;
+ typedef uint8_t RegIndex;
+
+ enum {
+ MemoryEnd = 0xffffffffffffffffULL,
+
+ NumIntRegs = 32,
+ NumFloatRegs = 32,
+ NumMiscRegs = 32,
+
+ MaxRegsOfAnyType = 32,
+ // Static instruction parameters
+ MaxInstSrcRegs = 3,
+ MaxInstDestRegs = 2,
+
+ // semantically meaningful register indices
+ ZeroReg = 31, // architecturally meaningful
+ // the rest of these depend on the ABI
+ StackPointerReg = 30,
+ GlobalPointerReg = 29,
+ ReturnAddressReg = 26,
+ ReturnValueReg = 0,
+ 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
+ };
+
+ 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;
+
+ // control register file contents
+ typedef uint64_t MiscReg;
+ typedef struct {
+ 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
+ } MiscRegFile;
+
+#ifdef FULL_SYSTEM
+
+ typedef uint64_t InternalProcReg;
+
+#include "isa_fullsys_traits.hh"
+
+#else
+ enum {
+ NumInternalProcRegs = 0
+ };
+#endif
+
+ enum {
+ TotalNumRegs =
+ NumIntRegs + NumFloatRegs + NumMiscRegs + NumInternalProcRegs
+ };
+
+ 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
+#ifdef FULL_SYSTEM
+ IntReg palregs[NumIntRegs]; // PAL shadow registers
+ InternalProcReg ipr[NumInternalProcRegs]; // internal processor regs
+ int intrlock; // interrupt register lock flag
+ int intrflag; // interrupt flag
+ bool pal_shadow; // using pal_shadow registers
+#endif // FULL_SYSTEM
+ // Are these architectural, or just for convenience?
+ uint8_t opcode, ra; // current instruction details (for intr's)
+ };
+
+ static StaticInstPtr<AlphaISA> decodeInst(MachInst);
+
+ enum annotes {
+ ANNOTE_NONE = 0,
+ // An impossible number for instruction annotations
+ ITOUCH_ANNOTE = 0xffffffff,
+ };
+
+#if 0
+ static inline Addr
+ extractInstructionPrefetchTarget(const MachInst &IR, Addr PC) {
+ return(0);
+ }
+#endif
+
+ 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
+
+ static void saveMachineReg(AnyReg &savereg, const RegFile &reg_file,
+ int regnum);
+
+ static void restoreMachineReg(RegFile &regs, const AnyReg &reg,
+ int regnum);
+
+#if 0
+ static void serializeSpecialRegs(const Serializeable::Proxy &proxy,
+ const RegFile &regs);
+
+ static void unserializeSpecialRegs(IniFile &db,
+ const std::string &category,
+ ConfigNode *node,
+ RegFile &regs);
+#endif
+};
+
+
+typedef AlphaISA TheISA;
+
+typedef TheISA::MachInst MachInst;
+typedef TheISA::Addr Addr;
+typedef TheISA::RegIndex RegIndex;
+typedef TheISA::IntReg IntReg;
+typedef TheISA::IntRegFile IntRegFile;
+typedef TheISA::FloatReg FloatReg;
+typedef TheISA::FloatRegFile FloatRegFile;
+typedef TheISA::MiscReg MiscReg;
+typedef TheISA::MiscRegFile MiscRegFile;
+typedef TheISA::AnyReg AnyReg;
+typedef TheISA::RegFile RegFile;
+
+const int NumIntRegs = TheISA::NumIntRegs;
+const int NumFloatRegs = TheISA::NumFloatRegs;
+const int NumMiscRegs = TheISA::NumMiscRegs;
+const int TotalNumRegs = TheISA::TotalNumRegs;
+const int VMPageSize = TheISA::VMPageSize;
+const int LogVMPageSize = TheISA::LogVMPageSize;
+const int ZeroReg = TheISA::ZeroReg;
+const int StackPointerReg = TheISA::StackPointerReg;
+const int GlobalPointerReg = TheISA::GlobalPointerReg;
+const int ReturnAddressReg = TheISA::ReturnAddressReg;
+const int ReturnValueReg = TheISA::ReturnValueReg;
+const int ArgumentReg0 = TheISA::ArgumentReg0;
+const int ArgumentReg1 = TheISA::ArgumentReg1;
+const int BranchPredAddrShiftAmt = TheISA::BranchPredAddrShiftAmt;
+
+#ifdef FULL_SYSTEM
+typedef TheISA::InternalProcReg InternalProcReg;
+const int NumInternalProcRegs = TheISA::NumInternalProcRegs;
+const int NumInterruptLevels = TheISA::NumInterruptLevels;
+
+// more stuff that should be imported here, but I'm too tired to do it
+// right now...
+#include "ev5.hh"
+#endif
+
+#endif // __ALPHA_ISA_H__
diff --git a/arch/alpha/osfpal.cc b/arch/alpha/osfpal.cc
new file mode 100644
index 000000000..796651666
--- /dev/null
+++ b/arch/alpha/osfpal.cc
@@ -0,0 +1,304 @@
+/*
+ * 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.
+ */
+
+#include "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
+#if 0
+ 0, // 0xbf
+ 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
new file mode 100644
index 000000000..61e545306
--- /dev/null
+++ b/arch/alpha/osfpal.hh
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+#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,
+ NumCodes
+ };
+
+ static const char *name(int index);
+};
+
+#endif // __OSFPAL_HH__
diff --git a/arch/alpha/vtophys.cc b/arch/alpha/vtophys.cc
new file mode 100644
index 000000000..33f8f02ad
--- /dev/null
+++ b/arch/alpha/vtophys.cc
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+#include <string>
+
+#include "pmap.h"
+
+#include "exec_context.hh"
+#include "physical_memory.hh"
+#include "trace.hh"
+#include "vtophys.hh"
+
+using namespace std;
+
+inline Addr
+level3_index(Addr vaddr)
+{ return (vaddr >> ALPHA_PGSHIFT) & PTEMASK; }
+
+inline Addr
+level2_index(Addr vaddr)
+{ return (vaddr >> (ALPHA_PGSHIFT + NPTEPG_SHIFT)) & PTEMASK; }
+
+inline Addr
+level1_index(Addr vaddr)
+{ return (vaddr >> (ALPHA_PGSHIFT + 2 * NPTEPG_SHIFT)) & PTEMASK; }
+
+Addr
+kernel_pte_lookup(PhysicalMemory *pmem, Addr ptbr, Addr vaddr)
+{
+ uint64_t level1_map = ptbr;
+ Addr level1_pte = level1_map + (level1_index(vaddr) << PTESHIFT);
+
+ uint64_t level1 = pmem->phys_read_qword(level1_pte);
+ if (!entry_valid(level1)) {
+ DPRINTF(VtoPhys, "level 1 PTE not valid, va = %#\n", vaddr);
+ return 0;
+ }
+
+ uint64_t level2_map = PMAP_PTE_PA(level1);
+ Addr level2_pte = level2_map + (level2_index(vaddr) << PTESHIFT);
+ uint64_t level2 = pmem->phys_read_qword(level2_pte);
+ if (!entry_valid(level2)) {
+ DPRINTF(VtoPhys, "level 2 PTE not valid, va = %#x\n", vaddr);
+ return 0;
+ }
+
+ uint64_t level3_map = PMAP_PTE_PA(level2);
+ Addr level3_pte = level3_map + (level3_index(vaddr) << PTESHIFT);
+
+ return level3_pte;
+}
+
+Addr
+vtophys(PhysicalMemory *xc, Addr vaddr)
+{
+ Addr paddr = 0;
+ if (vaddr < ALPHA_K0SEG_BASE)
+ DPRINTF(VtoPhys, "vtophys: invalid vaddr %#x", vaddr);
+ else if (vaddr < ALPHA_K1SEG_BASE)
+ paddr = ALPHA_K0SEG_TO_PHYS(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 vaddr)
+{
+ Addr ptbr = xc->regs.ipr[AlphaISA::IPR_PALtemp20];
+ Addr paddr = 0;
+ if (vaddr < ALPHA_K0SEG_BASE) {
+ DPRINTF(VtoPhys, "vtophys: invalid vaddr %#x", vaddr);
+ } else if (vaddr < ALPHA_K1SEG_BASE) {
+ paddr = ALPHA_K0SEG_TO_PHYS(vaddr);
+ } else {
+ if (!ptbr)
+ panic("vtophys: ptbr is not set on virtual lookup");
+
+ Addr pte = kernel_pte_lookup(xc->physmem, ptbr, vaddr);
+ uint64_t entry = xc->physmem->phys_read_qword(pte);
+ if (pte && entry_valid(entry))
+ paddr = PMAP_PTE_PA(entry) | (vaddr & PGOFSET);
+ }
+
+ DPRINTF(VtoPhys, "vtophys(%#x) -> %#x\n", vaddr, paddr);
+
+ return paddr;
+}
+
+uint8_t *
+vtomem(ExecContext *xc, Addr vaddr, size_t len)
+{
+ Addr paddr = vtophys(xc, vaddr);
+ return xc->physmem->dma_addr(paddr, len);
+}
diff --git a/arch/alpha/vtophys.hh b/arch/alpha/vtophys.hh
new file mode 100644
index 000000000..0b65a506f
--- /dev/null
+++ b/arch/alpha/vtophys.hh
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+#ifndef __VTOPHYS_H__
+#define __VTOPHYS_H__
+
+#include "pmap.h"
+
+inline bool entry_valid(uint64_t entry)
+{ return (entry & ALPHA_PTE_VALID) != 0; }
+
+class ExecContext;
+class PhysicalMemory;
+
+Addr kernel_pte_lookup(PhysicalMemory *pmem, Addr ptbr, Addr vaddr);
+Addr vtophys(PhysicalMemory *xc, Addr vaddr);
+Addr vtophys(ExecContext *xc, Addr vaddr);
+uint8_t *vtomem(ExecContext *xc, Addr vaddr, size_t len);
+
+#endif // __VTOPHYS_H__
+
diff --git a/arch/isa_parser.py b/arch/isa_parser.py
new file mode 100644
index 000000000..a4b588197
--- /dev/null
+++ b/arch/isa_parser.py
@@ -0,0 +1,1446 @@
+#! /usr/bin/env python
+
+# $Id$
+
+# 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.
+
+import os
+import sys
+import re
+import string
+# get type names
+from types import *
+
+# Check arguments. Right now there are only two: the name of the ISA
+# description (input) file and the name of the C++ decoder (output) file.
+isa_desc_filename = sys.argv[1]
+decoder_filename = sys.argv[2]
+
+# Might as well suck the file in while we're here. This way if it's a
+# bad filename we don't waste a lot of time building the parser :-).
+input = open(isa_desc_filename)
+isa_desc = input.read()
+input.close()
+
+# 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', 'DECLARE', 'DECODE', 'DEFAULT', 'DEF', 'FORMAT',
+ 'LET', 'NAMESPACE', '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',
+# not used any more... commented out to suppress PLY warning
+# 'LBRACKET', 'RBRACKET',
+ 'LBRACE', 'RBRACE',
+ 'LESS', 'GREATER',
+ 'COMMA', 'SEMI', 'COLON', 'DBLCOLON',
+ 'ASTERISK',
+
+ # C preprocessor directives
+ 'CPPDIRECTIVE'
+)
+
+# Regular expressions for token matching
+t_LPAREN = r'\('
+t_RPAREN = r'\)'
+# not used any more... commented out to suppress PLY warning
+# t_LBRACKET = r'\['
+# t_RBRACKET = r'\]'
+t_LBRACE = r'\{'
+t_RBRACE = r'\}'
+t_LESS = r'\<'
+t_GREATER = 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
+
+#
+# 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]).
+#####################################################################
+
+# Not sure why, but we get a handful of shift/reduce conflicts on DECLARE.
+# By default these get resolved as shifts, which is correct, but
+# warnings are printed. Explicitly marking DECLARE as right-associative
+# suppresses the warnings.
+precedence = (
+ ('right', 'DECLARE'),
+ )
+
+# 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_declares name_decl opt_defs_and_declares decode_block'
+ global_decls1 = t[1]
+ isa_name = t[2]
+ namespace = isa_name + "Inst"
+ global_decls2 = t[3]
+ (inst_decls, code) = t[4]
+ code = indent(code)
+ # grab the last three path components of isa_desc_filename
+ filename = '/'.join(isa_desc_filename.split('/')[-3:])
+ # if the isa_desc file defines a 'rcs_id' string,
+ # echo that into the output too
+ try:
+ local_rcs_id = rcs_id
+ # strip $s out of ID so it doesn't get re-substituted
+ local_rcs_id = re.sub(r'\$', '', local_rcs_id)
+ except NameError:
+ local_rcs_id = 'Id: no RCS id found'
+ output = open(decoder_filename, 'w')
+ # split string to keep rcs from substituting this file's RCS id in
+ print >> output, '/* $Id' + '''$ */
+
+/*
+ * Copyright (c) 2003
+ * The Regents of The University of Michigan
+ * All Rights Reserved
+ *
+ * Permission is granted to use, copy, create derivative works and
+ * redistribute this software and such derivative works for any
+ * purpose, so long as the copyright notice above, this grant of
+ * permission, and the disclaimer below appear in all copies made; and
+ * so long as the name of The University of Michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization.
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE
+ * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND
+ * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE
+ * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT,
+ * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
+ * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGES.
+ */
+
+/*
+ * DO NOT EDIT THIS FILE!!!
+ *
+ * It was automatically generated from this ISA description:
+ * Filename: %(filename)s
+ * RCS %(local_rcs_id)s
+ */
+
+#include "bitfield.hh" // required for bitfield support
+
+
+/////////////////////////////////////
+// Global defs (outside namespace) //
+/////////////////////////////////////
+
+%(global_decls1)s
+
+/**
+ * Namespace for %(isa_name)s static instruction objects.
+ */
+namespace %(namespace)s
+{
+
+/////////////////////////////////////
+// Global defs (within namespace) //
+/////////////////////////////////////
+
+%(global_decls2)s
+
+////////////////////////////////////
+// Declares from inst definitions //
+////////////////////////////////////
+
+%(inst_decls)s
+
+} // namespace %(namespace)s
+
+//////////////////////
+// Decoder function //
+//////////////////////
+
+StaticInstPtr<%(isa_name)s>
+%(isa_name)s::decodeInst(%(isa_name)s::MachInst machInst)
+{
+ using namespace %(namespace)s;
+%(code)s
+} // decodeInst
+''' % vars()
+ output.close()
+
+# ISA name declaration looks like "namespace <foo>;"
+def p_name_decl(t):
+ 'name_decl : NAMESPACE ID SEMI'
+ t[0] = t[2]
+
+# 'opt_defs_and_declares' is a possibly empty sequence of
+# defs and/or declares.
+def p_opt_defs_and_declares_0(t):
+ 'opt_defs_and_declares : empty'
+ t[0] = ''
+
+def p_opt_defs_and_declares_1(t):
+ 'opt_defs_and_declares : defs_and_declares'
+ t[0] = t[1]
+
+def p_defs_and_declares_0(t):
+ 'defs_and_declares : def_or_declare'
+ t[0] = t[1]
+
+def p_defs_and_declares_1(t):
+ 'defs_and_declares : defs_and_declares def_or_declare'
+ t[0] = t[1] + t[2]
+
+# The list of possible definition/declaration statements.
+def p_def_or_declare(t):
+ '''def_or_declare : def_format
+ | def_bitfield
+ | def_template
+ | global_declare
+ | global_let
+ | cpp_directive'''
+ t[0] = t[1]
+
+# preprocessor directives are copied directly to the output.
+def p_cpp_directive(t):
+ '''cpp_directive : CPPDIRECTIVE'''
+ t[0] = t[1]
+
+# Global declares 'declare {{...}}' (C++ code blocks) are copied
+# directly to the output.
+def p_global_declare(t):
+ 'global_declare : DECLARE CODELIT SEMI'
+ t[0] = substBitOps(t[2])
+
+# global let blocks 'let {{...}}' (Python code blocks) are executed
+# directly when seen. These are typically used to initialize global
+# Python variables used in later format definitions.
+def p_global_let(t):
+ 'global_let : LET CODELIT SEMI'
+ try:
+ exec(fixPythonIndentation(t[2]))
+ except:
+ error_bt(t.lineno(1), 'error in global let block "%s".' % t[2])
+ t[0] = '' # 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)
+ t[0] = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr)
+
+# 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)
+ t[0] = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr)
+
+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]] = t[4]
+ t[0] = ''
+
+# 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))
+ # insert a comment into the output to note that the def was processed
+ t[0] = '''
+//
+// parser: format %s defined
+//
+''' % id
+
+# The formal parameter list for an instruction format is a possibly
+# empty list of comma-separated parameters.
+def p_param_list_0(t):
+ 'param_list : empty'
+ t[0] = [ ]
+
+def p_param_list_1(t):
+ 'param_list : param'
+ t[0] = [t[1]]
+
+def p_param_list_2(t):
+ 'param_list : param_list COMMA param'
+ t[0] = t[1]
+ t[0].append(t[3])
+
+# Each formal parameter is either an identifier or an identifier
+# preceded by an asterisk. As in Python, the latter (if present) gets
+# a tuple containing all the excess positional arguments, allowing
+# varargs functions.
+def p_param_0(t):
+ 'param : ID'
+ t[0] = t[1]
+
+def p_param_1(t):
+ 'param : ASTERISK ID'
+ # just concatenate them: '*ID'
+ 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()
+ (decls, code, has_default) = t[5]
+ # use the "default defaults" only if there was no explicit
+ # default statement in decode_stmt_list
+ if not has_default:
+ (default_decls, default_code) = default_defaults
+ decls += default_decls
+ code += default_code
+ t[0] = (decls, '''
+switch (%s) {
+%s
+}
+''' % (t[2], indent(code)))
+
+# 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
+ (decls, code) = t[2]
+ defaultStack.push((decls, '\ndefault:\n%sbreak;' % code))
+ # 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'
+ (decls1, code1, has_default1) = t[1]
+ (decls2, code2, has_default2) = t[2]
+ if (has_default1 and has_default2):
+ error(t.lineno(1), 'Two default cases in decode block')
+ t[0] = (decls1 + '\n' + decls2, code1 + '\n' + code2,
+ has_default1 or has_default2)
+
+#
+# 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 both the declaration and decode
+# 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] = (t[1], t[1], 0)
+
+# 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, is_default) = t[1]
+ (decls, code) = t[3]
+ # just wrap the decoding code from the block as a case in the
+ # outer switch statement.
+ t[0] = (decls, '\n%s:\n%s' % (label, indent(code)), is_default)
+
+# Instruction definition (finally!).
+def p_decode_stmt_inst(t):
+ 'decode_stmt : case_label COLON inst SEMI'
+ (label, is_default) = t[1]
+ (decls, code) = t[3]
+ t[0] = (decls, '\n%s:%sbreak;' % (label, indent(code)), is_default)
+
+# 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])), 0)
+
+def p_case_label_1(t):
+ 'case_label : DEFAULT'
+ t[0] = ('default', 1)
+
+#
+# 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()
+ (decls, code) = 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 = '// %s::%s(%s)\n' % (currentFormat.id, t[1], args)
+ t[0] = (comment + decls, comment + code)
+
+# 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])
+ (decls, code) = format.defineInst(t[3], t[5], t.lineno(1))
+ comment = '// %s::%s(%s)\n' % (t[1], t[3], t[5])
+ t[0] = (comment + decls, comment + code)
+
+def p_arg_list_0(t):
+ 'arg_list : empty'
+ t[0] = [ ]
+
+def p_arg_list_1(t):
+ 'arg_list : arg'
+ t[0] = [t[1]]
+
+def p_arg_list_2(t):
+ 'arg_list : arg_list COMMA arg'
+ t[0] = t[1]
+ t[0].append(t[3])
+
+def p_arg(t):
+ '''arg : ID
+ | INTLIT
+ | STRLIT
+ | CODELIT'''
+ t[0] = t[1]
+
+#
+# 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_bt(0, "unknown syntax error")
+
+# END OF GRAMMAR RULES
+#
+# Now build the parser.
+yacc.yacc()
+
+################
+# Format object.
+#
+# A format object encapsulates an instruction format. It must provide
+# a defineInst() method that generates the code for an instruction
+# definition.
+
+class Format:
+ def __init__(self, id, params, code):
+ # constructor: just save away arguments
+ self.id = id
+ self.params = params
+ # strip blank lines from code (ones at the end are troublesome)
+ code = re.sub(r'(?m)^\s*$', '', code);
+ if code == '':
+ code = ' pass\n'
+ param_list = string.join(params, ", ")
+ f = 'def defInst(name, Name, ' + param_list + '):\n' + code
+ exec(f)
+ self.func = defInst
+
+ def defineInst(self, name, args, lineno):
+ # automatically provide a capitalized version of mnemonic
+ Name = string.capitalize(name)
+ try:
+ retval = self.func(name, Name, *args)
+ except:
+ error_bt(lineno, 'error defining "%s".' % name)
+ return retval
+
+# 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).
+
+class Stack:
+ def __init__(self, initItem):
+ self.stack = [ initItem ]
+
+ def push(self, item):
+ self.stack.append(item);
+
+ def pop(self):
+ return self.stack.pop()
+
+ def top(self):
+ return self.stack[-1]
+
+# The global format stack.
+formatStack = Stack(NoFormat())
+
+# The global default case stack.
+defaultStack = Stack( None )
+
+###################
+# 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.
+def error(lineno, string):
+ sys.exit("%s:%d: %s" % (isa_desc_filename, lineno, string))
+
+# Like error(), but include a Python stack backtrace (for processing
+# Python exceptions).
+def error_bt(lineno, string):
+ print >> sys.stderr, "%s:%d: %s" % (isa_desc_filename, lineno, string)
+ raise
+
+
+#####################################################################
+#
+# 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
+
+
+#####################################################################
+#
+# Code Parser
+#
+# The remaining code is the support for automatically extracting
+# instruction characteristics from pseudocode.
+#
+#####################################################################
+
+# Force the argument to be a list
+def makeList(list_or_item):
+ if not list_or_item:
+ return []
+ elif type(list_or_item) == ListType:
+ return list_or_item
+ else:
+ return [ list_or_item ]
+
+# generate operandSizeMap based on provided operandTypeMap:
+# basically generate equiv. C++ type and make is_signed flag
+def buildOperandSizeMap():
+ global operandSizeMap
+ operandSizeMap = {}
+ for ext in operandTypeMap.keys():
+ (desc, size) = operandTypeMap[ext]
+ if desc == 'signed int':
+ type = 'int%d_t' % size
+ is_signed = 1
+ elif desc == 'unsigned int':
+ type = 'uint%d_t' % size
+ is_signed = 0
+ elif desc == 'float':
+ is_signed = 1 # shouldn't really matter
+ if size == 32:
+ type = 'float'
+ elif size == 64:
+ type = 'double'
+ if type == '':
+ error(0, 'Unrecognized type description "%s" in operandTypeMap')
+ operandSizeMap[ext] = (size, type, is_signed)
+
+#
+# Base class for operand traits. An instance of this class (or actually
+# a class derived from this one) encapsulates the traits of a particular
+# operand type (e.g., "32-bit integer register").
+#
+class OperandTraits:
+ def __init__(self, dflt_ext, reg_spec, flags, sort_pri):
+ # Force construction of operandSizeMap from operandTypeMap
+ # if it hasn't happened yet
+ if not globals().has_key('operandSizeMap'):
+ buildOperandSizeMap()
+ self.dflt_ext = dflt_ext
+ (self.dflt_size, self.dflt_type, self.dflt_is_signed) = \
+ operandSizeMap[dflt_ext]
+ self.reg_spec = reg_spec
+ # 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')
+ self.flags = ( [], [], [] )
+ elif type(flags) == StringType:
+ # a single flag: assumed to be unconditional
+ self.flags = ( [ flags ], [], [] )
+ elif type(flags) == ListType:
+ # a list of flags: also assumed to be unconditional
+ self.flags = ( flags, [], [] )
+ elif type(flags) == TupleType:
+ # 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
+ self.flags = (makeList(uncond_flags),
+ makeList(src_flags), makeList(dest_flags))
+ self.sort_pri = sort_pri
+
+ 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, op_desc):
+ # note the empty slice '[:]' gives us a copy of self.flags[0]
+ # instead of a reference to it
+ my_flags = self.flags[0][:]
+ if op_desc.is_src:
+ my_flags += self.flags[1]
+ if op_desc.is_dest:
+ my_flags += self.flags[2]
+ return my_flags
+
+ def makeDecl(self, op_desc):
+ (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
+ # Note that initializations in the declarations are solely
+ # to avoid 'uninitialized variable' errors from the compiler.
+ return type + ' ' + op_desc.munged_name + ' = 0;\n';
+
+class IntRegOperandTraits(OperandTraits):
+ def isReg(self):
+ return 1
+
+ def isIntReg(self):
+ return 1
+
+ def makeConstructor(self, op_desc):
+ c = ''
+ if op_desc.is_src:
+ c += '\n\t_srcRegIdx[%d] = %s;' % \
+ (op_desc.src_reg_idx, self.reg_spec)
+ if op_desc.is_dest:
+ c += '\n\t_destRegIdx[%d] = %s;' % \
+ (op_desc.dest_reg_idx, self.reg_spec)
+ return c
+
+ def makeRead(self, op_desc, cpu_model):
+ (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
+ if (type == 'float' or type == 'double'):
+ error(0, 'Attempt to read integer register as FP')
+ if (size == self.dflt_size):
+ return '%s = xc->readIntReg(_srcRegIdx[%d]);\n' % \
+ (op_desc.munged_name, op_desc.src_reg_idx)
+ else:
+ return '%s = bits(xc->readIntReg(_srcRegIdx[%d]), %d, 0);\n' % \
+ (op_desc.munged_name, op_desc.src_reg_idx, size-1)
+
+ def makeWrite(self, op_desc, cpu_model):
+ (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
+ if (type == 'float' or type == 'double'):
+ error(0, 'Attempt to write integer register as FP')
+ if (size != self.dflt_size and is_signed):
+ final_val = 'sext<%d>(%s)' % (size, op_desc.munged_name)
+ else:
+ final_val = op_desc.munged_name
+ wb = '''
+ {
+ %s final_val = %s;
+ xc->setIntReg(_destRegIdx[%d], final_val);\n
+ if (traceData) { traceData->setData(final_val); }
+ }''' % (self.dflt_type, final_val, op_desc.dest_reg_idx)
+ return wb
+
+class FloatRegOperandTraits(OperandTraits):
+ def isReg(self):
+ return 1
+
+ def isFloatReg(self):
+ return 1
+
+ def makeConstructor(self, op_desc):
+ c = ''
+ if op_desc.is_src:
+ c += '\n\t_srcRegIdx[%d] = %s + FP_Base_DepTag;' % \
+ (op_desc.src_reg_idx, self.reg_spec)
+ if op_desc.is_dest:
+ c += '\n\t_destRegIdx[%d] = %s + FP_Base_DepTag;' % \
+ (op_desc.dest_reg_idx, self.reg_spec)
+ return c
+
+ def makeRead(self, op_desc, cpu_model):
+ (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
+ bit_select = 0
+ if (type == 'float'):
+ func = 'readFloatRegSingle'
+ elif (type == 'double'):
+ func = 'readFloatRegDouble'
+ else:
+ func = 'readFloatRegInt'
+ if (size != self.dflt_size):
+ bit_select = 1
+ base = 'xc->%s(_srcRegIdx[%d] - FP_Base_DepTag)' % \
+ (func, op_desc.src_reg_idx)
+ if bit_select:
+ return '%s = bits(%s, %d, 0);\n' % \
+ (op_desc.munged_name, base, size-1)
+ else:
+ return '%s = %s;\n' % (op_desc.munged_name, base)
+
+ def makeWrite(self, op_desc, cpu_model):
+ (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
+ final_val = op_desc.munged_name
+ if (type == 'float'):
+ func = 'setFloatRegSingle'
+ elif (type == 'double'):
+ func = 'setFloatRegDouble'
+ else:
+ func = 'setFloatRegInt'
+ type = 'uint%d_t' % self.dflt_size
+ if (size != self.dflt_size and is_signed):
+ final_val = 'sext<%d>(%s)' % (size, op_desc.munged_name)
+ wb = '''
+ {
+ %s final_val = %s;
+ xc->%s(_destRegIdx[%d] - FP_Base_DepTag, final_val);\n
+ if (traceData) { traceData->setData(final_val); }
+ }''' % (type, final_val, func, op_desc.dest_reg_idx)
+ return wb
+
+class ControlRegOperandTraits(OperandTraits):
+ def isReg(self):
+ return 1
+
+ def isControlReg(self):
+ return 1
+
+ def makeConstructor(self, op_desc):
+ c = ''
+ if op_desc.is_src:
+ c += '\n\t_srcRegIdx[%d] = %s_DepTag;' % \
+ (op_desc.src_reg_idx, self.reg_spec)
+ if op_desc.is_dest:
+ c += '\n\t_destRegIdx[%d] = %s_DepTag;' % \
+ (op_desc.dest_reg_idx, self.reg_spec)
+ return c
+
+ def makeRead(self, op_desc, cpu_model):
+ (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
+ bit_select = 0
+ if (type == 'float' or type == 'double'):
+ error(0, 'Attempt to read control register as FP')
+ base = 'xc->read%s()' % self.reg_spec
+ if size == self.dflt_size:
+ return '%s = %s;\n' % (op_desc.munged_name, base)
+ else:
+ return '%s = bits(%s, %d, 0);\n' % \
+ (op_desc.munged_name, base, size-1)
+
+ def makeWrite(self, op_desc, cpu_model):
+ (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
+ if (type == 'float' or type == 'double'):
+ error(0, 'Attempt to write control register as FP')
+ wb = 'xc->set%s(%s);\n' % (self.reg_spec, op_desc.munged_name)
+ wb += 'if (traceData) { traceData->setData(%s); }' % \
+ op_desc.munged_name
+ return wb
+
+class MemOperandTraits(OperandTraits):
+ def isMem(self):
+ return 1
+
+ def makeConstructor(self, op_desc):
+ return ''
+
+ def makeDecl(self, op_desc):
+ (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
+ # 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' % (type, op_desc.munged_name)
+ # Declare var to hold memory access flags.
+ c += 'unsigned %s_flags = memAccessFlags;\n' % op_desc.base_name
+ # If this operand is a dest (i.e., it's a store operation),
+ # then we need to declare a variable for the write result code
+ # as well.
+ if op_desc.is_dest:
+ c += 'uint64_t %s_write_result = 0;\n' % op_desc.base_name
+ return c
+
+ def makeRead(self, op_desc, cpu_model):
+ (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
+ eff_type = 'uint%d_t' % size
+ return 'fault = memAccessObj->read(EA, (%s&)%s, %s_flags);\n' \
+ % (eff_type, op_desc.munged_name, op_desc.base_name)
+
+ def makeWrite(self, op_desc, cpu_model):
+ (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
+ eff_type = 'uint%d_t' % size
+ return 'fault = memAccessObj->write((%s&)%s, EA, %s_flags,' \
+ ' &%s_write_result);\n' \
+ % (eff_type, op_desc.munged_name, op_desc.base_name,
+ op_desc.base_name)
+
+class NPCOperandTraits(OperandTraits):
+ def makeConstructor(self, op_desc):
+ return ''
+
+ def makeRead(self, op_desc, cpu_model):
+ return '%s = xc->readPC() + 4;\n' % op_desc.munged_name
+
+ def makeWrite(self, op_desc, cpu_model):
+ return 'xc->setNextPC(%s);\n' % op_desc.munged_name
+
+
+#
+# Define operand variables that get derived from the basic declaration
+# of ISA-specific operands in operandTraitsMap. This function must be
+# called by the ISA description file explicitly after defining
+# operandTraitsMap (in a 'let' block).
+#
+def defineDerivedOperandVars():
+ global operands
+ operands = operandTraitsMap.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)
+
+
+#
+# Operand descriptor class. An instance of this class represents
+# a specific operand for a code block.
+#
+class OperandDescriptor:
+ def __init__(self, full_name, base_name, ext, is_src, is_dest):
+ self.full_name = full_name
+ self.base_name = base_name
+ self.ext = ext
+ self.is_src = is_src
+ self.is_dest = is_dest
+ self.traits = operandTraitsMap[base_name]
+ # The 'effective extension' (eff_ext) is either the actual
+ # extension, if one was explicitly provided, or the default.
+ # The 'munged name' replaces the '.' between the base and
+ # extension (if any) with a '_' to make a legal C++ variable name.
+ if ext:
+ self.eff_ext = ext
+ self.munged_name = base_name + '_' + ext
+ else:
+ self.eff_ext = self.traits.dflt_ext
+ self.munged_name = base_name
+
+ # 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.traits.getFlags(self)
+ self.constructor = self.traits.makeConstructor(self)
+ self.exec_decl = self.traits.makeDecl(self)
+
+ if self.is_src:
+ self.simple_rd = self.traits.makeRead(self, 'simple')
+ self.dtld_rd = self.traits.makeRead(self, 'dtld')
+ else:
+ self.simple_rd = ''
+ self.dtld_rd = ''
+
+ if self.is_dest:
+ self.simple_wb = self.traits.makeWrite(self, 'simple')
+ self.dtld_wb = self.traits.makeWrite(self, 'dtld')
+ else:
+ self.simple_wb = ''
+ self.dtld_wb = ''
+
+class OperandDescriptorList:
+ def __init__(self):
+ self.items = []
+ self.bases = {}
+
+ 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.traits.sort_pri - b.traits.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)
+
+#
+# Find all the operands in the given code block. Returns an operand
+# descriptor list (instance of class OperandDescriptorList).
+#
+def findOperands(code):
+ operands = OperandDescriptorList()
+ # delete comments so we don't accidentally 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 = operands.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 = OperandDescriptor(op_full, op_base, op_ext,
+ is_src, is_dest)
+ operands.append(op_desc)
+ # start next search after end of current match
+ next_pos = match.end()
+ operands.sort()
+ # enumerate source & dest register operands... used in building
+ # constructor later
+ srcRegs = 0
+ destRegs = 0
+ operands.numFPDestRegs = 0
+ operands.numIntDestRegs = 0
+ for op_desc in operands:
+ if op_desc.traits.isReg():
+ if op_desc.is_src:
+ op_desc.src_reg_idx = srcRegs
+ srcRegs += 1
+ if op_desc.is_dest:
+ op_desc.dest_reg_idx = destRegs
+ destRegs += 1
+ if op_desc.traits.isFloatReg():
+ operands.numFPDestRegs += 1
+ elif op_desc.traits.isIntReg():
+ operands.numIntDestRegs += 1
+ operands.numSrcRegs = srcRegs
+ operands.numDestRegs = destRegs
+ # now make a final pass to finalize op_desc fields that may depend
+ # on the register enumeration
+ for op_desc in operands:
+ op_desc.finalize()
+ return operands
+
+# Munge operand names in code string to make legal C++ variable names.
+# (Will match munged_name attribute of OperandDescriptor object.)
+def substMungedOpNames(code):
+ return operandsWithExtRE.sub(r'\1_\2', 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 = findOperands(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.exec_decl = self.operands.concatAttrStrings('exec_decl')
+
+ is_mem = lambda op: op.traits.isMem()
+ not_mem = lambda op: not op.traits.isMem()
+
+ self.simple_rd = self.operands.concatAttrStrings('simple_rd')
+ self.simple_wb = self.operands.concatAttrStrings('simple_wb')
+ self.simple_mem_rd = \
+ self.operands.concatSomeAttrStrings(is_mem, 'simple_rd')
+ self.simple_mem_wb = \
+ self.operands.concatSomeAttrStrings(is_mem, 'simple_wb')
+ self.simple_nonmem_rd = \
+ self.operands.concatSomeAttrStrings(not_mem, 'simple_rd')
+ self.simple_nonmem_wb = \
+ self.operands.concatSomeAttrStrings(not_mem, 'simple_wb')
+
+ self.dtld_rd = self.operands.concatAttrStrings('dtld_rd')
+ self.dtld_wb = self.operands.concatAttrStrings('dtld_wb')
+ self.dtld_mem_rd = \
+ self.operands.concatSomeAttrStrings(is_mem, 'dtld_rd')
+ self.dtld_mem_wb = \
+ self.operands.concatSomeAttrStrings(is_mem, 'dtld_wb')
+ self.dtld_nonmem_rd = \
+ self.operands.concatSomeAttrStrings(not_mem, 'dtld_rd')
+ self.dtld_nonmem_wb = \
+ self.operands.concatSomeAttrStrings(not_mem, 'dtld_wb')
+
+ self.flags = self.operands.concatAttrLists('flags')
+
+ # 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 = 'WrPort'
+ elif 'IsLoad' in self.flags or 'IsPrefetch' in self.flags:
+ self.op_class = 'RdPort'
+ elif 'IsFloating' in self.flags:
+ self.op_class = 'FloatADD'
+ else:
+ self.op_class = 'IntALU'
+
+# Assume all instruction flags are of the form 'IsFoo'
+instFlagRE = re.compile(r'Is.*')
+
+# OpClass constants are just a little more complicated
+opClassRE = re.compile(r'Int.*|Float.*|.*Port|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 = ''
+
+ def subst(self, *args):
+ result = []
+ for t in args:
+ if not templateMap.has_key(t):
+ error(0, 'InstObjParams::subst: undefined template "%s"' % t)
+ try:
+ result.append(templateMap[t] % self.__dict__)
+ except KeyError, key:
+ error(0, 'InstObjParams::subst: no definition for "%s"' % key)
+ if len(args) == 1:
+ result = result[0]
+ return result
+
+#
+# All set... read in and parse the ISA description.
+#
+yacc.parse(isa_desc)
diff --git a/base/bitfield.hh b/base/bitfield.hh
new file mode 100644
index 000000000..ee5ea72cf
--- /dev/null
+++ b/base/bitfield.hh
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+#ifndef __BITFIELD_HH
+#define __BITFIELD_HH
+
+#include <inttypes.h>
+
+/**
+ * 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
diff --git a/base/callback.hh b/base/callback.hh
new file mode 100644
index 000000000..a1d23b5ed
--- /dev/null
+++ b/base/callback.hh
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#ifndef __CALLBACK_HH__
+#define __CALLBACK_HH__
+
+#include <list>
+
+class Callback {
+ public:
+ virtual ~Callback() {}
+ virtual void process() = 0;
+};
+
+class CallbackQueue
+{
+ protected:
+ std::list<Callback *> callbacks;
+
+ public:
+ void add(Callback *callback) { callbacks.push_back(callback); }
+ bool empty() const { return callbacks.empty(); }
+ void processOne() {
+ Callback *c = callbacks.front();
+ callbacks.pop_front();
+ c->process();
+ }
+ void processAll() { while (!empty()) processOne(); }
+};
+
+#endif // __CALLBACK_HH__
diff --git a/base/circlebuf.cc b/base/circlebuf.cc
new file mode 100644
index 000000000..482c97f84
--- /dev/null
+++ b/base/circlebuf.cc
@@ -0,0 +1,187 @@
+/*
+ * 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.
+ */
+
+#include <algorithm>
+#include <string>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "cprintf.hh"
+#include "circlebuf.hh"
+#include "intmath.h"
+
+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::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
new file mode 100644
index 000000000..e0abed31c
--- /dev/null
+++ b/base/circlebuf.hh
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#ifndef __CIRCLEBUF_HH__
+#define __CIRCLEBUF_HH__
+
+
+class CircleBuf
+{
+protected:
+ char *buf;
+ bool rollover;
+ int buflen;
+ int size;
+ int start;
+ int stop;
+
+public:
+ explicit CircleBuf(int l);
+ ~CircleBuf();
+
+ bool empty() { return size == 0; }
+ void dump();
+ void flush();
+ void read(char *b, int len);
+ void read(int fd, int len);
+ void read(int fd);
+ 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/cprintf.cc b/base/cprintf.cc
new file mode 100644
index 000000000..be6e64f59
--- /dev/null
+++ b/base/cprintf.cc
@@ -0,0 +1,277 @@
+/*
+ * 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.
+ */
+
+#include <cassert>
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+
+#include "cprintf.hh"
+
+using namespace std;
+
+namespace cp {
+
+void
+ArgList::dump(const string &format)
+{
+ const char *p = format.c_str();
+
+ stream->fill(' ');
+ stream->flags((ios::fmtflags)0);
+
+ Format fmt;
+
+ while (*p) {
+ switch (*p) {
+ case '%': {
+ if (p[1] == '%') {
+ *stream << '%';
+ p += 2;
+ continue;
+ }
+
+ if (objects.empty())
+ format_invalid(*stream);
+
+ Base *data = objects.front();
+
+ fmt.clear();
+ 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;
+ }
+ }
+
+ ios::fmtflags saved_flags = stream->flags();
+ char old_fill = stream->fill();
+ int old_precision = stream->precision();
+
+ data->process(*stream, fmt);
+
+ stream->flags(saved_flags);
+ stream->fill(old_fill);
+ stream->precision(old_precision);
+
+ delete data;
+ objects.pop_front();
+ ++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;
+ }
+
+ ios::iostate state = stream->rdstate();
+ if (state) {
+#if 0
+ cout << "stream->rdstate() == " << state << endl;
+ if (state & ios::badbit)
+ cout << "stream is bad!\n";
+ if (state & ios::eofbit)
+ cout << "stream at eof!\n";
+ if (state & ios::failbit)
+ cout << "stream failed!\n";
+ if (state & ios::goodbit)
+ cout << "stream is good!!\n";
+#endif
+ stream->clear();
+ }
+ }
+
+ while (!objects.empty()) {
+ Base *data = objects.front();
+ data->process(*stream, fmt);
+ delete data;
+ objects.pop_front();
+ }
+}
+
+string
+ArgList::dumpToString(const string &format)
+{
+ stringstream ss;
+
+ dump(ss, format);
+
+ return ss.str();
+}
+
+}
diff --git a/base/cprintf.hh b/base/cprintf.hh
new file mode 100644
index 000000000..2dc84502a
--- /dev/null
+++ b/base/cprintf.hh
@@ -0,0 +1,197 @@
+/*
+ * 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.
+ */
+
+#ifndef __CPRINTF_HH__
+#define __CPRINTF_HH__
+
+#include <iostream>
+#include <list>
+#include <sstream>
+#include <string>
+
+namespace cp {
+
+#include "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:
+ format_invalid(out);
+ break;
+ }
+ }
+ };
+
+ typedef std::list<Base *> list_t;
+
+ protected:
+ list_t objects;
+ std::ostream *stream;
+
+ public:
+ ArgList() : stream(&std::cout) {}
+
+ 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
new file mode 100644
index 000000000..1e5de4fdf
--- /dev/null
+++ b/base/cprintf_formats.hh
@@ -0,0 +1,354 @@
+/*
+ * 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.
+ */
+
+#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() { }
+ 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;
+ }
+};
+
+inline void
+format_invalid(std::ostream &out)
+{
+ using namespace std;
+
+ out << "format invalid!!!" << endl;
+}
+
+
+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)
+{ format_invalid(out); }
+
+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); }
+
+#if 0
+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); }
+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)
+{ format_invalid(out); }
+
+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/date.cc b/base/date.cc
new file mode 100644
index 000000000..f961b9c21
--- /dev/null
+++ b/base/date.cc
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+const char *compileDate = __DATE__ " " __TIME__;
diff --git a/base/dbl_list.hh b/base/dbl_list.hh
new file mode 100644
index 000000000..4f6d61a45
--- /dev/null
+++ b/base/dbl_list.hh
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+
+#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
new file mode 100644
index 000000000..2877744ae
--- /dev/null
+++ b/base/endian.hh
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#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
new file mode 100644
index 000000000..290e59113
--- /dev/null
+++ b/base/fast_alloc.cc
@@ -0,0 +1,191 @@
+/*
+ * 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.
+ */
+
+/*
+ * This code was originally written by Steve Reinhardt as part of
+ * the Wisconsin Wind Tunnel simulator. Relicensed as part of M5
+ * by permission.
+ */
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <assert.h>
+#include "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
diff --git a/base/fast_alloc.hh b/base/fast_alloc.hh
new file mode 100644
index 000000000..7d699abd1
--- /dev/null
+++ b/base/fast_alloc.hh
@@ -0,0 +1,203 @@
+/*
+ * 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.
+ */
+
+/*
+ * 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
+
+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 // __FAST_ALLOC_H__
diff --git a/base/fifo_buffer.cc b/base/fifo_buffer.cc
new file mode 100644
index 000000000..d0b59e832
--- /dev/null
+++ b/base/fifo_buffer.cc
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#include "fifo_buffer.hh"
+
+template<class T>
+void
+FifoBuffer<T>::dump(void)
+{
+ 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
new file mode 100644
index 000000000..27b4973ac
--- /dev/null
+++ b/base/fifo_buffer.hh
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+#ifndef __FIFO_BUFFER_HH__
+#define __FIFO_BUFFER_HH__
+
+#include "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(void) { return buffer->head(); }
+ iterator tail(void) { return buffer->tail(); }
+
+ unsigned count(void) {return buffer->count();}
+ unsigned free_slots(void) {return buffer->num_free();}
+
+ T * peek(void)
+ {
+ if (count() > 0) {
+ return tail().data_ptr();
+ }
+ else {
+ return 0;
+ }
+ }
+
+ T remove(void)
+ {
+ assert(buffer->count() > 0);
+ T rval = *buffer->tail();
+ buffer->remove_tail();
+ return rval;
+ }
+
+ void dump(void);
+
+ ~FifoBuffer() { delete buffer; }
+};
+
+
+#endif
+
diff --git a/base/hashmap.hh b/base/hashmap.hh
new file mode 100644
index 000000000..21d4a818e
--- /dev/null
+++ b/base/hashmap.hh
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+#ifndef __HASHMAP_HH__
+#define __HASHMAP_HH__
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#include <ext/hash_map>
+#else
+#include <hash_map>
+#endif
+
+#include <string>
+
+#include "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 {
+ template<>
+ struct hash<uint64_t> {
+ size_t operator()(uint64_t r) const {
+ return r;
+ }
+ };
+
+ template<>
+ struct hash<Counter> {
+ size_t operator()(Counter r) const {
+ return r;
+ };
+ };
+
+ 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/inet.cc b/base/inet.cc
new file mode 100644
index 000000000..33483bb32
--- /dev/null
+++ b/base/inet.cc
@@ -0,0 +1,161 @@
+/*
+ * 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.
+ */
+
+#include <sstream>
+#include <string>
+
+#include "cprintf.hh"
+#include "host.hh"
+#include "inet.hh"
+
+using namespace::std;
+string
+eaddr_string(const uint8_t a[6])
+{
+ stringstream stream;
+ ccprintf(stream, "%x:%x:%x:%x:%x:%x", a[0], a[1], a[2], a[3], a[4], a[5]);
+
+ return stream.str();
+}
+
+/*
+ * 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.
+ */
+/***********************************************************************
+ This section of code taken from NetBSD
+***********************************************************************/
+
+#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);
+}
+
+/***********************************************************************
+ This is the end of the NetBSD code
+***********************************************************************/
diff --git a/base/inet.hh b/base/inet.hh
new file mode 100644
index 000000000..1c48d0730
--- /dev/null
+++ b/base/inet.hh
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#ifndef __INET_HH__
+#define __INET_HH__
+
+#include "host.hh"
+
+uint32_t crc32be(const uint8_t *buf, size_t len);
+uint32_t crc32le(const uint8_t *buf, size_t len);
+std::string eaddr_string(const uint8_t a[6]);
+#endif // __INET_HH__
diff --git a/base/inifile.cc b/base/inifile.cc
new file mode 100644
index 000000000..3f80ec259
--- /dev/null
+++ b/base/inifile.cc
@@ -0,0 +1,437 @@
+/*
+ * 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.
+ */
+
+#define USE_CPP
+// #define CPP_PIPE
+
+
+#ifdef USE_CPP
+#include <sys/signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#endif
+
+#include <fstream>
+#include <iostream>
+#if __GNUC__ >= 3
+#include <ext/stdio_filebuf.h>
+#endif
+
+#include <vector>
+#include <string>
+
+#include "inifile.hh"
+#include "str.hh"
+
+using namespace std;
+
+IniFile::IniFile()
+{}
+
+IniFile::~IniFile()
+{
+ ConfigTable::iterator i = table.begin();
+ ConfigTable::iterator end = table.end();
+
+ while (i != end) {
+ delete (*i).second;
+ ++i;
+ }
+}
+
+
+#ifdef USE_CPP
+bool
+IniFile::loadCPP(const string &file, vector<char *> &cppArgs)
+{
+ int fd[2];
+
+#ifdef CPP_PIPE
+ if (pipe(fd) == -1)
+ return false;
+#else
+ char tempfile[] = "/tmp/configXXXXXX";
+ fd[0] = fd[1] = mkstemp(tempfile);
+#endif
+
+ int pid = fork();
+
+ if (pid == -1)
+ return 1;
+
+ 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];
+
+ args[nextArg++] = filename;
+ args[nextArg++] = NULL;
+
+ close(STDOUT_FILENO);
+ if (dup2(fd[1], STDOUT_FILENO) == -1)
+ return 1;
+
+ execvp("g++", args);
+
+ exit(1);
+ }
+
+ int retval;
+ waitpid(pid, &retval, 0);
+
+ // check for normal completion of CPP
+ if (!WIFEXITED(retval) || WEXITSTATUS(retval) != 0)
+ return false;
+
+#ifdef CPP_PIPE
+ close(fd[1]);
+#else
+ lseek(fd[0], 0, SEEK_SET);
+#endif
+
+ bool status = false;
+
+#if __GNUC__ >= 3
+ using namespace __gnu_cxx;
+ stdio_filebuf<char> fbuf(fd[0], ios_base::in, true,
+ static_cast<stdio_filebuf<char>::int_type>(BUFSIZ));
+
+ if (fbuf.is_open()) {
+ istream f(&fbuf);
+ status = load(f);
+ }
+
+#else
+ ifstream f(fd[0]);
+ if (f.is_open())
+ status = load(f);
+#endif
+
+#ifndef CPP_PIPE
+ unlink(tempfile);
+#endif
+
+ 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)
+{
+ EntryTable::iterator ei = table.find(entryName);
+
+ if (ei == table.end()) {
+ // new entry
+ table[entryName] = new Entry(value);
+ }
+ else {
+ // override old entry
+ ei->second->setValue(value);
+ }
+}
+
+
+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 &sectionName)
+{
+ ConfigTable::iterator ci = table.find(sectionName);
+
+ if (ci != table.end()) {
+ return ci->second;
+ }
+ else {
+ // new entry
+ Section *sec = new Section();
+ table[sectionName] = sec;
+ return sec;
+ }
+}
+
+
+IniFile::Section *
+IniFile::findSection(const string &sectionName) const
+{
+ ConfigTable::const_iterator ci = table.find(sectionName);
+
+ return (ci == table.end()) ? NULL : ci->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);
+
+ offset = rest.find('=');
+ if (offset == string::npos) // no '='found
+ return false;
+
+ string entryName = rest.substr(0, offset);
+ string value = rest.substr(offset + 1);
+
+ eat_white(sectionName);
+ eat_white(entryName);
+ eat_white(value);
+
+ Section *s = addSection(sectionName);
+ s->addEntry(entryName, value);
+
+ return true;
+}
+
+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;
+
+ string::size_type offset = line.find('=');
+ string entryName = line.substr(0, offset);
+ string value = line.substr(offset + 1);
+
+ eat_white(entryName);
+ eat_white(value);
+
+ section->addEntry(entryName, value);
+ }
+
+ return true;
+}
+
+bool
+IniFile::find(const string &sectionName, 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::findDefault(const string &_section, const string &entry,
+ string &value) const
+{
+ string section = _section;
+ while (!find(section, entry, value)) {
+ if (!find(section, "default", section))
+ return false;
+ }
+
+ return true;
+}
+
+
+bool
+IniFile::Section::printUnreferenced(const string &sectionName)
+{
+ 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 (ConfigTable::iterator ci = table.begin();
+ ci != table.end(); ++ci) {
+ const string &sectionName = ci->first;
+ Section *section = ci->second;
+
+ if (!section->isReferenced()) {
+ if (section->findEntry("unref_section_ok") == NULL) {
+ cerr << "Section " << sectionName << " not referenced."
+ << endl;
+ unref = true;
+ }
+ }
+ else {
+#if 0
+ if (section->findEntry("unref_entries_ok") == NULL) {
+ bool unrefEntries = section->printUnreferenced(sectionName);
+ unref = unref || unrefEntries;
+ }
+#else
+ if (section->printUnreferenced(sectionName)) {
+ unref = true;
+ }
+#endif
+ }
+ }
+
+ return unref;
+}
+
+
+void
+IniFile::Section::dump(const string &sectionName)
+{
+ for (EntryTable::iterator ei = table.begin();
+ ei != table.end(); ++ei) {
+ cout << sectionName << ": " << (*ei).first << " => "
+ << (*ei).second << "\n";
+ }
+}
+
+void
+IniFile::dump()
+{
+ for (ConfigTable::iterator ci = table.begin();
+ ci != table.end(); ++ci) {
+ ci->second->dump(ci->first);
+ }
+}
diff --git a/base/inifile.hh b/base/inifile.hh
new file mode 100644
index 000000000..b384fe21a
--- /dev/null
+++ b/base/inifile.hh
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+#ifndef __INIFILE_HH__
+#define __INIFILE_HH__
+
+#include <fstream>
+#include <list>
+#include <string>
+#include <vector>
+
+#include "hashmap.hh"
+
+class IniFile
+{
+ protected:
+ class Entry
+ {
+ std::string value;
+ mutable bool referenced;
+
+ public:
+ Entry(const std::string &v)
+ : value(v), referenced(false)
+ {
+ }
+
+ bool isReferenced() { return referenced; }
+
+ const std::string &getValue() const;
+
+ void setValue(const std::string &v) { value = v; }
+ };
+
+ class Section
+ {
+ typedef m5::hash_map<std::string, Entry *> EntryTable;
+
+ EntryTable table;
+ mutable bool referenced;
+
+ public:
+ Section()
+ : table(), referenced(false)
+ {
+ }
+
+ bool isReferenced() { return referenced; }
+
+ void addEntry(const std::string &entryName, const std::string &value);
+ Entry *findEntry(const std::string &entryName) const;
+
+ bool printUnreferenced(const std::string &sectionName);
+ void dump(const std::string &sectionName);
+ };
+
+ typedef m5::hash_map<std::string, Section *> ConfigTable;
+
+ protected:
+ ConfigTable table;
+
+ Section *addSection(const std::string &sectionName);
+ Section *findSection(const std::string &sectionName) const;
+
+ bool load(std::istream &f);
+
+ public:
+ IniFile();
+ ~IniFile();
+
+ bool loadCPP(const std::string &file, std::vector<char *> &cppFlags);
+ bool load(const std::string &file);
+
+ bool add(const std::string &s);
+
+ bool find(const std::string &section, const std::string &entry,
+ std::string &value) const;
+ bool findDefault(const std::string &section, const std::string &entry,
+ std::string &value) const;
+
+ bool printUnreferenced();
+
+ void dump();
+};
+
+#endif // __INIFILE_HH__
diff --git a/base/intmath.cc b/base/intmath.cc
new file mode 100644
index 000000000..8d08e59a8
--- /dev/null
+++ b/base/intmath.cc
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#include "intmath.h"
+
+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.h b/base/intmath.h
new file mode 100644
index 000000000..814dacd5f
--- /dev/null
+++ b/base/intmath.h
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+#ifndef __INTMATH_H__
+#define __INTMATH_H__
+
+// Returns the prime number one less than n.
+int PrevPrime(int n);
+
+// Determine if a number is prime
+inline bool
+IsPrime(int n)
+{
+ int 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;
+}
+
+inline unsigned
+LeastSigBit(unsigned n)
+{ return n & ~(n - 1); }
+
+inline bool
+IsPowerOf2(unsigned n)
+{ return n != 0 && LeastSigBit(n) == n; }
+
+inline int
+FloorLog2(unsigned x)
+{
+ if (x == 0)
+ return -1;
+
+ 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
+CeilLog2(unsigned n)
+{ return FloorLog2(n-1)+1; }
+
+inline unsigned
+FloorPow2(unsigned n)
+{ return 1 << FloorLog2(n); }
+
+inline unsigned
+CeilPow2(unsigned n)
+{ return 1 << CeilLog2(n); }
+
+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_H__
diff --git a/base/kgdb.h b/base/kgdb.h
new file mode 100644
index 000000000..35f74f4ba
--- /dev/null
+++ b/base/kgdb.h
@@ -0,0 +1,203 @@
+/* $Id$ */
+/*
+ * Copyright (c) 1992, 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.
+ *
+ * @(#)remote-sl.h 8.1 (Berkeley) 6/11/93
+ */
+
+/* $NetBSD: kgdb.h,v 1.4 1998/08/13 02:10:59 eeh Exp $ */
+
+#ifndef __KGDB_H__
+#define __KGDB_H__
+
+/*
+ * Message types.
+ */
+#define KGDB_SIGNAL '?' // last sigal
+#define KGDB_SET_BAUD 'b' // set baud (deprecated)
+#define KGDB_SET_BREAK 'B' // set breakpoint (deprecated)
+#define KGDB_CONT 'c' // resume
+#define KGDB_ASYNC_CONT 'C' // continue with signal
+#define KGDB_DEBUG 'd' // toggle debug flags (deprecated)
+#define KGDB_DETACH 'D' // detach remote gdb
+#define KGDB_REG_R 'g' // read general registers
+#define KGDB_REG_W 'G' // write general registers
+#define KGDB_SET_THREAD 'H' // set thread
+#define KGDB_CYCLE_STEP 'i' // step a single cycle
+#define KGDB_SIG_CYCLE_STEP 'I' // signal then single cycle step
+#define KGDB_KILL 'k' // kill program
+#define KGDB_MEM_R 'm' // read memory
+#define KGDB_MEM_W 'M' // write memory
+#define KGDB_READ_REG 'p' // read register
+#define KGDB_SET_REG 'P' // write register
+#define KGDB_QUERY_VAR 'q' // query variable
+#define KGDB_SET_VAR 'Q' // set variable
+#define KGDB_RESET 'r' // reset system. (Deprecated)
+#define KGDB_STEP 's' // step
+#define KGDB_ASYNC_STEP 'S' // signal and step
+#define KGDB_THREAD_ALIVE 'T' // find out if the thread is alive.
+#define KGDB_TARGET_EXIT 'W' // target exited
+#define KGDB_BINARY_DLOAD 'X' // write memory
+#define KGDB_CLR_HW_BKPT 'z' // remove breakpoint or watchpoint
+#define KGDB_SET_HW_BKPT 'Z' // insert breakpoint or watchpoint
+
+/*
+ * start of frame/end of frame
+ */
+#define KGDB_START '$'
+#define KGDB_END '#'
+#define KGDB_GOODP '+'
+#define KGDB_BADP '-'
+
+/*
+ * Stuff for KGDB.
+ */
+#define KGDB_NUMREGS 66 /* from tm-alpha.h, NUM_REGS */
+#define KGDB_REG_V0 0
+#define KGDB_REG_T0 1
+#define KGDB_REG_T1 2
+#define KGDB_REG_T2 3
+#define KGDB_REG_T3 4
+#define KGDB_REG_T4 5
+#define KGDB_REG_T5 6
+#define KGDB_REG_T6 7
+#define KGDB_REG_T7 8
+#define KGDB_REG_S0 9
+#define KGDB_REG_S1 10
+#define KGDB_REG_S2 11
+#define KGDB_REG_S3 12
+#define KGDB_REG_S4 13
+#define KGDB_REG_S5 14
+#define KGDB_REG_S6 15 /* FP */
+#define KGDB_REG_A0 16
+#define KGDB_REG_A1 17
+#define KGDB_REG_A2 18
+#define KGDB_REG_A3 19
+#define KGDB_REG_A4 20
+#define KGDB_REG_A5 21
+#define KGDB_REG_T8 22
+#define KGDB_REG_T9 23
+#define KGDB_REG_T10 24
+#define KGDB_REG_T11 25
+#define KGDB_REG_RA 26
+#define KGDB_REG_T12 27
+#define KGDB_REG_AT 28
+#define KGDB_REG_GP 29
+#define KGDB_REG_SP 30
+#define KGDB_REG_ZERO 31
+#define KGDB_REG_F0 32
+#define KGDB_REG_F1 33
+#define KGDB_REG_F2 34
+#define KGDB_REG_F3 35
+#define KGDB_REG_F4 36
+#define KGDB_REG_F5 37
+#define KGDB_REG_F6 38
+#define KGDB_REG_F7 39
+#define KGDB_REG_F8 40
+#define KGDB_REG_F9 41
+#define KGDB_REG_F10 42
+#define KGDB_REG_F11 43
+#define KGDB_REG_F12 44
+#define KGDB_REG_F13 45
+#define KGDB_REG_F14 46
+#define KGDB_REG_F15 47
+#define KGDB_REG_F16 48
+#define KGDB_REG_F17 49
+#define KGDB_REG_F18 50
+#define KGDB_REG_F19 51
+#define KGDB_REG_F20 52
+#define KGDB_REG_F21 53
+#define KGDB_REG_F22 54
+#define KGDB_REG_F23 55
+#define KGDB_REG_F24 56
+#define KGDB_REG_F25 57
+#define KGDB_REG_F26 58
+#define KGDB_REG_F27 59
+#define KGDB_REG_F28 60
+#define KGDB_REG_F29 61
+#define KGDB_REG_F30 62
+#define KGDB_REG_F31 63
+#define KGDB_REG_PC 64
+#define KGDB_REG_VFP 65
+
+/* Too much? Must be large enough for register transfer. */
+#define KGDB_BUFLEN 1024
+
+/*
+ * Kernel Entry Vectors. [OSF/1 PALcode Specific]
+ */
+
+#define ALPHA_KENTRY_INT 0
+#define ALPHA_KENTRY_ARITH 1
+#define ALPHA_KENTRY_MM 2
+#define ALPHA_KENTRY_IF 3
+#define ALPHA_KENTRY_UNA 4
+#define ALPHA_KENTRY_SYS 5
+
+/*
+ * MMCSR Fault Type Codes. [OSF/1 PALcode Specific]
+ */
+
+#define ALPHA_MMCSR_INVALTRANS 0
+#define ALPHA_MMCSR_ACCESS 1
+#define ALPHA_MMCSR_FOR 2
+#define ALPHA_MMCSR_FOE 3
+#define ALPHA_MMCSR_FOW 4
+
+/*
+ * Instruction Fault Type Codes. [OSF/1 PALcode Specific]
+ */
+
+#define ALPHA_IF_CODE_BPT 0
+#define ALPHA_IF_CODE_BUGCHK 1
+#define ALPHA_IF_CODE_GENTRAP 2
+#define ALPHA_IF_CODE_FEN 3
+#define ALPHA_IF_CODE_OPDEC 4
+
+#define BKPT_INST 0x00000080 // breakpoint instruction
+#define BKPT_SIZE (4) // size of breakpoint inst
+
+#define IS_BREAKPOINT_TRAP(type, code) ((type) == ALPHA_KENTRY_IF && \
+ (code) == ALPHA_IF_CODE_BPT)
+#define IS_WATCHPOINT_TRAP(type, code) 0
+
+
+#endif /* __KGDB_H__ */
diff --git a/base/misc.cc b/base/misc.cc
new file mode 100644
index 000000000..0ce9f7be9
--- /dev/null
+++ b/base/misc.cc
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+#include <iostream>
+#include <string>
+
+#include "host.hh"
+#include "cprintf.hh"
+#include "misc.hh"
+#include "universe.hh"
+#include "trace.hh"
+
+using namespace std;
+
+void
+__panic(const string &format, cp::ArgList &args, const char *func,
+ const char *file, int line)
+{
+ string fmt = "panic: " + format + " [%s:%s, line %d]\n";
+ args.append(func);
+ args.append(file);
+ args.append(line);
+ args.dump(cerr, fmt);
+
+ delete &args;
+
+#if TRACING_ON
+ // dump trace buffer, if there is one
+ Trace::theLog.dump(cerr);
+#endif
+
+ abort();
+}
+
+void
+__fatal(const string &format, cp::ArgList &args, const char *func,
+ const char *file, int line)
+{
+ long mem_usage();
+
+ string fmt = "fatal: " + format + " [%s:%s, line %d]\n"
+ "\n%d\nMemory Usage: %ld KBytes\n";
+
+ args.append(func);
+ args.append(file);
+ args.append(line);
+ args.append(curTick);
+ args.append(mem_usage());
+ 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;
+#ifdef VERBOSE_WARN
+ fmt += " [%s:%s, line %d]\n";
+ args.append(func);
+ args.append(file);
+ args.append(line);
+#else
+ fmt += "\n";
+#endif
+ args.dump(cerr, fmt);
+
+ delete &args;
+}
diff --git a/base/misc.hh b/base/misc.hh
new file mode 100644
index 000000000..3ac4d1491
--- /dev/null
+++ b/base/misc.hh
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#ifndef __MISC_HH__
+#define __MISC_HH__
+
+#include <assert.h>
+#include "cprintf.hh"
+
+//
+// This implements a cprintf based panic
+//
+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
+//
+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
new file mode 100644
index 000000000..3b4ef9bb8
--- /dev/null
+++ b/base/mod_num.hh
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ */
+
+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/object_file.cc b/base/object_file.cc
new file mode 100644
index 000000000..b9542f280
--- /dev/null
+++ b/base/object_file.cc
@@ -0,0 +1,173 @@
+/*
+ * 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.
+ */
+
+#include <list>
+#include <string>
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "cprintf.hh"
+#include "ecoff.hh"
+#include "object_file.hh"
+#include "symtab.hh"
+
+using namespace std;
+
+ObjectFile::ObjectFile()
+ : descriptor(-1), data(NULL)
+{}
+
+ObjectFile::ObjectFile(string file)
+ : descriptor(-1), data(NULL)
+{ open(file); }
+
+ObjectFile::~ObjectFile()
+{ close(); }
+
+bool
+ObjectFile::open(string file_name)
+{
+ close();
+
+ name = file_name;
+
+ descriptor = ::open(name.c_str(), O_RDONLY);
+ if (descriptor < 0)
+ return false;
+
+ len = (size_t)::lseek(descriptor, 0, SEEK_END);
+
+ data = (uint8_t *)::mmap(NULL, len, PROT_READ, MAP_SHARED, descriptor, 0);
+ if (data == MAP_FAILED)
+ return false;
+
+ postOpen();
+
+ return true;
+}
+
+void
+ObjectFile::close()
+{
+ if (descriptor >= 0)
+ ::close(descriptor);
+
+ if (data)
+ ::munmap(data, len);
+}
+
+void
+EcoffObject::postOpen()
+{
+ exec = &(((EcoffExecHeader *)data)->f);
+ aout = &(((EcoffExecHeader *)data)->a);
+
+ text_off = aout->text_start;
+ data_off = aout->data_start;
+ bss_off = aout->bss_start;
+
+ text_size = aout->tsize;
+ data_size = aout->dsize;
+ bss_size = aout->bsize;
+}
+
+bool
+EcoffObject::loadGlobals(SymbolTable *symtab)
+{
+ if (!symtab)
+ return false;
+
+ if (exec->f_magic != ALPHAMAGIC) {
+ cprintf("wrong magic\n");
+ return false;
+ }
+
+ EcoffSymHeader *syms = (EcoffSymHeader *)(data + exec->f_symptr);
+ if (syms->magic != ECOFF_SYM_MAGIC) {
+ cprintf("bad symbol header magic\n");
+ exit(1);
+ }
+
+ EcoffExtSymEntry *ext_syms =
+ (EcoffExtSymEntry *)(data + syms->cbExtOffset);
+
+ char *ext_strings = (char *)(data + syms->cbSsExtOffset);
+ for (int i = 0; i < syms->iextMax; i++) {
+ EcoffSymEntry *entry = &(ext_syms[i].asym);
+ if (entry->iss != -1)
+ symtab->insert(entry->value, ext_strings + entry->iss);
+ }
+
+ return true;
+}
+
+bool
+EcoffObject::loadLocals(SymbolTable *symtab)
+{
+ if (!symtab)
+ return false;
+
+ if (exec->f_magic != ALPHAMAGIC) {
+ cprintf("wrong magic\n");
+ return false;
+ }
+
+ EcoffSymHeader *syms = (EcoffSymHeader *)(data + exec->f_symptr);
+ if (syms->magic != ECOFF_SYM_MAGIC) {
+ cprintf("bad symbol header magic\n");
+ exit(1);
+ }
+
+ EcoffSymEntry *local_syms = (EcoffSymEntry *)(data + syms->cbSymOffset);
+ char *local_strings = (char *)(data + syms->cbSsOffset);
+ EcoffFileDesc *fdesc = (EcoffFileDesc *)(data + syms->cbFdOffset);
+
+ for (int i = 0; i < syms->ifdMax; i++) {
+ EcoffSymEntry *entry =
+ (EcoffSymEntry *)(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 == 1 || entry[j].st == 6)
+ if (entry[j].iss != -1)
+ symtab->insert(entry[j].value, strings + entry[j].iss);
+ }
+ }
+
+ for (int i = 0; i < syms->isymMax; i++) {
+ EcoffSymEntry *entry = &(local_syms[i]);
+ if (entry->st == 6)
+ if (entry->st == 1 || entry->st == 6)
+ symtab->insert(entry->value, local_strings + entry->iss);
+ }
+
+ return true;
+}
diff --git a/base/object_file.hh b/base/object_file.hh
new file mode 100644
index 000000000..c100efc94
--- /dev/null
+++ b/base/object_file.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.
+ */
+
+#ifndef __OBJECT_FILE_HH__
+#define __OBJECT_FILE_HH__
+
+#include "ecoff.hh"
+#include "isa_traits.hh" // for Addr
+
+class SymbolTable;
+
+class ObjectFile
+{
+ protected:
+ std::string name;
+ int descriptor;
+ uint8_t *data;
+ size_t len;
+
+ public:
+ ObjectFile();
+ explicit ObjectFile(std::string file);
+ virtual ~ObjectFile();
+
+ bool open(std::string file);
+ void close();
+
+ virtual bool loadGlobals(SymbolTable *symtab) = 0;
+ virtual bool loadLocals(SymbolTable *symtab) = 0;
+ virtual void postOpen() = 0;
+
+ protected:
+ Addr text_off;
+ Addr data_off;
+ Addr bss_off;
+
+ size_t text_size;
+ size_t data_size;
+ size_t bss_size;
+
+ public:
+ Addr textOffset() const { return text_off; }
+ Addr dataOffset() const { return data_off; }
+ Addr bssOffset() const { return bss_off; }
+
+ size_t textSize() const { return text_size; }
+ size_t dataSize() const { return data_size; }
+ size_t bssSize() const { return bss_size; }
+};
+
+class EcoffObject : public ObjectFile
+{
+ protected:
+ EcoffFileHeader *exec;
+ EcoffAOutHeader *aout;
+
+ public:
+ EcoffObject() {}
+ explicit EcoffObject(std::string file) { open(file); }
+ virtual ~EcoffObject() {}
+
+ virtual bool loadGlobals(SymbolTable *symtab);
+ virtual bool loadLocals(SymbolTable *symtab);
+ virtual void postOpen();
+};
+
+#endif // __OBJECT_FILE_HH__
diff --git a/base/pollevent.cc b/base/pollevent.cc
new file mode 100644
index 000000000..fd08d4c4c
--- /dev/null
+++ b/base/pollevent.cc
@@ -0,0 +1,254 @@
+/*
+ * 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.
+ */
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include "async.hh"
+#include "host.hh"
+#include "misc.hh"
+#include "pollevent.hh"
+#include "universe.hh"
+
+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();
+}
+
+/////////////////////////////////////////////////////
+//
+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 = 0;
+
+ if (sigaction(SIGIO, &act, &oldio) == -1)
+ panic("could not do sigaction");
+
+ act.sa_handler = handleALRM;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+
+ 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
new file mode 100644
index 000000000..57e12f549
--- /dev/null
+++ b/base/pollevent.hh
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+#ifndef __POLLEVENT_H__
+#define __POLLEVENT_H__
+
+#include <vector>
+#include <poll.h>
+#include "universe.hh"
+
+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;
+};
+
+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/random.cc b/base/random.cc
new file mode 100644
index 000000000..42a169c06
--- /dev/null
+++ b/base/random.cc
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+#include <cstdlib>
+#include <cmath>
+
+#include "param.hh"
+#include "random.hh"
+
+using namespace std;
+
+class RandomContext : public ParamContext
+{
+ public:
+ RandomContext(const string &_iniSection)
+ : ::ParamContext(_iniSection) {}
+ ~RandomContext();
+
+ void checkParams();
+};
+
+RandomContext paramContext("random");
+
+Param<unsigned>
+seed(&paramContext, "seed", "seed to random number generator", 1);
+
+void
+RandomContext::checkParams()
+{
+ ::srandom(seed);
+}
+
+long
+getLong()
+{
+ return random();
+}
+
+// idea for generating a double from erand48
+double
+getDouble()
+{
+ union {
+ uint32_t _long[2];
+ uint16_t _short[4];
+ };
+
+ _long[0] = random();
+ _long[1] = random();
+
+ 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
new file mode 100644
index 000000000..f1b383eda
--- /dev/null
+++ b/base/random.hh
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+#ifndef __RANDOM_HH__
+#define __RANDOM_HH__
+
+#include "host.hh"
+
+long getLong();
+double getDouble();
+
+template <typename T>
+struct Random;
+
+struct Random<int8_t>
+{
+ static int8_t get()
+ { return getLong() & (int8_t)-1; }
+};
+
+struct Random<uint8_t>
+{
+ uint8_t get()
+ { return getLong() & (uint8_t)-1; }
+};
+
+struct Random<int16_t>
+{
+ int16_t get()
+ { return getLong() & (int16_t)-1; }
+};
+
+struct Random<uint16_t>
+{
+ uint16_t get()
+ { return getLong() & (uint16_t)-1; }
+};
+
+struct Random<int32_t>
+{
+ int32_t get()
+ { return (int32_t)getLong(); }
+};
+
+struct Random<uint32_t>
+{
+ uint32_t get()
+ { return (uint32_t)getLong(); }
+};
+
+struct Random<int64_t>
+{
+ int64_t get()
+ { return (int64_t)getLong() << 32 || (uint64_t)getLong(); }
+};
+
+struct Random<uint64_t>
+{
+ uint64_t get()
+ { return (uint64_t)getLong() << 32 || (uint64_t)getLong(); }
+};
+
+struct Random<float>
+{
+ float get()
+ { return getDouble(); }
+};
+
+struct Random<double>
+{
+ double get()
+ { return getDouble(); }
+};
+
+#endif // __RANDOM_HH__
diff --git a/base/range.hh b/base/range.hh
new file mode 100644
index 000000000..254e71460
--- /dev/null
+++ b/base/range.hh
@@ -0,0 +1,260 @@
+/*
+ * 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.
+ */
+
+#ifndef __RANGE_HH__
+#define __RANGE_HH__
+
+#include <assert.h>
+
+#include "str.hh"
+#include "intmath.h"
+
+template<class T>
+class Range
+{
+ private:
+ bool valid;
+
+ public:
+ T start;
+ T end;
+
+ public:
+ Range() {}
+
+ Range(const Range &r) { operator=(r); }
+
+ Range(const T& s, const T& e)
+ : start(s), end(e)
+ {
+ valid = (start <= end);
+ }
+
+ Range(const std::string &s) { valid = parse(s); }
+
+ ~Range() {}
+
+ int compare(const T &p);
+ bool parse(const std::string &s);
+ const Range &operator=(const Range &r);
+
+ bool isValid() const { return valid; }
+};
+
+
+template<class T>
+inline int
+Range<T>::compare(const T &p)
+{
+ assert(isValid());
+
+ if (p < start)
+ return -1;
+ else if (p > end)
+ return 1;
+ else
+ return 0;
+}
+
+// Parse a range string
+//
+// Ranges are in the following format:
+// <range> := {<start_val>}:{<end>}
+// <end> := <end_val> | +<delta>
+template<class T>
+inline bool
+Range<T>::parse(const std::string &str)
+{
+ std::vector<std::string> values;
+ tokenize(values, str, ':');
+
+ T thestart, theend;
+
+ if (values.size() != 2)
+ return false;
+
+ std::string s = values[0];
+ std::string e = values[1];
+
+ if (!to_number(s, thestart))
+ return false;
+
+ bool increment = (e[0] == '+');
+ if (increment)
+ e = e.substr(1);
+
+ if (!to_number(e, theend))
+ return false;
+
+ if (increment)
+ theend += thestart;
+
+ start = thestart;
+ end = theend;
+
+ if (start > end)
+ return false;
+
+ return true;
+}
+
+
+template<class T>
+inline const Range<T> &
+Range<T>::operator=(const Range<T> &r)
+{
+ if (this != &r) {
+ start = r.start;
+ end = r.end;
+
+ valid = r.valid;
+ }
+ else {
+ valid = false;
+ }
+
+ return *this;
+}
+
+template<class T>
+inline std::ostream &
+operator<<(std::ostream &o, const Range<T> &r)
+{
+ // don't currently support output of invalid ranges
+ assert(r.isValid());
+ o << r.start << ":" << r.end;
+ return o;
+}
+
+//////////////////////////////////////////
+//
+// Compare two ranges
+//
+template<class T>
+inline bool
+operator==(const Range<T> &l, const Range<T> &r)
+{
+ // ranges must both be valid to be equal
+ return (l.isValid() && r.isValid() &&
+ (l.start == r.start) && (l.end == r.end));
+}
+
+template<class T>
+inline bool
+operator!=(const Range<T> &l, const Range<T> &r)
+{
+ // for symmetry with ==, an invalid range is not equal to any other
+ return (!l.isValid() || !r.isValid() ||
+ (l.start != r.start) || (l.end != r.end));
+}
+
+//////////////////////////////////////////
+//
+// Compare position to a range
+//
+// - 'pos == range' indicates that position pos is within the given range.
+// This test always returns false if the range is invalid.
+//
+// - 'pos < range' and 'pos > range' indicate that the position is
+// before the start of or after the end of the range, respectively.
+// The range must be valid for these comparisons to be made.
+//
+// All other comparisons do the obvious thing based on these definitions.
+//
+//
+
+//
+// Basic comparisons
+//
+template<class T>
+inline bool
+operator==(const T &pos, const Range<T> &range)
+{ return range.isValid() && pos >= range.start && pos <= range.end; }
+
+template<class T>
+inline bool
+operator<(const T &pos, const Range<T> &range)
+{ assert(range.isValid()); return pos < range.start; }
+
+template<class T>
+inline bool
+operator>(const T &pos, const Range<T> &range)
+{ assert(range.isValid()); return pos > range.end; }
+
+//
+// Derived comparisons
+//
+template<class T>
+inline bool
+operator<=(const T &pos, const Range<T> &range)
+{ assert(range.isValid()); return pos <= range.end; }
+
+template<class T>
+inline bool
+operator>=(const T &pos, const Range<T> &range)
+{ assert(range.isValid()); return pos >= range.start; }
+
+template<class T>
+inline bool
+operator!=(const T &pos, const Range<T> &range)
+{ return !(pos == range); }
+
+//
+// Define symmetric comparisons based on above
+//
+template<class T>
+inline bool
+operator>(const Range<T> &range, const T &pos)
+{ return pos < range; }
+
+template<class T>
+inline bool
+operator<(const Range<T> &range, const T &pos)
+{ return pos > range; }
+
+template<class T>
+inline bool
+operator<=(const Range<T> &range, const T &pos)
+{ return pos >= range; }
+
+template<class T>
+inline bool
+operator>=(const Range<T> &range, const T &pos)
+{ return pos <= range; }
+
+template<class T>
+inline bool
+operator==(const Range<T> &range, const T &pos)
+{ return (pos == range); }
+
+template<class T>
+inline bool
+operator!=(const Range<T> &range, const T &pos)
+{ return (pos != range); }
+
+#endif // __RANGE_HH__
diff --git a/base/refcnt.hh b/base/refcnt.hh
new file mode 100644
index 000000000..5bc62ae23
--- /dev/null
+++ b/base/refcnt.hh
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+#ifndef __REFCNT_HH__
+#define __REFCNT_HH__
+
+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
+{
+ private:
+ T *data;
+
+ void copy(T *d) {
+ data = d;
+ if (data)
+ data->incref();
+ }
+ void del() {
+ if (data)
+ data->decref();
+ }
+
+ 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) {
+ if (data != p) {
+ del();
+ copy(p);
+ }
+ return *this;
+ }
+
+ RefCountingPtr &operator=(const RefCountingPtr& r) {
+ if (data != r.data) {
+ del();
+ copy(r.data);
+ }
+ return *this;
+ }
+
+ 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
new file mode 100644
index 000000000..5a6987877
--- /dev/null
+++ b/base/remote_gdb.cc
@@ -0,0 +1,1150 @@
+/* $Id$ */
+/*
+ * 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 <unistd.h>
+
+#include <string>
+
+#include "exec_context.hh"
+#include "intmath.h"
+#include "kgdb.h"
+
+#include "physical_memory.hh"
+#include "remote_gdb.hh"
+#include "socket.hh"
+#include "trace.hh"
+#include "vtophys.hh"
+#include "system.hh"
+#include "static_inst.hh"
+
+using namespace std;
+
+#ifdef DEBUG
+RemoteGDB *theDebugger = NULL;
+
+void
+debugger()
+{
+ if (theDebugger)
+ theDebugger->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)
+{}
+
+GDBListener::~GDBListener()
+{
+ if (event)
+ delete event;
+}
+
+void
+GDBListener::listen()
+{
+ while (!listener.listen(port, true)) {
+ DPRINTF(RGDB, "GDBListener(listen): Can't bind port %d\n", port);
+ port++;
+ }
+
+ cerr << "Listening for remote gdb connection on port " << port << endl;
+ event = new Event(this, listener.getfd(), POLLIN);
+ pollQueue.schedule(event);
+}
+
+void
+GDBListener::accept()
+{
+ if (!listener.islistening())
+ panic("GDBListener(accept): cannot accept a connection 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)
+{ gdb->trap(ALPHA_KENTRY_IF); }
+
+RemoteGDB::RemoteGDB(System *_system, ExecContext *c)
+ : event(NULL), fd(-1), active(false), attached(false),
+ system(_system), pmem(_system->physmem), context(c)
+{
+#ifdef DEBUG
+ theDebugger = this;
+#endif
+ memset(gdbregs, 0, sizeof(gdbregs));
+}
+
+RemoteGDB::~RemoteGDB()
+{
+ if (event)
+ delete event;
+}
+
+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;
+ Addr pte;
+
+ va = alpha_trunc_page(va);
+ last_va = alpha_round_page(va + len);
+
+ do {
+ if (va < ALPHA_K0SEG_BASE) {
+ DPRINTF(RGDB, "RGDB(acc): Mapping is invalid %#x < K0SEG\n", va);
+ return false;
+ }
+
+ if (va < ALPHA_K1SEG_BASE) {
+ if (va < (ALPHA_K0SEG_BASE + pmem->getSize())) {
+ DPRINTF(RGDB, "RGDB(acc): Mapping is valid K0SEG <= "
+ "%#x < K0SEG + size\n", va);
+ return true;
+ } else {
+ DPRINTF(RGDB, "RGDB(acc): Mapping is invalid %#x < K0SEG\n",
+ va);
+ return false;
+ }
+ }
+
+ Addr ptbr = context->regs.ipr[AlphaISA::IPR_PALtemp20];
+ pte = kernel_pte_lookup(pmem, ptbr, va);
+ if (!pte || !entry_valid(pmem->phys_read_qword(pte))) {
+ DPRINTF(RGDB, "RGDB(acc): %#x pte is invalid\n", va);
+ return false;
+ }
+ va += ALPHA_PGBYTES;
+ } while (va < last_va);
+
+ DPRINTF(RGDB, "RGDB(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_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));
+ memcpy(&gdbregs[KGDB_REG_V0], context->regs.intRegFile, 32 * sizeof(uint64_t));
+#ifdef KGDB_FP_REGS
+ memcpy(&gdbregs[KGDB_REG_F0], context->regs.floatRegFile.q,
+ 32 * sizeof(uint64_t));
+#endif
+ gdbregs[KGDB_REG_PC] = context->regs.pc;
+}
+
+///////////////////////////////////////////////////////////
+// RemoteGDB::setregs
+//
+// Translate the GDB register format into the kernel
+// debugger register format.
+//
+void
+RemoteGDB::setregs()
+{
+ memcpy(context->regs.intRegFile, &gdbregs[KGDB_REG_V0], 32 * sizeof(uint64_t));
+#ifdef KGDB_FP_REGS
+ memcpy(context->regs.floatRegFile.q, &gdbregs[KGDB_REG_F0],
+ 32 * sizeof(uint64_t));
+#endif
+ context->regs.pc = gdbregs[KGDB_REG_PC];
+}
+
+void
+RemoteGDB::setTempBreakpoint(TempBreakpoint &bkpt, Addr addr)
+{
+ DPRINTF(RGDB, "RGDB(setTempBreakpoint): addr=%#x\n", addr);
+
+ bkpt.address = addr;
+ insertHardBreak(addr, 4);
+}
+
+void
+RemoteGDB::clearTempBreakpoint(TempBreakpoint &bkpt)
+{
+ DPRINTF(RGDB, "RGDB(setTempBreakpoint): addr=%#x\n",
+ bkpt.address);
+
+
+ removeHardBreak(bkpt.address, 4);
+ bkpt.address = 0;
+}
+
+void
+RemoteGDB::clearSingleStep()
+{
+ DPRINTF(RGDB, "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->regs.pc;
+ 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<TheISA> 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(RGDB, "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(RGDB, "RGDB(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(RGDB, "RGDB(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(RGDB, "\nRGDB(read): reading memory location zero!\n");
+ vaddr = lastaddr + lastsize;
+ }
+
+ DPRINTF(RGDB, "RGDB(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(RGDB)) {
+ char buf[1024];
+ mem2hex(buf, d, s);
+ cprintf(": %s\n", buf);
+ }
+#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(RGDB, "RGDB(write): writing memory location zero!\n");
+ vaddr = lastaddr + lastsize;
+ }
+
+ if (DTRACE(RGDB)) {
+ char buf[1024];
+ mem2hex(buf, data, size);
+ cprintf("RGDB(write): addr=%#x, size=%d: %s\n", vaddr, size, buf);
+ }
+
+ 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(RGDB, "creating hardware breakpoint at %#x\n", evpc);
+ schedule();
+}
+
+void
+RemoteGDB::HardBreakpoint::process(ExecContext *xc)
+{
+ DPRINTF(RGDB, "handling hardware breakpoint at %#x\n", pc());
+
+ if (xc == gdb->context)
+ gdb->trap(ALPHA_KENTRY_IF);
+}
+
+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(RGDB, "inserting hardware breakpoint at %#x\n", addr);
+
+ HardBreakpoint *&bkpt = hardBreakMap[addr];
+ if (bkpt == 0)
+ bkpt = new HardBreakpoint(this, addr);
+
+ bkpt->refcount++;
+
+ return true;
+
+#if 0
+ break_iter_t i = hardBreakMap.find(addr);
+ if (i == hardBreakMap.end()) {
+ HardBreakpoint *bkpt = new HardBreakpoint(this, addr);
+ hardBreakMap[addr] = bkpt;
+ i = hardBreakMap.insert(make_pair(addr, bkpt));
+ if (i == hardBreakMap.end())
+ return false;
+ }
+
+ (*i).second->refcount++;
+#endif
+}
+
+bool
+RemoteGDB::removeHardBreak(Addr addr, size_t len)
+{
+ if (len != sizeof(MachInst))
+ panic("invalid length\n");
+
+ DPRINTF(RGDB, "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(RGDB, "RGDB(trap): PC=%#x NPC=%#x\n",
+ context->regs.pc, context->regs.npc);
+
+ 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) {
+ if (!IS_BREAKPOINT_TRAP(type, 0)) {
+ // No debugger active -- let trap handle this.
+ return false;
+ }
+ active = true;
+ } else {
+ // Tell remote host that an exception has occurred.
+ sprintf((char *)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".
+ sprintf((char *)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->regs.pc = val;
+ context->regs.npc = val + sizeof(MachInst);
+ }
+ clearSingleStep();
+ goto out;
+
+ case KGDB_CONT:
+ if (p - data < datalen) {
+ val = hex2i(&p);
+ context->regs.pc = val;
+ context->regs.npc = val + sizeof(MachInst);
+ }
+ clearSingleStep();
+ goto out;
+
+ case KGDB_ASYNC_STEP:
+ subcmd = hex2i(&p);
+ if (*p++ == ';') {
+ val = hex2i(&p);
+ context->regs.pc = val;
+ context->regs.npc = val + sizeof(MachInst);
+ }
+ setSingleStep();
+ goto out;
+
+ case KGDB_STEP:
+ if (p - data < datalen) {
+ val = hex2i(&p);
+ context->regs.pc = val;
+ context->regs.npc = 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(RGDB, "kgdb: 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(RGDB, "kgdb: 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(RGDB, "kgdb: Unsupported command: %s\n",
+ gdb_command(command));
+ DDUMP(RGDB, (uint8_t *)data, datalen);
+ send("");
+ continue;
+
+ default:
+ // Unknown command.
+ DPRINTF(RGDB, "kgdb: 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
new file mode 100644
index 000000000..315860ead
--- /dev/null
+++ b/base/remote_gdb.hh
@@ -0,0 +1,189 @@
+/*
+ * 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.
+ */
+
+#ifndef __REMOTE_GDB_HH__
+#define __REMOTE_GDB_HH__
+
+#include "kgdb.h"
+#include "pc_event.hh"
+#include "pollevent.hh"
+#include "socket.hh"
+
+class System;
+class ExecContext;
+class PhysicalMemory;
+
+class RemoteGDB
+{
+ 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;
+
+ 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 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:
+ HardBreakpoint(RemoteGDB *_gdb, Addr addr);
+
+ int refcount;
+ 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);
+};
+
+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();
+};
+
+#endif /* __REMOTE_GDB_H__ */
diff --git a/base/res_list.hh b/base/res_list.hh
new file mode 100644
index 000000000..b5eb209c9
--- /dev/null
+++ b/base/res_list.hh
@@ -0,0 +1,756 @@
+/*
+ * 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.
+ */
+
+#ifndef __RES_LIST_HH__
+#define __RES_LIST_HH__
+
+#include "cprintf.hh"
+#include "std_types.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)
+ 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/sched_list.hh b/base/sched_list.hh
new file mode 100644
index 000000000..f5b90f571
--- /dev/null
+++ b/base/sched_list.hh
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ */
+
+#ifndef SCHED_LIST_HH
+#define SCHED_LIST_HH
+
+#include <list>
+#include "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 (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>
+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
new file mode 100644
index 000000000..00fdf1ba3
--- /dev/null
+++ b/base/socket.cc
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+#include "host.hh"
+#include "misc.hh"
+#include "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!");
+
+ 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;
+}
+
+#if !defined(__OpenBSD__) && !defined(linux)
+typedef int socklen_t;
+#endif
+
+// 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
new file mode 100644
index 000000000..39bacba94
--- /dev/null
+++ b/base/socket.hh
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+#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
new file mode 100644
index 000000000..1e8cd2565
--- /dev/null
+++ b/base/statistics.cc
@@ -0,0 +1,823 @@
+/*
+ * 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.
+ */
+
+#include <iomanip>
+#include <iostream>
+#include <list>
+#include <map>
+#include <string>
+#include <sstream>
+
+#include <math.h>
+
+#include "cprintf.hh"
+#include "intmath.h"
+#include "misc.hh"
+#include "statistics.hh"
+#include "str.hh"
+#include "universe.hh"
+
+#ifdef __M5_NAN
+float
+__nan()
+{
+ union {
+ uint32_t ui;
+ float f;
+ } nan;
+
+ nan.ui = 0x7fc00000;
+ return nan.f;
+}
+#endif
+
+#ifdef STAT_DEBUG
+static int total_stats = 0;
+#endif
+
+using namespace std;
+
+// This is a hack to get this parameter from the old stats package.
+namespace Statistics {
+bool PrintDescriptions = true;
+
+namespace Detail {
+struct SubData
+{
+ string name;
+ string desc;
+};
+
+struct StatData
+{
+ StatData();
+ ~StatData();
+
+ bool init;
+ bool print;
+ string name;
+ vector<SubData> *subdata;
+ string desc;
+ int precision;
+ FormatFlags flags;
+ const Stat *prereq;
+};
+
+StatData::StatData()
+ : init(false), print(false), subdata(NULL), precision(-1), flags(none),
+ prereq(NULL)
+{
+}
+
+StatData::~StatData()
+{
+ if (subdata)
+ delete subdata;
+}
+
+class Database
+{
+ private:
+ Database(const Database &) {}
+
+ private:
+ typedef list<Stat *> list_t;
+ typedef map<const Stat *, StatData *> map_t;
+
+ list_t allStats;
+ list_t printStats;
+ map_t map;
+
+ public:
+ Database();
+ ~Database();
+
+ void dump(ostream &stream);
+
+ StatData *find(const Stat *stat);
+ void check();
+ void regStat(Stat *stat);
+ StatData *print(Stat *stat);
+};
+
+Database::Database()
+{}
+
+Database::~Database()
+{}
+
+void
+Database::dump(ostream &stream)
+{
+ list_t::iterator i = printStats.begin();
+ list_t::iterator end = printStats.end();
+
+ while (i != end) {
+ Stat *stat = *i;
+ if (stat->dodisplay())
+ stat->display(stream);
+ ++i;
+ }
+}
+
+StatData *
+Database::find(const Stat *stat)
+{
+ map_t::const_iterator i = map.find(stat);
+
+ if (i == map.end())
+ return NULL;
+
+ return (*i).second;
+}
+
+void
+Database::check()
+{
+ list_t::iterator i = allStats.begin();
+ list_t::iterator end = allStats.end();
+
+ while (i != end) {
+ Stat *stat = *i;
+ StatData *data = find(stat);
+ if (!data || !data->init) {
+#ifdef STAT_DEBUG
+ cprintf("this is stat number %d\n",(*i)->number);
+#endif
+ panic("Not all stats have been initialized");
+ }
+
+ if (data->print) {
+ if (data->name.empty())
+ panic("all printable stats must be named");
+
+ list_t::iterator j = printStats.insert(printStats.end(), *i);
+ inplace_merge(printStats.begin(), j,
+ printStats.end(), Stat::less);
+ }
+
+ ++i;
+ }
+}
+
+void
+Database::regStat(Stat *stat)
+{
+ if (map.find(stat) != map.end())
+ panic("shouldn't register stat twice!");
+
+ allStats.push_back(stat);
+
+ StatData *data = new StatData;
+ bool success = (map.insert(make_pair(stat, data))).second;
+ assert(map.find(stat) != map.end());
+ assert(success && "this should never fail");
+}
+
+bool
+Stat::less(Stat *stat1, Stat *stat2)
+{
+ const string &name1 = stat1->myname();
+ const string &name2 = stat2->myname();
+
+ 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;
+}
+
+StatData *
+Database::print(Stat *stat)
+{
+ StatData *data = find(stat);
+ assert(data);
+
+ data->print = true;
+
+ return data;
+}
+
+Database &
+StatDB()
+{
+ static Database db;
+ return db;
+}
+
+Stat::Stat(bool reg)
+{
+#if 0
+ // This assert can help you find that pesky stat.
+ assert(this != (void *)0xbffff5c0);
+#endif
+
+ if (reg)
+ StatDB().regStat(this);
+#ifdef STAT_DEBUG
+ number = ++total_stats;
+ cprintf("I'm stat number %d\n",number);
+#endif
+}
+
+void
+Stat::setInit()
+{ mydata()->init = true; }
+
+StatData *
+Stat::mydata()
+{
+ StatData *data = StatDB().find(this);
+ assert(data);
+
+ return data;
+}
+
+const StatData *
+Stat::mydata() const
+{
+ StatData *data = StatDB().find(this);
+ assert(data);
+
+ return data;
+}
+
+const SubData *
+Stat::mysubdata(int index) const
+{
+ assert(index >= 0);
+ if (index >= size())
+ return NULL;
+
+ const StatData *data = this->mydata();
+ if (!data->subdata || data->subdata->size() <= index)
+ return NULL;
+
+ return &(*data->subdata)[index];
+}
+
+SubData *
+Stat::mysubdata_create(int index)
+{
+ int size = this->size();
+ assert(index >= 0 && (size == 0 || size > 0 && index < size));
+
+ StatData *data = this->mydata();
+ if (!data->subdata) {
+ if (!data->subdata) {
+ if (size == 0)
+ size = index + 1;
+
+ data->subdata = new vector<SubData>(size);
+ }
+ } else if (data->subdata->size() <= index)
+ data->subdata->resize(index + 1);
+
+ SubData *sd = &(*data->subdata)[index];
+ assert(sd);
+
+ return sd;
+}
+
+string
+Stat::myname() const
+{ return mydata()->name; }
+
+string
+Stat::mysubname(int index) const
+{
+ const SubData *sd = mysubdata(index);
+ return sd ? sd->name : "";
+}
+
+string
+Stat::mydesc() const
+{ return mydata()->desc; }
+
+string
+Stat::mysubdesc(int index) const
+{
+ const SubData *sd = mysubdata(index);
+ return sd ? sd->desc : "";
+}
+
+int
+Stat::myprecision() const
+{ return mydata()->precision; }
+
+FormatFlags
+Stat::myflags() const
+{ return mydata()->flags; }
+
+bool
+Stat::dodisplay() const
+{ return !mydata()->prereq || !mydata()->prereq->zero(); }
+
+StatData *
+Stat::print()
+{
+ StatData *data = StatDB().print(this);
+ assert(data && data->init);
+
+ return data;
+}
+
+Stat &
+Stat::name(const string &name)
+{
+ print()->name = name;
+ return *this;
+}
+
+Stat &
+Stat::desc(const string &desc)
+{
+ print()->desc = desc;
+ return *this;
+}
+
+Stat &
+Stat::precision(int precision)
+{
+ print()->precision = precision;
+ return *this;
+}
+
+Stat &
+Stat::flags(FormatFlags flags)
+{
+ if (flags & __reserved)
+ panic("Cannot set reserved flags!\n");
+
+ print()->flags |= flags;
+ return *this;
+}
+
+Stat &
+Stat::prereq(const Stat &prereq)
+{
+ print()->prereq = &prereq;
+ return *this;
+}
+
+Stat &
+Stat::subname(int index, const string &name)
+{
+ print();
+ mysubdata_create(index)->name = name;
+ return *this;
+}
+Stat &
+Stat::subdesc(int index, const string &desc)
+{
+ print();
+ mysubdata_create(index)->desc = desc;
+ return *this;
+}
+
+bool
+ScalarStat::zero() const
+{
+ return val() == 0.0;
+}
+
+bool
+VectorStat::zero() const
+{
+ return val()[0] == 0.0;
+}
+
+string
+ValueToString(result_t value, int precision)
+{
+ 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 {
+#ifndef STAT_DISPLAY_COMPAT
+ val << "no value";
+#else
+ val << "<err: div-0>";
+#endif
+ }
+
+ return val.str();
+}
+
+void
+PrintOne(ostream &stream, result_t value,
+ const string &name, const string &desc, int precision,
+ FormatFlags flags, result_t pdf = NAN, result_t cdf = NAN)
+{
+ 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);
+
+#ifdef STAT_DISPLAY_COMPAT
+ if (flags & __substat) {
+ ccprintf(stream, "%32s%12s%10s%10s", name,
+ ValueToString(value, precision),
+ pdfstr, cdfstr);
+ } else
+#endif
+ {
+ ccprintf(stream, "%-40s%12s%10s%10s", name,
+ ValueToString(value, precision), pdfstr, cdfstr);
+ }
+
+ if (PrintDescriptions) {
+ if (!desc.empty())
+ ccprintf(stream, " # %s", desc);
+ }
+ stream << endl;
+}
+
+void
+ScalarStat::display(ostream &stream) const
+{
+ PrintOne(stream, val(), myname(), mydesc(), myprecision(), myflags());
+}
+
+void
+VectorStat::display(ostream &stream) const
+{
+ bool have_subname = false;
+ bool have_subdesc = false;
+ int size = this->size();
+ for (int i = 0; i < size; ++i) {
+ if (!mysubname(i).empty())
+ have_subname = true;
+ if (!mysubdesc(i).empty())
+ have_subdesc = true;
+ }
+
+ vector<string> *subnames = 0;
+ vector<string> *subdescs = 0;
+ if (have_subname) {
+ subnames = new vector<string>(size);
+ for (int i = 0; i < size; ++i)
+ (*subnames)[i] = mysubname(i);
+ }
+ if (have_subdesc) {
+ subdescs = new vector<string>(size);
+ for (int i = 0; i < size; ++i)
+ (*subdescs)[i] = mysubdesc(i);
+ }
+
+ VectorDisplay(stream, myname(), subnames, mydesc(), subdescs,
+ myprecision(), myflags(), val(), total());
+}
+
+#ifndef STAT_DISPLAY_COMPAT
+#define NAMESEP "::"
+#else
+#define NAMESEP "_"
+#endif
+
+#ifndef STAT_DISPLAY_COMPAT
+void
+VectorDisplay(std::ostream &stream,
+ const std::string &myname,
+ const std::vector<std::string> *mysubnames,
+ const std::string &mydesc,
+ const std::vector<std::string> *mysubdescs,
+ int myprecision, FormatFlags myflags,
+ const rvec_t &vec, result_t mytotal)
+{
+ int _size = vec.size();
+ result_t _total = 0.0;
+ result_t _pdf, _cdf = 0.0;
+
+ if (myflags & (pdf | cdf)) {
+ for (int i = 0; i < _size; ++i) {
+ _total += vec[i];
+ }
+ }
+
+ if (_size == 1) {
+ PrintOne(stream, vec[0], myname, mydesc, myprecision, myflags);
+ } else {
+ for (int i = 0; i < _size; ++i) {
+ string subname;
+ if (mysubnames) {
+ subname = (*mysubnames)[i];
+ if (subname.empty())
+ continue;
+ } else {
+ subname = to_string(i);
+ }
+
+ string name = myname + NAMESEP + subname;
+ if (!(myflags & pdf))
+ PrintOne(stream, vec[i], name, mydesc, myprecision, myflags);
+ else {
+ _pdf = vec[i] / _total;
+ _cdf += _pdf;
+ PrintOne(stream, vec[i], name, mydesc, myprecision, myflags,
+ _pdf, _cdf);
+ }
+ }
+
+ if (myflags & total)
+ PrintOne(stream, mytotal, myname + NAMESEP + "total",
+ mydesc, myprecision, myflags);
+ }
+}
+#else
+void
+VectorDisplay(std::ostream &stream,
+ const std::string &myname,
+ const std::vector<std::string> *mysubnames,
+ const std::string &mydesc,
+ const std::vector<std::string> *mysubdescs,
+ int myprecision, FormatFlags myflags,
+ const rvec_t &vec, result_t mytotal)
+{
+ int _size = vec.size();
+ result_t _total = 0.0;
+ result_t _pdf, _cdf = 0.0;
+
+ if (myflags & (pdf | cdf)) {
+ for (int i = 0; i < _size; ++i) {
+ _total += vec[i];
+ }
+ }
+
+ if (_size == 1) {
+ PrintOne(stream, vec[0], myname, mydesc, myprecision, myflags);
+ } else {
+ if (myflags & total)
+ PrintOne(stream, mytotal, myname, mydesc, myprecision, myflags);
+
+ if (myflags & dist) {
+ ccprintf(stream, "%s.start_dist\n", myname);
+ for (int i = 0; i < _size; ++i) {
+ string subname, subdesc;
+ subname = to_string(i);
+ if (mysubnames) {
+ if (!subname.empty()) {
+ subname = (*mysubnames)[i];
+ }
+ }
+ if (mysubdescs) {
+ subdesc = (*mysubdescs)[i];
+ }
+ if (!(myflags & (pdf | cdf))) {
+ PrintOne(stream, vec[i], subname, subdesc, myprecision,
+ myflags | __substat);
+ } else {
+ if (_total) {
+ _pdf = vec[i] / _total;
+ _cdf += _pdf;
+ } else {
+ _pdf = _cdf = 0.0;
+ }
+ if (!(myflags & cdf)) {
+ PrintOne(stream, vec[i], subname, subdesc, myprecision,
+ myflags | __substat, _pdf);
+ } else {
+ PrintOne(stream, vec[i], subname, subdesc, myprecision,
+ myflags | __substat, _pdf, _cdf);
+ }
+ }
+ }
+ ccprintf(stream, "%s.end_dist\n", myname);
+ } else {
+ for (int i = 0; i < _size; ++i) {
+ string subname;
+ if (mysubnames) {
+ subname = (*mysubnames)[i];
+ if (subname.empty())
+ continue;
+ } else {
+ subname = to_string(i);
+ }
+
+ string name = myname + NAMESEP + subname;
+ if (!(myflags & pdf)) {
+ PrintOne(stream, vec[i], name, mydesc, myprecision,
+ myflags);
+ } else {
+ if (_total) {
+ _pdf = vec[i] / _total;
+ _cdf += _pdf;
+ } else {
+ _pdf = _cdf = 0.0;
+ }
+ _pdf = vec[i] / _total;
+ _cdf += _pdf;
+ PrintOne(stream, vec[i], name, mydesc, myprecision,
+ myflags, _pdf, _cdf);
+ }
+ }
+ }
+ }
+}
+#endif
+
+#ifndef STAT_DISPLAY_COMPAT
+void
+DistDisplay(ostream &stream, const string &name, const string &desc,
+ int precision, FormatFlags flags,
+ result_t min_val, result_t max_val,
+ result_t underflow, result_t overflow,
+ const rvec_t &vec, int min, int max, int bucket_size, int size);
+{
+ assert(size == vec.size());
+
+ result_t total = 0.0;
+ result_t pdf, cdf = 0.0;
+
+ total += underflow;
+ for (int i = 0; i < size; ++i)
+ total += vec[i];
+ total += overflow;
+
+ pdf = underflow / total;
+ cdf += pdf;
+
+ PrintOne(stream, underflow, name + NAMESEP + "underflow", desc,
+ precision, myflags, pdf, cdf);
+
+ for (int i = 0; i < size; ++i) {
+ stringstream namestr;
+ namestr << name;
+
+ int low = i * bucket_size + min;
+ int high = ::std::min((i + 1) * bucket_size + min - 1, max);
+ namestr << low;
+ if (low < high)
+ namestr << "-" << high;
+
+ pdf = vec[i] / total;
+ cdf += pdf;
+ PrintOne(stream, vec[i], namestr.str(), desc, precision, myflags,
+ pdf, cdf);
+ }
+
+ pdf = overflow / total;
+ cdf += pdf;
+ PrintOne(stream, overflow, name + NAMESEP + "overflow", desc,
+ precision, myflags, pdf, cdf);
+ PrintOne(stream, total, name + NAMESEP + "total", desc,
+ precision, myflags);
+}
+#else
+void
+DistDisplay(ostream &stream, const string &name, const string &desc,
+ int precision, FormatFlags flags,
+ result_t min_val, result_t max_val,
+ result_t underflow, result_t overflow,
+ const rvec_t &vec, int min, int max, int bucket_size, int size)
+{
+ assert(size == vec.size());
+ string blank;
+
+ result_t total = 0.0;
+
+ total += underflow;
+ for (int i = 0; i < size; ++i)
+ total += vec[i];
+ total += overflow;
+
+ ccprintf(stream, "%-42s", name + ".start_dist");
+ if (PrintDescriptions && !desc.empty())
+ ccprintf(stream, " # %s", desc);
+ stream << endl;
+
+ PrintOne(stream, total, name + ".samples", blank, precision, flags);
+ PrintOne(stream, min_val, name + ".min_value", blank, precision, flags);
+
+ if (underflow > 0)
+ PrintOne(stream, min_val, name + ".underflows", blank, precision,
+ flags);
+
+ int _min;
+ result_t _pdf, _cdf, mypdf, mycdf;
+
+ _cdf = 0.0;
+ for (int i = 0; i < size; ++i) {
+ if (flags & nozero && vec[i] == 0.0 ||
+ flags & nonan && isnan(vec[i]))
+ return;
+
+ _min = i * bucket_size + min;
+ _pdf = vec[i] / total * 100.0;
+ _cdf += _pdf;
+
+ mypdf = (flags & pdf) ? _pdf : NAN;
+ mycdf = (flags & cdf) ? _cdf : NAN;
+
+ PrintOne(stream, vec[i], ValueToString(_min, 0), blank, precision,
+ flags | __substat, mypdf, mycdf);
+ }
+
+ if (overflow > 0)
+ PrintOne(stream, overflow, name + ".overflows", blank, precision,
+ flags);
+ PrintOne(stream, max_val, name + ".max_value", blank, precision, flags);
+ ccprintf(stream, "%s.end_dist\n\n", name);
+}
+#endif
+
+void
+FancyDisplay(ostream &stream, const string &name, const string &desc,
+ int precision, FormatFlags flags, result_t mean,
+ result_t variance)
+{
+ result_t stdev = isnan(variance) ? NAN : sqrt(variance);
+ PrintOne(stream, mean, name + NAMESEP + "mean", desc, precision, flags);
+ PrintOne(stream, stdev, name + NAMESEP + "stdev", desc, precision, flags);
+}
+
+BinBase::BinBase(size_t size)
+ : memsize(CeilPow2(size)), mem(NULL)
+{
+}
+
+BinBase::~BinBase()
+{
+ if (mem)
+ delete [] mem;
+}
+
+char *
+BinBase::memory()
+{
+ if (!mem) {
+ mem = new char[memsize];
+ memset(mem, 0, memsize);
+ }
+
+ return mem;
+}
+
+} // namespace Detail
+
+void
+check()
+{
+ Detail::StatDB().check();
+}
+
+void
+dump(ostream &stream)
+{
+ Detail::StatDB().dump(stream);
+}
+
+} // namespace Statistics
diff --git a/base/statistics.hh b/base/statistics.hh
new file mode 100644
index 000000000..3d9d654ed
--- /dev/null
+++ b/base/statistics.hh
@@ -0,0 +1,1682 @@
+/*
+ * 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.
+ */
+
+/*
+ * @todo
+ *
+ * Generalized N-dimensinal vector
+ * documentation
+ * fix AvgStor
+ * key stats
+ * interval stats
+ * -- these both can use the same function that prints out a
+ * specific set of stats
+ * VectorStandardDeviation totals
+ *
+ */
+#ifndef __STATISTICS_HH__
+#define __STATISTICS_HH__
+
+#include <algorithm>
+#include <functional>
+#include <iosfwd>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <assert.h>
+
+#include "host.hh"
+#include "refcnt.hh"
+#include "str.hh"
+
+#ifndef NAN
+float __nan();
+#define NAN (__nan())
+#define __M5_NAN
+#endif
+
+#define STAT_DISPLAY_COMPAT
+
+extern Tick curTick;
+
+namespace Statistics {
+typedef double result_t;
+typedef std::vector<result_t> rvec_t;
+
+typedef u_int32_t FormatFlags;
+const FormatFlags none = 0x0000;
+const FormatFlags total = 0x0001;
+const FormatFlags pdf = 0x0002;
+const FormatFlags nozero = 0x0004;
+const FormatFlags nonan = 0x0008;
+const FormatFlags cdf = 0x0010;
+const FormatFlags dist = 0x0020;
+const FormatFlags __substat = 0x8000;
+const FormatFlags __reserved = __substat;
+
+namespace Detail {
+//////////////////////////////////////////////////////////////////////
+//
+// Statistics Framework Base classes
+//
+//////////////////////////////////////////////////////////////////////
+struct StatData;
+struct SubData;
+
+class Stat
+{
+ protected:
+ void setInit();
+ StatData *mydata();
+ const StatData *mydata() const;
+ StatData *print();
+ const SubData *mysubdata(int index) const;
+ SubData *mysubdata_create(int index);
+
+ public:
+ virtual std::string myname() const;
+ virtual std::string mysubname(int index) const;
+ virtual std::string mydesc() const;
+ virtual std::string mysubdesc(int index) const;
+ virtual FormatFlags myflags() const;
+ virtual bool dodisplay() const;
+ virtual int myprecision() const;
+
+ public:
+ Stat(bool reg);
+ virtual ~Stat() {}
+
+ virtual void display(std::ostream &stream) const = 0;
+ virtual size_t size() const = 0;
+ virtual bool zero() const = 0;
+
+ Stat &name(const std::string &name);
+ Stat &desc(const std::string &desc);
+ Stat &precision(int p);
+ Stat &flags(FormatFlags f);
+ Stat &prereq(const Stat &prereq);
+ Stat &subname(int index, const std::string &name);
+ Stat &subdesc(int index, const std::string &name);
+
+ public:
+ static bool less(Stat *stat1, Stat *stat2);
+
+#ifdef STAT_DEBUG
+ int number;
+#endif
+};
+
+// Scalar stats involved in formulas
+class ScalarStat : public Stat
+{
+ public:
+ ScalarStat(bool reg) : Stat(reg) {}
+ virtual result_t val() const = 0;
+ virtual bool zero() const;
+ virtual void display(std::ostream &stream) const;
+};
+
+void
+VectorDisplay(std::ostream &stream, const std::string &myname,
+ const std::vector<std::string> *mysubnames,
+ const std::string &mydesc,
+ const std::vector<std::string> *mysubdescs,
+ int myprecision, FormatFlags myflags, const rvec_t &vec,
+ result_t mytotal);
+
+// Vector stats involved in formulas
+class VectorStat : public Stat
+{
+ public:
+ VectorStat(bool reg) : Stat(reg) {}
+ virtual const rvec_t &val() const = 0;
+ virtual result_t total() const = 0;
+ virtual bool zero() const;
+ virtual void display(std::ostream &stream) const;
+};
+
+//////////////////////////////////////////////////////////////////////
+//
+// Simple Statistics
+//
+//////////////////////////////////////////////////////////////////////
+template <typename T>
+struct StatStor
+{
+ public:
+ struct Params { };
+
+ private:
+ T data;
+
+ public:
+ StatStor(const Params &) : data(T()) {}
+
+ void set(T val, const Params &p) { data = val; }
+ void inc(T val, const Params &p) { data += val; }
+ void dec(T val, const Params &p) { data -= val; }
+ result_t val(const Params &p) const { return (result_t)data; }
+ T value(const Params &p) const { return data; }
+};
+
+template <typename T>
+struct AvgStor
+{
+ public:
+ struct Params { };
+
+ private:
+ T current;
+ mutable result_t total;
+ mutable Tick last;
+
+ public:
+ AvgStor(const Params &) : current(T()), total(0), last(0) { }
+
+ void set(T val, const Params &p) {
+ total += current * (curTick - last);
+ last = curTick;
+ current = val;
+ }
+ void inc(T val, const Params &p) { set(current + val, p); }
+ void dec(T val, const Params &p) { set(current - val, p); }
+ result_t val(const Params &p) const {
+ total += current * (curTick - last);
+ last = curTick;
+ return (result_t)(total + current) / (result_t)(curTick + 1);
+ }
+ T value(const Params &p) const { return current; }
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+class ScalarBase : public ScalarStat
+{
+ protected:
+ typedef Storage<T> storage_t;
+ typedef typename storage_t::Params params_t;
+ typedef typename Bin::Bin<storage_t> bin_t;
+
+ protected:
+ bin_t bin;
+ params_t params;
+
+ protected:
+ storage_t *data() { return bin.data(params); }
+ const storage_t *data() const {
+ return (const_cast<bin_t *>(&bin))->data(params);
+ }
+
+ protected:
+ // Copying stats is not allowed
+ ScalarBase(const ScalarBase &stat);
+ const ScalarBase &operator=(const ScalarBase &);
+
+ public:
+ result_t val() const { return data()->val(params); }
+ T value() const { return data()->value(params); }
+
+ public:
+ ScalarBase() : ScalarStat(true) {
+ bin.init(params);
+ setInit();
+ }
+
+ public:
+ // Common operators for stats
+ void operator++() { data()->inc(1, params); }
+ void operator--() { data()->dec(1, params); }
+
+ void operator++(int) { ++*this; }
+ void operator--(int) { --*this; }
+
+ template <typename U>
+ void operator=(const U& v) { data()->set(v, params); }
+
+ template <typename U>
+ void operator+=(const U& v) { data()->inc(v, params); }
+
+ template <typename U>
+ void operator-=(const U& v) { data()->dec(v, params); }
+
+ virtual size_t size() const { return 1; }
+};
+
+//////////////////////////////////////////////////////////////////////
+//
+// Vector Statistics
+//
+//////////////////////////////////////////////////////////////////////
+template <typename T, template <typename T> class Storage, class Bin>
+class ScalarProxy;
+
+template <typename T, template <typename T> class Storage, class Bin>
+class VectorBase : public VectorStat
+{
+ protected:
+ typedef Storage<T> storage_t;
+ typedef typename storage_t::Params params_t;
+ typedef typename Bin::VectorBin<storage_t> bin_t;
+
+ private:
+ mutable rvec_t *vec;
+
+ protected:
+ bin_t bin;
+ params_t params;
+
+ protected:
+ storage_t *data(int index) { return bin.data(index, params); }
+ const storage_t *data(int index) const {
+ return (const_cast<bin_t *>(&bin))->data(index, params);
+ }
+
+ protected:
+ // Copying stats is not allowed
+ VectorBase(const VectorBase &stat);
+ const VectorBase &operator=(const VectorBase &);
+
+ public:
+ const rvec_t &val() const {
+ if (vec)
+ vec->resize(size());
+ else
+ vec = new rvec_t(size());
+
+ for (int i = 0; i < size(); ++i)
+ (*vec)[i] = data(i)->val(params);
+
+ return *vec;
+ }
+
+ result_t total() const {
+ result_t total = 0.0;
+ for (int i = 0; i < size(); ++i)
+ total += data(i)->val(params);
+ return total;
+ }
+
+ public:
+ VectorBase() : VectorStat(true), vec(NULL) {}
+ ~VectorBase() { if (vec) delete vec; }
+
+ VectorBase &init(size_t size) {
+ bin.init(size, params);
+ setInit();
+
+ return *this;
+ }
+
+ friend class ScalarProxy<T, Storage, Bin>;
+ ScalarProxy<T, Storage, Bin> operator[](int index);
+
+ virtual size_t size() const { return bin.size(); }
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+class ScalarProxy : public ScalarStat
+{
+ protected:
+ typedef Storage<T> storage_t;
+ typedef typename storage_t::Params params_t;
+ typedef typename Bin::VectorBin<storage_t> bin_t;
+
+ private:
+ bin_t *bin;
+ params_t *params;
+ int index;
+
+ protected:
+ storage_t *data() { return bin->data(index, *params); }
+ const storage_t *data() const { return bin->data(index, *params); }
+
+ public:
+ result_t val() const { return data()->val(*params); }
+ T value() const { return data()->value(*params); }
+
+ public:
+ ScalarProxy(bin_t &b, params_t &p, int i)
+ : ScalarStat(false), bin(&b), params(&p), index(i) {}
+ ScalarProxy(const ScalarProxy &sp)
+ : ScalarStat(false), bin(sp.bin), params(sp.params), index(sp.index) {}
+ const ScalarProxy &operator=(const ScalarProxy &sp) {
+ bin = sp.bin;
+ params = sp.params;
+ index = sp.index;
+ return *this;
+ }
+
+ public:
+ // Common operators for stats
+ void operator++() { data()->inc(1, *params); }
+ void operator--() { data()->dec(1, *params); }
+
+ void operator++(int) { ++*this; }
+ void operator--(int) { --*this; }
+
+ template <typename U>
+ void operator=(const U& v) { data()->set(v, *params); }
+
+ template <typename U>
+ void operator+=(const U& v) { data()->inc(v, *params); }
+
+ template <typename U>
+ void operator-=(const U& v) { data()->dec(v, *params); }
+
+ virtual size_t size() const { return 1; }
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+inline ScalarProxy<T, Storage, Bin>
+VectorBase<T, Storage, Bin>::operator[](int index)
+{
+ assert (index >= 0 && index < size());
+ return ScalarProxy<T, Storage, Bin>(bin, params, index);
+}
+
+template <typename T, template <typename T> class Storage, class Bin>
+class VectorProxy;
+
+template <typename T, template <typename T> class Storage, class Bin>
+class Vector2dBase : public Stat
+{
+ protected:
+ typedef Storage<T> storage_t;
+ typedef typename storage_t::Params params_t;
+ typedef typename Bin::VectorBin<storage_t> bin_t;
+
+ protected:
+ size_t x;
+ size_t y;
+ bin_t bin;
+ params_t params;
+ std::vector<std::string> *y_subnames;
+
+ protected:
+ storage_t *data(int index) { return bin.data(index, params); }
+ const storage_t *data(int index) const {
+ return (const_cast<bin_t *>(&bin))->data(index, params);
+ }
+
+ protected:
+ // Copying stats is not allowed
+ Vector2dBase(const Vector2dBase &stat);
+ const Vector2dBase &operator=(const Vector2dBase &);
+
+ public:
+ Vector2dBase() : Stat(true) {}
+ ~Vector2dBase() { }
+
+ Vector2dBase &init(size_t _x, size_t _y) {
+ x = _x;
+ y = _y;
+ bin.init(x * y, params);
+ setInit();
+ y_subnames = new std::vector<std::string>(y);
+
+ return *this;
+ }
+
+ /**
+ * This makes the assumption that if you're gonna subnames a 2d vector,
+ * you're subnaming across all y
+ */
+ Vector2dBase &ysubnames(const char **names)
+ {
+ for (int i=0; i < y; ++i) {
+ (*y_subnames)[i] = names[i];
+ }
+ return *this;
+ }
+ Vector2dBase &ysubname(int index, const std::string subname)
+ {
+ (*y_subnames)[i] = subname.c_str();
+ return *this;
+ }
+ std::string ysubname(int i) const { return (*y_subnames)[i]; }
+
+ friend class VectorProxy<T, Storage, Bin>;
+ VectorProxy<T, Storage, Bin> operator[](int index);
+
+ virtual size_t size() const { return bin.size(); }
+ virtual bool zero() const { return data(0)->value(params) == 0.0; }
+
+ virtual void
+ display(std::ostream &out) const
+ {
+ bool have_subname = false;
+ for (int i = 0; i < x; ++i) {
+ if (!mysubname(i).empty())
+ have_subname = true;
+ }
+
+ rvec_t tot_vec(y);
+ result_t super_total = 0.0;
+ for (int i = 0; i < x; ++i) {
+ std::string subname;
+ if (have_subname) {
+ subname = mysubname(i);
+ if (subname.empty())
+ continue;
+ } else
+ subname = to_string(i);
+
+ int iy = i * y;
+ rvec_t vec(y);
+
+ result_t total = 0.0;
+ for (int j = 0; j < y; ++j) {
+ vec[j] = data(iy + j)->val(params);
+ tot_vec[j] += vec[j];
+ total += vec[j];
+ super_total += vec[j];
+ }
+
+ std::string desc;
+ if (mysubdesc(i).empty()) {
+ desc = mydesc();
+ } else {
+ desc = mysubdesc(i);
+ }
+
+ VectorDisplay(out, myname() + "_" + subname, y_subnames, desc, 0,
+ myprecision(), myflags(), vec, total);
+
+ }
+ if ((myflags() & ::Statistics::total) && (x > 1)) {
+ VectorDisplay(out, myname(), y_subnames, mydesc(), 0,
+ myprecision(), myflags(), tot_vec, super_total);
+
+ }
+ }
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+class VectorProxy : public VectorStat
+{
+ protected:
+ typedef Storage<T> storage_t;
+ typedef typename storage_t::Params params_t;
+ typedef typename Bin::VectorBin<storage_t> bin_t;
+
+ private:
+ bin_t *bin;
+ params_t *params;
+ int offset;
+ int len;
+
+ private:
+ mutable rvec_t *vec;
+
+ storage_t *data(int index) {
+ assert(index < len);
+ return bin->data(offset + index, *params);
+ }
+
+ const storage_t *data(int index) const {
+ return (const_cast<bin_t *>(bin))->data(offset + index, *params);
+ }
+
+ public:
+ const rvec_t &val() const {
+ if (vec)
+ vec->resize(size());
+ else
+ vec = new rvec_t(size());
+
+ for (int i = 0; i < size(); ++i)
+ (*vec)[i] = data(i)->val(*params);
+
+ return *vec;
+ }
+
+ result_t total() const {
+ result_t total = 0.0;
+ for (int i = 0; i < size(); ++i)
+ total += data(i)->val(*params);
+ return total;
+ }
+
+ public:
+ VectorProxy(bin_t &b, params_t &p, int o, int l)
+ : VectorStat(false), bin(&b), params(&p), offset(o), len(l), vec(NULL)
+ { }
+ VectorProxy(const VectorProxy &sp)
+ : VectorStat(false), bin(sp.bin), params(sp.params), offset(sp.offset),
+ len(sp.len), vec(NULL)
+ { }
+ ~VectorProxy() {
+ if (vec)
+ delete vec;
+ }
+
+ const VectorProxy &operator=(const VectorProxy &sp) {
+ bin = sp.bin;
+ params = sp.params;
+ offset = sp.offset;
+ len = sp.len;
+ if (vec)
+ delete vec;
+ vec = NULL;
+ return *this;
+ }
+
+ virtual size_t size() const { return len; }
+
+ ScalarProxy<T, Storage, Bin> operator[](int index) {
+ assert (index >= 0 && index < size());
+ return ScalarProxy<T, Storage, Bin>(*bin, *params, offset + index);
+ }
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+inline VectorProxy<T, Storage, Bin>
+Vector2dBase<T, Storage, Bin>::operator[](int index)
+{
+ int offset = index * y;
+ assert (index >= 0 && offset < size());
+ return VectorProxy<T, Storage, Bin>(bin, params, offset, y);
+}
+
+//////////////////////////////////////////////////////////////////////
+//
+// Non formula statistics
+//
+//////////////////////////////////////////////////////////////////////
+
+void DistDisplay(std::ostream &stream, const std::string &name,
+ const std::string &desc, int precision, FormatFlags flags,
+ result_t min_val, result_t max_val,
+ result_t underflow, result_t overflow,
+ const rvec_t &vec, int min, int max, int bucket_size,
+ int size);
+
+template <typename T>
+struct DistStor
+{
+ public:
+ struct Params
+ {
+ int min;
+ int max;
+ int bucket_size;
+ int size;
+ };
+
+ private:
+ T min_val;
+ T max_val;
+ T underflow;
+ T overflow;
+ std::vector<T> vec;
+
+ public:
+ DistStor(const Params &params)
+ : min_val(INT_MAX), max_val(INT_MIN), underflow(0), overflow(0),
+ vec(params.size) {
+ }
+ void sample(T val, int number, const Params &params) {
+ if (val < params.min)
+ underflow += number;
+ else if (val > params.max)
+ overflow += number;
+ else {
+ int index = (val - params.min) / params.bucket_size;
+ assert(index < size(params));
+ vec[index] += number;
+ }
+
+ if (val < min_val)
+ min_val = val;
+
+ if (val > max_val)
+ max_val = val;
+ }
+
+ size_t size(const Params &) const { return vec.size(); }
+
+ bool zero(const Params &params) const {
+ if (underflow != 0 || overflow != 0)
+ return true;
+
+ int s = size(params);
+ for (int i = 0; i < s; i++)
+ if (vec[i] != 0)
+ return true;
+
+ return false;
+ }
+
+ void display(std::ostream &stream, const std::string &name,
+ const std::string &desc, int precision, FormatFlags flags,
+ const Params &params) const {
+
+#ifdef STAT_DISPLAY_COMPAT
+ result_t min = params.min;
+#else
+ result_t min = (min_val == INT_MAX) ? params.min : min_val;
+#endif
+ result_t max = (max_val == INT_MIN) ? 0 : max_val;
+
+ rvec_t rvec(params.size);
+ for (int i = 0; i < params.size; ++i)
+ rvec[i] = vec[i];
+
+ DistDisplay(stream, name, desc, precision, flags,
+ (result_t)min, (result_t)max,
+ (result_t)underflow, (result_t)overflow,
+ rvec, params.min, params.max, params.bucket_size,
+ params.size);
+ }
+};
+
+void FancyDisplay(std::ostream &stream, const std::string &name,
+ const std::string &desc, int precision, FormatFlags flags,
+ result_t mean, result_t variance);
+template <typename T>
+struct FancyStor
+{
+ public:
+ struct Params {};
+
+ private:
+ T sum;
+ T squares;
+ int total;
+
+ public:
+ FancyStor(const Params &) : sum(0), squares(0), total(0) {}
+
+ void sample(T val, int number, const Params &) {
+ T value = val * number;
+ sum += value;
+ squares += value * value;
+ total += number;
+ }
+ void display(std::ostream &stream, const std::string &name,
+ const std::string &desc, int precision, FormatFlags flags,
+ const Params &) const {
+
+ result_t mean = NAN;
+ result_t variance = NAN;
+
+ if (total != 0) {
+ result_t fsum = sum;
+ result_t fsq = squares;
+ result_t ftot = total;
+
+ mean = fsum / ftot;
+ variance = (ftot * fsq - (fsum * fsum)) / (ftot * (ftot - 1.0));
+ }
+
+ FancyDisplay(stream, name, desc, precision, flags, mean, variance);
+ }
+
+ size_t size(const Params &) const { return 1; }
+ bool zero(const Params &) const { return total == 0; }
+};
+
+template <typename T>
+struct AvgFancy
+{
+ public:
+ struct Params {};
+
+ private:
+ T sum;
+ T squares;
+
+ public:
+ AvgFancy(const Params &) : sum(0), squares(0) {}
+
+ void sample(T val, int number, const Params& p) {
+ T value = val * number;
+ sum += value;
+ squares += value * value;
+ }
+ void display(std::ostream &stream, const std::string &name,
+ const std::string &desc, int precision, FormatFlags flags,
+ const Params &params) const {
+ result_t mean = sum / curTick;
+ result_t variance = (squares - sum * sum) / curTick;
+
+ FancyDisplay(stream, name, desc, precision, flags, mean, variance);
+ }
+
+ size_t size(const Params &params) const { return 1; }
+ bool zero(const Params &params) const { return sum == 0; }
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+class DistBase : public Stat
+{
+ protected:
+ typedef Storage<T> storage_t;
+ typedef typename storage_t::Params params_t;
+ typedef typename Bin::Bin<storage_t> bin_t;
+
+ protected:
+ bin_t bin;
+ params_t params;
+
+ protected:
+ storage_t *data() { return bin.data(params); }
+ const storage_t *data() const {
+ return (const_cast<bin_t *>(&bin))->data(params);
+ }
+
+ protected:
+ // Copying stats is not allowed
+ DistBase(const DistBase &stat);
+ const DistBase &operator=(const DistBase &);
+
+ public:
+ DistBase() : Stat(true) { }
+ ~DistBase() { }
+
+ template <typename U>
+ void sample(const U& v, int n = 1) { data()->sample(v, n, params); }
+
+ virtual size_t size() const { return data()->size(params); }
+ virtual bool zero() const { return data()->zero(params); }
+ virtual void display(std::ostream &stream) const {
+ data()->display(stream, myname(), mydesc(), myprecision(), myflags(),
+ params);
+ }
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+class VectorDistProxy;
+
+template <typename T, template <typename T> class Storage, class Bin>
+class VectorDistBase : public Stat
+{
+ protected:
+ typedef Storage<T> storage_t;
+ typedef typename storage_t::Params params_t;
+ typedef typename Bin::VectorBin<storage_t> bin_t;
+
+ protected:
+ bin_t bin;
+ params_t params;
+
+ protected:
+ storage_t *data(int index) { return bin.data(index, params); }
+ const storage_t *data(int index) const {
+ return (const_cast<bin_t *>(&bin))->data(index, params);
+ }
+
+ protected:
+ // Copying stats is not allowed
+ VectorDistBase(const VectorDistBase &stat);
+ const VectorDistBase &operator=(const VectorDistBase &);
+
+ public:
+ VectorDistBase() : Stat(true) { }
+ ~VectorDistBase() { }
+
+ friend class VectorDistProxy<T, Storage, Bin>;
+ VectorDistProxy<T, Storage, Bin> operator[](int index);
+ const VectorDistProxy<T, Storage, Bin> operator[](int index) const;
+
+ virtual size_t size() const { return bin.size(); }
+ virtual bool zero() const { return false; }
+ virtual void display(std::ostream &stream) const;
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+class VectorDistProxy : public Stat
+{
+ protected:
+ typedef Storage<T> storage_t;
+ typedef typename storage_t::Params params_t;
+ typedef typename Bin::Bin<storage_t> bin_t;
+ typedef VectorDistBase<T, Storage, Bin> base_t;
+
+ private:
+ union {
+ base_t *stat;
+ const base_t *cstat;
+ };
+ int index;
+
+ protected:
+ storage_t *data() { return stat->data(index); }
+ const storage_t *data() const { return cstat->data(index); }
+
+ public:
+ VectorDistProxy(const VectorDistBase<T, Storage, Bin> &s, int i)
+ : Stat(false), cstat(&s), index(i) {}
+ VectorDistProxy(const VectorDistProxy &sp)
+ : Stat(false), cstat(sp.cstat), index(sp.index) {}
+ const VectorDistProxy &operator=(const VectorDistProxy &sp) {
+ cstat = sp.cstat; index = sp.index; return *this;
+ }
+
+ public:
+ template <typename U>
+ void sample(const U& v, int n = 1) { data()->sample(v, n, cstat->params); }
+
+ virtual size_t size() const { return 1; }
+ virtual bool zero() const {
+ return data()->zero(cstat->params);
+ }
+ virtual void display(std::ostream &stream) const {
+ std::stringstream name, desc;
+
+ if (!(cstat->mysubname(index).empty())) {
+ name << cstat->myname() << cstat->mysubname(index);
+ } else {
+ name << cstat->myname() << "_" << index;
+ }
+ if (!(cstat->mysubdesc(index).empty())) {
+ desc << cstat->mysubdesc(index);
+ } else {
+ desc << cstat->mydesc();
+ }
+
+ data()->display(stream, name.str(), desc.str(),
+ cstat->myprecision(), cstat->myflags(), cstat->params);
+ }
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+inline VectorDistProxy<T, Storage, Bin>
+VectorDistBase<T, Storage, Bin>::operator[](int index)
+{
+ assert (index >= 0 && index < size());
+ return VectorDistProxy<T, Storage, Bin>(*this, index);
+}
+
+template <typename T, template <typename T> class Storage, class Bin>
+inline const VectorDistProxy<T, Storage, Bin>
+VectorDistBase<T, Storage, Bin>::operator[](int index) const
+{
+ assert (index >= 0 && index < size());
+ return VectorDistProxy<T, Storage, Bin>(*this, index);
+}
+
+/**
+ * @todo Need a way to print Distribution totals across the Vector
+ */
+template <typename T, template <typename T> class Storage, class Bin>
+void
+VectorDistBase<T, Storage, Bin>::display(std::ostream &stream) const
+{
+ for (int i = 0; i < size(); ++i) {
+ VectorDistProxy<T, Storage, Bin> proxy(*this, i);
+ proxy.display(stream);
+ }
+}
+
+#if 0
+result_t
+VectorDistBase<T, Storage, Bin>::total(int index) const
+{
+ int total = 0;
+ for (int i=0; i < x_size(); ++i) {
+ total += data(i)->val(*params);
+ }
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////
+//
+// Formula Details
+//
+//////////////////////////////////////////////////////////////////////
+class Node : public RefCounted
+{
+ public:
+ virtual size_t size() const = 0;
+ virtual const rvec_t &val() const = 0;
+ virtual result_t total() const = 0;
+};
+
+typedef RefCountingPtr<Node> NodePtr;
+
+class ScalarStatNode : public Node
+{
+ private:
+ const ScalarStat &stat;
+ mutable rvec_t result;
+
+ public:
+ ScalarStatNode(const ScalarStat &s) : stat(s), result(1) {}
+ const rvec_t &val() const { result[0] = stat.val(); return result; }
+ virtual result_t total() const { return stat.val(); };
+
+ virtual size_t size() const { return 1; }
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+class ScalarProxyNode : public Node
+{
+ private:
+ const ScalarProxy<T, Storage, Bin> proxy;
+ mutable rvec_t result;
+
+ public:
+ ScalarProxyNode(const ScalarProxy<T, Storage, Bin> &p)
+ : proxy(p), result(1) { }
+ const rvec_t &val() const { result[0] = proxy.val(); return result; }
+ virtual result_t total() const { return proxy.val(); };
+
+ virtual size_t size() const { return 1; }
+};
+
+class VectorStatNode : public Node
+{
+ private:
+ const VectorStat &stat;
+
+ public:
+ VectorStatNode(const VectorStat &s) : stat(s) {}
+ const rvec_t &val() const { return stat.val(); }
+ virtual result_t total() const { return stat.total(); };
+
+ virtual size_t size() const { return stat.size(); }
+};
+
+template <typename T>
+class ConstNode : public Node
+{
+ private:
+ rvec_t data;
+
+ public:
+ ConstNode(T s) : data(1, (result_t)s) {}
+ const rvec_t &val() const { return data; }
+ virtual result_t total() const { return data[0]; };
+
+ virtual size_t size() const { return 1; }
+};
+
+template <typename T>
+class FunctorNode : public Node
+{
+ private:
+ T &functor;
+ mutable rvec_t result;
+
+ public:
+ FunctorNode(T &f) : functor(f) { result.resize(1); }
+ const rvec_t &val() const {
+ result[0] = (result_t)functor();
+ return result;
+ }
+ virtual result_t total() const { return (result_t)functor(); };
+
+ virtual size_t size() const { return 1; }
+};
+
+template <typename T>
+class ScalarNode : public Node
+{
+ private:
+ T &scalar;
+ mutable rvec_t result;
+
+ public:
+ ScalarNode(T &s) : scalar(s) { result.resize(1); }
+ const rvec_t &val() const {
+ result[0] = (result_t)scalar;
+ return result;
+ }
+ virtual result_t total() const { return (result_t)scalar; };
+
+ virtual size_t size() const { return 1; }
+};
+
+template <class Op>
+class UnaryNode : public Node
+{
+ public:
+ NodePtr l;
+ mutable rvec_t result;
+
+ public:
+ UnaryNode(NodePtr p) : l(p) {}
+
+ const rvec_t &val() const {
+ const rvec_t &lvec = l->val();
+ int size = lvec.size();
+
+ assert(size > 0);
+
+ result.resize(size);
+ Op op;
+ for (int i = 0; i < size; ++i)
+ result[i] = op(lvec[i]);
+
+ return result;
+ }
+
+ result_t total() const {
+ Op op;
+ return op(l->total());
+ }
+
+ virtual size_t size() const { return l->size(); }
+};
+
+template <class Op>
+class BinaryNode : public Node
+{
+ public:
+ NodePtr l;
+ NodePtr r;
+ mutable rvec_t result;
+
+ public:
+ BinaryNode(NodePtr a, NodePtr b) : l(a), r(b) {}
+
+ const rvec_t &val() const {
+ Op op;
+ const rvec_t &lvec = l->val();
+ const rvec_t &rvec = r->val();
+
+ assert(lvec.size() > 0 && rvec.size() > 0);
+
+ if (lvec.size() == 1 && rvec.size() == 1) {
+ result.resize(1);
+ result[0] = op(lvec[0], rvec[0]);
+ } else if (lvec.size() == 1) {
+ int size = rvec.size();
+ result.resize(size);
+ for (int i = 0; i < size; ++i)
+ result[i] = op(lvec[0], rvec[i]);
+ } else if (rvec.size() == 1) {
+ int size = lvec.size();
+ result.resize(size);
+ for (int i = 0; i < size; ++i)
+ result[i] = op(lvec[i], rvec[0]);
+ } else if (rvec.size() == lvec.size()) {
+ int size = rvec.size();
+ result.resize(size);
+ for (int i = 0; i < size; ++i)
+ result[i] = op(lvec[i], rvec[i]);
+ }
+
+ return result;
+ }
+
+ result_t 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;
+ }
+ }
+};
+
+template <class Op>
+class SumNode : public Node
+{
+ public:
+ NodePtr l;
+ mutable rvec_t result;
+
+ public:
+ SumNode(NodePtr p) : l(p), result(1) {}
+
+ const rvec_t &val() const {
+ const rvec_t &lvec = l->val();
+ int size = lvec.size();
+ assert(size > 0);
+
+ result[0] = 0.0;
+
+ Op op;
+ for (int i = 0; i < size; ++i)
+ result[0] = op(result[0], lvec[i]);
+
+ return result;
+ }
+
+ result_t total() const {
+ const rvec_t &lvec = l->val();
+ int size = lvec.size();
+ assert(size > 0);
+
+ result_t result = 0.0;
+
+ Op op;
+ for (int i = 0; i < size; ++i)
+ result = op(result, lvec[i]);
+
+ return result;
+ }
+
+ virtual size_t size() const { return 1; }
+};
+
+class Temp
+{
+ private:
+ NodePtr node;
+
+ public:
+ Temp(NodePtr n) : node(n) {}
+ Temp(const ScalarStat &s) : node(new ScalarStatNode(s)) {}
+ template <typename T, template <typename T> class Storage, class Bin>
+ Temp(const ScalarProxy<T, Storage, Bin> &p)
+ : node(new ScalarProxyNode<T, Storage, Bin>(p)) {}
+ Temp(const VectorStat &s) : node(new VectorStatNode(s)) {}
+
+#define TempSCALAR(T) \
+ Temp(T value) : node(new ConstNode<T>(value)) {}
+
+ TempSCALAR( signed char);
+ TempSCALAR(unsigned char);
+ TempSCALAR( signed short);
+ TempSCALAR(unsigned short);
+ TempSCALAR( signed int);
+ TempSCALAR(unsigned int);
+ TempSCALAR( signed long);
+ TempSCALAR(unsigned long);
+ TempSCALAR( signed long long);
+ TempSCALAR(unsigned long long);
+ TempSCALAR(float);
+ TempSCALAR(double);
+#undef TempSCALAR
+
+ operator NodePtr() { return node;}
+};
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Binning Interface
+//
+//////////////////////////////////////////////////////////////////////
+
+class BinBase
+{
+ private:
+ off_t memsize;
+ char *mem;
+
+ protected:
+ off_t size() const { return memsize; }
+ char *memory();
+
+ public:
+ BinBase(size_t size);
+ ~BinBase();
+};
+
+} // namespace Detail
+
+template <class BinType>
+struct StatBin : public Detail::BinBase
+{
+ static StatBin *&curBin() {
+ static StatBin *current = NULL;
+ return current;
+ }
+
+ static void setCurBin(StatBin *bin) { curBin() = bin; }
+ static StatBin *current() { assert(curBin()); return curBin(); }
+
+ static off_t &offset() {
+ static off_t offset = 0;
+ return offset;
+ }
+
+ static off_t new_offset(size_t size) {
+ size_t mask = sizeof(u_int64_t) - 1;
+ off_t off = offset();
+
+ // That one is for the last trailing flags byte.
+ offset() += (size + 1 + mask) & ~mask;
+
+ return off;
+ }
+
+ explicit StatBin(size_t size = 1024) : Detail::BinBase(size) {}
+
+ char *memory(off_t off) {
+ assert(offset() <= size());
+ return Detail::BinBase::memory() + off;
+ }
+
+ static void activate(StatBin &bin) { setCurBin(&bin); }
+
+ class BinBase
+ {
+ private:
+ int offset;
+
+ public:
+ BinBase() : offset(-1) {}
+ void allocate(size_t size) {
+ offset = new_offset(size);
+ }
+ char *access() {
+ assert(offset != -1);
+ return current()->memory(offset);
+ }
+ };
+
+ template <class Storage>
+ class Bin : public BinBase
+ {
+ public:
+ typedef typename Storage::Params Params;
+
+ public:
+ Bin() { allocate(sizeof(Storage)); }
+ bool initialized() const { return true; }
+ void init(const Params &params) { }
+
+ int size() const { return 1; }
+
+ Storage *data(const Params &params) {
+ assert(initialized());
+ char *ptr = access();
+ char *flags = ptr + sizeof(Storage);
+ if (!(*flags & 0x1)) {
+ *flags |= 0x1;
+ new (ptr) Storage(params);
+ }
+ return reinterpret_cast<Storage *>(ptr);
+ }
+ };
+
+ template <class Storage>
+ class VectorBin : public BinBase
+ {
+ public:
+ typedef typename Storage::Params Params;
+
+ private:
+ int _size;
+
+ public:
+ VectorBin() : _size(0) {}
+
+ bool initialized() const { return _size > 0; }
+ void init(int s, const Params &params) {
+ assert(!initialized());
+ assert(s > 0);
+ _size = s;
+ allocate(_size * sizeof(Storage));
+ }
+
+ int size() const { return _size; }
+
+ Storage *data(int index, const Params &params) {
+ assert(initialized());
+ assert(index >= 0 && index < size());
+ char *ptr = access();
+ char *flags = ptr + size() * sizeof(Storage);
+ if (!(*flags & 0x1)) {
+ *flags |= 0x1;
+ for (int i = 0; i < size(); ++i)
+ new (ptr + i * sizeof(Storage)) Storage(params);
+ }
+ return reinterpret_cast<Storage *>(ptr + index * sizeof(Storage));
+ }
+ };
+};
+
+class MainBinType {};
+typedef StatBin<MainBinType> MainBin;
+
+struct NoBin
+{
+ template <class Storage>
+ struct Bin
+ {
+ public:
+ typedef typename Storage::Params Params;
+
+ private:
+ char ptr[sizeof(Storage)];
+
+ public:
+ bool initialized() const { return true; }
+ void init(const Params &params) {
+ new (ptr) Storage(params);
+ }
+ int size() const{ return 1; }
+ Storage *data(const Params &params) {
+ assert(initialized());
+ return reinterpret_cast<Storage *>(ptr);
+ }
+ };
+
+ template <class Storage>
+ struct VectorBin
+ {
+ public:
+ typedef typename Storage::Params Params;
+
+ private:
+ char *ptr;
+ int _size;
+
+ public:
+ VectorBin() : ptr(NULL) { }
+ ~VectorBin() {
+ if (initialized())
+ delete [] ptr;
+ }
+ bool initialized() const { return ptr != NULL; }
+ void init(int s, const Params &params) {
+ assert(s > 0 && "size must be positive!");
+ assert(!initialized());
+ _size = s;
+ ptr = new char[_size * sizeof(Storage)];
+ for (int i = 0; i < _size; ++i)
+ new (ptr + i * sizeof(Storage)) Storage(params);
+ }
+
+ int size() const { return _size; }
+
+ Storage *data(int index, const Params &params) {
+ assert(initialized());
+ assert(index >= 0 && index < size());
+ return reinterpret_cast<Storage *>(ptr + index * sizeof(Storage));
+ }
+ };
+};
+
+//////////////////////////////////////////////////////////////////////
+//
+// Visible Statistics Types
+//
+//////////////////////////////////////////////////////////////////////
+template <typename T = Counter, class Bin = NoBin>
+class Scalar : public Detail::ScalarBase<T, Detail::StatStor, Bin>
+{
+ public:
+ typedef Detail::ScalarBase<T, Detail::StatStor, Bin> Base;
+
+ template <typename U>
+ void operator=(const U& v) { Base::operator=(v); }
+};
+
+template <typename T = Counter, class Bin = NoBin>
+class Average : public Detail::ScalarBase<T, Detail::AvgStor, Bin>
+{
+ public:
+ typedef Detail::ScalarBase<T, Detail::AvgStor, Bin> Base;
+
+ template <typename U>
+ void operator=(const U& v) { Base::operator=(v); }
+};
+
+template <typename T = Counter, class Bin = NoBin>
+class Vector : public Detail::VectorBase<T, Detail::StatStor, Bin>
+{ };
+
+template <typename T = Counter, class Bin = NoBin>
+class AverageVector : public Detail::VectorBase<T, Detail::AvgStor, Bin>
+{ };
+
+template <typename T = Counter, class Bin = NoBin>
+class Vector2d : public Detail::Vector2dBase<T, Detail::StatStor, Bin>
+{ };
+
+template <typename T = Counter, class Bin = NoBin>
+class Distribution : public Detail::DistBase<T, Detail::DistStor, Bin>
+{
+ private:
+ typedef Detail::DistBase<T, Detail::DistStor, Bin> Base;
+ typedef typename Detail::DistStor<T>::Params Params;
+
+ public:
+ Distribution &init(T min, T max, int bkt) {
+ params.min = min;
+ params.max = max;
+ params.bucket_size = bkt;
+ params.size = (max - min) / bkt + 1;
+ bin.init(params);
+ setInit();
+
+ return *this;
+ }
+};
+
+template <typename T = Counter, class Bin = NoBin>
+class StandardDeviation : public Detail::DistBase<T, Detail::FancyStor, Bin>
+{
+ private:
+ typedef Detail::DistBase<T, Detail::DistStor, Bin> Base;
+ typedef typename Detail::DistStor<T>::Params Params;
+
+ public:
+ StandardDeviation() {
+ bin.init(params);
+ setInit();
+ }
+};
+
+template <typename T = Counter, class Bin = NoBin>
+class AverageDeviation : public Detail::DistBase<T, Detail::AvgFancy, Bin>
+{
+ private:
+ typedef Detail::DistBase<T, Detail::DistStor, Bin> Base;
+ typedef typename Detail::DistStor<T>::Params Params;
+
+ public:
+ AverageDeviation() {
+ bin.init(params);
+ setInit();
+ }
+};
+
+template <typename T = Counter, class Bin = NoBin>
+class VectorDistribution
+ : public Detail::VectorDistBase<T, Detail::DistStor, Bin>
+{
+ private:
+ typedef Detail::VectorDistBase<T, Detail::DistStor, Bin> Base;
+ typedef typename Detail::DistStor<T>::Params Params;
+
+ public:
+ VectorDistribution &init(int size, T min, T max, int bkt) {
+ params.min = min;
+ params.max = max;
+ params.bucket_size = bkt;
+ params.size = (max - min) / bkt + 1;
+ bin.init(size, params);
+ setInit();
+
+ return *this;
+ }
+};
+
+template <typename T = Counter, class Bin = NoBin>
+class VectorStandardDeviation
+ : public Detail::VectorDistBase<T, Detail::FancyStor, Bin>
+{
+ private:
+ typedef Detail::VectorDistBase<T, Detail::FancyStor, Bin> Base;
+ typedef typename Detail::DistStor<T>::Params Params;
+
+ public:
+ VectorStandardDeviation &init(int size) {
+ bin.init(size, params);
+ setInit();
+
+ return *this;
+ }
+};
+
+template <typename T = Counter, class Bin = NoBin>
+class VectorAverageDeviation
+ : public Detail::VectorDistBase<T, Detail::AvgFancy, Bin>
+{
+ private:
+ typedef Detail::VectorDistBase<T, Detail::AvgFancy, Bin> Base;
+ typedef typename Detail::DistStor<T>::Params Params;
+
+ public:
+ VectorAverageDeviation &init(int size) {
+ bin.init(size, params);
+ setInit();
+
+ return *this;
+ }
+};
+
+class Formula : public Detail::VectorStat
+{
+ private:
+ Detail::NodePtr root;
+ friend class Detail::Temp;
+
+ public:
+ Formula() : VectorStat(true) { setInit(); }
+ Formula(Detail::Temp r) : VectorStat(true) {
+ root = r;
+ assert(size());
+ }
+
+ const Formula &operator=(Detail::Temp r) {
+ assert(!root && "Can't change formulas");
+ root = r;
+ assert(size());
+ return *this;
+ }
+
+ const Formula &operator+=(Detail::Temp r) {
+ using namespace Detail;
+ if (root)
+ root = NodePtr(new BinaryNode<std::plus<result_t> >(root, r));
+ else
+ root = r;
+ assert(size());
+ return *this;
+ }
+
+ const rvec_t &val() const { return root->val(); }
+ result_t total() const { return root->total(); }
+
+ size_t size() const {
+ if (!root)
+ return 0;
+ else
+ return root->size();
+ }
+};
+
+void check();
+void dump(std::ostream &stream);
+
+inline Detail::Temp
+operator+(Detail::Temp l, Detail::Temp r)
+{
+ using namespace Detail;
+ return NodePtr(new BinaryNode<std::plus<result_t> >(l, r));
+}
+
+inline Detail::Temp
+operator-(Detail::Temp l, Detail::Temp r)
+{
+ using namespace Detail;
+ return NodePtr(new BinaryNode<std::minus<result_t> >(l, r));
+}
+
+inline Detail::Temp
+operator*(Detail::Temp l, Detail::Temp r)
+{
+ using namespace Detail;
+ return NodePtr(new BinaryNode<std::multiplies<result_t> >(l, r));
+}
+
+inline Detail::Temp
+operator/(Detail::Temp l, Detail::Temp r)
+{
+ using namespace Detail;
+ return NodePtr(new BinaryNode<std::divides<result_t> >(l, r));
+}
+
+inline Detail::Temp
+operator%(Detail::Temp l, Detail::Temp r)
+{
+ using namespace Detail;
+ return NodePtr(new BinaryNode<std::modulus<result_t> >(l, r));
+}
+
+inline Detail::Temp
+operator-(Detail::Temp l)
+{
+ using namespace Detail;
+ return NodePtr(new UnaryNode<std::negate<result_t> >(l));
+}
+
+template <typename T>
+inline Detail::Temp
+constant(T val)
+{
+ using namespace Detail;
+ return NodePtr(new ConstNode<T>(val));
+}
+
+template <typename T>
+inline Detail::Temp
+functor(T &val)
+{
+ using namespace Detail;
+ return NodePtr(new FunctorNode<T>(val));
+}
+
+template <typename T>
+inline Detail::Temp
+scalar(T &val)
+{
+ using namespace Detail;
+ return NodePtr(new ScalarNode<T>(val));
+}
+
+inline Detail::Temp
+sum(Detail::Temp val)
+{
+ using namespace Detail;
+ return NodePtr(new SumNode<std::plus<result_t> >(val));
+}
+
+extern bool PrintDescriptions;
+
+} // namespace statistics
+
+#endif // __STATISTICS_HH__
diff --git a/base/str.cc b/base/str.cc
new file mode 100644
index 000000000..f54729813
--- /dev/null
+++ b/base/str.cc
@@ -0,0 +1,332 @@
+/*
+ * 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.
+ */
+
+#include <iostream>
+
+#include <string.h>
+#include <ctype.h>
+
+#include <string>
+#include <vector>
+
+#include "intmath.h"
+#include "str.hh"
+
+using namespace std;
+
+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 (ignore) {
+ if (last == first) {
+ while (last == first)
+ last = s.find_first_of(token, ++first);
+
+ if (last == string::npos) {
+ v.push_back(s);
+ 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));
+}
+
+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 T hexmax = maxnum & (((T)1 << (sizeof(T) * 8 - 4)) - 1);
+ static const T octmax = maxnum & (((T)1 << (sizeof(T) * 8 - 3)) - 1);
+ static const T signmax =
+ (sign) ? maxnum & (((T)1 << (sizeof(T) * 8 - 1)) - 1) : maxnum;
+ static const T decmax = signmax / 10 - 1;
+
+#if 0
+ cout << "maxnum = 0x" << hex << maxnum << "\n"
+ << "sign = 0x" << hex << sign << "\n"
+ << "hexmax = 0x" << hex << hexmax << "\n"
+ << "octmax = 0x" << hex << octmax << "\n"
+ << "signmax = 0x" << hex << signmax << "\n"
+ << "decmax = 0x" << hex << 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;
+ retval *= 10;
+ retval += c - '0';
+ if (sign && (retval & ((T)1 << (sizeof(T) * 8 - 1))))
+ return false;
+ }
+
+ c = value[last];
+ if (IsDec(c)) {
+
+ if (retval > decmax) return false;
+ retval *= 10;
+ retval += c - '0';
+ 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
new file mode 100644
index 000000000..29d2c03db
--- /dev/null
+++ b/base/str.hh
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ */
+
+#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;
+}
+
+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>
+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/symtab.cc b/base/symtab.cc
new file mode 100644
index 000000000..7beee182b
--- /dev/null
+++ b/base/symtab.cc
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include "host.hh"
+#include "misc.hh"
+#include "str.hh"
+#include "symtab.hh"
+
+using namespace std;
+
+bool
+SymbolTable::insert(Addr address, string symbol)
+{
+ 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) {
+ cerr << "Can't open symbol table file " << filename << endl;
+ fatal("file error");
+ }
+
+ 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;
+}
+
+bool
+SymbolTable::findSymbol(Addr address, string &symbol) const
+{
+ ATable::const_iterator i = addrTable.find(address);
+ if (i == addrTable.end())
+ return false;
+
+ symbol = (*i).second;
+ return true;
+}
+
+bool
+SymbolTable::findAddress(const string &symbol, Addr &address) const
+{
+ STable::const_iterator i = symbolTable.find(symbol);
+ if (i == symbolTable.end())
+ return false;
+
+ address = (*i).second;
+ return true;
+}
+
+string
+SymbolTable::find(Addr addr) const
+{
+ string s;
+ findSymbol(addr, s);
+ return s;
+}
+
+Addr
+SymbolTable::find(const string &symbol) const
+{
+ Addr a = 0;
+ findAddress(symbol, a);
+ return a;
+}
diff --git a/base/symtab.hh b/base/symtab.hh
new file mode 100644
index 000000000..073325eba
--- /dev/null
+++ b/base/symtab.hh
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#ifndef __SYMTAB_HH__
+#define __SYMTAB_HH__
+
+#include "hashmap.hh"
+#include "isa_traits.hh" // for Addr
+
+class SymbolTable
+{
+ private:
+ typedef m5::hash_map<Addr, std::string> ATable;
+ typedef m5::hash_map<std::string, Addr> STable;
+
+ ATable addrTable;
+ STable symbolTable;
+
+ public:
+ SymbolTable() {}
+ SymbolTable(const std::string &file) { load(file); }
+ ~SymbolTable() {}
+
+ bool insert(Addr address, std::string symbol);
+ bool load(const std::string &file);
+
+ bool findSymbol(Addr address, std::string &symbol) const;
+ bool findAddress(const std::string &symbol, Addr &address) const;
+
+ std::string find(Addr addr) const;
+ Addr find(const std::string &symbol) const;
+};
+
+#endif // __SYMTAB_HH__
diff --git a/base/trace.cc b/base/trace.cc
new file mode 100644
index 000000000..d1baf3000
--- /dev/null
+++ b/base/trace.cc
@@ -0,0 +1,325 @@
+/*
+ * 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.
+ */
+
+#include <ctype.h>
+#include <fstream>
+#include <iostream>
+#include <list>
+#include <string>
+#include <vector>
+
+#include "misc.hh"
+#include "trace.hh"
+#include "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 = NULL;
+
+int dprintf_ignore_size;
+vector<string> dprintf_ignore;
+vector<vector<string> > ignore_tokens;
+vector<int> ignore_size;
+
+bool
+dprintf_ignore_name(const string &name)
+{
+ vector<string> name_tokens;
+ tokenize(name_tokens, name, '.');
+ int ntsize = name_tokens.size();
+
+ for (int i = 0; i < dprintf_ignore_size; ++i) {
+ bool match = true;
+ int jstop = ignore_size[i];
+ for (int j = 0; j < jstop; ++j) {
+ if (j >= ntsize)
+ break;
+
+ const string &ignore = ignore_tokens[i][j];
+ if (ignore != "*" && ignore != name_tokens[j]) {
+ match = false;
+ break;
+ }
+ }
+
+ if (match == true)
+ return true;
+ }
+
+ return false;
+}
+
+
+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);
+ }
+
+ // 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();
+}
+
+
+
+RawDataRecord::RawDataRecord(Tick _cycle,
+ const uint8_t *_data, int _len)
+ : Record(_cycle), len(_len)
+{
+ data = new uint8_t[len];
+ memcpy(data, _data, len);
+}
+
+
+RawDataRecord::~RawDataRecord()
+{
+ delete [] data;
+}
+
+
+void
+RawDataRecord::dump(ostream &os)
+{
+ int c, i, j;
+
+ for (i = 0; i < len; i += 16) {
+ ccprintf(os, "%08x ", 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()
+{
+ if (Trace::dprintf_stream)
+ return *Trace::dprintf_stream;
+ else
+ return cerr;
+}
+
+/////////////////////////////////////////////
+//
+// 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;
+ }
+ }
+}
diff --git a/base/trace.hh b/base/trace.hh
new file mode 100644
index 000000000..42cd1722b
--- /dev/null
+++ b/base/trace.hh
@@ -0,0 +1,218 @@
+/*
+ * 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.
+ */
+
+#ifndef __TRACE_HH__
+#define __TRACE_HH__
+
+#include <vector>
+
+#include "cprintf.hh"
+#include "host.hh"
+#include "universe.hh"
+
+#ifndef TRACING_ON
+#ifdef DEBUG
+#define TRACING_ON 1
+#else
+#define TRACING_ON 0
+#endif
+#endif
+
+#include "trace_flags.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 RawDataRecord : public Record
+ {
+ private:
+ uint8_t *data;
+ int len;
+
+ public:
+ RawDataRecord(Tick cycle, const uint8_t *_data, int _len);
+ virtual ~RawDataRecord();
+
+ 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 int dprintf_ignore_size;
+
+ bool
+ dprintf_ignore_name(const std::string &name);
+
+ inline void
+ dprintf(const char *format, cp::ArgList &args, Tick cycle,
+ const std::string &name)
+ {
+ if (!dprintf_ignore_size || name.empty() || !dprintf_ignore_name(name))
+ theLog.append(new Trace::PrintfRecord(format, args, cycle, name));
+ }
+
+ inline void
+ rawDump(const uint8_t *data, int len)
+ {
+ theLog.append(new Trace::RawDataRecord(curTick, data, len));
+ }
+
+ extern const std::string DefaultName;
+};
+
+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 { \
+ using namespace Trace; \
+ if (Trace::IsOn(Trace::x)) \
+ rawDump(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, string(), args, cp::ArgListNull()); \
+} while (0)
+
+#define DPRINTFN(args...) \
+do { \
+ __dprintf(curTick, name(), 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 DDUMP(x, data, count) do {} while(0)
+
+#endif // TRACING_ON
+
+#endif // __TRACE_HH__
diff --git a/dev/alpha_access.h b/dev/alpha_access.h
new file mode 100644
index 000000000..ef33633e5
--- /dev/null
+++ b/dev/alpha_access.h
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+#ifndef __ALPHA_ACCESS_H__
+#define __ALPHA_ACCESS_H__
+
+/* @file
+ * System Console Memory Mapped Register Definition
+ */
+
+#define ALPHA_ACCESS_VERSION (1291+1) /* CH++*/
+
+#ifdef CONSOLE
+typedef uint32 UINT32;
+typedef uint64 UINT64;
+#else
+typedef uint32_t UINT32;
+typedef uint64_t UINT64;
+#endif
+
+// This structure hacked up from simos
+struct AlphaAccess
+{
+ UINT32 last_offset; // 00: must be first field
+ UINT32 version; // 04:
+ UINT32 numCPUs; // 08:
+ UINT32 align0; // 0C: Placeholder for alignment
+ UINT64 mem_size; // 10:
+ UINT64 cpuClock; // 18: MHz
+ UINT32 intrClockFrequency; // 20: Hz
+ UINT32 align1; // 24: Placeholder for alignment
+
+ // Loaded kernel
+ UINT64 kernStart; // 28:
+ UINT64 kernEnd; // 30:
+ UINT64 entryPoint; // 38:
+
+ // console disk stuff
+ UINT64 diskUnit; // 40:
+ UINT64 diskCount; // 48:
+ UINT64 diskPAddr; // 50:
+ UINT64 diskBlock; // 58:
+ UINT64 diskOperation; // 60:
+
+ // console simple output stuff
+ UINT64 outputChar; // 68:
+
+ // MP boot
+ UINT64 bootStrapImpure; // 70:
+ UINT32 bootStrapCPU; // 78:
+ UINT32 align2; // 7C: Dummy placeholder for alignment
+};
+
+#endif // __ALPHA_ACCESS_H__
diff --git a/dev/alpha_console.cc b/dev/alpha_console.cc
new file mode 100644
index 000000000..6a1e2b169
--- /dev/null
+++ b/dev/alpha_console.cc
@@ -0,0 +1,273 @@
+/*
+ * 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.
+ */
+
+/* @file
+ * System Console Definition
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+
+#include <string>
+
+#include "alpha_console.hh"
+#include "base_cpu.hh"
+#include "console.hh"
+#include "exec_context.hh"
+#include "memory_control.hh"
+#include "simple_disk.hh"
+#include "tlaser_clock.hh"
+#include "system.hh"
+#include "trace.hh"
+#include "inifile.hh"
+#include "str.hh" // for to_number()
+
+using namespace std;
+
+AlphaConsole::AlphaConsole(const string &name, SimConsole *cons,
+ SimpleDisk *d, int size, System *system,
+ BaseCPU *cpu, TlaserClock *clock, int num_cpus,
+ Addr addr, Addr mask, MemoryController *mmu)
+ : MmapDevice(name, addr, mask, mmu), disk(d), console(cons)
+{
+ consoleData = new uint8_t[size];
+ memset(consoleData, 0, size);
+
+ alphaAccess->last_offset = size - 1;
+ alphaAccess->kernStart = system->getKernelStart();
+ alphaAccess->kernEnd = system->getKernelEnd();
+ alphaAccess->entryPoint = system->getKernelEntry();
+
+ alphaAccess->version = ALPHA_ACCESS_VERSION;
+ alphaAccess->numCPUs = num_cpus;
+ alphaAccess->mem_size = system->physmem->getSize();
+ alphaAccess->cpuClock = cpu->getFreq() / 1000000;
+ alphaAccess->intrClockFrequency = clock->frequency();
+
+ alphaAccess->diskUnit = 1;
+}
+
+Fault
+AlphaConsole::read(MemReqPtr req, uint8_t *data)
+{
+ memset(data, 0, req->size);
+
+ if (req->size == sizeof(uint32_t)) {
+ Addr daddr = req->paddr & addr_mask;
+ *(uint32_t *)data = *(uint32_t *)(consoleData + daddr);
+
+#if 0
+ DPRINTF(AlphaConsole, "read: offset=%#x val=%#x\n",
+ daddr, *(uint32_t *)data);
+#endif
+ }
+
+ return No_Fault;
+}
+
+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 Machine_Check_Fault;
+ }
+
+ Addr paddr = req->paddr & addr_mask;
+
+ if (paddr == offsetof(AlphaAccess, diskUnit)) {
+ alphaAccess->diskUnit = val;
+ return No_Fault;
+ }
+
+ if (paddr == offsetof(AlphaAccess, diskCount)) {
+ alphaAccess->diskCount = val;
+ return No_Fault;
+ }
+
+ if (paddr == offsetof(AlphaAccess, diskPAddr)) {
+ alphaAccess->diskPAddr = val;
+ return No_Fault;
+ }
+
+ if (paddr == offsetof(AlphaAccess, diskBlock)) {
+ alphaAccess->diskBlock = val;
+ return No_Fault;
+ }
+
+ if (paddr == offsetof(AlphaAccess, diskOperation)) {
+ if (val == 0x13)
+ disk->read(alphaAccess->diskPAddr, alphaAccess->diskBlock,
+ alphaAccess->diskCount);
+ else
+ panic("Invalid disk operation!");
+
+ return No_Fault;
+ }
+
+ if (paddr == offsetof(AlphaAccess, outputChar)) {
+ console->simple((char)(val & 0xff));
+ return No_Fault;
+ }
+
+ if (paddr == offsetof(AlphaAccess, bootStrapImpure)) {
+ alphaAccess->bootStrapImpure = val;
+ return No_Fault;
+ }
+
+ if (paddr == offsetof(AlphaAccess, bootStrapCPU)) {
+ warn("%d: Trying to launch another CPU!", curTick);
+ int cpu = val;
+ assert(cpu > 0 && "Must not access primary cpu");
+
+ ExecContext *other_xc = req->xc->system->xc_array[cpu];
+ other_xc->regs.intRegFile[16] = cpu;
+ other_xc->regs.ipr[TheISA::IPR_PALtemp16] = cpu;
+ other_xc->regs.intRegFile[0] = cpu;
+ other_xc->regs.intRegFile[30] = alphaAccess->bootStrapImpure;
+ other_xc->setStatus(ExecContext::Active); //Start the cpu
+ return No_Fault;
+ }
+
+ return No_Fault;
+}
+
+void
+AlphaConsole::serialize()
+{
+ nameOut();
+ // assumes full AlphaAccess size
+ // might have unnecessary fields here
+ paramOut("last_offset",alphaAccess->last_offset);
+ paramOut("version",alphaAccess->version);
+ paramOut("numCPUs",alphaAccess->numCPUs);
+ paramOut("mem_size",alphaAccess->mem_size);
+ paramOut("cpuClock",alphaAccess->cpuClock);
+ paramOut("intrClockFrequency",alphaAccess->intrClockFrequency);
+ paramOut("kernStart",alphaAccess->kernStart);
+ paramOut("kernEnd",alphaAccess->kernEnd);
+ paramOut("entryPoint",alphaAccess->entryPoint);
+ paramOut("diskUnit",alphaAccess->diskUnit);
+ paramOut("diskCount",alphaAccess->diskCount);
+ paramOut("diskPAddr",alphaAccess->diskPAddr);
+ paramOut("diskBlock",alphaAccess->diskBlock);
+ paramOut("diskOperation",alphaAccess->diskOperation);
+ paramOut("outputChar",alphaAccess->outputChar);
+ paramOut("bootStrapImpure",alphaAccess->bootStrapImpure);
+ paramOut("bootStrapCPU",alphaAccess->bootStrapCPU);
+}
+
+void
+AlphaConsole::unserialize(IniFile &db, const std::string &category,
+ ConfigNode *node)
+{
+ string data;
+ db.findDefault(category,"last_offset",data);
+ to_number(data,alphaAccess->last_offset);
+ db.findDefault(category,"version",data);
+ to_number(data,alphaAccess->version);
+ db.findDefault(category,"numCPUs",data);
+ to_number(data,alphaAccess->numCPUs);
+ db.findDefault(category,"mem_size",data);
+ to_number(data,alphaAccess->mem_size);
+ db.findDefault(category,"cpuClock",data);
+ to_number(data,alphaAccess->cpuClock);
+ db.findDefault(category,"intrClockFrequency",data);
+ to_number(data,alphaAccess->intrClockFrequency);
+ db.findDefault(category,"kernStart",data);
+ to_number(data,alphaAccess->kernStart);
+ db.findDefault(category,"kernEnd",data);
+ to_number(data,alphaAccess->kernEnd);
+ db.findDefault(category,"entryPoint",data);
+ to_number(data,alphaAccess->entryPoint);
+ db.findDefault(category,"diskUnit",data);
+ to_number(data,alphaAccess->diskUnit);
+ db.findDefault(category,"diskCount",data);
+ to_number(data,alphaAccess->diskCount);
+ db.findDefault(category,"diskPAddr",data);
+ to_number(data,alphaAccess->diskPAddr);
+ db.findDefault(category,"diskBlock",data);
+ to_number(data,alphaAccess->diskBlock);
+ db.findDefault(category,"diskOperation",data);
+ to_number(data,alphaAccess->diskOperation);
+ db.findDefault(category,"outputChar",data);
+ to_number(data,alphaAccess->outputChar);
+ db.findDefault(category,"bootStrapImpure",data);
+ to_number(data,alphaAccess->bootStrapImpure);
+ db.findDefault(category,"bootStrapCPU",data);
+ to_number(data,alphaAccess->bootStrapCPU);
+
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaConsole)
+
+ SimObjectParam<SimConsole *> sim_console;
+ SimObjectParam<SimpleDisk *> disk;
+ Param<int> size;
+ Param<int> num_cpus;
+ SimObjectParam<MemoryController *> mmu;
+ Param<Addr> addr;
+ Param<Addr> mask;
+ SimObjectParam<System *> system;
+ SimObjectParam<BaseCPU *> cpu;
+ SimObjectParam<TlaserClock *> clock;
+
+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_DFLT(size, "AlphaConsole size", sizeof(AlphaAccess)),
+ INIT_PARAM_DFLT(num_cpus, "Number of CPU's", 1),
+ INIT_PARAM(mmu, "Memory Controller"),
+ INIT_PARAM(addr, "Device Address"),
+ INIT_PARAM(mask, "Address Mask"),
+ INIT_PARAM(system, "system object"),
+ INIT_PARAM(cpu, "Processor"),
+ INIT_PARAM(clock, "Turbolaser Clock")
+
+END_INIT_SIM_OBJECT_PARAMS(AlphaConsole)
+
+CREATE_SIM_OBJECT(AlphaConsole)
+{
+ return new AlphaConsole(getInstanceName(), sim_console,
+ disk, size, system,
+ cpu, clock, num_cpus,
+ addr, mask, mmu);
+}
+
+REGISTER_SIM_OBJECT("AlphaConsole", AlphaConsole)
diff --git a/dev/alpha_console.hh b/dev/alpha_console.hh
new file mode 100644
index 000000000..518f5fccb
--- /dev/null
+++ b/dev/alpha_console.hh
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+/* @file
+ * System Console Interface
+ */
+
+#ifndef __ALPHA_CONSOLE_HH__
+#define __ALPHA_CONSOLE_HH__
+
+#include "host.hh"
+#include "alpha_access.h"
+#include "mmap_device.hh"
+
+class BaseCPU;
+class SimConsole;
+class System;
+class TlaserClock;
+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 MmapDevice
+{
+ protected:
+ union {
+ AlphaAccess *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;
+
+ public:
+ /** Standard Constructor */
+ AlphaConsole(const std::string &name, SimConsole *cons,
+ SimpleDisk *d, int size,
+ System *system, BaseCPU *cpu,
+ TlaserClock *clock, int num_cpus,
+ Addr addr, Addr mask, MemoryController *mmu);
+
+ public:
+ /**
+ * 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();
+ virtual void unserialize(IniFile &db, const std::string &category,
+ ConfigNode *node);
+};
+
+#endif // __ALPHA_CONSOLE_HH__
diff --git a/dev/console.cc b/dev/console.cc
new file mode 100644
index 000000000..8141a6508
--- /dev/null
+++ b/dev/console.cc
@@ -0,0 +1,478 @@
+/* $Id$ */
+
+/* @file
+ * User Console Definitions
+ */
+
+#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 "misc.hh"
+#include "ev5.hh"
+
+#include "console.hh"
+#include "socket.hh"
+#include "trace.hh"
+#include "memory_control.hh"
+
+using namespace std;
+
+// check whether an int is pending
+inline bool
+IntPending(int status, int mask)
+{ return (status & mask) != 0; }
+
+inline bool
+IntTransition(int ostaus, int omask, int nstatus, int nmask)
+{ return IntPending(ostaus, omask) != IntPending(nstatus, nmask); }
+
+////////////////////////////////////////////////////////////////////////
+//
+//
+
+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, const string &file, int num)
+ : SimObject(name), event(NULL), number(num), in_fd(-1), out_fd(-1),
+ listener(NULL), txbuf(16384), rxbuf(16384), outfile(NULL),
+ intr_status(0), intr_enable(0), intr(NULL)
+{
+ if (!file.empty())
+ outfile = new ofstream(file.c_str());
+
+ if (outfile)
+ outfile->setf(ios::unitbuf);
+}
+
+SimConsole::~SimConsole()
+{
+ close();
+
+ if (outfile)
+ delete outfile;
+}
+
+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, "==== Simplescalar 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);
+ raiseInt(ReceiveInterrupt);
+ }
+}
+
+size_t
+SimConsole::read(uint8_t *buf, size_t len)
+{
+ if (in_fd < 0)
+ panic("SimConsole(read): Console not properly attached.\n");
+
+ size_t ret;
+ do {
+ ret = ::read(in_fd, buf, len);
+ } while (ret == -1 && errno == EINTR);
+
+
+ if (ret < 0)
+ DPRINTFN("SimConsole(read): 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("SimConsole(write): 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;
+}
+
+///////////////////////////////////////////////////////////////////////
+// ConfigureTerm turns off all character processing by the host OS so
+// the launched OS can control it.
+//
+// We ignore anything except stdin; the sconsole program runs this
+// same code on the ttys for the slave consoles before connecting.
+//
+void
+SimConsole::configTerm()
+{
+ struct termios ios;
+
+ if (isatty(out_fd)) {
+ if (tcgetattr(out_fd, &ios) < 0) {
+ panic( "tcgetattr\n");
+ }
+ ios.c_iflag &= ~(ISTRIP|ICRNL|IGNCR|ICRNL|IXOFF|IXON);
+ ios.c_oflag &= ~(OPOST);
+ ios.c_oflag &= (ONLCR);
+ ios.c_lflag &= ~(ISIG|ICANON|ECHO);
+ ios.c_cc[VMIN] = 1;
+ ios.c_cc[VTIME] = 0;
+ if (tcsetattr(out_fd, TCSANOW, &ios) < 0) {
+ panic( "tcsetattr\n");
+ }
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////
+// console i/o
+//
+
+///////////////////////////////////////////////////////////////////////
+//
+// Console input.
+// Returns -1 if there is no character pending, otherwise returns the
+// char. Calling this function clears the input int (if no further
+// chars are pending).
+//
+int
+SimConsole::in()
+{
+ if (rxbuf.empty()) {
+ clearInt(ReceiveInterrupt);
+ return -1;
+ }
+
+ char c;
+ rxbuf.read(&c, 1);
+
+ DPRINTF(Console, "in: \'%c\' %#02x status: %#x\n",
+ isprint(c) ? c : ' ', c, intr_status);
+
+ return c;
+}
+
+///////////////////////////////////////////////////////////////////////
+//
+// Console output.
+// NOTE: this very rudimentary device generates a TX int as soon as
+// a character is output, since it has unlimited TX buffer capacity.
+//
+// Console output.
+// Uses sim_console_out to perform functionality similar to 'write'
+void
+SimConsole::out(char c)
+{
+ txbuf.write(c);
+
+ if (out_fd >= 0)
+ write(c);
+
+ if (outfile)
+ outfile->write(&c, 1);
+
+ raiseInt(TransmitInterrupt);
+
+ DPRINTF(Console, "out: \'%c\' %#02x status: %#x\n",
+ isprint(c) ? c : ' ', (int)c, intr_status);
+}
+
+// Simple console output used by Alpha firmware (not by the OS) -
+// outputs the character to console n, and doesn't raise any
+// interrupts
+void
+SimConsole::simple(char c)
+{
+ txbuf.write(c);
+
+ if (out_fd >= 0)
+ write(c);
+
+ if (outfile)
+ outfile->write(&c, 1);
+
+ DPRINTF(Console, "simple char: \'%c\' %#02x\n",
+ isprint(c) ? c : ' ', (int)c);
+}
+
+// Read the current interrupt status of this console.
+int
+SimConsole::intStatus()
+{
+#if 0
+ DPRINTF(Console, "interrupt %d status: %#x\n",
+ number, intr_status);
+#endif
+
+ return intr_status;
+}
+
+int
+SimConsole::clearInt(int i)
+{
+ int old_status = intr_status;
+ intr_status &= ~i;
+ if (IntTransition(old_status, intr_enable, intr_status, intr_enable) &&
+ intr)
+ intr->clear(TheISA::INTLEVEL_IRQ0);
+ return old_status;
+}
+
+void
+SimConsole::raiseInt(int i)
+{
+ int old = intr_status;
+ intr_status |= i;
+ if (IntTransition(old, intr_enable, intr_status, intr_enable) && intr)
+ intr->post(TheISA::INTLEVEL_IRQ0);
+}
+
+void
+SimConsole::initInt(IntrControl *i)
+{
+ if (intr)
+ panic("Console has already been initialized.");
+
+ // note: intr_status and intr_enable will normally be 0, since
+ // cs is statically allocated. When restoring from a checkpoint,
+ // these fields will be set, so don't touch them here.
+ intr = i; // interrupt handler
+}
+
+// Set the interrupt enable bits.
+void
+SimConsole::setInt(int bits)
+{
+ int old_enable;
+
+ if (bits & ~(TransmitInterrupt | ReceiveInterrupt))
+ panic("An interrupt was not set!");
+
+ old_enable = intr_enable;
+ intr_enable |= bits;
+
+ if (IntTransition(intr_status, old_enable, intr_status, intr_enable) &&
+ intr) {
+ if (IntPending(intr_status, intr_enable))
+ intr->post(TheISA::INTLEVEL_IRQ0);
+ else
+ intr->clear(TheISA::INTLEVEL_IRQ0);
+ }
+}
+
+
+void
+SimConsole::serialize()
+{
+ panic("Unimplemented");
+}
+
+void
+SimConsole::unserialize(IniFile &db, const std::string &category,
+ ConfigNode *node)
+{
+ panic("Unimplemented");
+}
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimConsole)
+
+ SimObjectParam<ConsoleListener *> listener;
+ SimObjectParam<IntrControl *> intr_control;
+ Param<string> output;
+ 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_DFLT(output, "file to dump output to", ""),
+ INIT_PARAM_DFLT(number, "console number", 0)
+
+END_INIT_SIM_OBJECT_PARAMS(SimConsole)
+
+CREATE_SIM_OBJECT(SimConsole)
+{
+ SimConsole *console = new SimConsole(getInstanceName(), output, number);
+ ((ConsoleListener *)listener)->add(console);
+ ((SimConsole *)console)->initInt(intr_control);
+ ((SimConsole *)console)->setInt(SimConsole::TransmitInterrupt |
+ SimConsole::ReceiveInterrupt);
+
+ 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++;
+ }
+
+ cerr << "Listening for console connection on port " << port << endl;
+ 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 we're 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/console.hh b/dev/console.hh
new file mode 100644
index 000000000..092e6ea53
--- /dev/null
+++ b/dev/console.hh
@@ -0,0 +1,147 @@
+/* $Id$ */
+
+/* @file
+ * User Console Interface
+ */
+
+#ifndef __CONSOLE_HH__
+#define __CONSOLE_HH__
+
+#include <iostream>
+
+#include "circlebuf.hh"
+#include "intr_control.hh"
+#include "pollevent.hh"
+#include "socket.hh"
+#include "sim_object.hh"
+
+class ConsoleListener;
+class SimConsole : public SimObject
+{
+ 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;
+
+ protected:
+ ConsoleListener *listener;
+
+ public:
+ SimConsole(const std::string &name, const std::string &file, int num);
+ ~SimConsole();
+
+ protected:
+ CircleBuf txbuf;
+ CircleBuf rxbuf;
+ std::ostream *outfile;
+
+ 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);
+
+ void configTerm();
+
+ protected:
+ // interrupt status/enable
+ int intr_status;
+ int intr_enable;
+
+ // interrupt handle
+ IntrControl *intr;
+
+ public:
+ /////////////////
+ // OS interface
+
+ // Input a character from the console. Returns the character (if
+ // any) or -1 if there is no character pending on this console. If
+ // no further characters are pending, the (input) interrupt is
+ // cleared.
+ int in();
+
+ // Output a character to the console. This never fails, as this
+ // device doesn't model finite buffering capacity.
+ void out(char c);
+ void simple(char c);
+
+ enum {
+ TransmitInterrupt = 1,
+ ReceiveInterrupt = 2
+ };
+
+ // Read the current interrupt status of this console.
+ int intStatus();
+
+ // Set the interrupt enable bits.
+ int clearInt(int i);
+ void raiseInt(int i);
+
+ void initInt(IntrControl *i);
+ void setInt(int bits);
+
+ virtual void serialize();
+ virtual void unserialize(IniFile &db, const std::string &category,
+ ConfigNode *node);
+};
+
+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/disk_image.cc b/dev/disk_image.cc
new file mode 100644
index 000000000..17a7f3e9d
--- /dev/null
+++ b/dev/disk_image.cc
@@ -0,0 +1,427 @@
+/*
+ * 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.
+ */
+
+/* @file
+ * Disk Image Definitions
+ */
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <cstdio>
+#include <fstream>
+#include <string>
+
+#include "disk_image.hh"
+#include "misc.hh"
+#include "trace.hh"
+#include "sim_exit.hh"
+#include "callback.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");
+
+ off_t 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);
+
+ off_t 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()) {
+ 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)); }
+
+bool
+CowDiskImage::open()
+{
+ ifstream stream(filename.c_str());
+ if (!stream.is_open())
+ return false;
+
+ if (stream.fail() || stream.bad())
+ panic("Error opening %s", filename);
+
+ uint64_t magic;
+ SafeRead(stream, magic);
+
+ if (memcmp(&magic, "COWDISK!", sizeof(magic)) != 0)
+ panic("Could not open %s: Invalid magic", filename);
+
+ uint32_t major, minor;
+ SafeRead(stream, major);
+ SafeRead(stream, minor);
+
+ if (major != VersionMajor && minor != VersionMinor)
+ panic("Could not open %s: invalid version %d.%d != %d.%d",
+ filename, major, minor, VersionMajor, VersionMinor);
+
+ uint64_t sector_count;
+ SafeRead(stream, sector_count);
+ table = new SectorTable(sector_count);
+
+
+ for (uint64_t i = 0; i < sector_count; i++) {
+ uint64_t offset;
+ SafeRead(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)); }
+
+void
+CowDiskImage::save()
+{
+ if (!initialized)
+ panic("RawDiskImage not initialized");
+
+ ofstream stream(filename.c_str());
+ if (!stream.is_open() || stream.fail() || stream.bad())
+ panic("Error opening %s", filename);
+
+ uint64_t magic;
+ memcpy(&magic, "COWDISK!", sizeof(magic));
+ SafeWrite(stream, magic);
+
+ SafeWrite(stream, (uint32_t)VersionMajor);
+ SafeWrite(stream, (uint32_t)VersionMinor);
+ SafeWrite(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");
+
+ SafeWrite(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;
+}
+
+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
new file mode 100644
index 000000000..2cfa1490a
--- /dev/null
+++ b/dev/disk_image.hh
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+/* @file
+ * Disk Image Interfaces
+ */
+
+#ifndef __DISK_IMAGE_HH__
+#define __DISK_IMAGE_HH__
+
+#include <fstream>
+
+#include "hashmap.hh"
+#include "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();
+ void save();
+ void writeback();
+
+ 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
new file mode 100644
index 000000000..fa5a62208
--- /dev/null
+++ b/dev/etherbus.cc
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+
+/* @file
+ * Device module for modelling an ethernet hub
+ */
+
+#include <deque>
+#include <string>
+#include <vector>
+
+#include <math.h>
+
+#include "etherbus.hh"
+#include "etherdump.hh"
+#include "etherint.hh"
+#include "etherpkt.hh"
+#include "trace.hh"
+#include "universe.hh"
+
+using namespace std;
+
+EtherBus::EtherBus(const string &name, double rate, bool loop,
+ EtherDump *packet_dump)
+ : SimObject(name), ticks_per_byte(rate), 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 * ticks_per_byte) + 1.0);
+ DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n",
+ delay, ticks_per_byte);
+ event.schedule(curTick + delay);
+
+ return true;
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherBus)
+
+ Param<bool> loopback;
+ Param<int> speed;
+ SimObjectParam<EtherDump *> packet_dump;
+
+END_DECLARE_SIM_OBJECT_PARAMS(EtherBus)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(EtherBus)
+
+ INIT_PARAM_DFLT(loopback,
+ "send the packet back to the interface from which it came",
+ true),
+ INIT_PARAM_DFLT(speed, "bus speed in bits per second", 100000000),
+ INIT_PARAM_DFLT(packet_dump, "object to dump network packets to", NULL)
+
+END_INIT_SIM_OBJECT_PARAMS(EtherBus)
+
+CREATE_SIM_OBJECT(EtherBus)
+{
+ double rate = ((double)ticksPerSecond * 8.0) / (double)speed;
+ return new EtherBus(getInstanceName(), rate, loopback, packet_dump);
+}
+
+REGISTER_SIM_OBJECT("EtherBus", EtherBus)
diff --git a/dev/etherbus.hh b/dev/etherbus.hh
new file mode 100644
index 000000000..f64aa45e1
--- /dev/null
+++ b/dev/etherbus.hh
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+/* @file
+ * Device module for modelling an ethernet hub
+ */
+
+#ifndef __ETHERBUS_H__
+#define __ETHERBUS_H__
+
+#include "eventq.hh"
+#include "etherpkt.hh"
+#include "sim_object.hh"
+
+class EtherDump;
+class EtherInt;
+class EtherBus : public SimObject
+{
+ protected:
+ typedef std::list<EtherInt *> devlist_t;
+ devlist_t devlist;
+ double ticks_per_byte;
+ 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 ticks_per_byte, 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
new file mode 100644
index 000000000..034db86aa
--- /dev/null
+++ b/dev/etherdump.cc
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+
+/* @file
+ * Simple object for creating a simple pcap style packet trace
+ */
+
+#include <sys/time.h>
+
+#include <string>
+
+#include "universe.hh"
+#include "etherdump.hh"
+#include "universe.hh"
+
+using std::string;
+
+EtherDump::EtherDump(const string &name, const string &file)
+ : SimObject(name)
+{
+ if (!file.empty()) {
+ stream.open(file.c_str());
+ if (stream.is_open())
+ init();
+ }
+}
+
+#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 {
+ struct timeval ts; // time stamp
+ uint32_t caplen; // length of portion present
+ uint32_t len; // length this packet (off wire)
+};
+
+void
+EtherDump::init()
+{
+ curtime = time(NULL);
+ s_freq = ticksPerSecond;
+ us_freq = ticksPerSecond / ULL(1000000);
+
+ 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.ts.tv_sec = curtime;
+ pkthdr.ts.tv_usec = 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.ts.tv_sec = curtime + (curTick / s_freq);
+ pkthdr.ts.tv_usec = (curTick / us_freq) % ULL(1000000);
+ pkthdr.caplen = packet->length;
+ pkthdr.len = packet->length;
+ stream.write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr));
+ stream.write(reinterpret_cast<char *>(packet->data), packet->length);
+ stream.flush();
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherDump)
+
+ Param<string> file;
+
+END_DECLARE_SIM_OBJECT_PARAMS(EtherDump)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(EtherDump)
+
+ INIT_PARAM_DFLT(file, "file to dump packets to", "")
+
+END_INIT_SIM_OBJECT_PARAMS(EtherDump)
+
+CREATE_SIM_OBJECT(EtherDump)
+{
+ return new EtherDump(getInstanceName(), file);
+}
+
+REGISTER_SIM_OBJECT("EtherDump", EtherDump)
diff --git a/dev/etherdump.hh b/dev/etherdump.hh
new file mode 100644
index 000000000..87824c470
--- /dev/null
+++ b/dev/etherdump.hh
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+/* @file
+ * Simple object for creating a simple pcap style packet trace
+ */
+
+#ifndef __ETHERDUMP_H__
+#define __ETHERDUMP_H__
+
+#include <fstream>
+#include "etherpkt.hh"
+#include "sim_object.hh"
+
+/*
+ * Simple object for creating a simple pcap style packet trace
+ */
+class EtherDump : public SimObject
+{
+ private:
+ std::ofstream stream;
+ void dumpPacket(PacketPtr packet);
+ void init();
+
+ Tick curtime;
+ Tick s_freq;
+ Tick us_freq;
+
+ public:
+ EtherDump(const std::string &name, const std::string &file);
+
+ inline void dump(PacketPtr pkt) { if (stream.is_open()) dumpPacket(pkt); }
+};
+
+#endif // __ETHERDUMP_H__
diff --git a/dev/etherint.cc b/dev/etherint.cc
new file mode 100644
index 000000000..51b18c6aa
--- /dev/null
+++ b/dev/etherint.cc
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#include "etherint.hh"
+#include "misc.hh"
+#include "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
new file mode 100644
index 000000000..00e291fc9
--- /dev/null
+++ b/dev/etherint.hh
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+/* @file
+ * Class representing the actual interface between two ethernet
+ * components.
+ */
+
+#ifndef __ETHERINT_HH__
+#define __ETHERINT_HH__
+
+#include <string>
+
+#include "etherpkt.hh"
+#include "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);
+ virtual bool recvPacket(PacketPtr packet) = 0;
+ void recvDone() { peer->sendDone(); }
+ bool sendPacket(PacketPtr packet) { return peer->recvPacket(packet); }
+ virtual void sendDone() = 0;
+};
+
+#endif // __ETHERINT_HH__
diff --git a/dev/etherlink.cc b/dev/etherlink.cc
new file mode 100644
index 000000000..1d3578e58
--- /dev/null
+++ b/dev/etherlink.cc
@@ -0,0 +1,148 @@
+/*
+ * 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.
+ */
+
+/* @file
+ * Device module for modelling a fixed bandwidth full duplex ethernet link
+ */
+
+#include <deque>
+#include <string>
+#include <vector>
+
+#include <math.h>
+
+#include "etherlink.hh"
+#include "etherdump.hh"
+#include "etherint.hh"
+#include "etherpkt.hh"
+#include "trace.hh"
+#include "universe.hh"
+
+using namespace std;
+
+EtherLink::EtherLink(const std::string &name, EtherInt *i1, EtherInt *i2,
+ Tick speed, EtherDump *dump)
+ : SimObject(name)
+{
+ double rate = ((double)ticksPerSecond * 8.0) / (double)speed;
+
+ link1 = new Link(name + ".link1", rate, dump);
+ link2 = new Link(name + ".link2", rate, dump);
+
+ int1 = new Interface(name + ".int1", link1, link2);
+ int2 = new Interface(name + ".int2", link2, link1);
+
+ int1->setPeer(i1);
+ i1->setPeer(int1);
+ int2->setPeer(i2);
+ i2->setPeer(int2);
+}
+
+EtherLink::~EtherLink()
+{
+ delete link1;
+ delete link2;
+
+ delete int1;
+ delete int2;
+}
+
+EtherLink::Interface::Interface(const std::string &name, Link *tx, Link *rx)
+ : EtherInt(name), txlink(tx)
+{
+ tx->setTxInt(this);
+ rx->setRxInt(this);
+}
+
+EtherLink::Link::Link(const std::string &name, double rate, EtherDump *d)
+ : Serializeable(name), txint(NULL), rxint(NULL), ticks_per_byte(rate),
+ dump(d), event(&mainEventQueue, this)
+{}
+
+void
+EtherLink::Link::txDone()
+{
+ rxint->sendPacket(packet);
+
+ if (dump)
+ dump->dump(packet);
+
+ DPRINTF(Ethernet, "EtherLink packet received: len=%d\n", packet->length);
+ DDUMP(EthernetData, packet->data, packet->length);
+
+ packet = 0;
+ assert(!busy());
+
+ txint->sendDone();
+}
+
+bool
+EtherLink::Link::transmit(PacketPtr pkt)
+{
+ if (busy()) {
+ DPRINTF(Ethernet, "EtherLink packet not sent, link busy\n");
+ return false;
+ }
+
+ DPRINTF(Ethernet, "EtherLink packet sent: len=%d\n", pkt->length);
+ DDUMP(EthernetData, pkt->data, pkt->length);
+
+ packet = pkt;
+ int delay = (int)ceil(((double)pkt->length * ticks_per_byte) + 1.0);
+ DPRINTF(Ethernet, "EtherLink scheduling packet: delay=%d, (rate=%f)\n",
+ delay, ticks_per_byte);
+ event.schedule(curTick + delay);
+
+ return true;
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherLink)
+
+ SimObjectParam<EtherInt *> interface1;
+ SimObjectParam<EtherInt *> interface2;
+ Param<int> link_speed;
+ SimObjectParam<EtherDump *> packet_dump;
+
+END_DECLARE_SIM_OBJECT_PARAMS(EtherLink)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(EtherLink)
+
+ INIT_PARAM(interface1, "interface 1"),
+ INIT_PARAM(interface2, "interface 2"),
+ INIT_PARAM_DFLT(link_speed, "link speed in bits per second", 100000000),
+ INIT_PARAM_DFLT(packet_dump, "object to dump network packets to", NULL)
+
+END_INIT_SIM_OBJECT_PARAMS(EtherLink)
+
+CREATE_SIM_OBJECT(EtherLink)
+{
+ return new EtherLink(getInstanceName(), interface1, interface2, link_speed,
+ packet_dump);
+}
+
+REGISTER_SIM_OBJECT("EtherLink", EtherLink)
diff --git a/dev/etherlink.hh b/dev/etherlink.hh
new file mode 100644
index 000000000..b88d80420
--- /dev/null
+++ b/dev/etherlink.hh
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+/* @file
+ * Device module for modelling a fixed bandwidth full duplex ethernet link
+ */
+
+#ifndef __ETHERLINK_HH__
+#define __ETHERLINK_HH__
+
+#include "host.hh"
+#include "eventq.hh"
+#include "etherint.hh"
+#include "etherpkt.hh"
+#include "sim_object.hh"
+
+class EtherDump;
+
+/*
+ * Model for a fixed bandwidth full duplex ethernet link
+ */
+class EtherLink : public SimObject
+{
+ protected:
+ class Interface;
+
+ /*
+ * Model for a single uni-directional link
+ */
+ class Link : public Serializeable {
+ protected:
+ Interface *txint;
+ Interface *rxint;
+
+ double ticks_per_byte;
+ EtherDump *dump;
+
+ protected:
+ /*
+ * Transfer is complete
+ */
+ class DoneEvent : public Event
+ {
+ protected:
+ Link *link;
+
+ public:
+ DoneEvent(EventQueue *q, Link *l)
+ : Event(q), link(l) {}
+ virtual void process() { link->txDone(); }
+ virtual const char *description()
+ { return "ethernet link completion"; }
+ };
+
+ friend class DoneEvent;
+ DoneEvent event;
+ PacketPtr packet;
+
+ void txDone();
+
+ public:
+ Link(const std::string &name, double rate, EtherDump *dump);
+ ~Link() {}
+
+ 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; }
+ };
+
+ /*
+ * 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() { }
+ };
+
+ Link *link1;
+ Link *link2;
+
+ EtherInt *int1;
+ EtherInt *int2;
+
+ public:
+ EtherLink(const std::string &name, EtherInt *i1, EtherInt *i2,
+ Tick speed, EtherDump *dump);
+ virtual ~EtherLink();
+};
+
+#endif // __ETHERLINK_HH__
diff --git a/dev/etherpkt.hh b/dev/etherpkt.hh
new file mode 100644
index 000000000..4927cc779
--- /dev/null
+++ b/dev/etherpkt.hh
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+/* @file
+ * Reference counted class containing ethernet packet data
+ */
+
+#ifndef __ETHERPKT_HH__
+#define __ETHERPKT_HH__
+
+#include <memory>
+
+#include "host.hh"
+
+#include "refcnt.hh"
+
+/*
+ * Reference counted class containing ethernet packet data
+ */
+class EtherPacket : public RefCounted
+{
+ public:
+ uint8_t *data;
+ int length;
+
+ public:
+ EtherPacket() : data(NULL), length(0) {}
+ EtherPacket(std::auto_ptr<uint8_t> d, int l)
+ : data(d.release()), length(l) {}
+ ~EtherPacket() { if (data) delete [] data; }
+
+ public:
+ bool IsUnicast() { return data[0] == 0x00; }
+ bool IsMulticast() { return data[0] == 0x01; }
+ bool IsBroadcast() { return data[0] == 0xff; }
+};
+
+typedef RefCountingPtr<EtherPacket> PacketPtr;
+
+#endif // __ETHERPKT_HH__
diff --git a/dev/ethertap.cc b/dev/ethertap.cc
new file mode 100644
index 000000000..6643cab30
--- /dev/null
+++ b/dev/ethertap.cc
@@ -0,0 +1,295 @@
+/*
+ * 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.
+ */
+
+/* @file
+ * Interface to connect a simulated ethernet device to the real world
+ */
+
+#if defined(__OpenBSD__)
+#include <sys/param.h>
+#endif
+#include <netinet/in.h>
+
+#include <unistd.h>
+
+#include <deque>
+#include <string>
+
+#include "etherdump.hh"
+#include "etherint.hh"
+#include "etherpkt.hh"
+#include "ethertap.hh"
+#include "pollevent.hh"
+#include "socket.hh"
+#include "trace.hh"
+#include "misc.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;
+ 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 EtherPacket;
+ packet->data = new uint8_t[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 + 1000);
+ } 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 + 1000);
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherTap)
+
+ SimObjectParam<EtherInt *> peer;
+ SimObjectParam<EtherDump *> packet_dump;
+ Param<uint16_t> port;
+ Param<uint16_t> bufsz;
+
+END_DECLARE_SIM_OBJECT_PARAMS(EtherTap)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(EtherTap)
+
+ INIT_PARAM_DFLT(peer, "peer interface", NULL),
+ INIT_PARAM_DFLT(packet_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(), packet_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
new file mode 100644
index 000000000..434df47b0
--- /dev/null
+++ b/dev/ethertap.hh
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+
+/* @file
+ * Interface to connect a simulated ethernet device to the real world
+ */
+
+#ifndef __ETHERTAP_HH__
+#define __ETHERTAP_HH__
+
+#include <queue>
+#include <string>
+
+#include "etherint.hh"
+#include "etherpkt.hh"
+#include "eventq.hh"
+#include "pollevent.hh"
+#include "sim_object.hh"
+
+/*
+ * 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(EtherPacket *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();
+};
+
+#endif // __ETHERTAP_HH__
diff --git a/dev/pcireg.h b/dev/pcireg.h
new file mode 100644
index 000000000..2921c30be
--- /dev/null
+++ b/dev/pcireg.h
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+
+/* @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 hdr {
+ 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 {
+ 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;
+ } pci0;
+
+ struct {
+ uint32_t baseAddr0;
+ uint32_t baseAddr1;
+ uint8_t priBusNum;
+ uint8_t secBusNum;
+ uint8_t subBusNum;
+ uint8_t secLatency;
+ uint8_t ioBase;
+ uint8_t minimumGrantioLimit;
+ uint16_t secStatus;
+ uint16_t memBase;
+ uint16_t memLimit;
+ uint16_t prefetchMemBase;
+ uint16_t prefetchMemLimit;
+ uint32_t prfBaseUpper32;
+ uint32_t prfLimitUpper32;
+ uint16_t ioBaseUpper16;
+ uint16_t ioLimitUpper16;
+ uint32_t reserved0;
+ uint32_t expansionROM;
+ uint8_t interruptLine;
+ uint8_t interruptPin;
+ uint16_t bridgeControl;
+ } pci1;
+ };
+ } hdr;
+};
+
+// 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
+
+// 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/simple_disk.cc b/dev/simple_disk.cc
new file mode 100644
index 000000000..25645db5f
--- /dev/null
+++ b/dev/simple_disk.cc
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+/* @file
+ * Simple disk interface for the system console
+ */
+
+#include <string>
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "disk_image.hh"
+#include "misc.hh"
+#include "physical_memory.hh"
+#include "simple_disk.hh"
+#include "trace.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
new file mode 100644
index 000000000..bf684950d
--- /dev/null
+++ b/dev/simple_disk.hh
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+/* @file
+ * Simple disk interface for the system console
+ */
+
+#ifndef __SIMPLE_DISK_HH__
+#define __SIMPLE_DISK_HH__
+
+#include "physical_memory.hh"
+#include "sim_object.hh"
+
+class DiskImage;
+
+/*
+ * 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 // __SIMPLE_DISK_HH__
diff --git a/kern/tru64/tru64.hh b/kern/tru64/tru64.hh
new file mode 100644
index 000000000..f8bb8ee43
--- /dev/null
+++ b/kern/tru64/tru64.hh
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#ifndef __TRU64_HH__
+#define __TRU64_HH__
+
+class Tru64 {};
+
+#endif // __TRU64_HH__
diff --git a/kern/tru64/tru64_syscalls.cc b/kern/tru64/tru64_syscalls.cc
new file mode 100644
index 000000000..dbaf4dbff
--- /dev/null
+++ b/kern/tru64/tru64_syscalls.cc
@@ -0,0 +1,438 @@
+/*
+ * 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.
+ */
+
+#include "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
new file mode 100644
index 000000000..2e76234c0
--- /dev/null
+++ b/kern/tru64/tru64_syscalls.hh
@@ -0,0 +1,355 @@
+/*
+ * 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.
+ */
+
+#ifndef __TRU64_SYSCALLS_HH__
+#define __TRU64_SYSCALLS_HH__
+
+#include "syscalls.hh"
+#include "tru64.hh"
+
+struct SystemCalls<Tru64>
+{
+ 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 // __TRU64_SYSCALLS_HH__
diff --git a/sim/async.hh b/sim/async.hh
new file mode 100644
index 000000000..fb0e2ee06
--- /dev/null
+++ b/sim/async.hh
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+#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/base_cpu.cc b/sim/base_cpu.cc
new file mode 100644
index 000000000..43caa1fe4
--- /dev/null
+++ b/sim/base_cpu.cc
@@ -0,0 +1,158 @@
+/*
+ * 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.
+ */
+
+#include <string>
+#include <sstream>
+#include <iostream>
+
+#include "base_cpu.hh"
+#include "cprintf.hh"
+#include "stats.hh"
+#include "exec_context.hh"
+#include "misc.hh"
+#include "sim_events.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;
+
+#ifdef FULL_SYSTEM
+BaseCPU::BaseCPU(const string &_name, int _number_of_threads,
+ Counter max_insts_any_thread,
+ Counter max_insts_all_threads,
+ System *_system, int num, Tick freq)
+ : SimObject(_name), number(num), frequency(freq),
+ number_of_threads(_number_of_threads), system(_system)
+#else
+BaseCPU::BaseCPU(const string &_name, int _number_of_threads,
+ Counter max_insts_any_thread,
+ Counter max_insts_all_threads)
+ : SimObject(_name), number_of_threads(_number_of_threads)
+#endif
+{
+ // add self to global list of CPUs
+ cpuList.push_back(this);
+
+ if (number_of_threads > maxThreadsPerCPU)
+ maxThreadsPerCPU = number_of_threads;
+
+ // allocate per-thread instruction-based event queues
+ comInsnEventQueue = new (EventQueue *)[number_of_threads];
+ for (int i = 0; i < number_of_threads; ++i)
+ comInsnEventQueue[i] = new EventQueue("instruction-based event queue");
+
+ //
+ // set up instruction-count-based termination events, if any
+ //
+ if (max_insts_any_thread != 0)
+ for (int i = 0; i < number_of_threads; ++i)
+ new SimExitEvent(comInsnEventQueue[i], max_insts_any_thread,
+ "a thread reached the max instruction count");
+
+ if (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(comInsnEventQueue[i],
+ "all threads reached the max instruction count",
+ max_insts_all_threads, *counter);
+ }
+
+#ifdef FULL_SYSTEM
+ memset(interrupts, 0, sizeof(interrupts));
+ intstatus = 0;
+#endif
+}
+
+void
+BaseCPU::regStats()
+{
+ int size = contexts.size();
+ if (size > 1) {
+ for (int i = 0; i < size; ++i) {
+ stringstream namestr;
+ ccprintf(namestr, "%s.ctx%d", name(), i);
+ contexts[i]->regStats(namestr.str());
+ }
+ } else if (size == 1)
+ contexts[0]->regStats(name());
+}
+
+#ifdef FULL_SYSTEM
+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 >= NumInterruptLevels)
+ panic("int_num out of bounds\n");
+
+ if (index < 0 || index >= sizeof(uint8_t) * 8)
+ panic("int_num out of bounds\n");
+
+ AlphaISA::check_interrupts = 1;
+ 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 >= NumInterruptLevels)
+ panic("int_num out of bounds\n");
+
+ if (index < 0 || index >= sizeof(uint8_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;
+}
+
+#endif // FULL_SYSTEM
+
+DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU)
diff --git a/sim/base_cpu.hh b/sim/base_cpu.hh
new file mode 100644
index 000000000..745220d85
--- /dev/null
+++ b/sim/base_cpu.hh
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+#ifndef __BASE_CPU_HH__
+#define __BASE_CPU_HH__
+
+#include <vector>
+
+#include "eventq.hh"
+#include "sim_object.hh"
+
+#include "isa_traits.hh" // for Addr
+
+#ifdef FULL_SYSTEM
+class System;
+#endif
+
+class BranchPred;
+class ExecContext;
+
+class BaseCPU : public SimObject
+{
+#ifdef FULL_SYSTEM
+ protected:
+ int number;
+ Tick frequency;
+ uint8_t interrupts[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 check_interrupt(int int_num) const {
+ if (int_num > 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; }
+
+ Tick getFreq() const { return frequency; }
+#endif
+
+ protected:
+ std::vector<ExecContext *> contexts;
+
+ public:
+ virtual void execCtxStatusChg() {}
+
+ public:
+
+#ifdef FULL_SYSTEM
+ BaseCPU(const std::string &_name, int _number_of_threads,
+ Counter max_insts_any_thread, Counter max_insts_all_threads,
+ System *_system,
+ int num, Tick freq);
+#else
+ BaseCPU(const std::string &_name, int _number_of_threads,
+ Counter max_insts_any_thread = 0,
+ Counter max_insts_all_threads = 0);
+#endif
+
+ virtual ~BaseCPU() {}
+
+ virtual void regStats();
+
+ /// 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 **comInsnEventQueue;
+
+#ifdef FULL_SYSTEM
+ System *system;
+#endif
+
+ virtual bool filterThisInstructionPrefetch(int thread_number,
+ short asid, Addr prefetchTarget) const { return true; }
+
+ /// Return pointer to CPU's branch predictor (NULL if none).
+ virtual BranchPred *getBranchPred() { return NULL; };
+
+ private:
+ static std::vector<BaseCPU *> cpuList; //!< Static global cpu list
+
+ public:
+ static int numSimulatedCPUs() { return cpuList.size(); }
+};
+
+#endif // __BASE_CPU_HH__
diff --git a/sim/cache/lzss_compression.cc b/sim/cache/lzss_compression.cc
new file mode 100644
index 000000000..a1933215a
--- /dev/null
+++ b/sim/cache/lzss_compression.cc
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ */
+
+/** @file
+ * LZSSCompression definitions.
+ */
+
+#include <assert.h>
+
+#include "lzss_compression.hh"
+
+#include "misc.hh" //for fatal
+
+int
+LZSSCompression::findSubString(uint8_t *src, int front, int back, int size)
+{
+ int subSize = 0;
+ int max_length = 2048;
+ if (size - back < max_length) {
+ max_length = size - back;
+ }
+ for (int i = 0; i < max_length; ++i) {
+ if (src[front+i] != src[back+i]) {
+ return subSize;
+ }
+ ++subSize;
+ }
+ return subSize;
+}
+
+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;
+ }
+ for (int j = 0; j < i; ++j) {
+ int sub_size = findSubString(src, j, i, size);
+ if (sub_size >= L) {
+ L = sub_size;
+ P = j;
+ }
+ }
+ 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/sim/cache/lzss_compression.hh b/sim/cache/lzss_compression.hh
new file mode 100644
index 000000000..5fb47d3f1
--- /dev/null
+++ b/sim/cache/lzss_compression.hh
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+#ifndef __LZSS_COMPRESSION_HH__
+#define __LZSS_COMPRESSION_HH__
+
+/** @file
+ * LZSSCompression declarations.
+ */
+
+#include "host.hh" // for uint8_t
+
+/**
+ * Simple LZSS compression scheme.
+ */
+class LZSSCompression
+{
+ /**
+ * Finds the longest substrings that start at the given offsets.
+ * @param src The source block that we search for substrings.
+ * @param front The smaller offset.
+ * @param back The larger offset.
+ * @param size The size of the source block.
+ * @return The size of the longest substring.
+ */
+ int findSubString(uint8_t *src, int front, int back, int size);
+
+ /**
+ * 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/sim/cache/null_compression.hh b/sim/cache/null_compression.hh
new file mode 100644
index 000000000..d2bc76eef
--- /dev/null
+++ b/sim/cache/null_compression.hh
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#ifndef __NULL_COMPRESSION_HH__
+#define __NULL_COMPRESSION_HH__
+
+/**
+ * @file
+ * This file defines a doNothing compression algorithm.
+ */
+
+/**
+ * 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 //__NULL_COMPRESSION_HH__
diff --git a/sim/debug.cc b/sim/debug.cc
new file mode 100644
index 000000000..bfc5c9987
--- /dev/null
+++ b/sim/debug.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.
+ */
+
+#include <sys/types.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include "debug.hh"
+#include "eventq.hh"
+#include "param.hh"
+#include "sim_events.hh"
+
+using namespace std;
+
+void
+debug_break()
+{
+ kill(getpid(), SIGTRAP);
+}
+
+//
+// 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)
+{
+ schedule(_when, -20000);
+}
+
+//
+// handle debug event: set debugger breakpoint on this function
+//
+void
+DebugBreakEvent::process()
+{
+ debug_break();
+ delete this;
+}
+
+
+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 dump_stats()
+{
+ new DumpStatsEvent();
+}
+
+extern "C" void eventq_dump()
+{
+ mainEventQueue.dump();
+}
+
diff --git a/sim/debug.hh b/sim/debug.hh
new file mode 100644
index 000000000..eb0be772e
--- /dev/null
+++ b/sim/debug.hh
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#ifndef __DEBUG_HH__
+#define __DEBUG_HH__
+
+void debug_break();
+
+#endif // __DEBUG_HH__
diff --git a/sim/eventq.cc b/sim/eventq.cc
new file mode 100644
index 000000000..36ef8aab2
--- /dev/null
+++ b/sim/eventq.cc
@@ -0,0 +1,212 @@
+/*
+ * 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.
+ */
+
+#include <assert.h>
+
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <vector>
+
+#include "smt.hh"
+#include "misc.hh"
+
+#include "eventq.hh"
+#include "trace.hh"
+#include "universe.hh"
+
+using namespace std;
+
+const string Event::defaultName("event");
+
+//
+// Main Event Queue
+//
+// Events on this queue are processed at the *beginning* of each
+// cycle, before the pipeline simulation is performed.
+//
+EventQueue mainEventQueue("Main Event Queue");
+
+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))
+ delete event;
+}
+
+void
+EventQueue::nameChildren()
+{
+ int j = 0;
+
+ Event *event = head;
+ while (event) {
+ stringstream stream;
+ ccprintf(stream, "%s.event%d", name(), j++);
+ event->setName(stream.str());
+
+ event = event->next;
+ }
+}
+
+void
+EventQueue::serialize()
+{
+ string objects = "";
+
+ Event *event = head;
+ while (event) {
+ objects += event->name();
+ objects += " ";
+ event->serialize();
+
+ event = event->next;
+ }
+ nameOut("Serialized");
+ paramOut("objects",objects);
+}
+
+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");
+}
+
+
+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()
+{
+#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\n", when());
+ }
+ else {
+ cprintf(" Not Scheduled\n");
+ }
+}
diff --git a/sim/eventq.hh b/sim/eventq.hh
new file mode 100644
index 000000000..71b027768
--- /dev/null
+++ b/sim/eventq.hh
@@ -0,0 +1,351 @@
+/*
+ * 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.
+ */
+
+/* @file
+ * EventQueue interfaces
+ */
+
+#ifndef __EVENTQ_HH__
+#define __EVENTQ_HH__
+
+#include <assert.h>
+
+#include <algorithm>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "host.hh" // for Tick
+
+#include "fast_alloc.hh"
+#include "serialize.hh"
+#include "trace.hh"
+
+class EventQueue; // forward declaration
+
+/*
+ * 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 Serializeable, 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
+ };
+
+ 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:
+
+ static const std::string defaultName;
+
+ /*
+ * Event constructor
+ * @param queue that the event gets scheduled on
+ */
+ Event(EventQueue *q, int p = 0)
+ : Serializeable(defaultName), queue(q), next(NULL),
+ _priority(p), _flags(None),
+#if TRACING_ON
+ when_created(curTick), when_scheduled(0),
+#endif
+ annotated_value(0)
+ {
+ }
+
+ ~Event() {}
+
+ /// 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);
+
+ /// Schedule the event with a specific priority
+ void schedule(Tick t, int priority);
+
+ /// Reschedule the event with the current priority
+ void reschedule(Tick t);
+
+ /// Reschedule the event with a specific priority
+ void reschedule(Tick t, int priority);
+
+ /// 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();
+ }
+ };
+};
+
+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(AutoDestroy); schedule(when); }
+ void process() { (object->*F)(); }
+ const char *description() { return "delay"; }
+ };
+
+ new DelayEvent(when, object);
+}
+
+/*
+ * Queue of events sorted in time order
+ */
+class EventQueue : public Serializeable
+{
+ private:
+ Event *head;
+
+ void insert(Event *event);
+ void remove(Event *event);
+
+ public:
+
+ // constructor
+ EventQueue(const std::string &n)
+ : Serializeable(n), head(NULL)
+ {}
+
+ // 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;
+
+ 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 nameChildren();
+ virtual void serialize();
+};
+
+
+//////////////////////
+//
+// 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());
+ setFlags(Scheduled);
+#if TRACING_ON
+ when_scheduled = curTick;
+#endif
+ _when = t;
+ queue->schedule(this);
+}
+
+inline void
+Event::schedule(Tick t, int p)
+{
+ _priority = p;
+ schedule(t);
+}
+
+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
+Event::reschedule(Tick t, int p)
+{
+ _priority = p;
+ reschedule(t);
+}
+
+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");
+}
+
+
+//////////////////////
+//
+// 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;
+
+#endif // __EVENTQ_HH__
diff --git a/sim/exec_context.cc b/sim/exec_context.cc
new file mode 100644
index 000000000..c81d172a8
--- /dev/null
+++ b/sim/exec_context.cc
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+
+#include <string>
+
+#include "base_cpu.hh"
+#include "exec_context.hh"
+
+#ifdef FULL_SYSTEM
+#include "system.hh"
+#else
+#include "prog.hh"
+#endif
+
+using namespace std;
+
+// constructor
+#ifdef FULL_SYSTEM
+ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num, System *_sys,
+ AlphaItb *_itb, AlphaDtb *_dtb,
+ FunctionalMemory *_mem, int _cpu_id)
+ : kernelStats(this, _cpu), cpu(_cpu), thread_num(_thread_num), mem(_mem),
+ itb(_itb), dtb(_dtb), cpu_id(_cpu_id), system(_sys),
+ memCtrl(_sys->memCtrl), physmem(_sys->physmem)
+{
+ memset(&regs, 0, sizeof(RegFile));
+ _status = Active;
+ func_exe_insn = 0;
+ storeCondFailures = 0;
+ system->registerExecContext(this);
+}
+#else
+ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num,
+ Process *_process, int _asid)
+ : cpu(_cpu), thread_num(_thread_num), process(_process), asid (_asid)
+{
+
+ // Register with process object. Our 'active' will be set by the
+ // process iff we're the initial context. Others are reserved for
+ // dynamically created threads.
+ process->registerExecContext(this);
+
+ mem = process->getMemory();
+
+ func_exe_insn = 0;
+ storeCondFailures = 0;
+}
+
+ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num,
+ FunctionalMemory *_mem, int _asid)
+ : cpu(_cpu), thread_num(_thread_num), process(NULL), mem(_mem),
+ asid(_asid)
+{
+}
+#endif
+
+void
+ExecContext::setStatus(Status new_status)
+{
+#ifdef FULL_SYSTEM
+ if (status() == new_status)
+ return;
+
+ // Don't change the status from active if there are pending interrupts
+ if (new_status == Suspended && cpu->check_interrupts()) {
+ assert(status() == Active);
+ return;
+ }
+#endif
+
+ _status = new_status;
+ cpu->execCtxStatusChg();
+}
+
+void
+ExecContext::regStats(const string &name)
+{
+#ifdef FULL_SYSTEM
+ kernelStats.regStats(name + ".kern");
+#endif
+}
diff --git a/sim/exec_context.hh b/sim/exec_context.hh
new file mode 100644
index 000000000..56bce0aa9
--- /dev/null
+++ b/sim/exec_context.hh
@@ -0,0 +1,360 @@
+/*
+ * 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.
+ */
+
+#ifndef __EXEC_CONTEXT_HH__
+#define __EXEC_CONTEXT_HH__
+
+#include "host.hh"
+#include "stats.hh"
+#include "mem_req.hh"
+
+// forward declaration: see functional_memory.hh
+class FunctionalMemory;
+class PhysicalMemory;
+class BaseCPU;
+
+#ifdef FULL_SYSTEM
+
+#include "alpha_memory.hh"
+class MemoryController;
+
+#include "kernel_stats.hh"
+#include "system.hh"
+
+#else // !FULL_SYSTEM
+
+#include "prog.hh"
+
+#endif // FULL_SYSTEM
+
+//
+// The ExecContext object represents a functional context for
+// instruction execution. It incorporates everything required for
+// architecture-level functional simulation of a single thread.
+//
+
+class ExecContext
+{
+ public:
+ enum Status { Unallocated, Active, Suspended, Halted };
+
+ private:
+ Status _status;
+
+ public:
+ Status status() const { return _status; }
+ void setStatus(Status new_status);
+
+#ifdef FULL_SYSTEM
+ public:
+ KernelStats kernelStats;
+#endif
+
+ public:
+ RegFile regs; // correct-path register context
+
+ // pointer to CPU associated with this context
+ BaseCPU *cpu;
+
+ // Index of hardware thread context on the CPU that this represents.
+ int thread_num;
+
+#ifdef FULL_SYSTEM
+
+ FunctionalMemory *mem;
+ AlphaItb *itb;
+ AlphaDtb *dtb;
+ int cpu_id;
+ 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;
+
+#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
+
+
+ /*
+ * number of executed instructions, for matching with syscall trace
+ * points in EIO files.
+ */
+ Counter func_exe_insn;
+
+ //
+ // Count failed store conditionals so we can warn of apparent
+ // application deadlock situations.
+ unsigned storeCondFailures;
+
+ // constructor: initialize context from given process structure
+#ifdef FULL_SYSTEM
+ ExecContext(BaseCPU *_cpu, int _thread_num, System *_system,
+ AlphaItb *_itb, AlphaDtb *_dtb, FunctionalMemory *_dem,
+ int _cpu_id);
+#else
+ ExecContext(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid);
+ ExecContext(BaseCPU *_cpu, int _thread_num, FunctionalMemory *_mem,
+ int _asid);
+#endif
+ virtual ~ExecContext() {}
+
+ void regStats(const std::string &name);
+
+#ifdef FULL_SYSTEM
+ bool validInstAddr(Addr addr) { return true; }
+ bool validDataAddr(Addr addr) { return true; }
+ int getInstAsid() { return ITB_ASN_ASN(regs.ipr[TheISA::IPR_ITB_ASN]); }
+ int getDataAsid() { return DTB_ASN_ASN(regs.ipr[TheISA::IPR_DTB_ASN]); }
+
+ 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 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 No_Fault;
+ }
+ 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 defined(TARGET_ALPHA) && defined(FULL_SYSTEM)
+ if (req->flags & LOCKED) {
+ MiscRegFile *cregs = &req->xc->regs.miscRegs;
+ cregs->lock_addr = req->paddr;
+ cregs->lock_flag = true;
+ }
+#endif
+ return mem->read(req, data);
+ }
+
+ template <class T>
+ Fault write(MemReqPtr req, T& data)
+ {
+#if defined(TARGET_ALPHA) && defined(FULL_SYSTEM)
+
+ MiscRegFile *cregs;
+
+ // If this is a store conditional, act appropriately
+ if (req->flags & LOCKED) {
+ cregs = &req->xc->regs.miscRegs;
+
+ if (req->flags & UNCACHEABLE) {
+ // Don't update result register (see machine.def)
+ req->result = 2;
+ req->xc->storeCondFailures = 0;//Needed? [RGD]
+ } else {
+ req->result = cregs->lock_flag;
+ if (!cregs->lock_flag ||
+ ((cregs->lock_addr & ~0xf) != (req->paddr & ~0xf))) {
+ cregs->lock_flag = false;
+ if (((++req->xc->storeCondFailures) % 100000) == 0) {
+ std::cerr << "Warning: "
+ << req->xc->storeCondFailures
+ << " consecutive store conditional failures "
+ << "on cpu " << req->xc->cpu_id
+ << std::endl;
+ }
+ return No_Fault;
+ }
+ else req->xc->storeCondFailures = 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?)
+ // Unsuccesful Store Conditionals would have returned above,
+ // and wouldn't fall through
+ for(int i = 0; i < system->num_cpus; i++){
+ cregs = &system->xc_array[i]->regs.miscRegs;
+ if((cregs->lock_addr & ~0xf) == (req->paddr & ~0xf)) {
+ cregs->lock_flag = false;
+ }
+ }
+
+#endif
+ return mem->write(req, data);
+ }
+
+ virtual bool misspeculating();
+
+
+ //
+ // 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 setNextPC(uint64_t val)
+ {
+ regs.npc = val;
+ }
+
+ uint64_t readUniq()
+ {
+ return regs.miscRegs.uniq;
+ }
+
+ void setUniq(uint64_t val)
+ {
+ regs.miscRegs.uniq = val;
+ }
+
+ uint64_t readFpcr()
+ {
+ return regs.miscRegs.fpcr;
+ }
+
+ void setFpcr(uint64_t val)
+ {
+ regs.miscRegs.fpcr = val;
+ }
+
+#ifdef FULL_SYSTEM
+ uint64_t readIpr(int idx, Fault &fault);
+ Fault setIpr(int idx, uint64_t val);
+ Fault hwrei();
+ void ev5_trap(Fault fault);
+ bool simPalCheck(int palFunc);
+#endif
+
+#ifndef FULL_SYSTEM
+ void syscall()
+ {
+ process->syscall(this);
+ }
+#endif
+};
+
+
+// for non-speculative execution context, spec_mode is always false
+inline bool
+ExecContext::misspeculating()
+{
+ return false;
+}
+
+#endif // __EXEC_CONTEXT_HH__
diff --git a/sim/exetrace.cc b/sim/exetrace.cc
new file mode 100644
index 000000000..4c5d14893
--- /dev/null
+++ b/sim/exetrace.cc
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+#include <fstream>
+#include <iomanip>
+
+#include "dyn_inst.hh"
+#include "spec_state.hh"
+#include "issue.hh"
+#include "exetrace.hh"
+#include "exec_context.hh"
+#include "symtab.hh"
+#include "base_cpu.hh"
+#include "static_inst.hh"
+
+using namespace std;
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Methods for the InstRecord object
+//
+
+
+const SymbolTable *debugSymbolTable = NULL;
+
+void
+Trace::InstRecord::dump(ostream &outs)
+{
+ 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 << " : ";
+
+ 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() < 25)
+ mc += " ";
+ outs << mc;
+#else
+ outs << setw(25) << 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;
+ outs.flush();
+}
+
+
+vector<bool> Trace::InstRecord::flags(NUM_BITS);
+
+////////////////////////////////////////////////////////////////////////
+//
+// 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", false);
+
+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);
+
+//
+// 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;
+}
+
+void
+ExecutionTraceParamContext::checkParams()
+{
+ Trace::InstRecord::setParams();
+}
+
diff --git a/sim/exetrace.hh b/sim/exetrace.hh
new file mode 100644
index 000000000..d5b9dc218
--- /dev/null
+++ b/sim/exetrace.hh
@@ -0,0 +1,197 @@
+/*
+ * 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.
+ */
+
+#ifndef __EXETRACE_HH__
+#define __EXETRACE_HH__
+
+#include <fstream>
+#include <vector>
+
+#include "host.hh"
+#include "std_types.hh" // for InstSeqNum
+#include "trace.hh"
+#include "exec_context.hh"
+#include "static_inst.hh"
+
+class BaseCPU;
+
+
+namespace Trace {
+
+#if 0
+ static const FlagVec ALL = ULL(0x1);
+ static const FlagVec FULL = ULL(0x2);
+ static const FlagVec SYMBOLS = ULL(0x4);
+ static const FlagVec EXTENDED = ULL(0x8);
+ static const FlagVec BRANCH_TAKEN = ULL(0x10);
+ static const FlagVec BRANCH_NOTTAKEN = ULL(0x20);
+ static const FlagVec CALLPAL = ULL(0x40);
+ static const FlagVec SPECULATIVE = ULL(0x100);
+ static const FlagVec OMIT_COUNT = ULL(0x200);
+ static const FlagVec INCLUDE_THREAD_NUM = ULL(0x400);
+#endif
+
+class InstRecord : public Record
+{
+ protected:
+
+ // 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<TheISA> 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, StaticInstPtr<TheISA> _staticInst,
+ Addr _pc, bool spec, unsigned _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 &regs);
+
+ 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,
+ NUM_BITS
+ };
+
+ static std::vector<bool> flags;
+
+ static void setParams();
+
+ static bool traceMisspec() { return flags[TRACE_MISSPEC]; }
+};
+
+
+inline void
+InstRecord::setRegs(const IntRegFile &regs)
+{
+ 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<TheISA> 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/sim/host.hh b/sim/host.hh
new file mode 100644
index 000000000..489c4e042
--- /dev/null
+++ b/sim/host.hh
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+/**
+ * @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) N##ULL
+/** int64_t constant */
+#define LL(N) 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;
+
+#endif // __HOST_H__
diff --git a/sim/hybrid_pred.cc b/sim/hybrid_pred.cc
new file mode 100644
index 000000000..6a8384083
--- /dev/null
+++ b/sim/hybrid_pred.cc
@@ -0,0 +1,275 @@
+/*
+ * 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.
+ */
+
+#include <string>
+#include <sstream>
+
+#include "stats.hh"
+#include "hybrid_pred.hh"
+
+#include "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 Statistics;
+
+ 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 Statistics;
+
+ 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/sim/hybrid_pred.hh b/sim/hybrid_pred.hh
new file mode 100644
index 000000000..f6e14e3e3
--- /dev/null
+++ b/sim/hybrid_pred.hh
@@ -0,0 +1,203 @@
+/*
+ * 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.
+ */
+
+//==========================================================================
+//
+// 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 "sat_counter.hh"
+
+#include "statistics.hh"
+#include "sim_stats.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
+ //
+ Statistics::Scalar<> pred_one; //num_one_preds
+ Statistics::Scalar<> pred_zero; //num_zero_preds
+ Statistics::Scalar<> correct_pred_one; //num_one_correct
+ Statistics::Scalar<> correct_pred_zero; //num_zero_correct
+ Statistics::Scalar<> record_one; //num_one_updates
+ Statistics::Scalar<> record_zero; //num_zero_updates
+
+ Statistics::Formula total_preds;
+ Statistics::Formula frac_preds_zero;
+ Statistics::Formula frac_preds_one;
+ Statistics::Formula total_correct;
+ Statistics::Formula total_accuracy;
+ Statistics::Formula zero_accuracy;
+ Statistics::Formula one_accuracy;
+ Statistics::Formula zero_coverage;
+ Statistics::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/sim/intr_control.cc b/sim/intr_control.cc
new file mode 100644
index 000000000..7ad32a2b9
--- /dev/null
+++ b/sim/intr_control.cc
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#include <string>
+#include <vector>
+
+#include "base_cpu.hh"
+#include "intr_control.hh"
+#include "sim_object.hh"
+
+using namespace std;
+
+IntrControl::IntrControl(const string &name, BaseCPU *c)
+ : SimObject(name), cpu(c)
+{}
+
+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 processor")
+
+END_INIT_SIM_OBJECT_PARAMS(IntrControl)
+
+CREATE_SIM_OBJECT(IntrControl)
+{
+ return new IntrControl(getInstanceName(), cpu);
+}
+
+REGISTER_SIM_OBJECT("IntrControl", IntrControl)
diff --git a/sim/intr_control.hh b/sim/intr_control.hh
new file mode 100644
index 000000000..660d6d704
--- /dev/null
+++ b/sim/intr_control.hh
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#ifndef __INTR_CONTROL_HH__
+#define __INTR_CONTROL_HH__
+
+#include "misc.hh"
+#include "base_cpu.hh"
+#include "sim_object.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);
+};
+
+inline void
+IntrControl::post(int int_num, int index)
+{ cpu->post_interrupt(int_num, index); }
+
+inline void
+IntrControl::clear(int int_num, int index)
+{ cpu->clear_interrupt(int_num, index); }
+
+#endif // __INTR_CONTROL_HH__
+
+
+
+
+
+
+
diff --git a/sim/main.cc b/sim/main.cc
new file mode 100644
index 000000000..84f8e78cc
--- /dev/null
+++ b/sim/main.cc
@@ -0,0 +1,429 @@
+/*
+ * 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.
+ */
+
+///
+/// @file sim/main.cc
+///
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <signal.h>
+
+#include <string>
+#include <vector>
+
+#include "host.hh"
+#include "misc.hh"
+#include "stats.hh"
+
+#include "copyright.hh"
+#include "inifile.hh"
+#include "configfile.hh"
+#include "pollevent.hh"
+#include "statistics.hh"
+#include "sim_events.hh"
+#include "sim_exit.hh"
+#include "sim_object.hh"
+#include "sim_stats.hh"
+#include "sim_time.hh"
+#include "smt.hh"
+
+#include "base_cpu.hh"
+#include "async.hh"
+
+using namespace std;
+
+// See async.h.
+volatile bool async_event = false;
+volatile bool async_dump = 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;
+}
+
+/// Exit signal handler.
+void
+exitNowHandler(int sigtype)
+{
+ async_event = true;
+ async_exit = true;
+}
+
+/// Simulator executable name
+const char *myProgName = "";
+
+/// Show brief help message.
+static void
+showBriefHelp(ostream &out)
+{
+ out << "Usage: " << myProgName
+ << " [-hn] [-Dname[=def]] [-Uname] [-I[dir]] "
+ << "[--<section>:<param>=<value>] [<config file> ...]" << endl
+ << " -h: print long help (including parameter listing)" << endl
+ << " -n: don't load default.ini" << endl
+ << " -u: don't quit on unreferenced parameters" << endl
+ << " -D,-U,-I: passed to cpp for preprocessing .ini files" << endl;
+}
+
+/// Show verbose help message. Includes parameter listing from
+/// showBriefHelp(), plus an exhaustive list of ini-file parameters
+/// and SimObjects (with their parameters).
+static void
+showLongHelp(ostream &out)
+{
+ showBriefHelp(out);
+
+ out << endl
+ << endl
+ << "-----------------" << endl
+ << "Global Parameters" << endl
+ << "-----------------" << endl
+ << endl;
+
+ ParamContext::describeAllContexts(out);
+
+ out << endl
+ << endl
+ << "-----------------" << endl
+ << "Simulator Objects" << endl
+ << "-----------------" << endl
+ << endl;
+
+ SimObjectClass::describeAllClasses(out);
+}
+
+/// Print welcome message.
+static 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).
+///
+static 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;
+}
+
+
+///
+/// The simulator configuration database. This is the union of all
+/// specified .ini files. This shouldn't need to be visible outside
+/// this file, as it is passed as a parameter to all the param-parsing
+/// routines.
+///
+static IniFile simConfigDB;
+
+/// Check for a default.ini file and load it if necessary.
+static void
+handleDefaultIni(bool &loadIt, vector<char *> &cppArgs)
+{
+ struct stat sb;
+
+ if (loadIt) {
+ if (stat("default.ini", &sb) == 0) {
+ if (!simConfigDB.loadCPP("default.ini", cppArgs)) {
+ cout << "Error processing file default.ini" << endl;
+ exit(1);
+ }
+ }
+
+ // set this whether it actually was found or not, so we don't
+ // bother to check again next time
+ loadIt = false;
+ }
+}
+
+
+/// M5 entry point.
+int
+main(int argc, char **argv)
+{
+ // Save off program name
+ myProgName = argv[0];
+
+ signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGTRAP, SIG_IGN);
+ signal(SIGUSR1, dumpStatsHandler); // dump intermediate stats
+ signal(SIGINT, exitNowHandler); // dump final stats and exit
+
+ sayHello(cerr);
+
+ // Initialize statistics database
+ init_old_stats();
+ initBaseStats();
+
+ vector<char *> cppArgs;
+
+ // Should we use default.ini if it exists? By default, yes. (Use
+ // -n to override.)
+ bool loadDefaultIni = true;
+
+ // Should we quit if there are unreferenced parameters? By
+ // default, yes... it's a good way of catching typos in
+ // section/parameter names (which otherwise go by silently). Use
+ // -u to override.
+ bool quitOnUnreferenced = true;
+
+ // Parse command-line options. The tricky part here is figuring
+ // out whether to look for & load default.ini, and if needed,
+ // doing so at the right time w.r.t. processing the other
+ // parameters.
+ //
+ // 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 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 'h':
+ // -h: show help
+ showLongHelp(cerr);
+ exit(1);
+
+ case 'n':
+ // -n: don't load default.ini
+ if (!loadDefaultIni) {
+ cerr << "Warning: -n option needs to precede any "
+ << "explicit configuration file name " << endl
+ << " or command-line configuration parameter."
+ << endl;
+ }
+ loadDefaultIni = false;
+ break;
+
+ case 'u':
+ // -u: don't quit on unreferenced parameters
+ quitOnUnreferenced = false;
+ break;
+
+ 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>'
+
+ // Load default.ini if necessary -- see comment in
+ // else clause below.
+ handleDefaultIni(loadDefaultIni, cppArgs);
+
+ 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:
+ showBriefHelp(cerr);
+ ccprintf(cerr, "Fatal: invalid argument '%s'\n", arg_str);
+ exit(0);
+ }
+ }
+ else {
+ // no '-', treat as config file name
+
+ // If we haven't loaded default.ini yet, and we want to,
+ // now is the time. Can't do it sooner because we need to
+ // look for '-n', can't do it later since we want
+ // default.ini loaded first (so that any other settings
+ // override it).
+ handleDefaultIni(loadDefaultIni, cppArgs);
+
+ if (!simConfigDB.loadCPP(arg_str, cppArgs)) {
+ cprintf("Error processing file %s\n", arg_str);
+ exit(1);
+ }
+ }
+ }
+
+ // Final check for default.ini, in case no config files or
+ // command-line config parameters were given.
+ handleDefaultIni(loadDefaultIni, cppArgs);
+
+ // The configuration database is now complete; start processing it.
+
+ // Parse and check all non-config-hierarchy parameters.
+ ParamContext::parseAllContexts(simConfigDB);
+ ParamContext::checkAllContexts();
+
+ // Print header info into stats file. Can't do this sooner since
+ // the stat file name is set via a .ini param... thus it just got
+ // opened above during 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 (statStreamIsFile)
+ sayHello(*statStream);
+
+ // Echo command line and all parameter settings to stats file as well.
+ echoCommandLine(argc, argv, *statStream);
+ ParamContext::showAllContexts(*statStream);
+
+ // Now process the configuration hierarchy and create the SimObjects.
+ ConfigHierarchy configHierarchy(simConfigDB);
+ configHierarchy.build();
+ configHierarchy.createSimObjects();
+
+ // Restore checkpointed state, if any.
+ configHierarchy.unserializeSimObjects();
+
+ // Done processing the configuration database.
+ // Check for unreferenced entries.
+ if (simConfigDB.printUnreferenced() && quitOnUnreferenced) {
+ cerr << "Fatal: unreferenced .ini sections/entries." << endl
+ << "If this is not an error, add 'unref_section_ok=y' or "
+ << "'unref_entries_ok=y' to the appropriate sections "
+ << "to suppress this message." << endl;
+ exit(1);
+ }
+
+ 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
+ Statistics::check();
+
+ // Nothing to simulate if we don't have at least one CPU somewhere.
+ if (BaseCPU::numSimulatedCPUs() == 0) {
+ cerr << "Fatal: no CPUs to simulate." << endl;
+ exit(1);
+ }
+
+ 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;
+ new DumpStatsEvent();
+ }
+
+ 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("improperly exited event loop!", 1);
+
+ return 0;
+}
diff --git a/sim/memtest.cc b/sim/memtest.cc
new file mode 100644
index 000000000..70b6fbf13
--- /dev/null
+++ b/sim/memtest.cc
@@ -0,0 +1,324 @@
+/*
+ * 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.
+ */
+
+// FIX ME: make trackBlkAddr use blocksize from actual cache, not hard coded
+
+#include <string>
+#include <sstream>
+#include <iomanip>
+#include <vector>
+
+#include "memtest.hh"
+#include "misc.hh"
+#include "sim_events.hh"
+#include "main_memory.hh"
+#include "base_cache.hh"
+
+#include "statistics.hh"
+#include "sim_stats.hh"
+
+using namespace std;
+
+MemTest::MemTest(const string &name,
+ MemInterface *_cache_interface,
+ FunctionalMemory *main_mem,
+ FunctionalMemory *check_mem,
+ unsigned _memorySize,
+ unsigned _percentReads,
+ unsigned _percentUncacheable,
+ unsigned _maxReads,
+ unsigned _progressInterval,
+ Addr _traceAddr)
+ : BaseCPU(name, 1),
+ tickEvent(this),
+ cacheInterface(_cache_interface),
+ mainMem(main_mem),
+ checkMem(check_mem),
+ size(_memorySize),
+ percentReads(_percentReads),
+ percentUncacheable(_percentUncacheable),
+ maxReads(_maxReads),
+ progressInterval(_progressInterval),
+ nextProgressMessage(_progressInterval)
+{
+ vector<string> cmd;
+ cmd.push_back("/bin/ls");
+ vector<string> null_vec;
+ xc = new ExecContext(this ,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;
+ numWrites = 0;
+ tickEvent.schedule(0);
+}
+
+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)
+{
+ switch (req->cmd) {
+ case Read:
+ if (memcmp(req->data, data, req->size) != 0) {
+ cerr << name() << ": on read of 0x" << hex << 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++;
+
+ if (numReads.val() == nextProgressMessage) {
+ cerr << name() << ": completed " << numReads.val()
+ << " read accesses @ " << curTick << endl;
+ nextProgressMessage += progressInterval;
+ }
+
+ if (numReads.val() == maxReads) {
+ stringstream stream;
+ stream << name() << " reached max read count (" << maxReads
+ << ")" << endl;
+
+ new SimExitEvent(stream.str());
+ }
+ break;
+
+ case Write:
+ numWrites++;
+ break;
+
+
+ default:
+ panic("invalid command");
+ }
+
+ if (blockAddr(req->paddr) == traceBlockAddr) {
+ cerr << name() << ": completed "
+ << (req->cmd.isWrite() ? "write" : "read") << " access of "
+ << req->size << " bytes at address 0x"
+ << hex << req->paddr << ", value = 0x";
+ printData(cerr, req->data, req->size);
+ cerr << endl;
+ }
+
+ noResponseCycles = 0;
+ delete [] data;
+}
+
+
+void
+MemTest::regStats()
+{
+ using namespace Statistics;
+
+ numReads
+ .name(name() + ".num_reads")
+ .desc("number of read accesses completed")
+ ;
+
+ numWrites
+ .name(name() + ".num_writes")
+ .desc("number of write accesses completed")
+ ;
+
+ numCopies
+ .name(name() + ".num_copies")
+ .desc("number of copy accesses completed")
+ ;
+}
+
+void
+MemTest::tick()
+{
+ if (!tickEvent.scheduled())
+ tickEvent.schedule(curTick + 1);
+
+ if (++noResponseCycles >= 5000) {
+ cerr << name() << ": deadlocked at cycle " << curTick << endl;
+ fatal("");
+ }
+
+ if (cacheInterface->isBlocked()) {
+ return;
+ }
+
+ //make new request
+ unsigned cmd = rand() % 100;
+ unsigned offset1 = random() % size;
+ unsigned base = random() % 2;
+ uint64_t data = random();
+ unsigned access_size = random() % 4;
+ unsigned cacheable = rand() % 100;
+
+ MemReqPtr req = new MemReq();
+
+ if (cacheable < percentUncacheable) {
+ req->flags |= UNCACHEABLE;
+ req->paddr = uncacheAddr + offset1;
+ } else {
+ req->paddr = ((base) ? baseAddr1 : baseAddr2) + offset1;
+ }
+
+ req->size = 1 << access_size;
+ req->data = new uint8_t[req->size];
+ req->paddr &= ~(req->size - 1);
+ req->time = curTick;
+ req->xc = xc;
+
+ if (cmd < percentReads) {
+ // read
+ 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 of "
+ << req->size << " bytes from addr 0x"
+ << hex << req->paddr << " at cycle "
+ << dec << curTick << endl;
+ }
+
+ req->completionEvent = new MemCompleteEvent(req, result, this);
+ cacheInterface->access(req);
+ } else {
+ // write
+ 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 of "
+ << req->size << " bytes (value = 0x";
+ printData(cerr, req->data, req->size);
+ cerr << ") to addr 0x"
+ << hex << req->paddr << " at cycle "
+ << dec << curTick << endl;
+ }
+ req->completionEvent = new MemCompleteEvent(req, NULL, this);
+ cacheInterface->access(req);
+ }
+}
+
+
+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_uncacheable;
+ Param<unsigned> max_reads;
+ Param<unsigned> progress_interval;
+ Param<Addr> trace_addr;
+
+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_DFLT(memory_size, "memory size", 65536),
+ INIT_PARAM_DFLT(percent_reads, "target read percentage", 65),
+ INIT_PARAM_DFLT(percent_uncacheable, "target uncacheable percentage", 10),
+ INIT_PARAM_DFLT(max_reads, "number of reads to simulate", 0),
+ INIT_PARAM_DFLT(progress_interval,
+ "progress report interval (in accesses)", 1000000),
+ INIT_PARAM_DFLT(trace_addr, "address to trace", 0)
+
+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_uncacheable, max_reads, progress_interval,
+ trace_addr);
+}
+
+REGISTER_SIM_OBJECT("MemTest", MemTest)
diff --git a/sim/memtest.hh b/sim/memtest.hh
new file mode 100644
index 000000000..aa652abbd
--- /dev/null
+++ b/sim/memtest.hh
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+
+#ifndef __MEMTEST_HH__
+#define __MEMTEST_HH__
+
+#include "sim_object.hh"
+#include "mem_interface.hh"
+#include "functional_memory.hh"
+#include "base_cpu.hh"
+#include "exec_context.hh"
+
+#include "statistics.hh"
+#include "sim_stats.hh"
+
+class MemTest : public BaseCPU
+{
+ public:
+
+ MemTest(const std::string &name,
+ MemInterface *_cache_interface,
+ FunctionalMemory *main_mem,
+ FunctionalMemory *check_mem,
+ unsigned _memorySize,
+ unsigned _percentReads,
+ unsigned _percentUncacheable,
+ unsigned _maxReads,
+ unsigned _progressInterval,
+ Addr _traceAddr);
+
+ // register statistics
+ virtual void regStats();
+ // main simulation loop (one cycle)
+ void tick();
+
+ protected:
+ class TickEvent : public Event
+ {
+ private:
+ MemTest *cpu;
+ public:
+ TickEvent(MemTest *c)
+ : Event(&mainEventQueue, 100), cpu(c) {}
+ void process() {cpu->tick();}
+ virtual const char *description() { return "tick event"; }
+ };
+
+ TickEvent tickEvent;
+
+ MemInterface *cacheInterface;
+ FunctionalMemory *mainMem;
+ FunctionalMemory *checkMem;
+ ExecContext *xc;
+
+ unsigned size; // size of testing memory region
+
+ unsigned percentReads; // target percentage of read accesses
+ unsigned percentUncacheable;
+
+ Tick maxReads; // max # of reads to perform (then quit)
+
+ 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
+
+ Tick noResponseCycles;
+
+ Statistics::Scalar<long long int> numReads;
+ Statistics::Scalar<long long int> numWrites;
+ Statistics::Scalar<long long int> numCopies;
+
+ // 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 // __MEMTEST_HH__
+
+
+
diff --git a/sim/op_class.hh b/sim/op_class.hh
new file mode 100644
index 000000000..67ccaabad
--- /dev/null
+++ b/sim/op_class.hh
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#ifndef __OP_CLASS_HH__
+#define __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 */
+ IntALU, /* integer ALU */
+ IntMULT, /* integer multiplier */
+ IntDIV, /* integer divider */
+ FloatADD, /* floating point adder/subtractor */
+ FloatCMP, /* floating point comparator */
+ FloatCVT, /* floating point<->integer converter */
+ FloatMULT, /* floating point multiplier */
+ FloatDIV, /* floating point divider */
+ FloatSQRT, /* floating point square root */
+ RdPort, /* memory read port */
+ WrPort, /* memory write port */
+ LvqPort, /* load value queue read port (redundant threading) */
+ IPrefPort,
+ Num_OpClasses /* total functional unit classes */
+};
+
+/**
+ * Array mapping OpClass enum values to strings.
+ */
+extern const char *opClassStrings[];
+
+#endif // __OP_CLASS_HH__
diff --git a/sim/param.cc b/sim/param.cc
new file mode 100644
index 000000000..432953670
--- /dev/null
+++ b/sim/param.cc
@@ -0,0 +1,760 @@
+/*
+ * 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.
+ */
+
+#include <algorithm>
+#include <list>
+#include <string>
+#include <vector>
+#include <stdio.h> // for sscanf()
+
+#include <assert.h>
+
+#include "param.hh"
+#include "sim_object.hh"
+#include "inifile.hh"
+#include "configfile.hh"
+#include "config_node.hh"
+#include "misc.hh"
+#include "str.hh"
+#include "trace.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.
+//
+////////////////////////////////////////////////////////////////////////
+
+//
+// Integer types all use to_number for parsing and '<<' for
+// displaying
+//
+#define INT_PARAM(type) \
+bool \
+parseParam(const string &s, type &value) \
+{ \
+ return to_number(s, value); \
+} \
+ \
+void \
+showParam(ostream &os, type value) \
+{ \
+ os << value; \
+}
+
+INT_PARAM(unsigned long long)
+INT_PARAM(signed long long)
+INT_PARAM(unsigned long)
+INT_PARAM(signed long)
+INT_PARAM(unsigned int)
+INT_PARAM(signed int)
+INT_PARAM(unsigned short)
+INT_PARAM(signed short)
+INT_PARAM(unsigned char)
+INT_PARAM(signed char)
+
+#undef INT_PARAM
+
+//
+// Floating-point types
+//
+bool
+parseParam(const string &s, float &value)
+{
+ return (sscanf(s.c_str(), "%f", &value) == 1);
+}
+
+bool
+parseParam(const string &s, double &value)
+{
+ return (sscanf(s.c_str(), "%lf", &value) == 1);
+}
+
+void showParam(ostream &os, float value) { os << value; }
+void showParam(ostream &os, double value) { os << value; }
+
+//
+// bool
+//
+bool
+parseParam(const string &s, bool &value)
+{
+ const string &lower = to_lower(s);
+
+ if (lower == "true" || lower == "t" || lower == "yes" || lower == "y") {
+ value = true;
+ return true;
+ }
+
+ if (lower == "false" || lower == "f" || lower == "no" || lower == "n") {
+ value = false;
+ return true;
+ }
+
+ return false;
+}
+
+
+void
+showParam(ostream &os, bool value)
+{
+ os << (value ? "true" : "false");
+}
+
+
+//
+// string
+//
+bool
+parseParam(const string &s, string &value)
+{
+ value = s;
+ return true;
+}
+
+
+void
+showParam(ostream &os, const string &value)
+{
+ os << value;
+}
+
+//
+// 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)
+{
+ 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 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; \
+void Param<type>::showType(ostream &os) const { os << typestr; } \
+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")
+
+#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;
+
+ 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 EnumParam<const char *>;
+template EnumVectorParam<const char *>;
+
+template EnumParam<EnumParamMap>;
+template 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, bool noAutoParse)
+ : iniFilePtr(NULL), // initialized on call to parseParams()
+ iniSection(_iniSection), paramList(NULL)
+{
+ if (!noAutoParse) {
+ if (ctxList == NULL)
+ ctxList = new list<ParamContext *>();
+
+ (*ctxList).push_back(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.findDefault(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)
+{
+ // look for a colon
+ string::size_type i = _name.find(':');
+ string name = _name;
+ if (i != string::npos) {
+ // colon found: local object
+ // add as child to current node and create it
+ name = _name.substr(0, i);
+ string objConfigClassName = _name.substr(i + 1);
+ getConfigNode()->addChild(name, objConfigClassName);
+ }
+ 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
new file mode 100644
index 000000000..983032854
--- /dev/null
+++ b/sim/param.hh
@@ -0,0 +1,757 @@
+/*
+ * 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.
+ */
+
+#ifndef __PARAM_HH__
+#define __PARAM_HH__
+
+#include <list>
+#include <string>
+#include <vector>
+
+#include "configfile.hh"
+
+// forward decls
+class BaseParam;
+class SimObject;
+struct stat_sdb_t;
+
+//
+// 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
+{
+ 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:
+
+ // Second arg, if set to true, says don't put on paramContextList
+ // (i.e. don't automatically parse params). Used by derived
+ // SimObjectBuilder class, where parsing is done in
+ // SimObject::create()
+ ParamContext(const std::string &_iniSection, bool noAutoParse = false);
+
+ 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[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) \
+void \
+SimObjectParam<OBJ_CLASS *>::showType(std::ostream &os) const \
+{ \
+ os << CLASS_NAME; \
+} \
+ \
+void \
+SimObjectVectorParam<OBJ_CLASS *>::showType(std::ostream &os) const \
+{ \
+ os << "vector of " << CLASS_NAME; \
+}
+
+#endif // _PARAM_HH
diff --git a/sim/pc_event.cc b/sim/pc_event.cc
new file mode 100644
index 000000000..4de425199
--- /dev/null
+++ b/sim/pc_event.cc
@@ -0,0 +1,231 @@
+/*
+ * 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.
+ */
+
+#include <algorithm>
+#include <map>
+#include <string>
+#include <utility>
+
+#include "debug.hh"
+#include "exec_context.hh"
+#include "pc_event.hh"
+#include "trace.hh"
+#include "universe.hh"
+
+#ifdef FULL_SYSTEM
+#include "arguments.hh"
+#include "pmap.h"
+#include "kernel.hh"
+#include "memory_control.hh"
+#include "cpu.hh"
+#include "system.hh"
+#include "bpred.hh"
+#endif
+
+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::service(ExecContext *xc)
+{
+ Addr pc = xc->regs.pc;
+ 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->regs.pc)
+ 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());
+}
+
+#ifdef FULL_SYSTEM
+void
+SkipFuncEvent::process(ExecContext *xc)
+{
+ Addr newpc = xc->regs.intRegFile[ReturnAddressReg];
+
+ DPRINTF(PCEvent, "skipping %s: pc=%x, newpc=%x\n", description,
+ xc->regs.pc, newpc);
+
+ xc->regs.pc = newpc;
+ xc->regs.npc = xc->regs.pc + sizeof(MachInst);
+
+ BranchPred *bp = xc->cpu->getBranchPred();
+ if (bp != NULL) {
+ bp->popRAS(xc->thread_num);
+ }
+}
+
+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->regs.intRegFile[ArgumentReg0];
+
+ if (a0 < ALPHA_K0SEG_BASE || a0 >= ALPHA_K1SEG_BASE ||
+ xc->memCtrl->badaddr(ALPHA_K0SEG_TO_PHYS(a0) & PA_IMPL_MASK)) {
+
+ DPRINTF(BADADDR, "badaddr arg=%#x bad\n", a0);
+ xc->regs.intRegFile[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->cpu->name() << ": ";
+
+ AlphaArguments args(xc);
+ Kernel::Printf(args);
+ }
+}
+
+void
+DebugPrintfEvent::process(ExecContext *xc)
+{
+ if (DTRACE(DebugPrintf)) {
+ if (!raw)
+ DebugOut() << curTick << ": " << xc->cpu->name() << ": ";
+
+ AlphaArguments args(xc);
+ Kernel::Printf(args);
+ }
+}
+
+void
+DumpMbufEvent::process(ExecContext *xc)
+{
+ if (DTRACE(DebugPrintf)) {
+ AlphaArguments args(xc);
+ Kernel::DumpMbuf(args);
+ }
+}
+#endif
+
+BreakPCEvent::BreakPCEvent(PCEventQueue *q, const std::string &desc, bool del)
+ : PCEvent(q, desc), remove(del)
+{
+}
+
+void
+BreakPCEvent::process(ExecContext *xc)
+{
+ debug_break();
+ if (remove)
+ delete this;
+}
+
+#ifdef FULL_SYSTEM
+extern "C"
+void
+sched_break_pc_sys(System *sys, Addr addr)
+{
+ PCEvent *event = new BreakPCEvent(&sys->pcEventQueue, "debug break", true);
+ event->schedule(addr);
+}
+
+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/sim/pc_event.hh b/sim/pc_event.hh
new file mode 100644
index 000000000..24442f5f4
--- /dev/null
+++ b/sim/pc_event.hh
@@ -0,0 +1,215 @@
+/*
+ * 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.
+ */
+
+#ifndef __PC_EVENT_HH__
+#define __PC_EVENT_HH__
+
+#include <vector>
+
+#include "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() : queue(0), evpc(badpc) { }
+
+ PCEvent(const std::string &desc)
+ : description(desc), queue(0), evpc(badpc) { }
+
+ PCEvent(PCEventQueue *q, Addr pc = badpc) : queue(q), evpc(pc) { }
+
+ PCEvent(PCEventQueue *q, const std::string &desc, Addr pc = badpc)
+ : description(desc), queue(q), evpc(pc) { }
+
+ virtual ~PCEvent() { if (queue) remove(); }
+
+ std::string descr() const { return description; }
+ Addr pc() const { return evpc; }
+
+ bool remove();
+ bool schedule();
+ bool schedule(Addr pc);
+ bool schedule(PCEventQueue *q, Addr pc);
+ 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;
+
+ public:
+ PCEventQueue();
+ ~PCEventQueue();
+
+ bool remove(PCEvent *event);
+ bool schedule(PCEvent *event);
+ bool service(ExecContext *xc);
+
+ range_t equal_range(Addr pc);
+ range_t equal_range(PCEvent *event) { return equal_range(event->pc()); }
+
+ void dump() const;
+};
+
+inline bool
+PCEvent::remove()
+{
+ if (!queue)
+ panic("cannot remove an uninitialized event;");
+
+ return queue->remove(this);
+}
+
+inline bool
+PCEvent::schedule()
+{
+ if (!queue || evpc == badpc)
+ panic("cannot schedule an uninitialized event;");
+
+ return queue->schedule(this);
+}
+
+inline bool
+PCEvent::schedule(Addr pc)
+{
+ if (evpc != badpc)
+ panic("cannot switch PC");
+ evpc = pc;
+
+ return schedule();
+}
+
+inline bool
+PCEvent::schedule(PCEventQueue *q, Addr pc)
+{
+ if (queue)
+ panic("cannot switch event queues");
+
+ if (evpc != badpc)
+ panic("cannot switch addresses");
+
+ queue = q;
+ evpc = pc;
+
+ return schedule();
+}
+
+
+#ifdef FULL_SYSTEM
+class SkipFuncEvent : public PCEvent
+{
+ public:
+ SkipFuncEvent(PCEventQueue *q, const std::string &desc)
+ : PCEvent(q, desc) {}
+ virtual void process(ExecContext *xc);
+};
+
+class BadAddrEvent : public SkipFuncEvent
+{
+ public:
+ BadAddrEvent(PCEventQueue *q, const std::string &desc)
+ : SkipFuncEvent(q, desc) {}
+ virtual void process(ExecContext *xc);
+};
+
+class PrintfEvent : public PCEvent
+{
+ public:
+ PrintfEvent(PCEventQueue *q, const std::string &desc)
+ : PCEvent(q, desc) {}
+ virtual void process(ExecContext *xc);
+};
+
+class DebugPrintfEvent : public PCEvent
+{
+ private:
+ bool raw;
+
+ public:
+ DebugPrintfEvent(PCEventQueue *q, const std::string &desc, bool r = false)
+ : PCEvent(q, desc), raw(r) {}
+ virtual void process(ExecContext *xc);
+};
+
+class DumpMbufEvent : public PCEvent
+{
+ public:
+ DumpMbufEvent(PCEventQueue *q, const std::string &desc)
+ : PCEvent(q, desc) {}
+ virtual void process(ExecContext *xc);
+};
+#endif
+
+class BreakPCEvent : public PCEvent
+{
+ protected:
+ bool remove;
+
+ public:
+ BreakPCEvent(PCEventQueue *q, const std::string &desc, bool del = false);
+ virtual void process(ExecContext *xc);
+};
+
+
+#endif // __PC_EVENT_HH__
diff --git a/sim/predictor.hh b/sim/predictor.hh
new file mode 100644
index 000000000..7c446f26c
--- /dev/null
+++ b/sim/predictor.hh
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+//
+// Abstract base class for a generic predictor
+//
+//
+
+#ifndef __PREDICTOR_HH__
+#define __PREDICTOR_HH__
+
+struct stat_sdb_t;
+
+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/sim/prog.cc b/sim/prog.cc
new file mode 100644
index 000000000..8615cab68
--- /dev/null
+++ b/sim/prog.cc
@@ -0,0 +1,281 @@
+/*
+ * 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.
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include <string>
+
+#include "main_memory.hh"
+#include "prog.hh"
+
+#include "eio.hh"
+#include "thread.hh"
+#include "fake_syscall.hh"
+#include "loader.hh"
+#include "exec_context.hh"
+#include "smt.hh"
+
+#include "statistics.hh"
+#include "sim_stats.hh"
+
+using namespace std;
+
+//
+// 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
+//
+#ifdef FULL_SYSTEM
+#error "prog.cc not compatible with FULL_SYSTEM"
+#endif
+
+// max allowable number of processes: should be no real cost to
+// cranking this up if necessary
+const int MAX_PROCESSES = 8;
+
+// current number of allocated processes
+int num_processes = 0;
+
+Process::Process(const string &name,
+ int stdin_fd, // initial I/O descriptors
+ int stdout_fd,
+ int stderr_fd)
+ : SimObject(name)
+{
+ // allocate memory space
+ memory = new MainMemory(name + ".MainMem");
+
+ // allocate initial register file
+ init_regs = new RegFile;
+
+ // 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;
+ }
+
+ numCpus = 0;
+
+ num_syscalls = 0;
+
+ // other parameters will be initialized when the program is loaded
+}
+
+void
+Process::regStats()
+{
+ using namespace Statistics;
+
+ 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;
+}
+
+
+void
+Process::registerExecContext(ExecContext *ec)
+{
+ if (execContexts.empty()) {
+ // first exec context for this process... initialize & enable
+
+ // copy process's initial regs struct
+ ec->regs = *init_regs;
+
+ // mark this context as active
+ ec->setStatus(ExecContext::Active);
+ }
+ else {
+ ec->setStatus(ExecContext::Unallocated);
+ }
+
+ // add to list
+ execContexts.push_back(ec);
+
+ // increment available CPU count
+ ++numCpus;
+}
+
+
+// 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::open_fd(int sim_fd)
+{
+ int free_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 (free_fd = 0; fd_map[free_fd] >= 0; ++free_fd) {
+ if (free_fd == MAX_FD)
+ panic("Process::open_fd: out of file descriptors!");
+ }
+
+ fd_map[free_fd] = sim_fd;
+
+ return free_fd;
+}
+
+
+// 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 object", Process)
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// LiveProcess member definitions
+//
+////////////////////////////////////////////////////////////////////////
+
+LiveProcess::LiveProcess(const string &name,
+ int stdin_fd, int stdout_fd, int stderr_fd,
+ vector<string> &argv, vector<string> &envp)
+ : Process(name, stdin_fd, stdout_fd, stderr_fd)
+{
+ smt_load_prog(argv, envp, init_regs, this);
+}
+
+
+void
+LiveProcess::syscall(ExecContext *xc)
+{
+ num_syscalls++;
+
+ fake_syscall(this, xc);
+}
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(LiveProcess)
+
+ VectorParam<string> cmd;
+ 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(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)
+{
+ // initialize file descriptors to default: same as simulator
+ int stdin_fd = input.isValid() ? Process::openInputFile(input) : 0;
+ int stdout_fd = output.isValid() ? Process::openOutputFile(output) : 1;
+ int stderr_fd = output.isValid() ? stdout_fd : 2;
+
+ // dummy for default env
+ vector<string> null_vec;
+
+ // We do this with "temp" because of the bogus compiler warning
+ // you get with g++ 2.95 -O if you just "return new LiveProcess(..."
+ LiveProcess *temp = new LiveProcess(getInstanceName(),
+ stdin_fd, stdout_fd, stderr_fd,
+ cmd,
+ env.isValid() ? env : null_vec);
+
+ return temp;
+}
+
+
+REGISTER_SIM_OBJECT("LiveProcess", LiveProcess)
diff --git a/sim/prog.hh b/sim/prog.hh
new file mode 100644
index 000000000..a38afee14
--- /dev/null
+++ b/sim/prog.hh
@@ -0,0 +1,180 @@
+/*
+ * 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.
+ */
+
+#ifndef __PROG_HH__
+#define __PROG_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.
+//
+#ifndef FULL_SYSTEM
+
+#include <list>
+
+#include "stats.hh"
+#include "sim_object.hh"
+
+#include "statistics.hh"
+#include "sim_stats.hh"
+
+class ExecContext;
+class FunctionalMemory;
+class Process : public SimObject
+{
+ 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::list<ExecContext *> execContexts;
+ // number of CPUs assigned to this process: should match number of
+ // contexts in execContexts list
+ unsigned numCpus;
+
+ // 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
+
+ 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 environ_base; // environment base address
+ 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;
+
+ std::string prog_fname; // file name
+ Addr prog_entry; // entry point (initial PC)
+
+ Statistics::Scalar<> num_syscalls; // number of syscalls executed
+
+
+ protected:
+ // constructor
+ Process(const std::string &name,
+ int stdin_fd, // initial I/O descriptors
+ int stdout_fd,
+ int stderr_fd);
+
+
+ protected:
+ FunctionalMemory *memory;
+
+ private:
+ // file descriptor remapping support
+ static const int MAX_FD = 100; // 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
+ void registerExecContext(ExecContext *);
+
+ // 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 open_fd(int sim_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) ||
+ ((stack_base - 16*1024*1024) <= addr && addr < stack_base) ||
+ (text_base <= addr && addr < (text_base + text_size)));
+ }
+
+ virtual void syscall(ExecContext *xc) = 0;
+
+ virtual FunctionalMemory *getMemory() { return memory; }
+};
+
+//
+// "Live" process with system calls redirected to host system
+//
+class MainMemory;
+class LiveProcess : public Process
+{
+ public:
+ LiveProcess(const std::string &name,
+ int stdin_fd, int stdout_fd, int stderr_fd,
+ std::vector<std::string> &argv,
+ std::vector<std::string> &envp);
+
+ virtual void syscall(ExecContext *xc);
+};
+
+#endif // !FULL_SYSTEM
+
+#endif // __PROG_HH__
diff --git a/sim/sat_counter.cc b/sim/sat_counter.cc
new file mode 100644
index 000000000..bd1b6de0b
--- /dev/null
+++ b/sim/sat_counter.cc
@@ -0,0 +1,270 @@
+/*
+ * 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.
+ */
+
+#include <sstream>
+
+#include "stats.hh"
+#include "sat_counter.hh"
+
+#include "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 Statistics;
+ 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 Statistics;
+ 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/sim/sat_counter.hh b/sim/sat_counter.hh
new file mode 100644
index 000000000..18eab3574
--- /dev/null
+++ b/sim/sat_counter.hh
@@ -0,0 +1,192 @@
+/*
+ * 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.
+ */
+
+#ifndef __SAT_COUNTER_HH__
+#define __SAT_COUNTER_HH__
+
+#include <string>
+
+#include "predictor.hh"
+
+#include "statistics.hh"
+#include "sim_stats.hh"
+
+struct stat_sdb_t;
+
+//
+//
+// 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
+ Statistics::Scalar<> predicted_one; // Total predictions of one, preds_one
+ Statistics::Scalar<> predicted_zero; // Total predictions of zero, preds_zero
+ Statistics::Scalar<> correct_pred_one; // Total correct predictions of one, correct_one
+ Statistics::Scalar<> correct_pred_zero; // Total correct predictions of zero, correct_zero
+
+ Statistics::Scalar<> record_zero; //updates_zero
+ Statistics::Scalar<> record_one; //updates_one
+
+ Statistics::Formula preds_total;
+ Statistics::Formula pred_frac_zero;
+ Statistics::Formula pred_frac_one;
+ Statistics::Formula correct_total;
+ Statistics::Formula updates_total;
+ Statistics::Formula pred_rate;
+ Statistics::Formula frac_correct_zero;
+ Statistics::Formula frac_correct_one;
+ Statistics::Formula coverage_zero;
+ Statistics::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/sim/serialize.cc b/sim/serialize.cc
new file mode 100644
index 000000000..a2e3d7250
--- /dev/null
+++ b/sim/serialize.cc
@@ -0,0 +1,353 @@
+/*
+ * 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.
+ */
+
+#include <sys/time.h>
+
+#include <fstream>
+#include <list>
+#include <string>
+#include <vector>
+
+#include "misc.hh"
+
+#include "eventq.hh"
+#include "param.hh"
+#include "serialize.hh"
+#include "inifile.hh"
+#include "sim_events.hh"
+#include "sim_object.hh"
+#include "trace.hh"
+
+using namespace std;
+
+Serializer *Serializeable::serializer = NULL;
+
+Serializeable::Serializeable(const string &n)
+ : proxy(this), objName(n), serialized(false)
+{ }
+
+Serializeable::~Serializeable()
+{ }
+
+void
+Serializeable::mark()
+{
+ if (!serialized)
+ serializer->add_object(this);
+
+ serialized = true;
+}
+
+ostream &
+Serializeable::out() const
+{
+ return serializer->out();
+}
+
+void
+Serializeable::nameOut()
+{
+ out() << "\n[" << name() << "]\n";
+}
+
+void
+Serializeable::nameOut(const string &_name)
+{
+ out() << "\n[" << _name << "]\n";
+}
+
+template<> void
+Serializeable::paramOut(const string &name, const uint64_t& param)
+{
+ out() << name << "=0x" << hex << param << dec << "\n";
+}
+
+void
+Serializeable::childOut(const string &name, Serializeable *child)
+{
+ child->mark();
+ if (child->name() == "")
+ panic("child is unnamed");
+
+ out() << name << "=" << child->name() << "\n";
+}
+
+void
+Serializeable::setName(const string &name)
+{
+ if (objName != "")
+ panic("Cannot change object name");
+
+ objName = name;
+}
+
+Serializer::Serializer()
+{ }
+
+Serializer::~Serializer()
+{ }
+
+ostream &
+Serializer::out() const
+{
+ if (!output)
+ panic("must set output before serializing");
+
+ return *output;
+}
+
+void
+Serializer::add_object(Serializeable *obj)
+{
+ objects.push_back(obj);
+}
+
+void
+Serializer::add_objects()
+{
+ mainEventQueue.mark();
+
+ SimObject::SimObjectList::iterator i = SimObject::simObjectList.begin();
+ SimObject::SimObjectList::iterator end = SimObject::simObjectList.end();
+
+ while (i != end) {
+ (*i)->mark();
+ ++i;
+ }
+}
+
+void
+Serializer::serialize(const string &f)
+{
+ if (Serializeable::serializer != NULL)
+ panic("in process of serializing!");
+
+ Serializeable::serializer = this;
+
+ file = f;
+ string cpt_file = file + ".cpt";
+ output = new ofstream(cpt_file.c_str());
+ time_t t = time(NULL);
+ *output << "// checkpoint generated: " << ctime(&t);
+
+ serlist_t list;
+
+ add_objects();
+ while (!objects.empty()) {
+ Serializeable *serial = objects.front();
+ DPRINTF(Serialize, "Name Children of %s\n", serial->name());
+ serial->nameChildren();
+ objects.pop_front();
+ list.push_back(serial);
+ }
+
+ while (!list.empty()) {
+ list.front()->serialized = false;
+ list.pop_front();
+ }
+
+ add_objects();
+ while (!objects.empty()) {
+ Serializeable *serial = objects.front();
+ DPRINTF(Serialize, "Name Children of %s\n", serial->name());
+ serial->serialize();
+ objects.pop_front();
+ list.push_back(serial);
+ }
+
+ while (!list.empty()) {
+ list.front()->serialized = false;
+ list.pop_front();
+ }
+
+ Serializeable::serializer = NULL;
+
+ delete output;
+ output = NULL;
+ file = "";
+}
+
+class SerializeEvent : public Event
+{
+ protected:
+ string file;
+
+ public:
+ SerializeEvent(EventQueue *q, Tick when, const string &file);
+ ~SerializeEvent();
+
+ virtual void process();
+ virtual void serialize();
+};
+
+SerializeEvent::SerializeEvent(EventQueue *q, Tick when, const string &f)
+ : Event(q), file(f)
+{
+ setFlags(AutoDelete);
+ schedule(when);
+}
+
+SerializeEvent::~SerializeEvent()
+{
+}
+
+void
+SerializeEvent::process()
+{
+ Serializer serial;
+ serial.serialize(file);
+ new SimExitEvent("Serialization caused exit");
+}
+
+void
+SerializeEvent::serialize()
+{
+ panic("Cannot serialize the SerializeEvent");
+}
+
+class SerializeParamContext : public ParamContext
+{
+ private:
+ SerializeEvent *event;
+
+ public:
+ SerializeParamContext(const string &section);
+ ~SerializeParamContext();
+ void checkParams();
+};
+
+SerializeParamContext serialParams("serialize");
+
+Param<Counter> serialize_cycle(&serialParams,
+ "cycle",
+ "cycle to serialize",
+ 0);
+
+Param<string> serialize_file(&serialParams,
+ "file",
+ "file to write to", "");
+
+SerializeParamContext::SerializeParamContext(const string &section)
+ : ParamContext(section), event(NULL)
+{ }
+
+SerializeParamContext::~SerializeParamContext()
+{
+}
+
+void
+SerializeParamContext::checkParams()
+{
+ if (!((string)serialize_file).empty() && serialize_cycle > 0)
+ event = new SerializeEvent(&mainEventQueue, serialize_cycle,
+ serialize_file);
+}
+
+void
+debug_serialize(const char *file)
+{
+ Serializer serial;
+ serial.serialize(file);
+ new SimExitEvent("Serialization caused exit");
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// SerializeableClass member definitions
+//
+////////////////////////////////////////////////////////////////////////
+
+// Map of class names to SerializeableBuilder creation functions.
+// Need to make this a pointer so we can force initialization on the
+// first reference; otherwise, some SerializeableClass constructors
+// may be invoked before the classMap constructor.
+map<string,SerializeableClass::CreateFunc> *SerializeableClass::classMap = 0;
+
+// SerializeableClass constructor: add mapping to classMap
+SerializeableClass::SerializeableClass(const string &className,
+ CreateFunc createFunc)
+{
+ if (classMap == NULL)
+ classMap = new map<string,SerializeableClass::CreateFunc>();
+
+ if ((*classMap)[className])
+ {
+ cerr << "Error: simulation object class " << className << " redefined"
+ << endl;
+ fatal("");
+ }
+
+ // add className --> createFunc to class map
+ (*classMap)[className] = createFunc;
+}
+
+
+//
+//
+Serializeable *
+SerializeableClass::createObject(IniFile &configDB,
+ const string &configClassName)
+{
+ // find simulation object class name from configuration class
+ // (specified by 'type=' parameter)
+ string simObjClassName;
+
+ if (!configDB.findDefault(configClassName, "type", simObjClassName)) {
+ cerr << "Configuration class '" << configClassName << "' not found."
+ << endl;
+ abort();
+ }
+
+ // look up className to get appropriate createFunc
+ if (classMap->find(simObjClassName) == classMap->end()) {
+ cerr << "Simulator object class '" << simObjClassName << "' not found."
+ << endl;
+ abort();
+ }
+
+ CreateFunc createFunc = (*classMap)[simObjClassName];
+
+ // builder instance
+ SerializeableBuilder *objectBuilder = (*createFunc)();
+
+ assert(objectBuilder != NULL);
+
+ // now create the actual simulation object
+ Serializeable *object = objectBuilder->create();
+
+ assert(object != NULL);
+
+ // done with the SerializeableBuilder now
+ delete objectBuilder;
+
+ return object;
+}
+
diff --git a/sim/serialize.hh b/sim/serialize.hh
new file mode 100644
index 000000000..c5fb86140
--- /dev/null
+++ b/sim/serialize.hh
@@ -0,0 +1,241 @@
+/*
+ * 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.
+ */
+
+/* @file
+ * Serialization Interface Declarations
+ */
+
+#ifndef __SERIALIZE_HH__
+#define __SERIALIZE_HH__
+
+
+#include <list>
+#include <iostream>
+
+#include "host.hh"
+#include "configfile.hh"
+
+class IniFile;
+
+/*
+ * Basic support for object serialization.
+ */
+class Serializeable
+{
+ public:
+ // To allow other classes to do some of the serialization work.
+ class Proxy {
+ private:
+ Serializeable *obj;
+
+ // Make it so only Serializables can construct one of these.
+ Proxy(Serializeable *o) : obj(o) {};
+
+ friend class Serializeable;
+
+ public:
+ template <class T>
+ void paramOut(const std::string &name, const T& param) const {
+ obj->paramOut(name, param);
+ };
+ };
+
+ friend class Serializer;
+ friend class Proxy;
+
+ private:
+ Proxy proxy;
+
+ protected:
+ const Proxy &getProxy() { return(proxy); };
+
+ // object name: should be unique
+ std::string objName;
+
+ bool serialized;
+ static Serializer *serializer;
+
+ void mark();
+ void nameOut();
+ void nameOut(const std::string &_name);
+ void childOut(const std::string &name, Serializeable *child);
+ template <class T>
+ void paramOut(const std::string &name, const T& param);
+
+ std::ostream &out() const;
+
+ public:
+ Serializeable(const std::string &n);
+ virtual ~Serializeable();
+
+ void setName(const std::string &name);
+
+ // return name
+ const std::string &name() const { return objName; }
+
+ virtual void nameChildren() {}
+ virtual void serialize() {}
+ virtual void unserialize(IniFile &db, const std::string &category,
+ ConfigNode *node = NULL)
+ {
+ std::cout << name() << " is being unserialized" << std::endl;
+ }
+};
+
+class Serializer
+{
+ friend class Serializeable;
+
+ protected:
+ typedef std::list<Serializeable *> serlist_t;
+ serlist_t objects;
+ std::string file;
+ std::ostream *output;
+ std::ostream &out() const;
+
+ public:
+ Serializer();
+ virtual ~Serializer();
+
+ private:
+ void add_object(Serializeable *obj);
+ void add_objects();
+
+ public:
+ void serialize(const std::string &file);
+ const std::string &filename() const { return file; }
+};
+
+template <class T>
+inline void
+Serializeable::paramOut(const std::string &name, const T& param)
+{
+ out() << name << "=" << param << "\n";
+}
+
+template <> void
+Serializeable::paramOut(const std::string &name, const uint64_t& param);
+
+
+//
+// A SerializeableBuilder serves as an evaluation context for a set of
+// parameters that describe a specific instance of a Serializeable. 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
+// Serializeable references. SerializeableBuilder is an abstract superclass;
+// derived classes specialize the class for particular subclasses of
+// Serializeable (e.g., BaseCache).
+//
+// For typical usage, see the definition of
+// SerializeableClass::createObject().
+//
+class SerializeableBuilder
+{
+ public:
+
+ SerializeableBuilder() {}
+
+ virtual ~SerializeableBuilder() {}
+
+ // Create the actual Serializeable 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 Serializeable.
+ virtual Serializeable *create() = 0;
+};
+
+//
+// An instance of SerializeableClass corresponds to a class derived from
+// Serializeable. The SerializeableClass 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 SerializeableClass
+{
+ 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 SerializeableBuilder is returned.
+ typedef SerializeableBuilder *(*CreateFunc)();
+
+ static std::map<std::string,CreateFunc> *classMap;
+
+ // Constructor. For example:
+ //
+ // SerializeableClass baseCacheSerializeableClass("BaseCacheSerializeable",
+ // newBaseCacheSerializeableBuilder);
+ //
+ SerializeableClass(const std::string &className, CreateFunc createFunc);
+
+ // create Serializeable given name of class and pointer to
+ // configuration hierarchy node
+ static Serializeable *createObject(IniFile &configDB,
+ const std::string &configClassName);
+
+};
+
+//
+// Macros to encapsulate the magic of declaring & defining
+// SerializeableBuilder and SerializeableClass objects
+//
+
+#define CREATE_SERIALIZEABLE(OBJ_CLASS) \
+OBJ_CLASS *OBJ_CLASS##Builder::create()
+
+#define REGISTER_SERIALIZEABLE(CLASS_NAME, OBJ_CLASS) \
+class OBJ_CLASS##Builder : public SerializeableBuilder \
+{ \
+ public: \
+ \
+ OBJ_CLASS##Builder() {} \
+ virtual ~OBJ_CLASS##Builder() {} \
+ \
+ OBJ_CLASS *create(); \
+}; \
+ \
+ \
+SerializeableBuilder * \
+new##OBJ_CLASS##Builder() \
+{ \
+ return new OBJ_CLASS##Builder(); \
+} \
+ \
+SerializeableClass the##OBJ_CLASS##Class(CLASS_NAME, \
+ new##OBJ_CLASS##Builder);
+
+
+
+#endif // __SERIALIZE_HH__
diff --git a/sim/sim_events.cc b/sim/sim_events.cc
new file mode 100644
index 000000000..ffabc3006
--- /dev/null
+++ b/sim/sim_events.cc
@@ -0,0 +1,271 @@
+/*
+ * 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.
+ */
+
+#include <string>
+
+#include "cpu.hh"
+#include "eventq.hh"
+#include "sim_events.hh"
+#include "sim_exit.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),
+ cause(_cause),
+ downCounter(_downCounter)
+{
+ // catch stupid mistakes
+ assert(downCounter > 0);
+
+ schedule(_when, 1000);
+}
+
+
+//
+// handle termination event
+//
+void
+CountedExitEvent::process()
+{
+ if (--downCounter == 0) {
+ new SimExitEvent(cause, 1);
+ }
+}
+
+
+const char *
+CountedExitEvent::description()
+{
+ return "counted exit";
+}
+
+
+void
+DumpStatsEvent::process()
+{
+ dumpStats();
+}
+
+const char *
+DumpStatsEvent::description()
+{
+ return "stats dump";
+}
+
+
+#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 = proc_info("/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";
+}
+
+
+class DumpStatsContext : public ParamContext
+{
+ public:
+ DumpStatsContext(const string &_iniSection)
+ : ParamContext(_iniSection) {}
+ void checkParams();
+};
+
+DumpStatsContext dumpStatsParams("stats");
+
+VectorParam<Tick> dump_cycle(&dumpStatsParams, "dump_cycles",
+ "cycles on which to dump stats");
+
+void
+DumpStatsContext::checkParams()
+{
+ if (dump_cycle.isValid()) {
+ vector<Tick> &cycles = dump_cycle;
+
+ vector<Tick>::iterator i = cycles.begin();
+ vector<Tick>::iterator end = cycles.end();
+
+ for (; i < end; ++i)
+ new DumpStatsEvent(*i);
+ }
+}
+
+///////////////////////////////////////////////////
+//
+// Simulation termination parameters
+//
+///////////////////////////////////////////////////
+
+class TermParamContext : public ParamContext
+{
+ public:
+ TermParamContext(const string &_iniSection)
+ : ParamContext(_iniSection) {}
+ void checkParams();
+};
+
+TermParamContext simTerminationParams("max");
+
+Param<Tick> max_cycle(&simTerminationParams, "cycle",
+ "maximum number of cycles to execute");
+
+void
+TermParamContext::checkParams()
+{
+ // if a max cycle count was specified, put a termination event on
+ // the event queue at that point
+ if (max_cycle.isValid())
+ new SimExitEvent(max_cycle, "reached maximum cycle count");
+}
+
+//
+// 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 interval);
+
+ void process(); // process event
+ virtual const char *description();
+};
+
+//
+// constructor: schedule at specified time
+//
+ProgressEvent::ProgressEvent(EventQueue *q, Tick _interval)
+ : Event(q), interval(_interval)
+{
+ schedule(interval);
+}
+
+//
+// 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";
+}
+
+/////////
+//
+// Periodic progress message support: print out a message every n
+// cycles so we know we're making forward progress.
+//
+/////////
+
+// Parameter space for execution address tracing options. Derive
+// from ParamContext so we can override checkParams() function.
+class ProgressParamContext : public ParamContext
+{
+ public:
+ ProgressParamContext(const string &_iniSection)
+ : ParamContext(_iniSection) {}
+ void checkParams();
+};
+
+ProgressParamContext progessMessageParams("progress");
+
+Param<Tick> progress_interval(&progessMessageParams, "cycle",
+ "cycle interval for progress messages");
+
+/* check execute options */
+void
+ProgressParamContext::checkParams()
+{
+ if (progress_interval.isValid())
+ new ProgressEvent(&mainEventQueue, progress_interval);
+}
diff --git a/sim/sim_events.hh b/sim/sim_events.hh
new file mode 100644
index 000000000..e9a5f3251
--- /dev/null
+++ b/sim/sim_events.hh
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ */
+
+#ifndef __SIM_EVENTS_HH__
+#define __SIM_EVENTS_HH__
+
+#include "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), cause(_cause),
+ code(c)
+ { schedule(curTick, 1000); }
+
+ SimExitEvent(Tick _when, const std::string &_cause, int c = 0)
+ : Event(&mainEventQueue), cause(_cause),
+ code(c)
+ { schedule(_when, 1000); }
+
+ SimExitEvent(EventQueue *q, const std::string &_cause, int c = 0)
+ : Event(q), cause(_cause), code(c)
+ { schedule(curTick, 1000); }
+
+ SimExitEvent(EventQueue *q, Tick _when, const std::string &_cause,
+ int c = 0)
+ : Event(q), cause(_cause), code(c)
+ { schedule(_when, 1000); }
+
+ 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 cause a statistics dump
+//
+class DumpStatsEvent : public Event
+{
+ public:
+ DumpStatsEvent()
+ : Event(&mainEventQueue)
+ { setFlags(AutoDelete); schedule(curTick, 999); }
+
+ DumpStatsEvent(EventQueue *q)
+ : Event(q)
+ { setFlags(AutoDelete); schedule(curTick, 999); }
+
+ DumpStatsEvent(Tick when)
+ : Event(&mainEventQueue)
+ { setFlags(AutoDelete); schedule(when, 999); }
+
+ DumpStatsEvent(EventQueue *q, Tick when)
+ : Event(q)
+ { setFlags(AutoDelete); schedule(when, 999); }
+
+ void process();
+
+ virtual const char *description();
+};
+
+class CheckSwapEvent : public Event
+{
+ private:
+ int interval;
+
+ public:
+ CheckSwapEvent(EventQueue *q, int ival)
+ : Event(q), interval(ival)
+ { schedule(interval); }
+
+ void process(); // process event
+
+ virtual const char *description();
+};
+
+#endif // __SIM_EVENTS_HH__
diff --git a/sim/sim_exit.hh b/sim/sim_exit.hh
new file mode 100644
index 000000000..847d9eb10
--- /dev/null
+++ b/sim/sim_exit.hh
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#ifndef __SIM_EXIT_HH__
+#define __SIM_EXIT_HH__
+
+#include <string>
+
+class Callback;
+
+void registerExitCallback(Callback *);
+
+void exitNow(const std::string &cause, int exit_code);
+void exitNow(const char *cause, int exit_code);
+
+#endif // __SIM_EXIT_HH__
diff --git a/sim/sim_object.cc b/sim/sim_object.cc
new file mode 100644
index 000000000..e5506ee8f
--- /dev/null
+++ b/sim/sim_object.cc
@@ -0,0 +1,280 @@
+/*
+ * 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.
+ */
+
+#include <assert.h>
+
+#include "sim_object.hh"
+#include "inifile.hh"
+#include "configfile.hh"
+#include "host.hh"
+#include "misc.hh"
+#include "trace.hh"
+#include "sim_stats.hh"
+#include "stats.hh"
+
+using namespace std;
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// SimObject member definitions
+//
+////////////////////////////////////////////////////////////////////////
+
+//
+// static list of all SimObjects, used for initialization etc.
+//
+SimObject::SimObjectList SimObject::simObjectList;
+
+//
+// SimObject constructor: used to maintain static simObjectList
+//
+SimObject::SimObject(const string &_name)
+ : Serializeable(_name)
+{
+ simObjectList.push_back(this);
+}
+
+//
+// no default statistics, so nothing to do in base implementation
+//
+void
+SimObject::reg_stats(struct stat_sdb_t *sdb)
+{
+}
+
+void
+SimObject::regStats()
+{
+}
+
+void
+SimObject::regFormulas()
+{
+}
+
+//
+// no default extra output
+//
+void
+SimObject::printExtraOutput(ostream &os)
+{
+}
+
+//
+// static function: call reg_stats() on all SimObjects.
+//
+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)->reg_stats(sim_sdb);
+ (*i)->regStats();
+ }
+
+ for (i = simObjectList.begin(); i != end; ++i) {
+#ifdef STAT_DEBUG
+ cprintf("registering formulas for %s\n", (*i)->name());
+#endif
+ (*i)->regFormulas();
+ }
+}
+
+//
+// static function: call printExtraOutput() on all SimObjects.
+//
+void
+SimObject::printAllExtraOutput(ostream &os)
+{
+ SimObjectList::iterator i;
+
+ for (i = simObjectList.begin(); i != simObjectList.end(); ++i) {
+ (*i)->printExtraOutput(os);
+ }
+}
+
+///////////////////////////////////////////
+//
+// 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.findDefault(instanceName, (*i)->name, string_value)) {
+ (*i)->parse(string_value);
+ }
+ else if (iniFile.findDefault(iniSection, (*i)->name, string_value)) {
+ (*i)->parse(string_value);
+ }
+ }
+}
+
+
+void
+SimObjectBuilder::printErrorProlog(ostream &os)
+{
+ os << "Error creating object '" << getInstanceName()
+ << "' of type '" << simObjClassName
+ << "', section '" << iniSection << "':" << endl;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// 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])
+ {
+ cerr << "Error: simulation object class " << className << " redefined"
+ << endl;
+ fatal("");
+ }
+
+ // add className --> createFunc to class map
+ (*classMap)[className] = createFunc;
+}
+
+
+//
+//
+SimObject *
+SimObjectClass::createObject(IniFile &configDB,
+ const string &configClassName,
+ const string &objName,
+ ConfigNode *configNode)
+{
+ // find simulation object class name from configuration class
+ // (specified by 'type=' parameter)
+ string simObjClassName;
+
+ if (!configDB.findDefault(configClassName, "type", simObjClassName)) {
+ cerr << "Configuration class '" << configClassName << "' not found."
+ << endl;
+ abort();
+ }
+
+ // look up className to get appropriate createFunc
+ if (classMap->find(simObjClassName) == classMap->end()) {
+ cerr << "Simulator object class '" << simObjClassName << "' not found."
+ << endl;
+ abort();
+ }
+
+ CreateFunc createFunc = (*classMap)[simObjClassName];
+
+ // call createFunc with config hierarchy node to get object
+ // builder instance (context with parameters for object creation)
+ SimObjectBuilder *objectBuilder = (*createFunc)(configClassName,
+ objName, configNode,
+ simObjClassName);
+
+ 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)
+ *statStream << "[" << object->name() << "]" << endl;
+ *statStream << "type=" << simObjClassName << endl;
+ objectBuilder->showParams(*statStream);
+ *statStream << endl;
+
+ // 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/sim_object.hh b/sim/sim_object.hh
new file mode 100644
index 000000000..051c7b304
--- /dev/null
+++ b/sim/sim_object.hh
@@ -0,0 +1,261 @@
+/*
+ * 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.
+ */
+
+/* @file
+ * User Console Definitions
+ */
+
+#ifndef __SIM_OBJECT_HH__
+#define __SIM_OBJECT_HH__
+
+#include <map>
+#include <list>
+#include <vector>
+#include <iostream>
+
+#include "param.hh"
+#include "serialize.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 Serializeable
+{
+ private:
+ friend class Serializer;
+
+ typedef std::vector<SimObject *> SimObjectList;
+
+ // list of all instantiated simulation objects
+ static SimObjectList simObjectList;
+
+ public:
+ SimObject(const std::string &_name);
+
+ virtual ~SimObject() {}
+
+ // register statistics for this object
+ virtual void reg_stats(struct stat_sdb_t *sdb);
+ virtual void regStats();
+ virtual void regFormulas();
+
+ // print extra results for this object not covered by registered
+ // statistics (called at end of simulation)
+ virtual void printExtraOutput(std::ostream&);
+
+ // static: call reg_stats on all SimObjects
+ static void regAllStats();
+
+ // static: call printExtraOutput on all SimObjects
+ static void printAllExtraOutput(std::ostream&);
+};
+
+
+//
+// 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:
+ // name of the instance we are creating
+ std::string instanceName;
+
+ // The corresponding node in the configuration hierarchy.
+ // (optional: may be null if the created object is not in the
+ // hierarchy)
+ ConfigNode *configNode;
+
+ // The external SimObject class name (for error messages)
+ std::string simObjClassName;
+
+ public:
+ SimObjectBuilder(const std::string &_configClass,
+ const std::string &_instanceName,
+ ConfigNode *_configNode,
+ const std::string &_simObjClassName)
+ : ParamContext(_configClass, true),
+ instanceName(_instanceName),
+ configNode(_configNode),
+ simObjClassName(_simObjClassName)
+ {
+ }
+
+ 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 instanceName; }
+
+ // 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)(const std::string &configClassName,
+ const std::string &objName,
+ ConfigNode *configNode,
+ const std::string &simObjClassName);
+
+ 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,
+ const std::string &configClassName,
+ const std::string &objName,
+ 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(const std::string &configClass, \
+ const std::string &instanceName, \
+ ConfigNode *configNode, \
+ const std::string &simObjClassName); \
+ virtual ~OBJ_CLASS##Builder() {} \
+ \
+ OBJ_CLASS *create(); \
+};
+
+#define BEGIN_INIT_SIM_OBJECT_PARAMS(OBJ_CLASS) \
+OBJ_CLASS##Builder::OBJ_CLASS##Builder(const std::string &configClass, \
+ const std::string &instanceName, \
+ ConfigNode *configNode, \
+ const std::string &simObjClassName) \
+ : SimObjectBuilder(configClass, instanceName, \
+ configNode, simObjClassName),
+
+
+#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(const std::string &configClass, \
+ const std::string &instanceName, \
+ ConfigNode *configNode, \
+ const std::string &simObjClassName) \
+{ \
+ return new OBJ_CLASS##Builder(configClass, instanceName, \
+ configNode, simObjClassName); \
+} \
+ \
+SimObjectClass the##OBJ_CLASS##Class(CLASS_NAME, \
+ new##OBJ_CLASS##Builder); \
+ \
+/* see param.hh */ \
+DEFINE_SIM_OBJECT_CLASS_NAME(CLASS_NAME, OBJ_CLASS)
+
+
+#endif // __SIM_OBJECT_HH__
diff --git a/sim/sim_time.cc b/sim/sim_time.cc
new file mode 100644
index 000000000..c235be5db
--- /dev/null
+++ b/sim/sim_time.cc
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+#include <iostream>
+
+#include "sim_time.hh"
+
+using namespace std;
+
+namespace Time
+{
+ struct _timeval
+ {
+ timeval tv;
+ };
+
+ double
+ convert(const timeval &tv)
+ {
+ return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
+ }
+
+ Start::Start()
+ {
+ start = new _timeval;
+ ::gettimeofday(&start->tv, NULL);
+ }
+
+ Start::~Start()
+ {
+ delete start;
+ }
+
+ const timeval &
+ Start::get() const
+ {
+ return start->tv;
+ }
+
+ double
+ Start::operator()() const
+ {
+ return convert(get());
+ }
+
+ Now::Now()
+ : now(0)
+ {
+ }
+
+ Now::~Now()
+ {
+ if (now)
+ delete now;
+ }
+
+ const timeval &
+ Now::get() const
+ {
+ if (!now)
+ now = new _timeval;
+
+ ::gettimeofday(&now->tv, NULL);
+ return now->tv;
+ }
+
+ double
+ Now::operator()() const
+ {
+ return convert(get());
+ }
+
+
+ Elapsed::Elapsed()
+ : elapsed(0)
+ {}
+
+ Elapsed::~Elapsed()
+ {
+ if (elapsed)
+ delete elapsed;
+ }
+
+ const timeval &
+ Elapsed::get() const
+ {
+ if (!elapsed)
+ elapsed = new _timeval;
+
+ timersub(&now.get(), &start.get(), &elapsed->tv);
+ return elapsed->tv;
+ }
+
+ double
+ Elapsed::operator()() const
+ {
+ return convert(get());
+ }
+
+ Start start;
+ Now now;
+ Elapsed elapsed;
+
+ ostream &
+ operator<<(ostream &out, const Start &start)
+ {
+ out << ::ctime(&start.get().tv_sec);
+ return out;
+ }
+
+ ostream &
+ operator<<(ostream &out, const Now &now)
+ {
+ out << ::ctime(&now.get().tv_sec);
+ return out;
+ }
+
+ ostream &
+ operator<<(ostream &out, const Elapsed &elapsed)
+ {
+ out << ::ctime(&elapsed.get().tv_sec);
+ return out;
+ }
+}
diff --git a/sim/sim_time.hh b/sim/sim_time.hh
new file mode 100644
index 000000000..dbba42aa7
--- /dev/null
+++ b/sim/sim_time.hh
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+#ifndef __SIM_TIME_HH__
+#define __SIM_TIME_HH__
+
+#include <iosfwd>
+
+namespace Time {
+ struct _timeval;
+ class Start
+ {
+ private:
+ mutable _timeval *start;
+
+ public:
+ Start();
+ ~Start();
+
+ const timeval &get() const;
+ double operator()() const;
+ };
+
+ class Now
+ {
+ private:
+ mutable _timeval *now;
+
+ public:
+ Now();
+ ~Now();
+
+ const timeval &get() const;
+ double operator()() const;
+ };
+
+ class Elapsed
+ {
+ private:
+ mutable _timeval *elapsed;
+
+ public:
+ Elapsed();
+ ~Elapsed();
+
+ const timeval &get() const;
+ double operator()() const;
+ };
+
+ extern Start start;
+ extern Now now;
+ extern Elapsed elapsed;
+
+ std::ostream &operator<<(std::ostream &out, const Start &start);
+ std::ostream &operator<<(std::ostream &out, const Now &now);
+ std::ostream &operator<<(std::ostream &out, const Elapsed &elapsed);
+}
+
+#endif // __SIM_TIME_HH__
diff --git a/sim/simple_cpu.cc b/sim/simple_cpu.cc
new file mode 100644
index 000000000..96743d0fa
--- /dev/null
+++ b/sim/simple_cpu.cc
@@ -0,0 +1,747 @@
+/*
+ * 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.
+ */
+
+#include <iostream>
+#include <iomanip>
+#include <list>
+#include <sstream>
+#include <string>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "host.hh"
+#include "cprintf.hh"
+#include "misc.hh"
+#include "stats.hh"
+#include "smt.hh"
+
+#include "annotation.hh"
+#include "exec_context.hh"
+#include "base_cpu.hh"
+#include "debug.hh"
+#include "simple_cpu.hh"
+#include "inifile.hh"
+#include "mem_interface.hh"
+#include "base_mem.hh"
+#include "static_inst.hh"
+
+#ifdef FULL_SYSTEM
+#include "memory_control.hh"
+#include "physical_memory.hh"
+#include "alpha_memory.hh"
+#include "system.hh"
+#else // !FULL_SYSTEM
+#include "functional_memory.hh"
+#include "prog.hh"
+#include "eio.hh"
+#endif // FULL_SYSTEM
+
+#include "exetrace.hh"
+#include "trace.hh"
+#include "sim_events.hh"
+#include "pollevent.hh"
+#include "sim_object.hh"
+#include "sim_stats.hh"
+
+#include "range.hh"
+#include "symtab.hh"
+
+#ifdef FULL_SYSTEM
+#include "vtophys.hh"
+#include "pciareg.h"
+#include "remote_gdb.hh"
+#include "alpha_access.h"
+#endif
+
+
+using namespace std;
+
+SimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU *_cpu)
+ : Event(&mainEventQueue),
+ cpu(_cpu)
+{
+}
+
+void SimpleCPU::CacheCompletionEvent::process()
+{
+ cpu->processCacheCompletion();
+}
+
+const char *
+SimpleCPU::CacheCompletionEvent::description()
+{
+ return "cache completion event";
+}
+
+#ifdef FULL_SYSTEM
+SimpleCPU::SimpleCPU(const string &_name,
+ System *_system,
+ Counter max_insts_any_thread,
+ Counter max_insts_all_threads,
+ AlphaItb *itb, AlphaDtb *dtb,
+ FunctionalMemory *mem,
+ MemInterface *icache_interface,
+ MemInterface *dcache_interface,
+ int cpu_id, Tick freq)
+ : BaseCPU(_name, /* number_of_threads */ 1,
+ max_insts_any_thread, max_insts_all_threads,
+ _system, cpu_id, freq),
+#else
+SimpleCPU::SimpleCPU(const string &_name, Process *_process,
+ Counter max_insts_any_thread,
+ Counter max_insts_all_threads,
+ MemInterface *icache_interface,
+ MemInterface *dcache_interface)
+ : BaseCPU(_name, /* number_of_threads */ 1,
+ max_insts_any_thread, max_insts_all_threads),
+#endif
+ tickEvent(this), xc(NULL), cacheCompletionEvent(this)
+{
+#ifdef FULL_SYSTEM
+ xc = new ExecContext(this, 0, system, itb, dtb, mem, cpu_id);
+
+ _status = Running;
+ if (cpu_id != 0) {
+
+ xc->setStatus(ExecContext::Unallocated);
+
+ //Open a GDB debug session on port (7000 + the cpu_id)
+ (new GDBListener(new RemoteGDB(system, xc), 7000 + cpu_id))->listen();
+
+ AlphaISA::init(system->physmem, &xc->regs);
+
+ fault = Reset_Fault;
+
+ IntReg *ipr = xc->regs.ipr;
+ ipr[TheISA::IPR_MCSR] = 0x6;
+
+ AlphaISA::swap_palshadow(&xc->regs, true);
+
+ xc->regs.pc =
+ ipr[TheISA::IPR_PAL_BASE] + AlphaISA::fault_addr[fault];
+ xc->regs.npc = xc->regs.pc + sizeof(MachInst);
+
+ _status = Idle;
+ }
+ else {
+ system->initBootContext(xc);
+
+ // Reset the system
+ //
+ AlphaISA::init(system->physmem, &xc->regs);
+
+ fault = Reset_Fault;
+
+ IntReg *ipr = xc->regs.ipr;
+ ipr[TheISA::IPR_MCSR] = 0x6;
+
+ AlphaISA::swap_palshadow(&xc->regs, true);
+
+ xc->regs.pc = ipr[TheISA::IPR_PAL_BASE] + AlphaISA::fault_addr[fault];
+ xc->regs.npc = xc->regs.pc + sizeof(MachInst);
+
+ _status = Running;
+ tickEvent.schedule(0);
+ }
+
+#else
+ xc = new ExecContext(this, /* thread_num */ 0, _process, /* asid */ 0);
+ fault = No_Fault;
+ if (xc->status() == ExecContext::Active) {
+ _status = Running;
+ tickEvent.schedule(0);
+ } else
+ _status = Idle;
+#endif // !FULL_SYSTEM
+
+ icacheInterface = icache_interface;
+ dcacheInterface = dcache_interface;
+
+ memReq = new MemReq();
+ memReq->xc = xc;
+ memReq->asid = 0;
+
+ numInst = 0;
+ last_idle = 0;
+ lastIcacheStall = 0;
+ lastDcacheStall = 0;
+
+ contexts.push_back(xc);
+}
+
+SimpleCPU::~SimpleCPU()
+{
+}
+
+void
+SimpleCPU::regStats()
+{
+ BaseCPU::regStats();
+
+ numInsts
+ .name(name() + ".num_insts")
+ .desc("Number of instructions executed")
+ ;
+
+ numMemRefs
+ .name(name() + ".num_refs")
+ .desc("Number of memory references")
+ ;
+
+ idleCycles
+ .name(name() + ".idle_cycles")
+ .desc("Number of 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 = idleCycles / simTicks;
+
+ numInsts = Statistics::scalar(numInst);
+ simInsts += numInsts;
+}
+
+void
+SimpleCPU::serialize()
+{
+ nameOut();
+
+#ifdef FULL_SYSTEM
+#if 0
+ // do we need this anymore?? egh
+ childOut("itb", xc->itb);
+ childOut("dtb", xc->dtb);
+ childOut("physmem", physmem);
+#endif
+#endif
+
+ for (int i = 0; i < NumIntRegs; i++) {
+ stringstream buf;
+ ccprintf(buf, "R%02d", i);
+ paramOut(buf.str(), xc->regs.intRegFile[i]);
+ }
+ for (int i = 0; i < NumFloatRegs; i++) {
+ stringstream buf;
+ ccprintf(buf, "F%02d", i);
+ paramOut(buf.str(), xc->regs.floatRegFile.d[i]);
+ }
+ // CPUTraitsType::serializeSpecialRegs(getProxy(), xc->regs);
+}
+
+void
+SimpleCPU::unserialize(IniFile &db, const string &category, ConfigNode *node)
+{
+ string data;
+
+ for (int i = 0; i < NumIntRegs; i++) {
+ stringstream buf;
+ ccprintf(buf, "R%02d", i);
+ db.findDefault(category, buf.str(), data);
+ to_number(data,xc->regs.intRegFile[i]);
+ }
+ for (int i = 0; i < NumFloatRegs; i++) {
+ stringstream buf;
+ ccprintf(buf, "F%02d", i);
+ db.findDefault(category, buf.str(), data);
+ xc->regs.floatRegFile.d[i] = strtod(data.c_str(),NULL);
+ }
+
+ // Read in Special registers
+
+ // CPUTraitsType::unserializeSpecialRegs(db,category,node,xc->regs);
+}
+
+void
+change_thread_state(int thread_number, int activate, int priority)
+{
+}
+
+// precise architected memory state accessor macros
+template <class T>
+Fault
+SimpleCPU::read(Addr addr, T& data, unsigned flags)
+{
+ memReq->reset(addr, sizeof(T), flags);
+
+ // translate to physical address
+ Fault fault = xc->translateDataReadReq(memReq);
+
+ // do functional access
+ if (fault == No_Fault)
+ fault = xc->read(memReq, data);
+
+ if (traceData) {
+ traceData->setAddr(addr);
+ if (fault == No_Fault)
+ traceData->setData(data);
+ }
+
+ // if we have a cache, do cache access too
+ if (fault == No_Fault && dcacheInterface) {
+ memReq->cmd = Read;
+ memReq->completionEvent = NULL;
+ memReq->time = curTick;
+ memReq->flags &= ~UNCACHEABLE;
+ 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;
+ setStatus(DcacheMissStall);
+ }
+ }
+
+ 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)
+{
+ if (traceData) {
+ traceData->setAddr(addr);
+ traceData->setData(data);
+ }
+
+ memReq->reset(addr, sizeof(T), flags);
+
+ // translate to physical address
+ Fault fault = xc->translateDataWriteReq(memReq);
+
+ // do functional access
+ if (fault == No_Fault)
+ fault = xc->write(memReq, data);
+
+ if (fault == No_Fault && dcacheInterface) {
+ memReq->cmd = Write;
+ memReq->data = (uint8_t *)&data;
+ memReq->completionEvent = NULL;
+ memReq->time = curTick;
+ memReq->flags &= ~UNCACHEABLE;
+ 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;
+ setStatus(DcacheMissStall);
+ }
+ }
+
+ if (res && (fault == No_Fault))
+ *res = memReq->result;
+
+ 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);
+}
+
+
+#ifdef FULL_SYSTEM
+Addr
+SimpleCPU::dbg_vtophys(Addr addr)
+{
+ return vtophys(xc, addr);
+}
+#endif // FULL_SYSTEM
+
+Tick save_cycle = 0;
+
+
+void
+SimpleCPU::processCacheCompletion()
+{
+ switch (status()) {
+ case IcacheMissStall:
+ icacheStallCycles += curTick - lastIcacheStall;
+ setStatus(IcacheMissComplete);
+ break;
+ case DcacheMissStall:
+ dcacheStallCycles += curTick - lastDcacheStall;
+ setStatus(Running);
+ break;
+ default:
+ panic("SimpleCPU::processCacheCompletion: bad state");
+ break;
+ }
+}
+
+#ifdef FULL_SYSTEM
+void
+SimpleCPU::post_interrupt(int int_num, int index)
+{
+ BaseCPU::post_interrupt(int_num, index);
+
+ if (xc->status() == ExecContext::Suspended) {
+ DPRINTF(IPI,"Suspended Processor awoke\n");
+ xc->setStatus(ExecContext::Active);
+ Annotate::Resume(xc);
+ }
+}
+#endif // FULL_SYSTEM
+
+/* start simulation, program loaded, processor precise state initialized */
+void
+SimpleCPU::tick()
+{
+ traceData = NULL;
+
+#ifdef FULL_SYSTEM
+ if (fault == No_Fault && AlphaISA::check_interrupts &&
+ xc->cpu->check_interrupts() &&
+ !PC_PAL(xc->regs.pc) &&
+ status() != IcacheMissComplete) {
+ int ipl = 0;
+ int summary = 0;
+ AlphaISA::check_interrupts = 0;
+ IntReg *ipr = xc->regs.ipr;
+
+ if (xc->regs.ipr[TheISA::IPR_SIRR]) {
+ for (int i = TheISA::INTLEVEL_SOFTWARE_MIN;
+ i < TheISA::INTLEVEL_SOFTWARE_MAX; i++) {
+ if (ipr[TheISA::IPR_SIRR] & (ULL(1) << i)) {
+ // See table 4-19 of 21164 hardware reference
+ ipl = (i - TheISA::INTLEVEL_SOFTWARE_MIN) + 1;
+ summary |= (ULL(1) << i);
+ }
+ }
+ }
+
+ uint64_t interrupts = xc->cpu->intr_status();
+ for(int i = TheISA::INTLEVEL_EXTERNAL_MIN;
+ i < TheISA::INTLEVEL_EXTERNAL_MAX; i++) {
+ if (interrupts & (ULL(1) << i)) {
+ // See table 4-19 of 21164 hardware reference
+ ipl = i;
+ summary |= (ULL(1) << i);
+ }
+ }
+
+ if (ipr[TheISA::IPR_ASTRR])
+ panic("asynchronous traps not implemented\n");
+
+ if (ipl && ipl > xc->regs.ipr[TheISA::IPR_IPLR]) {
+ ipr[TheISA::IPR_ISR] = summary;
+ ipr[TheISA::IPR_INTID] = ipl;
+ xc->ev5_trap(Interrupt_Fault);
+
+ DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
+ ipr[TheISA::IPR_IPLR], ipl, summary);
+ }
+ }
+#endif
+
+ // maintain $r0 semantics
+ xc->regs.intRegFile[ZeroReg] = 0;
+#ifdef TARGET_ALPHA
+ xc->regs.floatRegFile.d[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.
+
+ setStatus(Running);
+ }
+ else {
+ // Try to fetch an instruction
+
+ // set up memory request for instruction fetch
+#ifdef FULL_SYSTEM
+#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0
+#else
+#define IFETCH_FLAGS(pc) 0
+#endif
+
+ memReq->cmd = Read;
+ memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t),
+ IFETCH_FLAGS(xc->regs.pc));
+
+ fault = xc->translateInstReq(memReq);
+
+ if (fault == No_Fault)
+ fault = xc->mem->read(memReq, inst);
+
+ if (icacheInterface && fault == No_Fault) {
+ memReq->completionEvent = NULL;
+
+ memReq->time = curTick;
+ memReq->flags &= ~UNCACHEABLE;
+ 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;
+ setStatus(IcacheMissStall);
+ return;
+ }
+ }
+ }
+
+ // If we've got a valid instruction (i.e., no fault on instruction
+ // fetch), then execute it.
+ if (fault == No_Fault) {
+
+ // keep an instruction count
+ numInst++;
+
+ // check for instruction-count-based events
+ comInsnEventQueue[0]->serviceEvents(numInst);
+
+ // decode the instruction
+ StaticInstPtr<TheISA> si(inst);
+
+ traceData = Trace::getInstRecord(curTick, xc, this, si,
+ xc->regs.pc);
+
+#ifdef FULL_SYSTEM
+ xc->regs.opcode = (inst >> 26) & 0x3f;
+ xc->regs.ra = (inst >> 21) & 0x1f;
+#endif // FULL_SYSTEM
+
+ xc->func_exe_insn++;
+
+ fault = si->execute(this, xc, traceData);
+
+ if (si->isMemRef()) {
+ numMemRefs++;
+ }
+
+ if (traceData)
+ traceData->finalize();
+
+ } // if (fault == No_Fault)
+
+ if (fault != No_Fault) {
+#ifdef FULL_SYSTEM
+ xc->ev5_trap(fault);
+#else // !FULL_SYSTEM
+ fatal("fault (%d) detected @ PC 0x%08p", fault, xc->regs.pc);
+#endif // FULL_SYSTEM
+ }
+ else {
+ // go to the next instruction
+ xc->regs.pc = xc->regs.npc;
+ xc->regs.npc += sizeof(MachInst);
+ }
+
+#ifdef FULL_SYSTEM
+ Addr oldpc;
+ do {
+ oldpc = xc->regs.pc;
+ system->pcEventQueue.service(xc);
+ } while (oldpc != xc->regs.pc);
+#endif
+
+ assert(status() == Running ||
+ status() == Idle ||
+ status() == DcacheMissStall);
+
+ if (status() == Running && !tickEvent.scheduled())
+ tickEvent.schedule(curTick + 1);
+}
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// SimpleCPU Simulation Object
+//
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
+
+ Param<Counter> max_insts_any_thread;
+ Param<Counter> max_insts_all_threads;
+
+#ifdef FULL_SYSTEM
+ SimObjectParam<AlphaItb *> itb;
+ SimObjectParam<AlphaDtb *> dtb;
+ SimObjectParam<FunctionalMemory *> mem;
+ SimObjectParam<System *> system;
+ Param<int> cpu_id;
+ Param<int> mult;
+#else
+ SimObjectParam<Process *> workload;
+#endif // FULL_SYSTEM
+
+ SimObjectParam<BaseMem *> icache;
+ SimObjectParam<BaseMem *> dcache;
+
+END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
+
+ INIT_PARAM_DFLT(max_insts_any_thread,
+ "terminate when any thread reaches this insn count",
+ 0),
+ INIT_PARAM_DFLT(max_insts_all_threads,
+ "terminate when all threads have reached this insn count",
+ 0),
+
+#ifdef FULL_SYSTEM
+ INIT_PARAM(itb, "Instruction TLB"),
+ INIT_PARAM(dtb, "Data TLB"),
+ INIT_PARAM(mem, "memory"),
+ INIT_PARAM(system, "system object"),
+ INIT_PARAM_DFLT(cpu_id, "CPU identification number", 0),
+ INIT_PARAM_DFLT(mult, "system clock multiplier", 1),
+#else
+ INIT_PARAM(workload, "processes to run"),
+#endif // FULL_SYSTEM
+
+ INIT_PARAM_DFLT(icache, "L1 instruction cache object", NULL),
+ INIT_PARAM_DFLT(dcache, "L1 data cache object", NULL)
+
+END_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
+
+
+CREATE_SIM_OBJECT(SimpleCPU)
+{
+#ifdef FULL_SYSTEM
+ if (mult != 1)
+ panic("processor clock multiplier must be 1\n");
+
+ return new SimpleCPU(getInstanceName(), system,
+ max_insts_any_thread, max_insts_all_threads,
+ itb, dtb, mem,
+ (icache) ? icache->getInterface() : NULL,
+ (dcache) ? dcache->getInterface() : NULL,
+ cpu_id, ticksPerSecond * mult);
+#else
+
+ return new SimpleCPU(getInstanceName(), workload,
+ max_insts_any_thread, max_insts_all_threads,
+ icache->getInterface(), dcache->getInterface());
+
+#endif // FULL_SYSTEM
+}
+
+REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU)
diff --git a/sim/simple_cpu.hh b/sim/simple_cpu.hh
new file mode 100644
index 000000000..c5671eb6f
--- /dev/null
+++ b/sim/simple_cpu.hh
@@ -0,0 +1,280 @@
+/*
+ * 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.
+ */
+
+#ifndef __SIMPLE_CPU_HH__
+#define __SIMPLE_CPU_HH__
+
+#include "base_cpu.hh"
+#include "eventq.hh"
+#include "symtab.hh"
+#include "pc_event.hh"
+#include "statistics.hh"
+
+
+// forward declarations
+#ifdef FULL_SYSTEM
+class Processor;
+class Kernel;
+class AlphaItb;
+class AlphaDtb;
+class PhysicalMemory;
+
+class RemoteGDB;
+class GDBListener;
+#endif // FULL_SYSTEM
+
+class MemInterface;
+class IniFile;
+
+namespace Trace {
+ class InstRecord;
+}
+
+class SimpleCPU : public BaseCPU
+{
+ public:
+ // main simulation loop (one cycle)
+ void tick();
+
+ private:
+ class TickEvent : public Event
+ {
+ private:
+ SimpleCPU *cpu;
+
+ public:
+ TickEvent(SimpleCPU *c)
+ : Event(&mainEventQueue, 100), cpu(c) { }
+ void process() { cpu->tick(); }
+ virtual const char *description() { return "tick event"; }
+ };
+
+ TickEvent tickEvent;
+
+ private:
+ Trace::InstRecord *traceData;
+ template<typename T>
+ void trace_data(T data) {
+ if (traceData) {
+ traceData->setData(data);
+ }
+ };
+
+ public:
+ //
+ enum Status {
+ Running,
+ Idle,
+ IcacheMissStall,
+ IcacheMissComplete,
+ DcacheMissStall
+ };
+
+ 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;
+ }
+ };
+
+#ifdef FULL_SYSTEM
+
+ SimpleCPU(const std::string &_name,
+ System *_system,
+ Counter max_insts_any_thread, Counter max_insts_all_threads,
+ AlphaItb *itb, AlphaDtb *dtb, FunctionalMemory *mem,
+ MemInterface *icache_interface, MemInterface *dcache_interface,
+ int cpu_id, Tick freq);
+
+#else
+
+ SimpleCPU(const std::string &_name, Process *_process,
+ Counter max_insts_any_thread,
+ Counter max_insts_all_threads,
+ MemInterface *icache_interface, MemInterface *dcache_interface);
+
+#endif
+
+ virtual ~SimpleCPU();
+
+ // execution context
+ ExecContext *xc;
+
+#ifdef 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;
+
+ // current fault status
+ Fault fault;
+
+ // Refcounted pointer to the one memory request.
+ MemReqPtr memReq;
+
+ 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 execCtxStatusChg() {
+ if (xc) {
+ if (xc->status() == ExecContext::Active)
+ setStatus(Running);
+ else
+ setStatus(Idle);
+ }
+ }
+
+ void setStatus(Status new_status) {
+ Status old_status = status();
+ _status = new_status;
+
+ switch (status()) {
+ case IcacheMissStall:
+ assert(old_status == Running);
+ lastIcacheStall = curTick;
+ if (tickEvent.scheduled())
+ tickEvent.squash();
+ break;
+
+ case IcacheMissComplete:
+ assert(old_status == IcacheMissStall);
+ if (tickEvent.squashed())
+ tickEvent.reschedule(curTick + 1);
+ else if (!tickEvent.scheduled())
+ tickEvent.schedule(curTick + 1);
+ break;
+
+ case DcacheMissStall:
+ assert(old_status == Running);
+ lastDcacheStall = curTick;
+ if (tickEvent.scheduled())
+ tickEvent.squash();
+ break;
+
+ case Idle:
+ assert(old_status == Running);
+ last_idle = curTick;
+ if (tickEvent.scheduled())
+ tickEvent.squash();
+ break;
+
+ case Running:
+ assert(old_status == Idle ||
+ old_status == DcacheMissStall ||
+ old_status == IcacheMissComplete);
+ if (old_status == Idle)
+ idleCycles += curTick - last_idle;
+
+ if (tickEvent.squashed())
+ tickEvent.reschedule(curTick + 1);
+ else if (!tickEvent.scheduled())
+ tickEvent.schedule(curTick + 1);
+ break;
+
+ default:
+ panic("can't get here");
+ }
+ }
+
+ // statistics
+ void regStats();
+
+ // number of simulated instructions
+ Counter numInst;
+ Statistics::Formula numInsts;
+
+ // number of simulated memory references
+ Statistics::Scalar<> numMemRefs;
+
+ // number of idle cycles
+ Statistics::Scalar<> idleCycles;
+ Statistics::Formula idleFraction;
+ Counter last_idle;
+
+ // number of cycles stalled for I-cache misses
+ Statistics::Scalar<> icacheStallCycles;
+ Counter lastIcacheStall;
+
+ // number of cycles stalled for D-cache misses
+ Statistics::Scalar<> dcacheStallCycles;
+ Counter lastDcacheStall;
+
+ void processCacheCompletion();
+
+ virtual void serialize();
+ virtual void unserialize(IniFile &db, const std::string &category,
+ ConfigNode *node);
+
+ 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);
+
+ Fault prefetch(Addr addr, unsigned flags)
+ {
+ // need to do this...
+ return No_Fault;
+ }
+
+ void writeHint(Addr addr, int size)
+ {
+ // need to do this...
+ }
+};
+
+#endif // __SIMPLE_CPU_HH__
diff --git a/sim/smt.hh b/sim/smt.hh
new file mode 100644
index 000000000..f9c1e4614
--- /dev/null
+++ b/sim/smt.hh
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file
+ * Defines SMT_MAX_CPUS and SMT_MAX_THREADS.
+ */
+
+#ifndef __SMT_HH__
+#define __SMT_HH__
+
+#ifndef SMT_MAX_CPUS
+/** The maximum number of cpus in any one system. */
+#define SMT_MAX_CPUS 4
+#endif
+
+#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/sim/static_inst.cc b/sim/static_inst.cc
new file mode 100644
index 000000000..cf25d5f05
--- /dev/null
+++ b/sim/static_inst.cc
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+#include <iostream>
+#include "static_inst.hh"
+#include "universe.hh"
+
+template <class ISA>
+StaticInstPtr<ISA> StaticInst<ISA>::nullStaticInstPtr;
+
+template <class ISA>
+typename StaticInst<ISA>::DecodeCache StaticInst<ISA>::decodeCache;
+
+// Define the decode cache hash map.
+template StaticInst<AlphaISA>::DecodeCache
+StaticInst<AlphaISA>::decodeCache;
+
+template <class ISA>
+void
+StaticInst<ISA>::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;
+ }
+}
+
+
+template StaticInstPtr<AlphaISA>
+StaticInst<AlphaISA>::nullStaticInstPtr;
+
+template <class ISA>
+bool
+StaticInst<ISA>::hasBranchTarget(Addr pc, ExecContext *xc, Addr &tgt)
+{
+ if (isDirectCtrl()) {
+ tgt = branchTarget(pc);
+ return true;
+ }
+
+ if (isIndirectCtrl()) {
+ tgt = branchTarget(xc);
+ return true;
+ }
+
+ return false;
+}
+
+
+// force instantiation of template function(s) above
+template StaticInst<AlphaISA>;
diff --git a/sim/static_inst.hh b/sim/static_inst.hh
new file mode 100644
index 000000000..b8f9cc00a
--- /dev/null
+++ b/sim/static_inst.hh
@@ -0,0 +1,433 @@
+/*
+ * 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.
+ */
+
+#ifndef __STATIC_INST_HH__
+#define __STATIC_INST_HH__
+
+#include <bitset>
+#include <string>
+
+#include "host.hh"
+#include "hashmap.hh"
+#include "refcnt.hh"
+
+#include "op_class.hh"
+#include "isa_traits.hh"
+
+// forward declarations
+class ExecContext;
+class SpecExecContext;
+class SimpleCPU;
+class CPU;
+class DynInst;
+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. Prefetches are marked as IsLoad, even if they
+ /// prefetch exclusive copies.
+ /// - 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.
+ ///
+ 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.
+ IsInstPrefetch, ///< Instruction-cache prefetch.
+ IsDataPrefetch, ///< Data-cache prefetch.
+
+ 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.
+
+ IsThreadSync, ///< Thread synchronization operation.
+
+ 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 isInstPrefetch() const { return flags[IsInstPrefetch]; }
+ bool isDataPrefetch() const { return flags[IsDataPrefetch]; }
+
+ 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]; }
+ //@}
+
+ /// Operation class. Used to select appropriate function unit in issue.
+ OpClass opClass() const { return _opClass; }
+};
+
+
+// forward declaration
+template <class ISA>
+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.
+ */
+template <class ISA>
+class StaticInst : public StaticInstBase
+{
+ public:
+
+ /// Binary machine instruction type.
+ typedef typename ISA::MachInst MachInst;
+ /// Memory address type.
+ typedef typename ISA::Addr Addr;
+ /// Logical register index type.
+ typedef typename ISA::RegIndex RegIndex;
+
+ enum {
+ MaxInstSrcRegs = ISA::MaxInstSrcRegs, //< Max source regs
+ MaxInstDestRegs = ISA::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) { 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) { 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<ISA> 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 StaticInstPtr<ISA> eaCompInst() { 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 StaticInstPtr<ISA> memAccInst() { return nullStaticInstPtr; }
+
+ /// The binary machine instruction.
+ const MachInst 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()).
+ */
+ std::string *cachedDisassembly;
+
+ /**
+ * Internal function to generate disassembly string.
+ */
+ virtual std::string generateDisassembly(Addr pc,
+ const SymbolTable *symtab) = 0;
+
+ /// Constructor.
+ StaticInst(const char *_mnemonic, MachInst _machInst, OpClass __opClass)
+ : StaticInstBase(__opClass),
+ machInst(_machInst), mnemonic(_mnemonic), cachedDisassembly(0)
+ {
+ }
+
+ public:
+
+ virtual ~StaticInst()
+ {
+ if (cachedDisassembly)
+ delete cachedDisassembly;
+ }
+
+ /**
+ * Execute this instruction under SimpleCPU model.
+ */
+ virtual Fault execute(SimpleCPU *cpu, ExecContext *xc,
+ Trace::InstRecord *traceData) = 0;
+
+ /**
+ * Execute this instruction under detailed CPU model.
+ */
+ virtual Fault execute(CPU *cpu, SpecExecContext *xc, DynInst *dynInst,
+ Trace::InstRecord *traceData) = 0;
+
+ /**
+ * 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)
+ {
+ 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.
+ * Invalid if not an indirect branch (i.e. isIndirectCtrl()
+ * should be true).
+ */
+ virtual Addr branchTarget(ExecContext *xc)
+ {
+ 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);
+
+ /**
+ * 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)
+ {
+ 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<MachInst, StaticInstPtr<ISA> > 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.
+ static
+ StaticInstPtr<ISA> decode(MachInst 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
+
+ typename DecodeCache::iterator iter = decodeCache.find(mach_inst);
+ if (iter != decodeCache.end()) {
+ return iter->second;
+ }
+
+ StaticInstPtr<ISA> si = ISA::decodeInst(mach_inst);
+ decodeCache[mach_inst] = si;
+ return si;
+ }
+};
+
+typedef RefCountingPtr<StaticInstBase> StaticInstBasePtr;
+
+/// Reference-counted pointer to a StaticInst object.
+/// This type should be used instead of "StaticInst<ISA> *" so that
+/// StaticInst objects can be properly reference-counted.
+template <class ISA>
+class StaticInstPtr : public RefCountingPtr<StaticInst<ISA> >
+{
+ public:
+ /// Constructor.
+ StaticInstPtr()
+ : RefCountingPtr<StaticInst<ISA> >()
+ {
+ }
+
+ /// Conversion from "StaticInst<ISA> *".
+ StaticInstPtr(StaticInst<ISA> *p)
+ : RefCountingPtr<StaticInst<ISA> >(p)
+ {
+ }
+
+ /// Copy constructor.
+ StaticInstPtr(const StaticInstPtr &r)
+ : RefCountingPtr<StaticInst<ISA> >(r)
+ {
+ }
+
+ /// Construct directly from machine instruction.
+ /// Calls StaticInst<ISA>::decode().
+ StaticInstPtr(typename ISA::MachInst mach_inst)
+ : RefCountingPtr<StaticInst<ISA> >(StaticInst<ISA>::decode(mach_inst))
+ {
+ }
+
+ /// Convert to pointer to StaticInstBase class.
+ operator const StaticInstBasePtr()
+ {
+ return get();
+ }
+};
+
+#endif // __STATIC_INST_HH__
diff --git a/sim/std_types.hh b/sim/std_types.hh
new file mode 100644
index 000000000..9c3898ff7
--- /dev/null
+++ b/sim/std_types.hh
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#ifndef __STD_TYPES_HH__
+#define __STD_TYPES_HH__
+
+// inst sequence type, used to order instructions in the ready list,
+// if this rolls over the ready list order temporarily will get messed
+// up, but execution will continue and complete correctly
+typedef unsigned long long InstSeqNum;
+
+// inst tag type, used to tag an operation instance in the IQ
+typedef unsigned int InstTag;
+
+#endif // __STD_TYPES_HH__
diff --git a/sim/system.cc b/sim/system.cc
new file mode 100644
index 000000000..04db8b134
--- /dev/null
+++ b/sim/system.cc
@@ -0,0 +1,250 @@
+/*
+ * 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.
+ */
+
+#include "kernel_loader.hh"
+#include "exec_context.hh"
+#include "object_file.hh"
+#include "memory_control.hh"
+#include "physical_memory.hh"
+#include "symtab.hh"
+#include "remote_gdb.hh"
+#include "vtophys.hh"
+#include "system.hh"
+#include "trace.hh"
+
+using namespace std;
+
+vector<System *> System::systemList;
+
+int System::numSystemsRunning = 0;
+
+System::System(const std::string _name,
+ MemoryController *_memCtrl,
+ PhysicalMemory *_physmem,
+ const std::string &kernel_path,
+ const std::string &console_path,
+ const std::string &palcode,
+ const std::string &boot_osflags)
+ : SimObject(_name),
+ kernel_panic_event(&pcEventQueue, "kernel panic"),
+ console_panic_event(&pcEventQueue, "console panic"),
+ badaddr_event(&pcEventQueue, "badaddr"),
+ skip_power_state(&pcEventQueue, "tl_v48_capture_power_state"),
+ skip_scavenge_boot(&pcEventQueue, "pmap_scavenge_boot"),
+ printf_event(&pcEventQueue, "printf"),
+ debug_printf_event(&pcEventQueue, "debug_printf", false),
+ debug_printfr_event(&pcEventQueue, "debug_printfr", true),
+ dump_mbuf_event(&pcEventQueue, "dump_mbuf"),
+ memCtrl(_memCtrl),
+ physmem(_physmem),
+ remoteGDB(NULL),
+ gdbListen(NULL)
+{
+ kernelSymtab = new SymbolTable;
+ consoleSymtab = new SymbolTable;
+
+ EcoffObject kernel(kernel_path);
+ EcoffObject console(console_path);
+
+ if (!kernel.loadGlobals(kernelSymtab))
+ panic("could not load kernel symbols\n");
+
+ if (!console.loadGlobals(consoleSymtab))
+ panic("could not load console symbols\n");
+
+ // Load pal file
+ loadPal(palcode, physmem, PAL_BASE);
+
+ // copy of initial reg file contents
+ initRegs = new RegFile;
+ memset(initRegs, 0, sizeof(RegFile));
+
+ // Load console file
+ loadKernel(console_path, physmem);
+
+ // Load kernel file
+ loadKernel(kernel_path, physmem, initRegs,
+ &kernelStart, &kernelEnd, &kernelEntry);
+
+ DPRINTF(Loader, "Kernel loaded...\n");
+
+#ifdef FULL_SYSTEM
+ Addr addr = 0;
+
+ for(int i = 0; i < 12/*MAX_CPUS*/; i++)
+ xc_array[i] = (ExecContext *) 0;
+
+ num_cpus = 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;
+ }
+
+ 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, boot_osflags.c_str());
+ }
+
+ if (kernelSymtab->findAddress("panic", addr))
+ kernel_panic_event.schedule(addr);
+ else
+ panic("could not find kernel symbol \'panic\'");
+
+ if (consoleSymtab->findAddress("panic", addr))
+ console_panic_event.schedule(addr);
+
+ if (kernelSymtab->findAddress("badaddr", addr))
+ badaddr_event.schedule(addr);
+ else
+ panic("could not find kernel symbol \'badaddr\'");
+
+ if (kernelSymtab->findAddress("tl_v48_capture_power_state", addr))
+ skip_power_state.schedule(addr);
+
+ if (kernelSymtab->findAddress("pmap_scavenge_boot", addr))
+ skip_scavenge_boot.schedule(addr);
+
+#if TRACING_ON
+ if (kernelSymtab->findAddress("printf", addr))
+ printf_event.schedule(addr);
+
+ if (kernelSymtab->findAddress("m5printf", addr))
+ debug_printf_event.schedule(addr);
+
+ if (kernelSymtab->findAddress("m5printfr", addr))
+ debug_printfr_event.schedule(addr);
+
+ if (kernelSymtab->findAddress("m5_dump_mbuf", addr))
+ dump_mbuf_event.schedule(addr);
+#endif
+
+#endif
+
+ // add self to global system list
+ systemList.push_back(this);
+
+ numSystemsRunning++;
+}
+
+
+System::~System()
+{
+ delete kernelSymtab;
+ delete consoleSymtab;
+ delete initRegs;
+}
+
+
+void
+System::initBootContext(ExecContext *xc)
+{
+ xc->regs = *initRegs;
+
+ remoteGDB = new RemoteGDB(this, xc);
+ gdbListen = new GDBListener(remoteGDB, 7000);
+ gdbListen->listen();
+
+ // Reset the system
+ //
+ TheISA::init(physmem, &xc->regs);
+}
+
+
+void
+System::registerExecContext(ExecContext *xc)
+{
+ if (num_cpus == 12/*MAX_CPUS*/)
+ panic("Too many CPU's\n");
+ xc_array[xc->cpu_id] = xc;
+ num_cpus++;
+}
+
+
+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();
+}
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(System)
+
+ SimObjectParam<MemoryController *> mem_ctl;
+ SimObjectParam<PhysicalMemory *> physmem;
+
+ Param<string> kernel_code;
+ Param<string> console_code;
+ Param<string> pal_code;
+ Param<string> boot_osflags;
+
+END_DECLARE_SIM_OBJECT_PARAMS(System)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(System)
+
+ INIT_PARAM(mem_ctl, "memory controller"),
+ INIT_PARAM(physmem, "phsyical memory"),
+ INIT_PARAM(kernel_code, "file that contains the kernel code"),
+ INIT_PARAM(console_code, "file that contains the console code"),
+ INIT_PARAM(pal_code, "file that contains palcode"),
+ INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot",
+ "a")
+
+END_INIT_SIM_OBJECT_PARAMS(System)
+
+
+CREATE_SIM_OBJECT(System)
+{
+ System *sys = new System(getInstanceName(), mem_ctl, physmem,
+ kernel_code, console_code, pal_code,
+ boot_osflags);
+
+ return sys;
+}
+
+REGISTER_SIM_OBJECT("System", System)
diff --git a/sim/system.hh b/sim/system.hh
new file mode 100644
index 000000000..bd2fd89b1
--- /dev/null
+++ b/sim/system.hh
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+#ifndef __SYSTEM_HH__
+#define __SYSTEM_HH__
+
+#include <string>
+
+#include "sim_object.hh"
+#include "pc_event.hh"
+#include "symtab.hh"
+
+class MemoryController;
+class PhysicalMemory;
+class RemoteGDB;
+class GDBListener;
+
+class ExecContext;
+
+class System : public SimObject
+{
+ private:
+
+ SymbolTable *kernelSymtab;
+ SymbolTable *consoleSymtab;
+
+ BreakPCEvent kernel_panic_event;
+ BreakPCEvent console_panic_event;
+ BadAddrEvent badaddr_event;
+ SkipFuncEvent skip_power_state;
+ SkipFuncEvent skip_scavenge_boot;
+ PrintfEvent printf_event;
+ DebugPrintfEvent debug_printf_event;
+ DebugPrintfEvent debug_printfr_event;
+ DumpMbufEvent dump_mbuf_event;
+
+ RegFile *initRegs;
+
+ Addr kernelStart;
+ Addr kernelEnd;
+ Addr kernelEntry;
+
+ public:
+
+ MemoryController *memCtrl;
+ PhysicalMemory *physmem;
+
+ PCEventQueue pcEventQueue;
+
+ ExecContext *xc_array[12/*MAX_CPUS*/];
+ int num_cpus;
+
+ RemoteGDB *remoteGDB;
+ GDBListener *gdbListen;
+
+ System(const std::string name,
+ MemoryController *, PhysicalMemory *,
+ const std::string &kernel_path, const std::string &console_path,
+ const std::string &palcode, const std::string &boot_osflags);
+
+ ~System();
+
+ const SymbolTable *getKernelSymtab() const { return kernelSymtab; }
+ const SymbolTable *getConsoleSymtab() const { return consoleSymtab; }
+
+ Addr getKernelStart() const { return kernelStart; }
+ Addr getKernelEnd() const { return kernelEnd; }
+ Addr getKernelEntry() const { return kernelEntry; }
+
+ void initBootContext(ExecContext *xc);
+ void registerExecContext(ExecContext *xc);
+
+ ////////////////////////////////////////////
+ //
+ // STATIC GLOBAL SYSTEM LIST
+ //
+ ////////////////////////////////////////////
+
+ public:
+
+ static std::vector<System *> systemList;
+
+ static int numSystemsRunning;
+
+ static void printSystems();
+};
+
+#endif // __SYSTEM_HH__
diff --git a/sim/universe.cc b/sim/universe.cc
new file mode 100644
index 000000000..83f268b14
--- /dev/null
+++ b/sim/universe.cc
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#include <list>
+#include <string>
+#include <vector>
+
+#include "universe.hh"
+#include "host.hh"
+#include "param.hh"
+
+using namespace std;
+
+Tick curTick = 0;
+Tick ticksPerSecond;
+
+class UniverseParamContext : public ParamContext
+{
+ public:
+ UniverseParamContext(const string &is) : ParamContext(is) {}
+ void checkParams();
+};
+
+UniverseParamContext universe("Universe");
+
+Param<Tick> universe_freq(&universe, "frequency", "tick frequency",
+ 200000000);
+
+void
+UniverseParamContext::checkParams()
+{
+ ticksPerSecond = universe_freq;
+}
diff --git a/test/Makefile b/test/Makefile
new file mode 100644
index 000000000..8c36f9806
--- /dev/null
+++ b/test/Makefile
@@ -0,0 +1,83 @@
+# $Id$
+
+CC= gcc
+CXX= g++
+
+CURDIR?= $(shell /bin/pwd)
+SRCDIR?= .
+TARGET?= alpha
+
+TEST_SRCDIR?= $(SRCDIR)
+ARCH_SRCDIR?= $(SRCDIR)/../arch/$(TARGET)
+BASE_SRCDIR?= $(SRCDIR)/../base
+SIM_SRCDIR?= $(SRCDIR)/../sim
+CACHE_SRCDIR?= $(SRCDIR)/../sim/cache
+OLD_SRCDIR= $(SRCDIR)/../old
+
+vpath % $(TEST_SRCDIR)
+vpath % $(BASE_SRCDIR)
+vpath % $(SIM_SRCDIR)
+vpath % $(CACHE_SRCDIR)
+vpath % $(OLD_SRCDIR)
+
+INCLDIRS= -I$(ARCH_SRCDIR) -I$(BASE_SRCDIR) -I$(SIM_SRCDIR) \
+ -I$(CACHE_SRCDIR) -I$(OLD_SRCDIR)
+CCFLAGS= -g -O0 -MMD -I. $(INCLDIRS) -I- -DTRACING_ON=0
+
+default:
+ @echo "You must specify a target"
+
+bitvectest: bitvectest.o
+ $(CXX) $(LFLAGS) -o $@ $^
+
+circletest: circletest.o circlebuf.o
+ $(CXX) $(LFLAGS) -o $@ $^
+
+cprintftest: cprintftest.o cprintf.o
+ $(CXX) $(LFLAGS) -o $@ $^
+
+initest: initest.o str.o inifile.o
+ $(CXX) $(LFLAGS) -o $@ $^
+
+lrutest: lru_test.o
+ $(CXX) $(LFLAGS) -o $@ $^
+
+nmtest: nmtest.o object_file.o symtab.o misc.o str.o
+ $(CXX) $(LFLAGS) -o $@ $^
+
+offtest: offtest.o
+ $(CXX) $(LFLAGS) -o $@ $^
+
+rangetest: rangetest.o str.o
+ $(CXX) $(LFLAGS) -o $@ $^
+
+stattest: statistics.o stattest.o cprintf.o misc.o omisc.o str.o
+ $(CXX) $(LFLAGS) -o $@ $^
+
+strnumtest: strnumtest.o str.o
+ $(CXX) $(LFLAGS) -o $@ $^
+
+symtest: misc.o symtest.o symtab.o str.o
+ $(CXX) $(LFLAGS) -o $@ $^
+
+tokentest: tokentest.o str.o
+ $(CXX) $(LFLAGS) -o $@ $^
+
+tracetest: tracetest.o trace.o trace_flags.o cprintf.o str.o misc.o omisc.o
+ $(CXX) $(LFLAGS) -o $@ $^
+
+clean:
+ @rm -f *.o *.d *test *~ .#* *.core core
+.PHONY: clean
+
+# C++ Compilation
+%.o: %.cc
+ @echo '$(CXX) $(CCFLAGS) -c $(notdir $<) -o $@'
+ @$(CXX) $(CCFLAGS) -c $< -o $@
+
+# C Compilation
+%.o: %.c
+ @echo '$(CC) $(CCFLAGS) -c $(notdir $<) -o $@'
+ @$(CC) $(CCFLAGS) -c $< -o $@
+
+-include *.d
diff --git a/test/bitvectest.cc b/test/bitvectest.cc
new file mode 100644
index 000000000..5c2a79a4e
--- /dev/null
+++ b/test/bitvectest.cc
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+#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
new file mode 100644
index 000000000..5123cfc9a
--- /dev/null
+++ b/test/circletest.cc
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#include <fcntl.h>
+#include <iostream.h>
+#include <unistd.h>
+
+#include "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
new file mode 100644
index 000000000..87518c3c3
--- /dev/null
+++ b/test/cprintftest.cc
@@ -0,0 +1,164 @@
+/*
+ * 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.
+ */
+
+#include <cstdio>
+#include <iostream>
+#include <list>
+#include <string>
+#include <sstream>
+
+#include "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/test/foo.ini
new file mode 100644
index 000000000..aa4305f12
--- /dev/null
+++ b/test/foo.ini
@@ -0,0 +1,7 @@
+#define JUNK
+[Foo]
+Foo1=89
+Foo2=384
+
+[General]
+Test3=89
diff --git a/test/initest.cc b/test/initest.cc
new file mode 100644
index 000000000..d45e9eaa7
--- /dev/null
+++ b/test/initest.cc
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+#include <iostream.h>
+#include <fstream.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include "inifile.hh"
+
+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 config;
+
+ progname = argv[0];
+
+ int cpp_options_count = 0;
+ char **cpp_options = new char*[argc * 2];
+ char **cur_opt = cpp_options;
+
+ int ch;
+ while ((ch = getopt(argc, argv, "D:")) != -1) {
+ switch (ch) {
+ case 'D':
+ *cur_opt++ = "-D";
+ *cur_opt++ = optarg;
+ cpp_options_count += 2;
+ break;
+
+ default:
+ usage();
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 1)
+ usage();
+
+ string file = argv[0];
+
+ if (!config.loadCPP(file, cpp_options, cpp_options_count)) {
+ cout << "File not found!\n";
+ exit(1);
+ }
+
+ string value;
+#define FIND(C, E) \
+ if (config.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";
+
+ config.dump();
+
+ return 0;
+}
diff --git a/test/initest.ini b/test/initest.ini
new file mode 100644
index 000000000..ebf2719d8
--- /dev/null
+++ b/test/initest.ini
@@ -0,0 +1,14 @@
+#define JUNK
+// General stuff
+#define FOO(X) BAR##X
+[General]
+ Test1=FOO(asdf)
+ Test2=bar
+
+#ifdef JUNK
+[Junk] // This is the junk
+Test3=yo
+Test4=mama
+#endif
+
+#include "foo.ini"
diff --git a/test/lru_test.cc b/test/lru_test.cc
new file mode 100644
index 000000000..b2b1350d0
--- /dev/null
+++ b/test/lru_test.cc
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+#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
new file mode 100644
index 000000000..701f83188
--- /dev/null
+++ b/test/nmtest.cc
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "ecoff.hh"
+#include "object_file.hh"
+#include "str.hh"
+#include "symtab.hh"
+
+Tick curTick;
+
+int
+main(int argc, char *argv[])
+{
+ EcoffObject obj;
+ if (argc != 3) {
+ cout << "usage: " << argv[0] << " <filename> <symbol>\n";
+ return 1;
+ }
+
+ if (!obj.open(argv[1])) {
+ cout << "file not found\n";
+ return 1;
+ }
+
+ SymbolTable symtab;
+ obj.loadGlobals(&symtab);
+
+ string symbol = argv[2];
+ Addr address;
+
+ if (symbol[0] == '0' && symbol[1] == 'x') {
+ if (to_number(symbol, address) && symtab.findSymbol(address, symbol))
+ cout << "address = 0x" << hex << address
+ << ", symbol = " << symbol << "\n";
+ else
+ cout << "address = 0x" << hex << address << " was not found\n";
+ } else {
+ if (symtab.findAddress(symbol, address))
+ cout << "symbol = " << symbol << ", address = 0x" << hex
+ << address << "\n";
+ else
+ cout << "symbol = " << symbol << " was not found\n";
+ }
+
+ return 0;
+}
diff --git a/test/offtest.cc b/test/offtest.cc
new file mode 100644
index 000000000..6970ecf72
--- /dev/null
+++ b/test/offtest.cc
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+#include <sys/types.h>
+#include <stddef.h>
+#include <stdio.h>
+#include "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
new file mode 100644
index 000000000..343d75b91
--- /dev/null
+++ b/test/paramtest.cc
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+//
+// 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_object.hh"
+#include "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<mem_hierarchy_obj *> memobj;
+ SimObjectVectorParam<mem_hierarchy_obj *> 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 },
+ { "fourty", 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
new file mode 100644
index 000000000..01c69bb26
--- /dev/null
+++ b/test/rangetest.cc
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+#include <iostream>
+#include <string>
+
+#include "range.hh"
+
+
+int
+main()
+{
+ Range<int> r1(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"
+
+ int i1 = 10;
+ int i2 = 0x1001;
+ RANGETEST(i1, < , r1);
+ RANGETEST(i1, <=, r1);
+ RANGETEST(i1, > , r1);
+ RANGETEST(i1, >=, r1);
+ RANGETEST(i1, ==, r1);
+ RANGETEST(i1, !=, r1);
+ RANGETEST(r1, < , i1);
+ RANGETEST(r1, <=, i1);
+ RANGETEST(r1, > , i1);
+ RANGETEST(r1, >=, i1);
+ RANGETEST(r1, ==, i1);
+ RANGETEST(r1, !=, i1);
+
+ RANGETEST(i2, < , r1);
+ RANGETEST(i2, <=, r1);
+ RANGETEST(i2, > , r1);
+ RANGETEST(i2, >=, r1);
+ RANGETEST(i2, ==, r1);
+ RANGETEST(i2, !=, r1);
+ RANGETEST(r1, < , i2);
+ RANGETEST(r1, <=, i2);
+ RANGETEST(r1, > , i2);
+ RANGETEST(r1, >=, i2);
+ RANGETEST(r1, ==, i2);
+ RANGETEST(r1, !=, i2);
+
+ unsigned u1 = 10;
+ unsigned u2 = 0x1001;
+ RANGETEST(u1, < , r2);
+ RANGETEST(u1, <=, r2);
+ RANGETEST(u1, > , r2);
+ RANGETEST(u1, >=, r2);
+ RANGETEST(u1, ==, r2);
+ RANGETEST(u1, !=, r2);
+ RANGETEST(r2, < , u1);
+ RANGETEST(r2, <=, u1);
+ RANGETEST(r2, > , u1);
+ RANGETEST(r2, >=, u1);
+ RANGETEST(r2, ==, u1);
+ RANGETEST(r2, !=, u1);
+
+ RANGETEST(u2, < , r2);
+ RANGETEST(u2, <=, r2);
+ RANGETEST(u2, > , r2);
+ RANGETEST(u2, >=, r2);
+ RANGETEST(u2, ==, r2);
+ RANGETEST(u2, !=, r2);
+ RANGETEST(r2, < , u2);
+ RANGETEST(r2, <=, u2);
+ RANGETEST(r2, > , u2);
+ RANGETEST(r2, >=, u2);
+ RANGETEST(r2, ==, u2);
+ RANGETEST(r2, !=, u2);
+
+ return 0;
+}
diff --git a/test/sized_test.cc b/test/sized_test.cc
new file mode 100644
index 000000000..fe52b7a41
--- /dev/null
+++ b/test/sized_test.cc
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+#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
new file mode 100644
index 000000000..02f65169a
--- /dev/null
+++ b/test/stattest.cc
@@ -0,0 +1,504 @@
+/*
+ * 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.
+ */
+
+#include <iomanip>
+#include <iostream>
+#include <string>
+#include <unistd.h>
+
+#include "cprintf.hh"
+#include "host.hh"
+#include "misc.hh"
+#include "statistics.hh"
+
+using namespace std;
+using namespace Statistics;
+
+Tick curTick = 0;
+//Tick ticksPerSecond = ULL(2000000000);
+
+Scalar<> s1;
+Scalar<> s2;
+Average<> s3;
+Scalar<Counter, MainBin> s4;
+Vector<Counter, MainBin> s5;
+Distribution<Counter, MainBin> s6;
+Vector<> s7;
+AverageVector<> s8;
+StandardDeviation<> s9;
+AverageDeviation<> s10;
+Scalar<Counter> s11;
+Distribution<> s12;
+VectorDistribution<> s13;
+VectorStandardDeviation<> s14;
+VectorAverageDeviation<> s15;
+Vector2d<> s16;
+
+Formula f1;
+Formula f2;
+Formula f3;
+Formula f4;
+Formula f5;
+Formula f6;
+
+MainBin bin1;
+MainBin bin2;
+
+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 [-v]\n", progname);
+}
+
+int
+main(int argc, char *argv[])
+{
+ char c;
+ progname = argv[0];
+ PrintDescriptions = false;
+ while ((c = getopt(argc, argv, "v")) != -1) {
+ cprintf("c == %c\n", c);
+ switch (c) {
+ case 'v':
+ PrintDescriptions = true;
+ break;
+ default:
+ 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, 2);
+
+ 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(s11)
+ ;
+
+ 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")
+ ;
+
+ 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
+ .name("Formula4")
+ .desc("this is formula 4")
+ ;
+
+ f5
+ .name("Formula5")
+ .desc("this is formula 5")
+ ;
+
+ f6
+ .name("Formula6")
+ .desc("this is formula 6")
+ ;
+
+ check();
+
+ MainBin::activate(bin1);
+
+ f1 = s1 + s2;
+ f2 = (-s1) / (-s2) * -s3 + ULL(100) + s4;
+ f3 = sum(s5) * s7;
+ f4 = functor(testfunc);
+ TestClass testclass;
+ f5 = functor(testclass);
+ f6 += constant(10.0);
+ f6 += s5[3];
+
+ s16[1][0] = 1;
+ s16[0][1] = 3;
+ s16[0][0] = 2;
+ s16[1][1] = 9;
+ s16[1][1] += 9;
+
+ 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);
+
+ MainBin::activate(bin2);
+ 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);
+
+ 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);
+
+ MainBin::activate(bin1);
+ dump(cout);
+ cout << endl << endl;
+
+ MainBin::activate(bin2);
+ dump(cout);
+ cout << endl << endl;
+
+ return 0;
+}
diff --git a/test/strnumtest.cc b/test/strnumtest.cc
new file mode 100644
index 000000000..1e0a6676f
--- /dev/null
+++ b/test/strnumtest.cc
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+#include <iostream.h>
+
+#include <string>
+#include <vector>
+
+#include "str.hh"
+
+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
new file mode 100644
index 000000000..bc03fc1df
--- /dev/null
+++ b/test/symtest.cc
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+#include <iostream.h>
+
+#include "str.hh"
+#include "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
new file mode 100644
index 000000000..4a4551883
--- /dev/null
+++ b/test/tokentest.cc
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+#include <iostream.h>
+#include <string>
+#include <vector>
+
+#include "str.hh"
+
+int
+main(int argc, char *argv[])
+{
+ 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()) {
+ for (i = 0; i < tokens1.size() - 1; i++)
+ cout << tokens1[i] << "(" << tokens1[i].size() << "), ";
+ cout << tokens1[i] << "(" << tokens1[i].size() << ")\n";
+ }
+
+ cout << "testing with ignore\n";
+ tokenize(tokens2, test, token, true);
+
+ if (tokens2.size()) {
+ for (i = 0; i < tokens2.size() - 1; i++)
+ cout << tokens2[i] << "(" << tokens2[i].size() << "), ";
+ cout << tokens2[i] << "(" << tokens2[i].size() << ")\n";
+ }
+
+ return 0;
+}
diff --git a/test/tracetest.cc b/test/tracetest.cc
new file mode 100644
index 000000000..51236123c
--- /dev/null
+++ b/test/tracetest.cc
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#include "host.hh"
+#include "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/rundiff b/util/rundiff
new file mode 100644
index 000000000..064e7e136
--- /dev/null
+++ b/util/rundiff
@@ -0,0 +1,511 @@
+#!/usr/bin/perl
+
+# Copyright (c) 2001 Nathan L. Binkert
+# All rights reserved.
+#
+# Permission to redistribute, use, copy, and modify this software
+# without fee is hereby granted, provided that the following
+# conditions are met:
+#
+# 1. This entire notice is included in all source code copies of any
+# software which is or includes a copy or modification of this
+# software.
+# 2. The name of the author may not be used to endorse or promote
+# products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+# OR IMPLIED 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.
+#
+
+use Algorithm::Diff qw(diff);
+use vars qw ($opt_C $opt_c $opt_u $opt_U);
+
+$opt_u = "";
+$opt_c = undef;
+
+$diffsize = 2000;
+# After we've read up to a certain point in each file, the number of items
+# we've read from each file will differ by $FLD (could be 0)
+my $File_Length_Difference = 0;
+my $Context_Lines = 9;
+
+$progname = $0;
+if (scalar(@ARGV) != 2) {
+ usage();
+}
+
+my ($filename1, $filename2);
+($filename1, $start1) = parse_filearg($ARGV[0]);
+($filename2, $start2) = parse_filearg($ARGV[1]);
+
+if ($filename1 eq "-" && $filename2 eq "-") {
+ die "Only one of the inputs may be standard in\n";
+}
+
+my ($file1, $file2);
+if ($filename1 eq "-") {
+ $file1 = STDIN;
+} else {
+ open(FILE1, $filename1) || die "can't open $file1: $!\n";
+ $file1 = FILE1;
+}
+
+if ($filename2 eq "-") {
+ $file2 = STDIN;
+} else {
+ open(FILE2, $filename2) || die "can't open $file2: $!\n";
+ $file2 = FILE2;
+}
+
+my $file_offset1 = ffw($file1, $start1);
+my $file_offset2 = ffw($file2, $start2);
+
+$skip_first = 0;
+my (@buf1, @buf2, @printbuf1, @printbuf2);
+
+$Compare_Ahead = 0;
+
+while (!eof($file1) && !eof($file2)) {
+ my $line1 = <$file1>; chomp $line1;
+ my $line2 = <$file2>; chomp $line2;
+ my $printline1 = $line1;
+ my $printline2 = $line2;
+
+ push @buf1, $line1;
+ push @buf2, $line2;
+ push @printbuf1, $printline1;
+ push @printbuf2, $printline2;
+
+# while ($Compare_Ahead < $Context_Lines) {
+# $line1 = @buf1[$Compare_Ahead];
+# $line2 = @buf2[$Compare_Ahead];
+# $line2 =~ s/ *--.*$//;
+# if ($line1 ne $line2) { last; }
+# ++$Compare_Ahead;
+# }
+
+ $line1 = @buf1[$Compare_Ahead];
+ $line2 = @buf2[$Compare_Ahead];
+ $line2 =~ s/ *--.*$//;
+
+ if ($line1 ne $line2) {
+ while (!eof($file1) && scalar(@buf1) < $diffsize) {
+ $line = <$file1>; chomp $line;
+ my $printline = $line;
+
+ push @printbuf1, $printline;
+ push @buf1, $line;
+ }
+
+ while (!eof($file2) && scalar(@buf2) < $diffsize) {
+ $line = <$file2>; chomp $line;
+ my $printline = $line;
+# $line =~ s/ *--.*$//;
+
+ push @printbuf2, $printline;
+ push @buf2, $line;
+ }
+
+ my $diffs = diff(\@buf1, \@buf2);
+
+ next unless @$diffs;
+
+ my @hunklist;
+ my ($hunk,$oldhunk);
+ # Loop over hunks. If a hunk overlaps with the last hunk, join them.
+ # Otherwise, print out the old one.
+ foreach my $piece (@$diffs) {
+ $hunk = new Hunk ($piece, $Context_Lines, scalar(@buf1));
+ next unless $oldhunk;
+
+ if ($hunk->does_overlap($oldhunk)) {
+ $hunk->prepend_hunk($oldhunk);
+ } else {
+ push @hunklist, $oldhunk;
+ }
+ } continue {
+ $oldhunk = $hunk;
+ }
+
+ my $change = 0;
+ while (scalar(@hunklist) && !$change) {
+ $hunk = pop @hunklist;
+ $change = $hunk->{"change"};
+ }
+ push @hunklist, $hunk;
+ $last_start1 = $hunk->{"start1"};
+ $last_start2 = $hunk->{"start2"};
+ $last_end1 = $hunk->{"end1"};
+ $last_end2 = $hunk->{"end2"};
+
+ while (scalar(@hunklist)) {
+ $hunk = shift @hunklist;
+# $hunk->output_diff(\@buf1, \@buf2);
+ $hunk->output_diff(\@printbuf1, \@printbuf2);
+ }
+
+ $last_end1 -= $Context_Lines - 1;
+ $last_end2 -= $Context_Lines - 1;
+ $file_offset1 += $last_end1;
+ $file_offset2 += $last_end2;
+ @printbuf1 = @printbuf1[$last_end1..$#printbuf1];
+ @printbuf2 = @printbuf2[$last_end2..$#printbuf2];
+ @buf1 = @buf1[$last_end1..$#buf1];
+ @buf2 = @buf2[$last_end2..$#buf2];
+ while (scalar(@buf1) > $Context_Lines &&
+ scalar(@buf2) > $Context_Lines) {
+ $foo1 = @buf1[$Context_Lines];
+ $foo2 = @buf2[$Context_Lines];
+ if (scalar($foo1) != scalar($foo2) || $foo1 ne $foo2) { last; }
+ $foo1 = shift @printbuf1;
+ $foo2 = shift @printbuf2;
+ $foo1 = shift @buf1;
+ $foo2 = shift @buf2;
+ ++$file_offset1;
+ ++$file_offset2;
+ }
+ } else {
+ ++$file_offset1;
+ ++$file_offset2;
+ $foo1 = shift @printbuf1;
+ $foo2 = shift @printbuf2;
+ $foo1 = shift @buf1;
+ $foo2 = shift @buf2;
+ }
+}
+
+close $file1;
+close $file2;
+
+sub ffw() {
+ if (scalar(@_) != 2) { die "improper usage of ffw\n"; }
+
+ my $FILE = $_[0];
+ my $start = $_[1];
+ my $count = 0;
+
+ while ($start-- > 0 && !eof($FILE)) {
+ <$FILE>;
+ $count++;
+ }
+
+ if ($start > 0) {die "File too short for ffw amount\n"; }
+ return $count;
+}
+
+sub parse_filearg() {
+ $start = 0;
+ split /:/, @_[0];
+ if (scalar(@_) > 2) { usage(); }
+
+ $file = $_[0];
+ if (scalar(@_) > 1) { $start = $_[1]; }
+
+ return ($file, $start);
+}
+
+sub usage() {
+ printf "usage: $progname <file1>[:start] <file2>[:start]\n";
+ exit 1;
+}
+
+
+# Package Hunk. A Hunk is a group of Blocks which overlap because of the
+# context surrounding each block. (So if we're not using context, every
+# hunk will contain one block.)
+{
+package Hunk;
+
+sub new {
+# Arg1 is output from &LCS::diff (which corresponds to one Block)
+# Arg2 is the number of items (lines, e.g.,) of context around each block
+#
+# This subroutine changes $File_Length_Difference
+#
+# Fields in a Hunk:
+# blocks - a list of Block objects
+# start - index in file 1 where first block of the hunk starts
+# end - index in file 1 where last block of the hunk ends
+#
+# Variables:
+# before_diff - how much longer file 2 is than file 1 due to all hunks
+# until but NOT including this one
+# after_diff - difference due to all hunks including this one
+ my ($class, $piece, $context_items, $maxlen) = @_;
+
+ my $block = new Block ($piece); # this modifies $FLD!
+
+ my $before_diff = $File_Length_Difference; # BEFORE this hunk
+ my $after_diff = $before_diff + $block->{"length_diff"};
+ $File_Length_Difference += $block->{"length_diff"};
+
+ # @remove_array and @insert_array hold the items to insert and remove
+ # Save the start & beginning of each array. If the array doesn't exist
+ # though (e.g., we're only adding items in this block), then figure
+ # out the line number based on the line number of the other file and
+ # the current difference in file lenghts
+ my @remove_array = $block->remove;
+ my @insert_array = $block->insert;
+ my ($a1, $a2, $b1, $b2, $start1, $start2, $end1, $end2, $change);
+ $a1 = @remove_array ? $remove_array[0 ]->{"item_no"} : -1;
+ $a2 = @remove_array ? $remove_array[-1]->{"item_no"} : -1;
+ $b1 = @insert_array ? $insert_array[0 ]->{"item_no"} : -1;
+ $b2 = @insert_array ? $insert_array[-1]->{"item_no"} : -1;
+
+ $start1 = $a1 == -1 ? $b1 - $before_diff : $a1;
+ $end1 = $a2 == -1 ? $b2 - $after_diff : $a2;
+ $start2 = $b1 == -1 ? $a1 + $before_diff : $b1;
+ $end2 = $b2 == -1 ? $a2 + $after_diff : $b2;
+ $change = scalar(@remove_array) && scalar(@insert_array);
+
+ # At first, a hunk will have just one Block in it
+ my $hunk = {
+ "start1" => $start1,
+ "start2" => $start2,
+ "end1" => $end1,
+ "end2" => $end2,
+ "maxlen" => $maxlen,
+ "change" => $change,
+ "blocks" => [$block],
+ };
+ bless $hunk, $class;
+
+ $hunk->flag_context($context_items);
+
+ return $hunk;
+}
+
+# Change the "start" and "end" fields to note that context should be added
+# to this hunk
+sub flag_context {
+ my ($hunk, $context_items) = @_;
+ return unless $context_items; # no context
+
+ # add context before
+ my $start1 = $hunk->{"start1"};
+ my $num_added = $context_items > $start1 ? $start1 : $context_items;
+ $hunk->{"start1"} -= $num_added;
+ $hunk->{"start2"} -= $num_added;
+
+ # context after
+ my $end1 = $hunk->{"end1"};
+ $num_added = ($end1+$context_items > $hunk->{"maxlen"}) ?
+ $hunk->{"maxlen"} - $end1 :
+ $context_items;
+ $hunk->{"end1"} += $num_added;
+ $hunk->{"end2"} += $num_added;
+}
+
+# Is there an overlap between hunk arg0 and old hunk arg1?
+# Note: if end of old hunk is one less than beginning of second, they overlap
+sub does_overlap {
+ my ($hunk, $oldhunk) = @_;
+ return "" unless $oldhunk; # first time through, $oldhunk is empty
+
+ # Do I actually need to test both?
+ return ($hunk->{"start1"} - $oldhunk->{"end1"} <= 1 ||
+ $hunk->{"start2"} - $oldhunk->{"end2"} <= 1);
+}
+
+# Prepend hunk arg1 to hunk arg0
+# Note that arg1 isn't updated! Only arg0 is.
+sub prepend_hunk {
+ my ($hunk, $oldhunk) = @_;
+
+ $hunk->{"start1"} = $oldhunk->{"start1"};
+ $hunk->{"start2"} = $oldhunk->{"start2"};
+
+ unshift (@{$hunk->{"blocks"}}, @{$oldhunk->{"blocks"}});
+}
+
+
+# DIFF OUTPUT ROUTINES. THESE ROUTINES CONTAIN DIFF FORMATTING INFO...
+sub output_diff {
+ if (defined $main::opt_u) {&output_unified_diff(@_)}
+ elsif (defined $main::opt_c) {&output_context_diff(@_)}
+ else {die "unknown diff"}
+}
+
+sub output_unified_diff {
+ my ($hunk, $fileref1, $fileref2) = @_;
+ my @blocklist;
+
+ # Calculate item number range.
+ my $range1 = $hunk->unified_range(1, $file_offset1);
+ my $range2 = $hunk->unified_range(2, $file_offset2);
+ print "@@ -$range1 +$range2 @@\n";
+
+ # Outlist starts containing the hunk of file 1.
+ # Removing an item just means putting a '-' in front of it.
+ # Inserting an item requires getting it from file2 and splicing it in.
+ # We splice in $num_added items. Remove blocks use $num_added because
+ # splicing changed the length of outlist.
+ # We remove $num_removed items. Insert blocks use $num_removed because
+ # their item numbers---corresponding to positions in file *2*--- don't take
+ # removed items into account.
+ my $low = $hunk->{"start1"};
+ my $hi = $hunk->{"end1"};
+ my ($num_added, $num_removed) = (0,0);
+ my @outlist = @$fileref1[$low..$hi];
+ map {s/^/ /} @outlist; # assume it's just context
+
+ foreach my $block (@{$hunk->{"blocks"}}) {
+ foreach my $item ($block->remove) {
+ my $op = $item->{"sign"}; # -
+ my $offset = $item->{"item_no"} - $low + $num_added;
+ $outlist[$offset] =~ s/^ /$op/;
+ $num_removed++;
+ }
+ foreach my $item ($block->insert) {
+ my $op = $item->{"sign"}; # +
+ my $i = $item->{"item_no"};
+ my $offset = $i - $hunk->{"start2"} + $num_removed;
+ splice(@outlist,$offset,0,"$op$$fileref2[$i]");
+ $num_added++;
+ }
+ }
+
+ map {s/$/\n/} @outlist; # add \n's
+ print @outlist;
+
+}
+
+sub output_context_diff {
+ my ($hunk, $fileref1, $fileref2) = @_;
+ my @blocklist;
+
+ print "***************\n";
+ # Calculate item number range.
+ my $range1 = $hunk->context_range(1, $file_offset1);
+ my $range2 = $hunk->context_range(2, $file_offset2);
+
+ # Print out file 1 part for each block in context diff format if there are
+ # any blocks that remove items
+ print "*** $range1 ****\n";
+ my $low = $hunk->{"start1"};
+ my $hi = $hunk->{"end1"};
+ if (@blocklist = grep {$_->remove} @{$hunk->{"blocks"}}) {
+ my @outlist = @$fileref1[$low..$hi];
+ map {s/^/ /} @outlist; # assume it's just context
+ foreach my $block (@blocklist) {
+ my $op = $block->op; # - or !
+ foreach my $item ($block->remove) {
+ $outlist[$item->{"item_no"} - $low] =~ s/^ /$op/;
+ }
+ }
+ map {s/$/\n/} @outlist; # add \n's
+ print @outlist;
+ }
+
+ print "--- $range2 ----\n";
+ $low = $hunk->{"start2"};
+ $hi = $hunk->{"end2"};
+ if (@blocklist = grep {$_->insert} @{$hunk->{"blocks"}}) {
+ my @outlist = @$fileref2[$low..$hi];
+ map {s/^/ /} @outlist; # assume it's just context
+ foreach my $block (@blocklist) {
+ my $op = $block->op; # + or !
+ foreach my $item ($block->insert) {
+ $outlist[$item->{"item_no"} - $low] =~ s/^ /$op/;
+ }
+ }
+ map {s/$/\n/} @outlist; # add \n's
+ print @outlist;
+ }
+}
+
+sub context_range {
+# Generate a range of item numbers to print. Only print 1 number if the range
+# has only one item in it. Otherwise, it's 'start,end'
+ my ($hunk, $flag, $offset) = @_;
+ my ($start, $end) = ($hunk->{"start$flag"},$hunk->{"end$flag"});
+
+ # index from 1, not zero
+ $start += $offset + 1;
+ $end += $offset + 1;
+ my $range = ($start < $end) ? "$start,$end" : $end;
+ return $range;
+}
+
+sub unified_range {
+# Generate a range of item numbers to print for unified diff
+# Print number where block starts, followed by number of lines in the block
+# (don't print number of lines if it's 1)
+ my ($hunk, $flag, $offset) = @_;
+ my ($start, $end) = ($hunk->{"start$flag"},$hunk->{"end$flag"});
+
+ # index from 1, not zero
+ $start += $offset + 1;
+ $end += $offset + 1;
+ my $length = $end - $start + 1;
+ my $first = $length < 2 ? $end : $start; # strange, but correct...
+ my $range = $length== 1 ? $first : "$first,$length";
+ return $range;
+}
+} # end Package Hunk
+
+# Package Block. A block is an operation removing, adding, or changing
+# a group of items. Basically, this is just a list of changes, where each
+# change adds or deletes a single item.
+# (Change could be a separate class, but it didn't seem worth it)
+{
+package Block;
+sub new {
+# Input is a chunk from &Algorithm::LCS::diff
+# Fields in a block:
+# length_diff - how much longer file 2 is than file 1 due to this block
+# Each change has:
+# sign - '+' for insert, '-' for remove
+# item_no - number of the item in the file (e.g., line number)
+# We don't bother storing the text of the item
+#
+ my ($class,$chunk) = @_;
+ my @changes = ();
+
+# This just turns each change into a hash.
+ foreach my $item (@$chunk) {
+ my ($sign, $item_no, $text) = @$item;
+ my $hashref = {"sign" => $sign, "item_no" => $item_no};
+ push @changes, $hashref;
+ }
+
+ my $block = { "changes" => \@changes };
+ bless $block, $class;
+
+ $block->{"length_diff"} = $block->insert - $block->remove;
+ return $block;
+}
+
+
+# LOW LEVEL FUNCTIONS
+sub op {
+# what kind of block is this?
+ my $block = shift;
+ my $insert = $block->insert;
+ my $remove = $block->remove;
+
+ $remove && $insert and return '!';
+ $remove and return '-';
+ $insert and return '+';
+ warn "unknown block type";
+ return '^'; # context block
+}
+
+# Returns a list of the changes in this block that remove items
+# (or the number of removals if called in scalar context)
+sub remove { return grep {$_->{"sign"} eq '-'} @{shift->{"changes"}}; }
+
+# Returns a list of the changes in this block that insert items
+sub insert { return grep {$_->{"sign"} eq '+'} @{shift->{"changes"}}; }
+
+} # end of package Block
diff --git a/util/tap/Makefile b/util/tap/Makefile
new file mode 100644
index 000000000..c7078158b
--- /dev/null
+++ b/util/tap/Makefile
@@ -0,0 +1,67 @@
+# 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: Nathan Binkert
+
+# $Id$
+
+CC= gcc
+CXX= g++
+
+CURDIR?= $(shell /bin/pwd)
+SRCDIR?= .
+
+BASE_SRCDIR?= $(SRCDIR)/../../base
+SIM_SRCDIR?= $(SRCDIR)/../../sim
+
+vpath % $(BASE_SRCDIR)
+vpath % $(SIM_SRCDIR)
+
+INCLDIRS= -I. -I$(BASE_SRCDIR) -I$(SIM_SRCDIR) -I- -I/usr/local/include
+CCFLAGS= -g -O0 -MMD $(INCLDIRS)
+
+default: m5tap
+
+m5tap: tap.o cprintf.o
+ $(CXX) $(LFLAGS) -o $@ $^ -lpcap -L/usr/local/lib -ldnet
+
+
+clean:
+ @rm -f m5tap *.o *.d *~ .#*
+
+.PHONY: clean
+
+# C++ Compilation
+%.o: %.cc
+ @echo '$(CXX) $(CCFLAGS) -c $(notdir $<) -o $@'
+ @$(CXX) $(CCFLAGS) -c $< -o $@
+
+# C Compilation
+%.o: %.c
+ @echo '$(CC) $(CCFLAGS) -c $(notdir $<) -o $@'
+ @$(CC) $(CCFLAGS) -c $< -o $@
+
+-include *.d
diff --git a/util/tap/tap.cc b/util/tap/tap.cc
new file mode 100644
index 000000000..0ef49dfd7
--- /dev/null
+++ b/util/tap/tap.cc
@@ -0,0 +1,415 @@
+/*
+ * 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.
+ */
+
+extern "C" {
+#include <pcap.h>
+}
+
+#include <dnet.h>
+
+#include <arpa/inet.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <netdb.h>
+#include <poll.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <list>
+#include <string>
+
+#include "cprintf.hh"
+
+#define panic(arg...) \
+ do { cprintf("Panic: " arg); exit(1); } while (0)
+
+char *program = "ethertap";
+void
+usage()
+{
+ cprintf(
+ "usage: \n"
+ "\t%s [-b bufsize] [-d] [-f filter] [-p port] [-v] <device> <host>\n"
+ "\t%s [-b bufsize] [-d] [-f filter] [-l] [-p port] [-v] <device>\n",
+ program, program);
+ exit(2);
+}
+
+int verbose = 0;
+#define DPRINTF(args...) do { \
+ if (verbose > 1) \
+ cprintf(args); \
+} while (0)
+
+#define DDUMP(args...) do { \
+ if (verbose > 2) \
+ dump((const u_char *)args); \
+} while (0)
+
+void
+dump(const u_char *data, int len)
+{
+ int c, i, j;
+
+ for (i = 0; i < len; i += 16) {
+ cprintf("%08x ", i);
+ c = len - i;
+ if (c > 16) c = 16;
+
+ for (j = 0; j < c; j++) {
+ cprintf("%02x ", data[i + j] & 0xff);
+ if ((j & 0xf) == 7 && j > 0)
+ cprintf(" ");
+ }
+
+ for (; j < 16; j++)
+ cprintf(" ");
+ cprintf(" ");
+
+ for (j = 0; j < c; j++) {
+ int ch = data[i + j] & 0x7f;
+ cprintf("%c", (char)(isprint(ch) ? ch : ' '));
+ }
+
+ cprintf("\n");
+
+ if (c < 16)
+ break;
+ }
+}
+
+bool quit = false;
+void
+quit_now(int sigtype)
+{
+ DPRINTF("User requested exit\n");
+ quit = true;
+}
+
+
+int
+Socket(int reuse)
+{
+ int fd = ::socket(PF_INET, SOCK_STREAM, 0);
+ if (fd < 0)
+ panic("Can't create socket!");
+
+ if (reuse) {
+ int i = 1;
+ if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&i,
+ sizeof(i)) < 0)
+ panic("setsockopt() SO_REUSEADDR failed!");
+ }
+
+ return fd;
+}
+
+void
+Listen(int fd, int port)
+{
+ 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 == -1)
+ panic("bind() failed!");
+
+ if (::listen(fd, 1) == -1)
+ panic("listen() failed!");
+}
+
+// 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
+Accept(int fd, bool nodelay)
+{
+ struct sockaddr_in sockaddr;
+ socklen_t slen = sizeof (sockaddr);
+ int sfd = ::accept(fd, (struct sockaddr *)&sockaddr, &slen);
+ if (sfd == -1)
+ panic("accept() failed!");
+
+ if (nodelay) {
+ int i = 1;
+ ::setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (char *)&i, sizeof(i));
+ }
+ return sfd;
+}
+
+void
+Connect(int fd, const string &host, int port)
+{
+ struct sockaddr_in sockaddr;
+ if (::inet_aton(host.c_str(), &sockaddr.sin_addr) == 0) {
+ struct hostent *hp;
+ hp = ::gethostbyname(host.c_str());
+ if (!hp)
+ panic("Host %s not found\n", host);
+
+ sockaddr.sin_family = hp->h_addrtype;
+ memcpy(&sockaddr.sin_addr, hp->h_addr, hp->h_length);
+ }
+
+ sockaddr.sin_port = htons(port);
+ if (::connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != 0)
+ panic("could not connect to %s on port %d", host, port);
+
+ DPRINTF("connected to %s on port %d\n", host, port);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int port = 3500;
+ int bufsize = 2000;
+ bool listening = false;
+ char *device = NULL;
+ char *filter = "";
+ char c;
+ int daemon = false;
+ string host;
+
+ program = basename(argv[0]);
+
+ while((c = getopt(argc, argv, "b:df:lp:v")) != -1) {
+ switch (c) {
+ case 'b':
+ bufsize = atoi(optarg);
+ break;
+ case 'd':
+ daemon = true;
+ break;
+ case 'f':
+ filter = optarg;
+ break;
+ case 'l':
+ listening = true;
+ break;
+ case 'p':
+ port = atoi(optarg);
+ break;
+ case 'v':
+ verbose++;
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+
+ signal(SIGINT, quit_now);
+ signal(SIGTERM, quit_now);
+ signal(SIGHUP, quit_now);
+
+ if (daemon) {
+ verbose = 0;
+ switch(fork()) {
+ case -1:
+ panic("Fork failed\n");
+ case 0:
+ break;
+ default:
+ exit(0);
+ }
+ }
+
+ char *buffer = new char[bufsize];
+ argc -= optind;
+ argv += optind;
+
+ if (argc-- == 0)
+ usage();
+
+ device = *argv++;
+
+ if (listening) {
+ if (argc)
+ usage();
+ } else {
+ if (argc != 1)
+ usage();
+
+ host = *argv;
+ }
+
+ char errbuf[PCAP_ERRBUF_SIZE];
+ pcap_t *pcap = pcap_open_live(device, 1500, 1, -1, errbuf);
+ if (pcap == NULL)
+ panic("pcap_open_live failed: %s\n", errbuf);
+
+ bpf_program program;
+ bpf_u_int32 localnet, netmask;
+ if (!pcap_lookupnet(device, &localnet, &netmask, errbuf))
+ panic("pcap_lookupnet failed: %s\n", errbuf);
+
+ if (pcap_compile(pcap, &program, filter, 1, netmask) == -1)
+ panic("pcap_compile failed, invalid filter:\n%s\n", filter);
+
+ if (pcap_setfilter(pcap, &program) == -1)
+ panic("pcap_setfilter failed\n");
+
+ eth_t *ethernet = eth_open(device);
+
+ pollfd pfds[3];
+ pfds[0].fd = Socket(true);
+ pfds[0].events = POLLIN;
+ pfds[0].revents = 0;
+
+ if (listening)
+ Listen(pfds[0].fd, port);
+ else
+ Connect(pfds[0].fd, host, port);
+
+ pfds[1].fd = pcap_fileno(pcap);
+ pfds[1].events = POLLIN;
+ pfds[1].revents = 0;
+
+ pfds[2].fd = 0;
+ pfds[2].events = POLLIN|POLLERR;
+ pfds[2].revents = 0;
+
+ pollfd *listen_pfd = listening ? &pfds[0] : NULL;
+ pollfd *tap_pfd = &pfds[1];
+ pollfd *client_pfd = listening ? NULL : &pfds[0];
+ int npfds = 2;
+
+ int32_t buffer_offset = 0;
+ int32_t data_len = 0;
+
+ while (!quit) {
+ int ret = ::poll(pfds, npfds, INFTIM);
+ if (ret < 0)
+ continue;
+
+ if (listen_pfd && listen_pfd->revents) {
+ if (listen_pfd->revents & POLLIN) {
+ int fd = Accept(listen_pfd->fd, false);
+ if (client_pfd) {
+ DPRINTF("Connection rejected\n");
+ close(fd);
+ } else {
+ DPRINTF("Connection accepted\n");
+ client_pfd = &pfds[2];
+ client_pfd->fd = fd;
+ npfds++;
+ }
+ }
+ listen_pfd->revents = 0;
+ }
+
+ if (tap_pfd && tap_pfd->revents) {
+ if (tap_pfd->revents & POLLIN) {
+ pcap_pkthdr hdr;
+ const u_char *data = pcap_next(pcap, &hdr);
+ if (data && client_pfd) {
+ DPRINTF("Received packet from ethernet len=%d\n", hdr.len);
+ DDUMP(data, hdr.len);
+ u_int32_t len = htonl(hdr.len);
+ write(client_pfd->fd, &len, sizeof(len));
+ write(client_pfd->fd, data, hdr.len);
+ }
+ }
+
+ tap_pfd->revents = 0;
+ }
+
+ if (client_pfd && client_pfd->revents) {
+ if (client_pfd->revents & POLLIN) {
+ if (buffer_offset < data_len + sizeof(u_int32_t)) {
+ int len = read(client_pfd->fd, buffer + buffer_offset,
+ bufsize - buffer_offset);
+
+ if (len <= 0) {
+ perror("read");
+ goto error;
+ }
+
+ buffer_offset += len;
+ if (data_len == 0)
+ data_len = ntohl(*(u_int32_t *)buffer);
+
+ DPRINTF("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)) {
+ char *data = buffer + sizeof(u_int32_t);
+ eth_send(ethernet, data, data_len);
+ DPRINTF("Sent packet to ethernet len = %d\n", data_len);
+ DDUMP(data, data_len);
+
+ buffer_offset -= data_len + sizeof(u_int32_t);
+ if (buffer_offset > 0 && data_len > 0) {
+ memmove(buffer, data + data_len, buffer_offset);
+ data_len = ntohl(*(u_int32_t *)buffer);
+ } else
+ data_len = 0;
+ }
+ }
+
+ if (client_pfd->revents & POLLERR) {
+ error:
+ DPRINTF("Error on client socket\n");
+ close(client_pfd->fd);
+ client_pfd = NULL;
+
+ if (listening)
+ npfds--;
+ else
+ quit = true;
+ }
+
+ if (client_pfd)
+ client_pfd->revents = 0;
+ }
+
+ }
+
+ delete [] buffer;
+ pcap_close(pcap);
+ eth_close(ethernet);
+ if(listen_pfd)
+ close(listen_pfd->fd);
+
+ if (client_pfd)
+ close(client_pfd->fd);
+
+ return 0;
+}
diff --git a/util/term/Makefile b/util/term/Makefile
new file mode 100644
index 000000000..39e396687
--- /dev/null
+++ b/util/term/Makefile
@@ -0,0 +1,45 @@
+# 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: Nathan Binkert
+
+# $Id$
+
+CC= gcc
+CCFLAGS= -g -O0
+
+default: m5term
+
+m5term: term.c
+ $(CC) $(LFLAGS) -o $@ $^
+
+install: m5term
+ $(SUDO) install -o root -m 555 m5term /usr/local/bin
+
+clean:
+ @rm -f m5term *~ .#*
+
+.PHONY: clean
diff --git a/util/term/term.c b/util/term/term.c
new file mode 100644
index 000000000..d445b4d37
--- /dev/null
+++ b/util/term/term.c
@@ -0,0 +1,312 @@
+/* $Id$ */
+/* $OpenBSD: netcat.c,v 1.57 2002/12/30 18:00:18 stevesk Exp $ */
+/*
+ * Copyright (c) 2001 Eric Jackson <ericj@monkey.org>
+ *
+ * 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 name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED 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.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/termios.h>
+#include <sys/time.h>
+#include <sys/un.h>
+
+#include <netinet/in.h>
+#include <arpa/telnet.h>
+
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <poll.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+ssize_t atomicio(ssize_t (*)(), int, void *, size_t);
+void readwrite(int);
+int remote_connect(char *, char *, struct addrinfo);
+
+struct termios saved_ios;
+void raw_term();
+void restore_term();
+
+char progname[256];
+void usage(int);
+
+int
+main(int argc, char *argv[])
+{
+ int ch, s, ret;
+ char *host, *port, *endp;
+ struct addrinfo hints;
+ socklen_t len;
+
+ ret = 1;
+ s = 0;
+ host = NULL;
+ port = NULL;
+ endp = NULL;
+
+ strncpy(progname, argv[0], sizeof progname);
+
+ /* Cruft to make sure options are clean, and used properly. */
+ if (argc != 3 || !argv[1] || !argv[2])
+ usage(1);
+
+ host = argv[1];
+ port = argv[2];
+
+
+ if (!isatty(STDIN_FILENO))
+ errx(1, "not attached to a terminal");
+
+ raw_term();
+
+ /* Initialize addrinfo structure */
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ s = remote_connect(host, port, hints);
+ ret = 0;
+ readwrite(s);
+
+ if (s)
+ close(s);
+
+ exit(ret);
+}
+
+/*
+ * remote_connect()
+ * Return's a socket connected to a remote host. Properly bind's to a local
+ * port or source address if needed. Return's -1 on failure.
+ */
+int
+remote_connect(char *host, char *port, struct addrinfo hints)
+{
+ struct addrinfo *res, *res0;
+ int s, error;
+
+ if ((error = getaddrinfo(host, port, &hints, &res)))
+ errx(1, "getaddrinfo: %s", gai_strerror(error));
+
+ res0 = res;
+ do {
+ if ((s = socket(res0->ai_family, res0->ai_socktype,
+ res0->ai_protocol)) < 0)
+ continue;
+
+ if (connect(s, res0->ai_addr, res0->ai_addrlen) == 0)
+ break;
+
+ close(s);
+ s = -1;
+ } while ((res0 = res0->ai_next) != NULL);
+
+ freeaddrinfo(res);
+
+ return (s);
+}
+
+/*
+ * readwrite()
+ * Loop that polls on the network file descriptor and stdin.
+ */
+void
+readwrite(int nfd)
+{
+ struct pollfd pfd[2];
+ char buf[BUFSIZ];
+ int wfd = fileno(stdin), n, ret;
+ int lfd = fileno(stdout);
+ int escape = 0;
+
+ /* Setup Network FD */
+ pfd[0].fd = nfd;
+ pfd[0].events = POLLIN;
+
+ /* Setup STDIN FD */
+ pfd[1].fd = wfd;
+ pfd[1].events = POLLIN;
+
+ while (pfd[0].fd != -1) {
+ if ((n = poll(pfd, 2, -1)) < 0) {
+ close(nfd);
+ err(1, "Polling Error");
+ }
+
+ if (n == 0)
+ return;
+
+ if (pfd[0].revents & POLLIN) {
+ if ((n = read(nfd, buf, sizeof(buf))) < 0)
+ return;
+ else if (n == 0) {
+ shutdown(nfd, SHUT_RD);
+ pfd[0].fd = -1;
+ pfd[0].events = 0;
+ } else {
+ if ((ret = atomicio(write, lfd, buf, n)) != n)
+ return;
+ }
+ }
+
+ if (pfd[1].revents & POLLIN) {
+ if ((n = read(wfd, buf, sizeof(buf))) < 0)
+ return;
+ else if (n == 0) {
+ shutdown(nfd, SHUT_WR);
+ pfd[1].fd = -1;
+ pfd[1].events = 0;
+ } else {
+ if (escape) {
+ char buf2[] = "~";
+ if (*buf == '.') {
+ printf("quit!\n");
+ return;
+ }
+ escape = 0;
+ if (*buf != '~' &&
+ (ret = atomicio(write, nfd, buf2, 1)) != n)
+ return;
+ } else {
+ escape = (*buf == '~');
+ if (escape)
+ continue;
+ }
+
+ if((ret = atomicio(write, nfd, buf, n)) != n)
+ return;
+ }
+ }
+ }
+}
+
+void
+usage(int ret)
+{
+ fprintf(stderr, "usage: %s hostname port\n", progname);
+ if (ret)
+ exit(1);
+}
+
+/*
+ * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED 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.
+ */
+
+/*
+ * ensure all of data on socket comes through. f==read || f==write
+ */
+ssize_t
+atomicio(ssize_t (*f) (), int fd, void *_s, size_t n)
+{
+ char *s = _s;
+ ssize_t res, pos = 0;
+
+ while (n > pos) {
+ res = (f) (fd, s + pos, n - pos);
+ switch (res) {
+ case -1:
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ case 0:
+ return (res);
+ default:
+ pos += res;
+ }
+ }
+ return (pos);
+}
+
+/*
+ * Copyright (c) 2003 Nathan L. Binkert <binkertn@umich.edu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+void
+raw_term()
+{
+ struct termios ios;
+
+ if (tcgetattr(STDIN_FILENO, &ios) < 0)
+ errx(1, "tcgetagttr\n");
+
+ memcpy(&saved_ios, &ios, sizeof(struct termios));
+
+ ios.c_iflag &= ~(ISTRIP|ICRNL|IGNCR|ICRNL|IXOFF|IXON);
+ ios.c_oflag &= ~(OPOST);
+ ios.c_oflag &= (ONLCR);
+ ios.c_lflag &= ~(ISIG|ICANON|ECHO);
+ ios.c_cc[VMIN] = 1;
+ ios.c_cc[VTIME] = 0;
+
+ if (tcsetattr(STDIN_FILENO, TCSANOW, &ios) < 0)
+ errx(1, "tcsetattr\n");
+
+ atexit(restore_term);
+}
+
+void
+restore_term()
+{
+ tcsetattr(STDIN_FILENO, TCSANOW, &saved_ios);
+}