diff options
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(®s, 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(®s, 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 ®_file, + int regnum); + + static void restoreMachineReg(RegFile ®s, const AnyReg ®, + int regnum); + +#if 0 + static void serializeSpecialRegs(const Serializeable::Proxy &proxy, + const RegFile ®s); + + static void unserializeSpecialRegs(IniFile &db, + const std::string &category, + ConfigNode *node, + RegFile ®s); +#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 §ionName) +{ + 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 §ionName) 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 §ionName, const string &entryName, + string &value) const +{ + Section *section = findSection(sectionName); + if (section == NULL) + return false; + + Entry *entry = section->findEntry(entryName); + if (entry == NULL) + return false; + + value = entry->getValue(); + + return true; +} + +bool +IniFile::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 §ionName) +{ + bool unref = false; + bool search_unref_entries = false; + vector<string> unref_ok_entries; + + Entry *entry = findEntry("unref_entries_ok"); + if (entry != NULL) { + tokenize(unref_ok_entries, entry->getValue(), ' '); + if (unref_ok_entries.size()) { + search_unref_entries = true; + } + } + + for (EntryTable::iterator ei = table.begin(); + ei != table.end(); ++ei) { + const string &entryName = ei->first; + Entry *entry = ei->second; + + if (entryName == "unref_section_ok" || + entryName == "unref_entries_ok") + { + continue; + } + + if (!entry->isReferenced()) { + if (search_unref_entries && + (std::find(unref_ok_entries.begin(), unref_ok_entries.end(), + entryName) != unref_ok_entries.end())) + { + continue; + } + + cerr << "Parameter " << sectionName << ":" << entryName + << " not referenced." << endl; + unref = true; + } + } + + return unref; +} + + +bool +IniFile::printUnreferenced() +{ + bool unref = false; + + for (ConfigTable::iterator ci = table.begin(); + ci != table.end(); ++ci) { + const string §ionName = 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 §ionName) +{ + 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 §ionName); + void dump(const std::string §ionName); + }; + + typedef m5::hash_map<std::string, Section *> ConfigTable; + + protected: + ConfigTable table; + + Section *addSection(const std::string §ionName); + Section *findSection(const std::string §ionName) 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 §ion, const std::string &entry, + std::string &value) const; + bool findDefault(const std::string §ion, 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(¶mContext, "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 ¶ms) + : min_val(INT_MAX), max_val(INT_MIN), underflow(0), overflow(0), + vec(params.size) { + } + void sample(T val, int number, const Params ¶ms) { + 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 ¶ms) 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 ¶ms) 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 ¶ms) 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 ¶ms) const { return 1; } + bool zero(const Params ¶ms) 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 ¶ms) { } + + int size() const { return 1; } + + Storage *data(const Params ¶ms) { + 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 ¶ms) { + assert(!initialized()); + assert(s > 0); + _size = s; + allocate(_size * sizeof(Storage)); + } + + int size() const { return _size; } + + Storage *data(int index, const Params ¶ms) { + 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 ¶ms) { + new (ptr) Storage(params); + } + int size() const{ return 1; } + Storage *data(const Params ¶ms) { + 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 ¶ms) { + 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 ¶ms) { + 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(®s, 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 ®s); + + void finalize() { theLog.append(this); } + + enum InstExecFlagBits { + TRACE_MISSPEC = 0, + PRINT_CYCLE, + PRINT_OP_CLASS, + PRINT_THREAD_NUM, + PRINT_RESULT_DATA, + PRINT_EFF_ADDR, + PRINT_INT_REGS, + PRINT_FETCH_SEQ, + PRINT_CP_SEQ, + NUM_BITS + }; + + static std::vector<bool> flags; + + static void setParams(); + + static bool traceMisspec() { return flags[TRACE_MISSPEC]; } +}; + + +inline void +InstRecord::setRegs(const IntRegFile ®s) +{ + if (!iregs) + iregs = new iRegFile; + + memcpy(&iregs->regs, regs, sizeof(IntRegFile)); + regs_valid = true; +} + +inline +InstRecord * +getInstRecord(Tick cycle, ExecContext *xc, BaseCPU *cpu, + const StaticInstPtr<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 §ion); + ~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 §ion) + : 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); +} |