From 88638f076a25cb66279ec3cd8e500858696a8bbc Mon Sep 17 00:00:00 2001 From: Stephen Checkoway Date: Sat, 12 Aug 2017 13:12:35 -0500 Subject: [PATCH] Initial commit. --- Doxyfile | 1462 ++++++++++++++++++++++++++++++++ LICENSE | 19 + Makefile | 172 ++++ include/zel/z80.h | 219 +++++ include/zel/z80_instructions.h | 252 ++++++ include/zel/z80_types.h | 46 + tables/cb_prefix.spec | 256 ++++++ tables/dd_prefix.spec | 252 ++++++ tables/ddcb_prefix.spec | 256 ++++++ tables/ed_prefix.spec | 78 ++ tables/fd_prefix.spec | 252 ++++++ tables/fdcb_prefix.spec | 256 ++++++ tables/gen.pl | 154 ++++ tables/no_prefix.spec | 252 ++++++ tests/Makefile | 57 ++ tests/itest.c | 52 ++ tests/template.c | 21 + tests/test.c | 129 +++ tests/test_arithmetic.c | 32 + tests/test_load.c | 35 + tests/test_set.c | 33 + z80.c | 1283 ++++++++++++++++++++++++++++ z80_instructions.c | 206 +++++ 23 files changed, 5774 insertions(+) create mode 100644 Doxyfile create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 include/zel/z80.h create mode 100644 include/zel/z80_instructions.h create mode 100644 include/zel/z80_types.h create mode 100644 tables/cb_prefix.spec create mode 100644 tables/dd_prefix.spec create mode 100644 tables/ddcb_prefix.spec create mode 100644 tables/ed_prefix.spec create mode 100644 tables/fd_prefix.spec create mode 100644 tables/fdcb_prefix.spec create mode 100755 tables/gen.pl create mode 100644 tables/no_prefix.spec create mode 100644 tests/Makefile create mode 100644 tests/itest.c create mode 100644 tests/template.c create mode 100644 tests/test.c create mode 100644 tests/test_arithmetic.c create mode 100644 tests/test_load.c create mode 100644 tests/test_set.c create mode 100644 z80.c create mode 100644 z80_instructions.c diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000..a12da4c --- /dev/null +++ b/Doxyfile @@ -0,0 +1,1462 @@ +# Doxyfile 1.5.7 + +# 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 (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = libzel + +# 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 = 0.1 + +# 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 = doc + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# 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: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, +# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, +# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, +# Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# 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 + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# 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. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# 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 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 regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_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 INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = 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 + +# 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 = + +# 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 = YES + +# 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 OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = NO + +# 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 + +# 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 + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = YES + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# 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 = NO + +# 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 = NO + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# 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 = NO + +# 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 + +# 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 +# and Mac users are advised to set this option to NO. + +CASE_SENSE_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 = YES + +# 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 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 the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# 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 + +# 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 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 + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# 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 = NO + +# 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 + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = 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. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +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 = include/zel + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# 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 *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = *.h + +# 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 = NO + +# 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 = tests + +# 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 = NO + +# 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. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# 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 , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# 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. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# 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 +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentstion. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# 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 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. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +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 HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = YES + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# 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 compiled 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 directory. + +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 CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# 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 = YES + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER +# are set, an additional index file will be generated that can be used as input for +# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated +# HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# Qt Help Project / Namespace. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# Qt Help Project / Virtual Folders. + +QHP_VIRTUAL_FOLDER = doc + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file . + +QHG_LOCATION = + +# 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 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to FRAME, 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. Other possible values +# for this tag are: HIERARCHIES, which will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list; +# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which +# disables this behavior completely. For backwards compatibility with previous +# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE +# respectively. + +GENERATE_TREEVIEW = NONE + +# 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 + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +#--------------------------------------------------------------------------- +# 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 = YES + +# 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 = YES + +# 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 = letter + +# 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 = YES + +# 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 = YES + +# 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 = YES + +#--------------------------------------------------------------------------- +# 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 optimized 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 assignments. 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 = YES + +# 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. + +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 = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# 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_DEFINED 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. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# 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::additions 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 superseded 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 = NO + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# 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 = NO + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# 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 GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar 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 options 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 = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller 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 caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# 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 + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = 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 in 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 DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# 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 the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# 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::additions 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 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..eb62077 --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2008 Steve Checkoway + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b7ebd86 --- /dev/null +++ b/Makefile @@ -0,0 +1,172 @@ +# Copyright (c) 2008 Steve Checkoway +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +CPPFLAGS += -Iinclude +CFLAGS += -O3 + +package := zel +version := 0.1 +distname := lib$(package)-$(version) + +prefix := /usr/local +exec_prefix := $(prefix) +includedir := $(prefix)/include +datarootdir := $(prefix)/share +datadir := $(datarootdir) +docdir := $(datarootdir)/doc/$(package) +htmldir := $(docdir) +pdfdir := $(docdir) +libdir := $(exec_prefix)/lib +mandir := $(datarootdir)/man +man3dir := $(mandir)/man3 + +INSTALL := install +INSTALL_PROGRAM := $(INSTALL) -m 0755 +INSTALL_DATA := $(INSTALL) -m 0644 + +spec := $(wildcard tables/*.spec) +itables := $(spec:.spec=.tab) + +here := $(shell pwd) + +dist_source := z80.c \ + z80_instructions.c \ + include/zel/z80.h \ + include/zel/z80_instructions.h \ + include/zel/z80_types.h \ + include/zel/z80_types.tab \ + tables/gen.pl \ + $(spec) \ + $(itables) \ + Makefile \ + Doxyfile \ + LICENSE \ + tests/Makefile \ + $(wildcard tests/*.c) \ + doc/$(distname).pdf + +.PHONY: all check clean distclean mostlyclean maintainer-clean dist distcheck doc-clean \ + install install-html install-pdf html pdf uninstall uninstall-doc install-doc installcheck + +all: libzel.a + +libzel.a: z80.o z80_instructions.o + $(AR) -cr $@ $? + ranlib $@ + +tables/%.tab: tables/%.spec tables/gen.pl + perl tables/gen.pl $< > $@ + +include/zel/z80_types.tab: $(itables) + awk '{ split($$2,a,/_/); sub(/,/,"",a[1]); printf "%s //!< %s\n", $$2, tolower(a[1]) }' \ + $(itables) |sort|uniq > $@ +z80.o: z80.c include/zel/z80.h include/zel/z80_instructions.h include/zel/z80_types.h include/zel/z80_types.tab +z80_instructions.o: z80_instructions.c include/zel/z80_instructions.h include/zel/z80.h include/zel/z80_types.h include/zel/z80_types.tab $(itables) + +check: all + $(MAKE) -C tests check + +installcheck: + $(MAKE) -C tests LDFLAGS='-L$(DESTDIR)$(libdir)' CPPFLAGS='-I$(DESTDIR)$(includedir)' check + +doc-clean: + $(RM) -r doc + +clean: doc-clean + $(MAKE) -C tests clean + $(RM) libzel.a z80.o z80_instructions.o *~ + +doc: Doxyfile $(wildcard include/zel/*.h) include/zel/z80_types.tab + doxygen + +pdf: doc/$(distname).pdf + +doc/$(distname).pdf: doc + $(MAKE) -C doc/latex -j1 + cp doc/latex/refman.pdf doc/$(distname).pdf + +html: doc + +man: doc + +# XXX: Install the man pages once those get sorted out +install: + $(INSTALL) -d $(DESTDIR)$(libdir) + $(INSTALL_PROGRAM) libzel.a $(DESTDIR)$(libdir) + $(INSTALL) -d $(DESTDIR)$(includedir)/zel + $(INSTALL_DATA) include/zel/z80.h $(DESTDIR)$(includedir)/zel + $(INSTALL_DATA) include/zel/z80_instructions.h $(DESTDIR)$(includedir)/zel + $(INSTALL_DATA) include/zel/z80_types.h $(DESTDIR)$(includedir)/zel + $(INSTALL_DATA) include/zel/z80_types.tab $(DESTDIR)$(includedir)/zel + +uninstall: uninstall-doc + $(RM) $(DESTDIR)$(libdir)/libzel.a + $(RM) $(DESTDIR)$(includedir)/zel/z80.h + $(RM) $(DESTDIR)$(includedir)/zel/z80_instructions.h + $(RM) $(DESTDIR)$(includedir)/zel/z80_types.h + $(RM) $(DESTDIR)$(includedir)/zel/z80_types.tab + rmdir $(DESTDIR)$(includedir)/zel + +install-doc: install-html install-pdf + +uninstall-doc: + $(RM) -r $(DESTDIR)$(htmldir)/html + $(RM) $(DESTDIR)$(pdfdir)/$(distname).pdf + rmdir $(DESTDIR)$(htmldir) + if [ x$(DESTDIR)$(htmldir) != x$(DESTDIR)$(pdfdir) ]; then \ + rmdir $(DESTDIR)$(pdfdir); \ + fi + +install-html: + $(INSTALL) -d $(DESTDIR)$(htmldir)/html + $(INSTALL_DATA) doc/html/* $(DESTDIR)$(htmldir)/html + +install-pdf: + $(INSTALL) -d $(DESTDIR)$(pdfdir) + $(INSTALL_DATA) doc/$(distname).pdf $(DESTDIR)$(pdfdir) + +dist: $(distname).tar.gz + +$(distname).tar.gz: $(dist_source) + mkdir $(distname) + for i in $(dist_source); do \ + d=`dirname $$i`; \ + mkdir -p $(distname)/$$d; \ + cp $$i $(distname)/$$i; \ + done + cp -r doc/html $(distname)/doc + cp -r doc/man $(distname)/doc + tar zcf $(distname).tar.gz $(distname) + $(RM) -r $(distname) + +distcheck: $(distname).tar.gz + tar zxf $(distname).tar.gz + $(MAKE) -C $(distname) prefix=$(here)/$(distname)/_inst check + $(MAKE) -C $(distname) prefix=$(here)/$(distname)/_inst doc + $(MAKE) -C $(distname) prefix=$(here)/$(distname)/_inst install + $(MAKE) -C $(distname) prefix=$(here)/$(distname)/_inst install-doc + $(MAKE) -C $(distname) prefix=$(here)/$(distname)/_inst installcheck + $(MAKE) -C $(distname) prefix=$(here)/$(distname)/_inst uninstall + $(RM) -r $(distname) + +distclean: clean +mostlyclean: clean +maintainer-clean: clean + $(RM) include/zel/z80_types.tab $(itables) diff --git a/include/zel/z80.h b/include/zel/z80.h new file mode 100644 index 0000000..dba7a05 --- /dev/null +++ b/include/zel/z80.h @@ -0,0 +1,219 @@ +/* Copyright (c) 2008 Steve Checkoway + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/*! \file + * + * Create and run a z80 processor instance. + * \author Steve Checkoway + * \version 0.1 + * \date 2008 + */ +#ifndef ZEL_Z80_H +#define ZEL_Z80_H + +#include +#ifdef __cplusplus +extern "C" { +#else +#include +#endif + +#include + +/*! Opaque type representing a z80 processor. */ +typedef struct Z80_t *Z80; + +/* NOTE: Changing the order of these requires changing z80_instructions.h! */ +/*! 16 bit paired z80 registers. The registers ending in P are the + * primed registers. + */ +enum +{ + REG_BC, //!< z80 register bc. + REG_DE, //!< z80 register de. + REG_HL, //!< z80 register hl. + REG_AF, //!< z80 register af. + REG_IX, //!< z80 register ix. + REG_IY, //!< z80 register iy. + REG_PC, //!< z80 register pc. + REG_SP, //!< z80 register sp. + REG_BCP, //!< z80 register bc'. + REG_DEP, //!< z80 register de'. + REG_HLP, //!< z80 register hl'. + REG_AFP, //!< z80 register af'. + REG_IR, //!< z80 register ir. + NUM_REG, //!< Number of 16 bit z80 paired registers. +}; + +/*! Enumerated value describing the control flow of the processor. + * \sa Z80FunctionBlock + */ +typedef enum +{ + CF_CALL, //!< Call instruction. + CF_JUMP, //!< Jump instruction. + CF_RETURN, //!< Return instruction. + CF_RETURN_I, //!< Return from interrupt instruction. + CF_RETURN_N, //!< Return from nonmaskable interrupt instruction. + CF_RESTART, //!< Restart instruction. + CF_INTERRUPT, //!< Maskable interrupt. + CF_NMI, //!< Nonmaskable interrupt. + CF_HALT, //!< Halt instruction. +} ControlFlowType; + +/*! A block of callbacks used by Z80_New() to control how the + * z80 interracts with its peripherials. + * \headerfile z80.h zel/z80.h + */ +typedef struct +{ + /*! Read a byte of memory. + * \param addr The address to read. + * \param inst True if the z80 is reading instructions. + * \param cpu The \c Z80 instance making the read call. + * \return The byte from memory. + */ + byte (*ReadMem)(word addr, bool inst, Z80 cpu); + /*! Write a byte of memory. + * \param addr The address to write. + * \param val The byte to write. + * \param cpu The \c Z80 instance making the write call. + */ + void (*WriteMem)(word addr, byte val, Z80 cpu); + /*! Read the interrupt data. + * \param n Read the \a n th byte of data. + * \param cpu The \c Z80 instance making the read call. + */ + byte (*ReadInterruptData)(word n, Z80 cpu); + /*! Read a byte from an I/O port. + * \param addr The contents of the address bus during the + * request. The low 8 bits specify the port. + * \param cpu The \c Z80 instance making the read call. + * \return The byte from the I/O port. + */ + byte (*ReadIO)(word addr, Z80 cpu); + /*! Write a byte from an I/O port. + * \param addr The contents of the address bus during the + * request. The low 8 bits specify the port. + * \param val The byte to write. + * \param cpu The \c Z80 instance making the read call. + */ + void (*WriteIO)(word addr, byte val, Z80 cpu); + /*! Notify the peripherials that a return from interrupt + * instruction has occured. + * \param cpu The \c Z80 instance performing the notification. + */ + void (*InterruptComplete)(Z80 cpu); + /*! Optional notification of control flow. This can be set to + * \c NULL if notification is not desired. + * \param pc The address of the current instruction. + * \param target The target address of the instruction. For + * example, the jump target. + * \param type The type of control flow. + * \param cpu The \c Z80 instance performing the notification. + */ + void (*ControlFlow)(word pc, word target, ControlFlowType type, Z80 cpu); +} Z80FunctionBlock; + +/*! Create a new \c Z80 instance using the callbacks specified in \a blk. + * \param blk A pointer to a block of callbacks. Only + * Z80FunctionBlock.ControlFlow() may be \c NULL. + * \return The new \c Z80 instance. + */ +Z80 Z80_New( const Z80FunctionBlock *blk ); + +/*! Frees the memory associated with \a cpu. + * \param cpu The \c Z80 instance to free. + */ +void Z80_Free( Z80 cpu ); + +/*! Perform a single step of the processor cpu. + * \param outPC If non\c NULL, \a *outPC is set to the program counter after + * the current instruction is executed. + * \param cpu The \c Z80 instance to step. + * \return The number of clock ticks that have elapsed while executing + * the instruction. + */ +int Z80_Step( word *outPC, Z80 cpu ); + +/*! Check if \a cpu has halted. + * \param cpu The \c Z80 instance. + * \return \c true if \a cpu has halted. + */ +bool Z80_HasHalted( Z80 cpu ); + +/*! Get a 16 bit paired register. + * \param reg The register to get. + * \param cpu The \c Z80 instance. + * \return The contents of the register specified by \a reg. + */ +word Z80_GetReg( int reg, Z80 cpu ); + +/*! Set a 16 bit paired register. + * \param reg The register to set. + * \param value The value to assign to the register. + * \param cpu The \c Z80 instance. + */ +void Z80_SetReg( int reg, word value, Z80 cpu ); + +/*! Disassemble the z80 instruction pointed to by \a address into \a buffer. + * \param address The address of the beginning the instruction. + * \param buffer A pointer to at least 25 bytes of storage. If buffer + * is \c NULL, then the instruction is not disassembled and only the + * length is returned. + * \param cpu The \c Z80 instance. The Z80FunctionBlock.ReadMem() + * function will be called to read the instructions. + * \return The length of the instruction in bytes. + */ +int Z80_Disassemble( word address, char *buffer, Z80 cpu ); + +/*! Simulate the NMI pin going active. This causes the z80 to jump to + * the nmi handler. + * \param cpu The Z80 instance. + */ +void Z80_RaiseNMI( Z80 cpu ); + +/*! Simulate the interrupt pin going active. If interrupts are not + * disabled, then the z80 handles the interrupt according to the + * interrupt mode. + * \param cpu The Z80 instance. + */ +void Z80_RaiseInterrupt( Z80 cpu ); + +/*! Cause the z80 to reissue the I/O instruction. This only has an + * effect when called during the Z80FunctionBlock.ReadIO() or + * Z80FunctionBlock.WriteIO() callbacks. It is to enable debugging by + * breaking on I/O. + * \param cpu The \c Z80 instance. + */ +void Z80_RestartIO( Z80 cpu ); + +/*! Clear the halt condition. Causes the processor to continue + * fetching instructions rather than performing NOPs. + * \param cpu The \c Z80 instance. + */ +void Z80_ClearHalt( Z80 cpu ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/zel/z80_instructions.h b/include/zel/z80_instructions.h new file mode 100644 index 0000000..616e56a --- /dev/null +++ b/include/zel/z80_instructions.h @@ -0,0 +1,252 @@ +/* Copyright (c) 2008 Steve Checkoway + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/*! \file + * + * Functions for decoding and disassembling z80 instructions. + * \author Steve Checkoway + * \version 0.1 + * \date 2008 + */ +#ifndef ZEL_Z80_INSTRUCTIONS_H +#define ZEL_Z80_INSTRUCTIONS_H + +#define _GNU_SOURCE +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#else +#include +#endif + +#include + +/*! The type of a z80 instruction. Many z80 instructions are similar + * and share a common type. For example, add a,b and + * add a,c have the same type. + * + * The type of each instruction can be decoded as follows. Given an + * instruction \c FOO_BAR_BAZ, \c FOO is the mnemonic, \c BAR is the + * type of the first operand and \c BAZ is the type of the second. The + * operand types are as follows: + * - \c N 8 bit immediate + * - \c NN 16 bit immediate + * - \c I 8 bit signed displacement from an index register + * - \c R 8 bit register + * - \c RR 16 bit paired register + * - \c MRR 16 bit paired register used as an address + * - \c MNN 16 bit immediate used as an address + */ +typedef enum +{ +#include +//! \includedoc z80_types.tab +} InstructionType; + +#ifndef BYTE_ORDER +#error define BYTE_ORDER +#endif +#if BYTE_ORDER == BIG_ENDIAN +/*! Register values for the 8 bit registers which comprise the 16 bit + * paired registers. + */ +enum +{ + REG_B, //!< z80 register b. + REG_C, //!< z80 register c. + REG_D, //!< z80 register d. + REG_E, //!< z80 register e. + REG_H, //!< z80 register h. + REG_L, //!< z80 register l. + REG_A, //!< z80 register a. + REG_F, //!< z80 register f. + REG_IXH, //!< z80 register ixh. + REG_IXL, //!< z80 register ixl. + REG_IYH, //!< z80 register iyh. + REG_IYL, //!< z80 register iyl. + REG_PCH, //!< z80 register pch. + REG_PCL, //!< z80 register pcl. + /* No REG_SPH */ + /* No REG_SPL */ + /* No REG_BP */ + /* No REG_CP */ + /* No REG_DP */ + /* No REG_EP */ + /* No REG_HP */ + /* No REG_LP */ + /* No REG_AP */ + /* No REG_FP */ + REG_I = 24, //!< z80 register I. Interrupt page address register. + REG_R, //!< z80 register r. Memory refresh register. + INV = 0xff, //!< Invalid. +}; +#elif BYTE_ORDER == LITTLE_ENDIAN +/*! Register values for the 8 bit registers which comprise the 16 bit + * paired registers. + */ +enum +{ + REG_C, //!< z80 register c. + REG_B, //!< z80 register b. + REG_E, //!< z80 register e. + REG_D, //!< z80 register d. + REG_L, //!< z80 register l. + REG_H, //!< z80 register h. + REG_F, //!< z80 register f. + REG_A, //!< z80 register a. + REG_IXL, //!< z80 register ixl. + REG_IXH, //!< z80 register ixh. + REG_IYL, //!< z80 register iyl. + REG_IYH, //!< z80 register iyh. + REG_PCL, //!< z80 register pcl. + REG_PCH, //!< z80 register pch. + /* No single byte regs */ + REG_R = 24, //!< z80 register r. Memory refresh register. + REG_I, //!< z80 register I. Interrupt page address register. + INV = 0xff, //!< Invalid. +}; +#else +#error What endianness are you using? +#endif + +/*! Condition flag bits as stored in register \c f. + * The flags \c x and \c y are listed as unspecified by the z80 CPU + * User's Manual but they are modified by a number of instructions. + */ +enum +{ + FLAG_C, //!< Carry flag. + FLAG_N, //!< Add/subtract flag. + FLAG_P, //!< Parity/overflow flag (P/V). + FLAG_X, //!< Flag 3. + FLAG_H, //!< Half-carry flag. + FLAG_Y, //!< Flag 5. + FLAG_Z, //!< Zero flag. + FLAG_S, //!< Sign flag. +}; + +/*! Condition flags. The condition is met if the corresponding flag is + * set appropriately. + */ +enum +{ + COND_NZ = -FLAG_Z-1, //!< Flag Z is reset. + COND_Z = FLAG_Z, //!< Flag Z is set. + COND_NC = -FLAG_C-1, //!< Flag C is reset. + COND_C = FLAG_C, //!< Flag C is set. + COND_PO = -FLAG_P-1, //!< Flag P/V is reset. + COND_PE = FLAG_P, //!< Flag P/V is set. + COND_P = -FLAG_S-1, //!< Flag S is reset. + COND_M = FLAG_S, //!< Flag S is set. +}; + +/* Exactly two instructions contain both an offset and an immediate: + * dd36 d n: ld (ix+d),n + * fd36 d n: ld (iy+d),n */ +/*! Describes the layout of the operands for an instruction. */ +enum +{ + TYPE_NONE, //!< No operands. + TYPE_IMM_N, //!< 8 bit immediate. + TYPE_IMM_NN, //!< 16 bit immediate. + TYPE_OFFSET, //!< 8 bit signed offset. + TYPE_DISP, //!< 8 bit signed offset - 2. + TYPE_OFFSET_IMM_N, //!< 8 bit signed offset and 8 bit immediate. +}; + +// 4 (3) words native sized words on 32 (64) bit machine. +/*! Uniform template for the instruction tables. + * \headerfile z80_instructions.h zel/z80_instructions.h + */ +typedef struct +{ + InstructionType type; //!< Type of the instruction. + int16_t operand1; //!< Type of the first operand, if any. + int16_t operand2; //!< Type of the second operand, if any. + int16_t extra; //!< Type of third operand or tstates when a branch is taken, if applicable. + uint8_t tstates; //!< Base number of clock ticks the instruction takes. + uint8_t operand_types; //!< Operand layout in memory for the instruction. + const char *format; //!< Format specifier string for disassembly. +} InstructionTemplate; + +/*! Completely describes an instruction. + * \headerfile z80_instructions.h zel/z80_instructions.h + */ +typedef struct +{ + const InstructionTemplate *IT; //!< Template for the instruction. + unsigned int immediate; //!< Immediate value, if any. + unsigned int additional_tstates;//!< Additional clock ticks. + unsigned int r_increment; //!< Amount by which the \c r register is incremented. + int offset; //!< Offset, if any. +} Instruction; + + +/*! Instruction table for unprefixed instructions. */ +extern const InstructionTemplate Unprefixed[256]; +/*! Instruction table for cb prefixed instructions. */ +extern const InstructionTemplate CB_Prefixed[256]; +/*! Instruction table for dd prefixed instructions. */ +extern const InstructionTemplate DD_Prefixed[256]; +/*! Instruction table for ddcb prefixed instructions. */ +extern const InstructionTemplate DDCB_Prefixed[256]; +/*! Instruction table for ed prefixed instructions. */ +extern const InstructionTemplate ED_Prefixed[256]; +/*! Instruction table for fd prefixed instructions. */ +extern const InstructionTemplate FD_Prefixed[256]; +/*! Instruction table for fdcb prefixed instructions. */ +extern const InstructionTemplate FDCB_Prefixed[256]; + +/*! Memory reading callback. + * \param addr The address to read. + * \param data Callback data from IF_ID(). + * \return The value at address \a addr. + */ +typedef byte (*ReadMemFunction)(word addr, void *data); + +/*! Instruction fetch and instruction decode. Fetchs and decodes the + * instruction pointed to by \a address into \a *inst. + * \param inst Pointer to an \c Instruction. \a *inst is set to the + * decoded instruction. + * \param address The address of the instruction. + * \param ReadMem Called repeatedly to get bytes of the instruction. + * \a data is passed as the \c data argument. + * \param data Arbitrary data passed to the \a ReadMem callback. + * \return The length of the instruction. + */ +int IF_ID( Instruction *inst, word address, ReadMemFunction ReadMem, void *data ); + +/*! Disassemble the instruction pointed to by \a inst into \a buffer. + * \param inst Pointer to an \c Instruction. + * \param buffer Buffer into which the disassembly is written. It must + * be large enough to hold 25 bytes. + */ +void DisassembleInstruction( const Instruction *inst, char *buffer ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/zel/z80_types.h b/include/zel/z80_types.h new file mode 100644 index 0000000..147cfae --- /dev/null +++ b/include/zel/z80_types.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2008 Steve Checkoway + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/*! \file + * + * Types used by the z80. + * \author Steve Checkoway + * \version 0.1 + * \date 2008 + */ +#ifndef ZEL_Z80_TYPES_H +#define ZEL_Z80_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*! A single byte. */ +typedef uint8_t byte; +/*! A signed byte used for displacement. */ +typedef int8_t sbyte; +/*! A 16 bit z80 word. */ +typedef uint16_t word; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tables/cb_prefix.spec b/tables/cb_prefix.spec new file mode 100644 index 0000000..62599a9 --- /dev/null +++ b/tables/cb_prefix.spec @@ -0,0 +1,256 @@ +CB00 RLC B 8 2 2 +CB01 RLC C 8 2 2 +CB02 RLC D 8 2 2 +CB03 RLC E 8 2 2 +CB04 RLC H 8 2 2 +CB05 RLC L 8 2 2 +CB06 RLC (HL) 15 4 2 +CB07 RLC A 8 2 2 +CB08 RRC B 8 2 2 +CB09 RRC C 8 2 2 +CB0A RRC D 8 2 2 +CB0B RRC E 8 2 2 +CB0C RRC H 8 2 2 +CB0D RRC L 8 2 2 +CB0E RRC (HL) 15 4 2 +CB0F RRC A 8 2 2 +CB10 RL B 8 2 2 +CB11 RL C 8 2 2 +CB12 RL D 8 2 2 +CB13 RL E 8 2 2 +CB14 RL H 8 2 2 +CB15 RL L 8 2 2 +CB16 RL (HL) 15 4 2 +CB17 RL A 8 2 2 +CB18 RR B 8 2 2 +CB19 RR C 8 2 2 +CB1A RR D 8 2 2 +CB1B RR E 8 2 2 +CB1C RR H 8 2 2 +CB1D RR L 8 2 2 +CB1E RR (HL) 15 4 2 +CB1F RR A 8 2 2 +CB20 SLA B 8 2 2 +CB21 SLA C 8 2 2 +CB22 SLA D 8 2 2 +CB23 SLA E 8 2 2 +CB24 SLA H 8 2 2 +CB25 SLA L 8 2 2 +CB26 SLA (HL) 15 4 2 +CB27 SLA A 8 2 2 +CB28 SRA B 8 2 2 +CB29 SRA C 8 2 2 +CB2A SRA D 8 2 2 +CB2B SRA E 8 2 2 +CB2C SRA H 8 2 2 +CB2D SRA L 8 2 2 +CB2E SRA (HL) 15 4 2 +CB2F SRA A 8 2 2 +CB30 SLL B 8 2 2 +CB31 SLL C 8 2 2 +CB32 SLL D 8 2 2 +CB33 SLL E 8 2 2 +CB34 SLL H 8 2 2 +CB35 SLL L 8 2 2 +CB36 SLL (HL) 15 4 2 +CB37 SLL A 8 2 2 +CB38 SRL B 8 2 2 +CB39 SRL C 8 2 2 +CB3A SRL D 8 2 2 +CB3B SRL E 8 2 2 +CB3C SRL H 8 2 2 +CB3D SRL L 8 2 2 +CB3E SRL (HL) 15 4 2 +CB3F SRL A 8 2 2 +CB40 BIT 0,B 8 2 2 +CB41 BIT 0,C 8 2 2 +CB42 BIT 0,D 8 2 2 +CB43 BIT 0,E 8 2 2 +CB44 BIT 0,H 8 2 2 +CB45 BIT 0,L 8 2 2 +CB46 BIT 0,(HL) 12 3 2 +CB47 BIT 0,A 8 2 2 +CB48 BIT 1,B 8 2 2 +CB49 BIT 1,C 8 2 2 +CB4A BIT 1,D 8 2 2 +CB4B BIT 1,E 8 2 2 +CB4C BIT 1,H 8 2 2 +CB4D BIT 1,L 8 2 2 +CB4E BIT 1,(HL) 12 3 2 +CB4F BIT 1,A 8 2 2 +CB50 BIT 2,B 8 2 2 +CB51 BIT 2,C 8 2 2 +CB52 BIT 2,D 8 2 2 +CB53 BIT 2,E 8 2 2 +CB54 BIT 2,H 8 2 2 +CB55 BIT 2,L 8 2 2 +CB56 BIT 2,(HL) 12 3 2 +CB57 BIT 2,A 8 2 2 +CB58 BIT 3,B 8 2 2 +CB59 BIT 3,C 8 2 2 +CB5A BIT 3,D 8 2 2 +CB5B BIT 3,E 8 2 2 +CB5C BIT 3,H 8 2 2 +CB5D BIT 3,L 8 2 2 +CB5E BIT 3,(HL) 12 3 2 +CB5F BIT 3,A 8 2 2 +CB60 BIT 4,B 8 2 2 +CB61 BIT 4,C 8 2 2 +CB62 BIT 4,D 8 2 2 +CB63 BIT 4,E 8 2 2 +CB64 BIT 4,H 8 2 2 +CB65 BIT 4,L 8 2 2 +CB66 BIT 4,(HL) 12 3 2 +CB67 BIT 4,A 8 2 2 +CB68 BIT 5,B 8 2 2 +CB69 BIT 5,C 8 2 2 +CB6A BIT 5,D 8 2 2 +CB6B BIT 5,E 8 2 2 +CB6C BIT 5,H 8 2 2 +CB6D BIT 5,L 8 2 2 +CB6E BIT 5,(HL) 12 3 2 +CB6F BIT 5,A 8 2 2 +CB70 BIT 6,B 8 2 2 +CB71 BIT 6,C 8 2 2 +CB72 BIT 6,D 8 2 2 +CB73 BIT 6,E 8 2 2 +CB74 BIT 6,H 8 2 2 +CB75 BIT 6,L 8 2 2 +CB76 BIT 6,(HL) 12 3 2 +CB77 BIT 6,A 8 2 2 +CB78 BIT 7,B 8 2 2 +CB79 BIT 7,C 8 2 2 +CB7A BIT 7,D 8 2 2 +CB7B BIT 7,E 8 2 2 +CB7C BIT 7,H 8 2 2 +CB7D BIT 7,L 8 2 2 +CB7E BIT 7,(HL) 12 3 2 +CB7F BIT 7,A 8 2 2 +CB80 RES 0,B 8 2 2 +CB81 RES 0,C 8 2 2 +CB82 RES 0,D 8 2 2 +CB83 RES 0,E 8 2 2 +CB84 RES 0,H 8 2 2 +CB85 RES 0,L 8 2 2 +CB86 RES 0,(HL) 15 4 2 +CB87 RES 0,A 8 2 2 +CB88 RES 1,B 8 2 2 +CB89 RES 1,C 8 2 2 +CB8A RES 1,D 8 2 2 +CB8B RES 1,E 8 2 2 +CB8C RES 1,H 8 2 2 +CB8D RES 1,L 8 2 2 +CB8E RES 1,(HL) 15 4 2 +CB8F RES 1,A 8 2 2 +CB90 RES 2,B 8 2 2 +CB91 RES 2,C 8 2 2 +CB92 RES 2,D 8 2 2 +CB93 RES 2,E 8 2 2 +CB94 RES 2,H 8 2 2 +CB95 RES 2,L 8 2 2 +CB96 RES 2,(HL) 15 4 2 +CB97 RES 2,A 8 2 2 +CB98 RES 3,B 8 2 2 +CB99 RES 3,C 8 2 2 +CB9A RES 3,D 8 2 2 +CB9B RES 3,E 8 2 2 +CB9C RES 3,H 8 2 2 +CB9D RES 3,L 8 2 2 +CB9E RES 3,(HL) 15 4 2 +CB9F RES 3,A 8 2 2 +CBA0 RES 4,B 8 2 2 +CBA1 RES 4,C 8 2 2 +CBA2 RES 4,D 8 2 2 +CBA3 RES 4,E 8 2 2 +CBA4 RES 4,H 8 2 2 +CBA5 RES 4,L 8 2 2 +CBA6 RES 4,(HL) 15 4 2 +CBA7 RES 4,A 8 2 2 +CBA8 RES 5,B 8 2 2 +CBA9 RES 5,C 8 2 2 +CBAA RES 5,D 8 2 2 +CBAB RES 5,E 8 2 2 +CBAC RES 5,H 8 2 2 +CBAD RES 5,L 8 2 2 +CBAE RES 5,(HL) 15 4 2 +CBAF RES 5,A 8 2 2 +CBB0 RES 6,B 8 2 2 +CBB1 RES 6,C 8 2 2 +CBB2 RES 6,D 8 2 2 +CBB3 RES 6,E 8 2 2 +CBB4 RES 6,H 8 2 2 +CBB5 RES 6,L 8 2 2 +CBB6 RES 6,(HL) 15 4 2 +CBB7 RES 6,A 8 2 2 +CBB8 RES 7,B 8 2 2 +CBB9 RES 7,C 8 2 2 +CBBA RES 7,D 8 2 2 +CBBB RES 7,E 8 2 2 +CBBC RES 7,H 8 2 2 +CBBD RES 7,L 8 2 2 +CBBE RES 7,(HL) 15 4 2 +CBBF RES 7,A 8 2 2 +CBC0 SET 0,B 8 2 2 +CBC1 SET 0,C 8 2 2 +CBC2 SET 0,D 8 2 2 +CBC3 SET 0,E 8 2 2 +CBC4 SET 0,H 8 2 2 +CBC5 SET 0,L 8 2 2 +CBC6 SET 0,(HL) 15 4 2 +CBC7 SET 0,A 8 2 2 +CBC8 SET 1,B 8 2 2 +CBC9 SET 1,C 8 2 2 +CBCA SET 1,D 8 2 2 +CBCB SET 1,E 8 2 2 +CBCC SET 1,H 8 2 2 +CBCD SET 1,L 8 2 2 +CBCE SET 1,(HL) 15 4 2 +CBCF SET 1,A 8 2 2 +CBD0 SET 2,B 8 2 2 +CBD1 SET 2,C 8 2 2 +CBD2 SET 2,D 8 2 2 +CBD3 SET 2,E 8 2 2 +CBD4 SET 2,H 8 2 2 +CBD5 SET 2,L 8 2 2 +CBD6 SET 2,(HL) 15 4 2 +CBD7 SET 2,A 8 2 2 +CBD8 SET 3,B 8 2 2 +CBD9 SET 3,C 8 2 2 +CBDA SET 3,D 8 2 2 +CBDB SET 3,E 8 2 2 +CBDC SET 3,H 8 2 2 +CBDD SET 3,L 8 2 2 +CBDE SET 3,(HL) 15 4 2 +CBDF SET 3,A 8 2 2 +CBE0 SET 4,B 8 2 2 +CBE1 SET 4,C 8 2 2 +CBE2 SET 4,D 8 2 2 +CBE3 SET 4,E 8 2 2 +CBE4 SET 4,H 8 2 2 +CBE5 SET 4,L 8 2 2 +CBE6 SET 4,(HL) 15 4 2 +CBE7 SET 4,A 8 2 2 +CBE8 SET 5,B 8 2 2 +CBE9 SET 5,C 8 2 2 +CBEA SET 5,D 8 2 2 +CBEB SET 5,E 8 2 2 +CBEC SET 5,H 8 2 2 +CBED SET 5,L 8 2 2 +CBEE SET 5,(HL) 15 4 2 +CBEF SET 5,A 8 2 2 +CBF0 SET 6,B 8 2 2 +CBF1 SET 6,C 8 2 2 +CBF2 SET 6,D 8 2 2 +CBF3 SET 6,E 8 2 2 +CBF4 SET 6,H 8 2 2 +CBF5 SET 6,L 8 2 2 +CBF6 SET 6,(HL) 15 4 2 +CBF7 SET 6,A 8 2 2 +CBF8 SET 7,B 8 2 2 +CBF9 SET 7,C 8 2 2 +CBFA SET 7,D 8 2 2 +CBFB SET 7,E 8 2 2 +CBFC SET 7,H 8 2 2 +CBFD SET 7,L 8 2 2 +CBFE SET 7,(HL) 15 4 2 +CBFF SET 7,A 8 2 2 diff --git a/tables/dd_prefix.spec b/tables/dd_prefix.spec new file mode 100644 index 0000000..95fff4d --- /dev/null +++ b/tables/dd_prefix.spec @@ -0,0 +1,252 @@ +DD00 NOP 8 +DD01 n n LD BC,nn 14 +DD02 LD (BC),A 11 +DD03 INC BC 10 +DD04 INC B 8 +DD05 DEC B 8 +DD06 n LD B,n 11 +DD07 RLCA 8 +DD08 EX AF,AF' 8 +DD09 ADD IX,BC 15 +DD0A LD A,(BC) 11 +DD0B DEC BC 10 +DD0C INC C 8 +DD0D DEC C 8 +DD0E n LD C,n 11 +DD0F RRCA 8 +DD10 e DJNZ (PC+e) 12/17 +DD11 n n LD DE,nn 14 +DD12 LD (DE),A 11 +DD13 INC DE 10 +DD14 INC D 8 +DD15 DEC D 8 +DD16 n LD D,n 11 +DD17 RLA 8 +DD18 e JR (PC+e) 16 +DD19 ADD IX,DE 15 +DD1A LD A,(DE) 11 +DD1B DEC DE 10 +DD1C INC E 8 +DD1D DEC E 8 +DD1E n LD E,n 11 +DD1F RRA 8 +DD20 e JR NZ,(PC+e) 16/11 +DD21 n n LD IX,nn 14 +DD22 n n LD (nn),IX 16 +DD23 INC IX 10 +DD24 INC IXH 10 guess +DD25 DEC IXH 10 guess +DD26 n LD IXH,n 11 guess +DD27 DAA 8 +DD28 e JR Z,(PC+e) 16/11 +DD29 ADD IX,IX 15 +DD2A n n LD IX,(nn) 14 +DD2B DEC IX 10 +DD2C INC IXL 10 guess +DD2D DEC IXL 10 guess +DD2E n LD IXL,n 11 guess +DD2F CPL 8 +DD30 e JR NC,(PC+e) 16/11 +DD31 n n LD SP,nn 14 +DD32 n n LD (nn),A 17 +DD33 INC SP 10 +DD34 d INC (IX+d) 23 +DD35 d DEC (IX+d) 23 +DD36 d n LD (IX+d),n 19 +DD37 SCF 8 +DD38 e JR c,(PC+e) 16/11 +DD39 ADD IX,SP 15 +DD3A n n LD A,(nn) 17 +DD3B DEC SP 10 +DD3C INC A 8 +DD3D DEC A 8 +DD3E n LD A,n 11 +DD3F CCF 8 +DD40 LD B,B 8 +DD41 LD B,C 8 +DD42 LD B,D 8 +DD43 LD B,E 8 +DD44 LD B,IXH 8 guess +DD45 LD B,IXL 8 guess +DD46 d LD B,(IX+d) 19 +DD47 LD B,A 8 +DD48 LD C,B 8 +DD49 LD C,C 8 +DD4A LD C,D 8 +DD4B LD C,E 8 +DD4C LD C,IXH 8 guess +DD4D LD C,IXL 8 guess +DD4E d LD C,(IX+d) 19 +DD4F LD C,A 8 +DD50 LD D,B 8 +DD51 LD D,C 8 +DD52 LD D,D 8 +DD53 LD D,E 8 +DD54 LD D,IXH 8 guess +DD55 LD D,IXL 8 guess +DD56 d LD D,(IX+d) 19 +DD57 LD D,A 8 +DD58 LD E,B 8 +DD59 LD E,C 8 +DD5A LD E,D 8 +DD5B LD E,E 8 +DD5C LD E,IXH 8 guess +DD5D LD E,IXL 8 guess +DD5E d LD E,(IX+d) 19 +DD5F LD E,A 8 +DD60 LD IXH,B 8 guess +DD61 LD IXH,C 8 guess +DD62 LD IXH,D 8 guess +DD63 LD IXH,E 8 guess +DD64 LD IXH,IXH 8 guess +DD65 LD IXH,IXL 8 guess +DD66 d LD H,(IX+d) 19 +DD67 LD IXH,A 8 guess +DD68 LD IXL,B 8 guess +DD69 LD IXL,C 8 guess +DD6A LD IXL,D 8 guess +DD6B LD IXL,E 8 guess +DD6C LD IXL,IXH 8 guess +DD6D LD IXL,IXL 8 guess +DD6E d LD L,(IX+d) 19 +DD6F LD IXL,A 8 guess +DD70 d LD (IX+d),B 19 +DD71 d LD (IX+d),C 19 +DD72 d LD (IX+d),D 19 +DD73 d LD (IX+d),E 19 +DD74 d LD (IX+d),H 19 +DD75 d LD (IX+d),L 19 +DD76 HALT 8 +DD77 d LD (IX+d),A 19 +DD78 LD A,B 8 +DD79 LD A,C 8 +DD7A LD A,D 8 +DD7B LD A,E 8 +DD7C LD A,IXH 8 guess +DD7D LD A,IXL 8 guess +DD7E d LD A,(IX+d) 19 +DD7F LD A,A 8 +DD80 ADD A,B 8 +DD81 ADD A,C 8 +DD82 ADD A,D 8 +DD83 ADD A,E 8 +DD84 ADD A,IXH 8 guess +DD85 ADD A,IXL 8 guess +DD86 d ADD A,(IX+d) 19 +DD87 ADD A,A 8 +DD88 ADC A,B 8 +DD89 ADC A,C 8 +DD8A ADC A,D 8 +DD8B ADC A,E 8 +DD8C ADC A,IXH 8 guess +DD8D ADC A,IXL 8 guess +DD8E d ADC A,(IX+d) 19 +DD8F ADC A,A 8 +DD90 SUB B 8 +DD91 SUB C 8 +DD92 SUB D 8 +DD93 SUB E 8 +DD94 SUB IXH 8 guess +DD95 SUB IXL 8 guess +DD96 d SUB (IX+d) 19 +DD97 SUB A 8 +DD98 SBC A,B 8 +DD99 SBC A,C 8 +DD9A SBC A,D 8 +DD9B SBC A,E 8 +DD9C SBC A,IXH 8 guess +DD9D SBC A,IXL 8 guess +DD9E d SBC A,(IX+d) 19 +DD9F SBC A,A 8 +DDA0 AND B 8 +DDA1 AND C 8 +DDA2 AND D 8 +DDA3 AND E 8 +DDA4 AND IXH 8 guess +DDA5 AND IXL 8 guess +DDA6 d AND (IX+d) 19 +DDA7 AND A 8 +DDA8 XOR B 8 +DDA9 XOR C 8 +DDAA XOR D 8 +DDAB XOR E 8 +DDAC XOR IXH 8 guess +DDAD XOR IXL 8 guess +DDAE d XOR (IX+d) 19 +DDAF XOR A 8 +DDB0 OR B 8 +DDB1 OR C 8 +DDB2 OR D 8 +DDB3 OR E 8 +DDB4 OR IXH 8 guess +DDB5 OR IXL 8 guess +DDB6 d OR (IX+d) 19 +DDB7 OR A 8 +DDB8 CP B 8 +DDB9 CP C 8 +DDBA CP D 8 +DDBB CP E 8 +DDBC CP IXH 8 guess +DDBD CP IXL 8 guess +DDBE d CP (IX+d) 19 +DDBF CP A 8 +DDC0 RET NZ 15/9 +DDC1 POP BC 14 +DDC2 n n JP NZ,(nn) 14 +DDC3 n n JP (nn) 14 +DDC4 n n CALL NZ,(nn) 21/14 +DDC5 PUSH BC 15 +DDC6 n ADD A,n 11 +DDC7 RST 0H 15 +DDC8 RET Z 15/9 +DDC9 RET 14 +DDCA n n JP Z,(nn) 14 +DDCC n n CALL Z,(nn) 21/14 +DDCD n n CALL (nn) 21 +DDCE n ADC A,n 11 +DDCF RST 8H 15 +DDD0 RET NC 9 +DDD1 POP DE 14 +DDD2 n n JP NC,(nn) 14 +DDD3 n OUT (n),A 15 +DDD4 n n CALL NC,(nn) 21/14 +DDD5 PUSH DE 15 +DDD6 n SUB n 11 +DDD7 RST 10H 15 +DDD8 RET c 9 +DDD9 EXX 8 +DDDA n n JP c,(nn) 14 +DDDB n IN A,(n) 15 +DDDC n n CALL c,(nn) 21/14 +DDDE n SBC A,n 19 +DDDF RST 18H 15 +DDE0 RET PO 15/9 +DDE1 POP IX 14 +DDE2 n n JP PO,(nn) 14 +DDE3 EX (SP),IX 23 +DDE4 n n CALL PO,(nn) 21/14 +DDE5 PUSH IX 15 +DDE6 n AND n 11 +DDE7 RST 20H 15 +DDE8 RET PE 15/9 +DDE9 JP (IX) 8 +DDEA n n JP PE,(nn) 14 +DDEB EX DE,HL 8 +DDEC n n CALL PE,(nn) 21/14 +DDEE n XOR n 11 +DDEF RST 28H 15 +DDF0 RET P 15/9 +DDF1 POP AF 14 +DDF2 n n JP P,(nn) 14 +DDF3 DI 8 +DDF4 n n CALL P,(nn) 21/14 +DDF5 PUSH AF 15 +DDF6 n OR n 11 +DDF7 RST 30H 15 +DDF8 RET M 15/9 +DDF9 LD SP,IX 10 +DDFA n n JP M,(nn) 14 +DDFB EI 8 +DDFC n n CALL M,(nn) 21/14 +DDFE n CP n 11 +DDFF RST 38H 15 diff --git a/tables/ddcb_prefix.spec b/tables/ddcb_prefix.spec new file mode 100644 index 0000000..c2bbc46 --- /dev/null +++ b/tables/ddcb_prefix.spec @@ -0,0 +1,256 @@ +DDCB d 00 LD B,RLC (IX+d) 23 +DDCB d 01 LD C,RLC (IX+d) 23 +DDCB d 02 LD D,RLC (IX+d) 23 +DDCB d 03 LD E,RLC (IX+d) 23 +DDCB d 04 LD H,RLC (IX+d) 23 +DDCB d 05 LD L,RLC (IX+d) 23 +DDCB d 06 RLC (IX+d) 23 +DDCB d 07 LD A,RLC (IX+d) 23 +DDCB d 08 LD B,RRC (IX+d) 23 +DDCB d 09 LD C,RRC (IX+d) 23 +DDCB d 0A LD D,RRC (IX+d) 23 +DDCB d 0B LD E,RRC (IX+d) 23 +DDCB d 0C LD H,RRC (IX+d) 23 +DDCB d 0D LD L,RRC (IX+d) 23 +DDCB d 0E RRC (IX+d) 23 +DDCB d 0F LD A,RRC (IX+d) 23 +DDCB d 10 LD B,RL (IX+d) 23 +DDCB d 11 LD C,RL (IX+d) 23 +DDCB d 12 LD D,RL (IX+d) 23 +DDCB d 13 LD E,RL (IX+d) 23 +DDCB d 14 LD H,RL (IX+d) 23 +DDCB d 15 LD L,RL (IX+d) 23 +DDCB d 16 RL (IX+d) 23 +DDCB d 17 LD A,RL (IX+d) 23 +DDCB d 18 LD B,RR (IX+d) 23 +DDCB d 19 LD C,RR (IX+d) 23 +DDCB d 1A LD D,RR (IX+d) 23 +DDCB d 1B LD E,RR (IX+d) 23 +DDCB d 1C LD H,RR (IX+d) 23 +DDCB d 1D LD L,RR (IX+d) 23 +DDCB d 1E RR (IX+d) 23 +DDCB d 1F LD A,RR (IX+d) 23 +DDCB d 20 LD B,SLA (IX+d) 23 +DDCB d 21 LD C,SLA (IX+d) 23 +DDCB d 22 LD D,SLA (IX+d) 23 +DDCB d 23 LD E,SLA (IX+d) 23 +DDCB d 24 LD H,SLA (IX+d) 23 +DDCB d 25 LD L,SLA (IX+d) 23 +DDCB d 26 SLA (IX+d) 23 +DDCB d 27 LD A,SLA (IX+d) 23 +DDCB d 28 LD B,SRA (IX+d) 23 +DDCB d 29 LD C,SRA (IX+d) 23 +DDCB d 2A LD D,SRA (IX+d) 23 +DDCB d 2B LD E,SRA (IX+d) 23 +DDCB d 2C LD H,SRA (IX+d) 23 +DDCB d 2D LD L,SRA (IX+d) 23 +DDCB d 2E SRA (IX+d) 23 +DDCB d 2F LD A,SRA (IX+d) 23 +DDCB d 30 LD B,SLL (IX+d) 23 +DDCB d 31 LD C,SLL (IX+d) 23 +DDCB d 32 LD D,SLL (IX+d) 23 +DDCB d 33 LD E,SLL (IX+d) 23 +DDCB d 34 LD H,SLL (IX+d) 23 +DDCB d 35 LD L,SLL (IX+d) 23 +DDCB d 36 SLL (IX+d) 23 +DDCB d 37 LD A,SLL (IX+d) 23 +DDCB d 38 LD B,SRL (IX+d) 23 +DDCB d 39 LD C,SRL (IX+d) 23 +DDCB d 3A LD D,SRL (IX+d) 23 +DDCB d 3B LD E,SRL (IX+d) 23 +DDCB d 3C LD H,SRL (IX+d) 23 +DDCB d 3D LD L,SRL (IX+d) 23 +DDCB d 3E SRL (IX+d) 23 +DDCB d 3F LD A,SRL (IX+d) 23 +DDCB d 40 BIT 0,(IX+d) 20 +DDCB d 41 BIT 0,(IX+d) 20 +DDCB d 42 BIT 0,(IX+d) 20 +DDCB d 43 BIT 0,(IX+d) 20 +DDCB d 44 BIT 0,(IX+d) 20 +DDCB d 45 BIT 0,(IX+d) 20 +DDCB d 46 BIT 0,(IX+d) 20 +DDCB d 47 BIT 0,(IX+d) 20 +DDCB d 48 BIT 1,(IX+d) 20 +DDCB d 49 BIT 1,(IX+d) 20 +DDCB d 4A BIT 1,(IX+d) 20 +DDCB d 4B BIT 1,(IX+d) 20 +DDCB d 4C BIT 1,(IX+d) 20 +DDCB d 4D BIT 1,(IX+d) 20 +DDCB d 4E BIT 1,(IX+d) 20 +DDCB d 4F BIT 1,(IX+d) 20 +DDCB d 50 BIT 2,(IX+d) 20 +DDCB d 51 BIT 2,(IX+d) 20 +DDCB d 52 BIT 2,(IX+d) 20 +DDCB d 53 BIT 2,(IX+d) 20 +DDCB d 54 BIT 2,(IX+d) 20 +DDCB d 55 BIT 2,(IX+d) 20 +DDCB d 56 BIT 2,(IX+d) 20 +DDCB d 57 BIT 2,(IX+d) 20 +DDCB d 58 BIT 3,(IX+d) 20 +DDCB d 59 BIT 3,(IX+d) 20 +DDCB d 5A BIT 3,(IX+d) 20 +DDCB d 5B BIT 3,(IX+d) 20 +DDCB d 5C BIT 3,(IX+d) 20 +DDCB d 5D BIT 3,(IX+d) 20 +DDCB d 5E BIT 3,(IX+d) 20 +DDCB d 5F BIT 3,(IX+d) 20 +DDCB d 60 BIT 4,(IX+d) 20 +DDCB d 61 BIT 4,(IX+d) 20 +DDCB d 62 BIT 4,(IX+d) 20 +DDCB d 63 BIT 4,(IX+d) 20 +DDCB d 64 BIT 4,(IX+d) 20 +DDCB d 65 BIT 4,(IX+d) 20 +DDCB d 66 BIT 4,(IX+d) 20 +DDCB d 67 BIT 4,(IX+d) 20 +DDCB d 68 BIT 5,(IX+d) 20 +DDCB d 69 BIT 5,(IX+d) 20 +DDCB d 6A BIT 5,(IX+d) 20 +DDCB d 6B BIT 5,(IX+d) 20 +DDCB d 6C BIT 5,(IX+d) 20 +DDCB d 6D BIT 5,(IX+d) 20 +DDCB d 6E BIT 5,(IX+d) 20 +DDCB d 6F BIT 5,(IX+d) 20 +DDCB d 70 BIT 6,(IX+d) 20 +DDCB d 71 BIT 6,(IX+d) 20 +DDCB d 72 BIT 6,(IX+d) 20 +DDCB d 73 BIT 6,(IX+d) 20 +DDCB d 74 BIT 6,(IX+d) 20 +DDCB d 75 BIT 6,(IX+d) 20 +DDCB d 76 BIT 6,(IX+d) 20 +DDCB d 77 BIT 6,(IX+d) 20 +DDCB d 78 BIT 7,(IX+d) 20 +DDCB d 79 BIT 7,(IX+d) 20 +DDCB d 7A BIT 7,(IX+d) 20 +DDCB d 7B BIT 7,(IX+d) 20 +DDCB d 7C BIT 7,(IX+d) 20 +DDCB d 7D BIT 7,(IX+d) 20 +DDCB d 7E BIT 7,(IX+d) 20 +DDCB d 7F BIT 7,(IX+d) 20 +DDCB d 80 LD B,RES 0,(IX+d) 23 +DDCB d 81 LD C,RES 0,(IX+d) 23 +DDCB d 82 LD D,RES 0,(IX+d) 23 +DDCB d 83 LD E,RES 0,(IX+d) 23 +DDCB d 84 LD H,RES 0,(IX+d) 23 +DDCB d 85 LD L,RES 0,(IX+d) 23 +DDCB d 86 RES 0,(IX+d) 23 +DDCB d 87 LD A,RES 0,(IX+d) 23 +DDCB d 88 LD B,RES 1,(IX+d) 23 +DDCB d 89 LD C,RES 1,(IX+d) 23 +DDCB d 8A LD D,RES 1,(IX+d) 23 +DDCB d 8B LD E,RES 1,(IX+d) 23 +DDCB d 8C LD H,RES 1,(IX+d) 23 +DDCB d 8D LD L,RES 1,(IX+d) 23 +DDCB d 8E RES 1,(IX+d) 23 +DDCB d 8F LD A,RES 1,(IX+d) 23 +DDCB d 90 LD B,RES 2,(IX+d) 23 +DDCB d 91 LD C,RES 2,(IX+d) 23 +DDCB d 92 LD D,RES 2,(IX+d) 23 +DDCB d 93 LD E,RES 2,(IX+d) 23 +DDCB d 94 LD H,RES 2,(IX+d) 23 +DDCB d 95 LD L,RES 2,(IX+d) 23 +DDCB d 96 RES 2,(IX+d) 23 +DDCB d 97 LD A,RES 2,(IX+d) 23 +DDCB d 98 LD B,RES 3,(IX+d) 23 +DDCB d 99 LD C,RES 3,(IX+d) 23 +DDCB d 9A LD D,RES 3,(IX+d) 23 +DDCB d 9B LD E,RES 3,(IX+d) 23 +DDCB d 9C LD H,RES 3,(IX+d) 23 +DDCB d 9D LD L,RES 3,(IX+d) 23 +DDCB d 9E RES 3,(IX+d) 23 +DDCB d 9F LD A,RES 3,(IX+d) 23 +DDCB d A0 LD B,RES 4,(IX+d) 23 +DDCB d A1 LD C,RES 4,(IX+d) 23 +DDCB d A2 LD D,RES 4,(IX+d) 23 +DDCB d A3 LD E,RES 4,(IX+d) 23 +DDCB d A4 LD H,RES 4,(IX+d) 23 +DDCB d A5 LD L,RES 4,(IX+d) 23 +DDCB d A6 RES 4,(IX+d) 23 +DDCB d A7 LD A,RES 4,(IX+d) 23 +DDCB d A8 LD B,RES 5,(IX+d) 23 +DDCB d A9 LD C,RES 5,(IX+d) 23 +DDCB d AA LD D,RES 5,(IX+d) 23 +DDCB d AB LD E,RES 5,(IX+d) 23 +DDCB d AC LD H,RES 5,(IX+d) 23 +DDCB d AD LD L,RES 5,(IX+d) 23 +DDCB d AE RES 5,(IX+d) 23 +DDCB d AF LD A,RES 5,(IX+d) 23 +DDCB d B0 LD B,RES 6,(IX+d) 23 +DDCB d B1 LD C,RES 6,(IX+d) 23 +DDCB d B2 LD D,RES 6,(IX+d) 23 +DDCB d B3 LD E,RES 6,(IX+d) 23 +DDCB d B4 LD H,RES 6,(IX+d) 23 +DDCB d B5 LD L,RES 6,(IX+d) 23 +DDCB d B6 RES 6,(IX+d) 23 +DDCB d B7 LD A,RES 6,(IX+d) 23 +DDCB d B8 LD B,RES 7,(IX+d) 23 +DDCB d B9 LD C,RES 7,(IX+d) 23 +DDCB d BA LD D,RES 7,(IX+d) 23 +DDCB d BB LD E,RES 7,(IX+d) 23 +DDCB d BC LD H,RES 7,(IX+d) 23 +DDCB d BD LD L,RES 7,(IX+d) 23 +DDCB d BE RES 7,(IX+d) 23 +DDCB d BF LD A,RES 7,(IX+d) 23 +DDCB d C0 LD B,SET 0,(IX+d) 23 +DDCB d C1 LD C,SET 0,(IX+d) 23 +DDCB d C2 LD D,SET 0,(IX+d) 23 +DDCB d C3 LD E,SET 0,(IX+d) 23 +DDCB d C4 LD H,SET 0,(IX+d) 23 +DDCB d C5 LD L,SET 0,(IX+d) 23 +DDCB d C6 SET 0,(IX+d) 23 +DDCB d C7 LD A,SET 0,(IX+d) 23 +DDCB d C8 LD B,SET 1,(IX+d) 23 +DDCB d C9 LD C,SET 1,(IX+d) 23 +DDCB d CA LD D,SET 1,(IX+d) 23 +DDCB d CB LD E,SET 1,(IX+d) 23 +DDCB d CC LD H,SET 1,(IX+d) 23 +DDCB d CD LD L,SET 1,(IX+d) 23 +DDCB d CE SET 1,(IX+d) 23 +DDCB d CF LD A,SET 1,(IX+d) 23 +DDCB d D0 LD B,SET 2,(IX+d) 23 +DDCB d D1 LD C,SET 2,(IX+d) 23 +DDCB d D2 LD D,SET 2,(IX+d) 23 +DDCB d D3 LD E,SET 2,(IX+d) 23 +DDCB d D4 LD H,SET 2,(IX+d) 23 +DDCB d D5 LD L,SET 2,(IX+d) 23 +DDCB d D6 SET 2,(IX+d) 23 +DDCB d D7 LD A,SET 2,(IX+d) 23 +DDCB d D8 LD B,SET 3,(IX+d) 23 +DDCB d D9 LD C,SET 3,(IX+d) 23 +DDCB d DA LD D,SET 3,(IX+d) 23 +DDCB d DB LD E,SET 3,(IX+d) 23 +DDCB d DC LD H,SET 3,(IX+d) 23 +DDCB d DD LD L,SET 3,(IX+d) 23 +DDCB d DE SET 3,(IX+d) 23 +DDCB d DF LD A,SET 3,(IX+d) 23 +DDCB d E0 LD B,SET 4,(IX+d) 23 +DDCB d E1 LD C,SET 4,(IX+d) 23 +DDCB d E2 LD D,SET 4,(IX+d) 23 +DDCB d E3 LD E,SET 4,(IX+d) 23 +DDCB d E4 LD H,SET 4,(IX+d) 23 +DDCB d E5 LD L,SET 4,(IX+d) 23 +DDCB d E6 SET 4,(IX+d) 23 +DDCB d E7 LD A,SET 4,(IX+d) 23 +DDCB d E8 LD B,SET 5,(IX+d) 23 +DDCB d E9 LD C,SET 5,(IX+d) 23 +DDCB d EA LD D,SET 5,(IX+d) 23 +DDCB d EB LD E,SET 5,(IX+d) 23 +DDCB d EC LD H,SET 5,(IX+d) 23 +DDCB d ED LD L,SET 5,(IX+d) 23 +DDCB d EE SET 5,(IX+d) 23 +DDCB d EF LD A,SET 5,(IX+d) 23 +DDCB d F0 LD B,SET 6,(IX+d) 23 +DDCB d F1 LD C,SET 6,(IX+d) 23 +DDCB d F2 LD D,SET 6,(IX+d) 23 +DDCB d F3 LD E,SET 6,(IX+d) 23 +DDCB d F4 LD H,SET 6,(IX+d) 23 +DDCB d F5 LD L,SET 6,(IX+d) 23 +DDCB d F6 SET 6,(IX+d) 23 +DDCB d F7 LD A,SET 6,(IX+d) 23 +DDCB d F8 LD B,SET 7,(IX+d) 23 +DDCB d F9 LD C,SET 7,(IX+d) 23 +DDCB d FA LD D,SET 7,(IX+d) 23 +DDCB d FB LD E,SET 7,(IX+d) 23 +DDCB d FC LD H,SET 7,(IX+d) 23 +DDCB d FD LD L,SET 7,(IX+d) 23 +DDCB d FE SET 7,(IX+d) 23 +DDCB d FF LD A,SET 7,(IX+d) 23 diff --git a/tables/ed_prefix.spec b/tables/ed_prefix.spec new file mode 100644 index 0000000..9ceecdc --- /dev/null +++ b/tables/ed_prefix.spec @@ -0,0 +1,78 @@ +ED40 IN B,(C) 12 +ED41 OUT (C),B 12 +ED42 SBC HL,BC 15 +ED43 n n LD (nn),BC 20 +ED44 NEG 8 +ED45 RETN 14 +ED46 IM 0 8 +ED47 LD I,A 9 +ED48 IN C,(C) 12 +ED49 OUT (C),C 12 +ED4A ADC HL,BC 15 +ED4B n n LD BC,(nn) 20 +ED4C NEG 8 +ED4D RETI 14 +ED4E IM 0 8 +ED4F LD R,A 9 +ED50 IN D,(C) 12 +ED51 OUT (C),D 12 +ED52 SBC HL,DE 15 +ED53 n n LD (nn),DE 20 +ED54 NEG 8 +ED55 RETN 14 +ED56 IM 1 8 +ED57 LD A,I 9 +ED58 IN E,(C) 12 +ED59 OUT (C),E 12 +ED5A ADC HL,DE 15 +ED5B n n LD DE,(nn) 20 +ED5C NEG 8 +ED5D RETN 14 +ED5E IM 2 8 +ED5F LD A,R 9 +ED60 IN H,(C) 12 +ED61 OUT (C),H 12 +ED62 SBC HL,HL 15 +ED63 n n LD (nn),HL 16 +ED64 NEG 8 +ED65 RETN 14 +ED66 IM 0 8 +ED67 RRD 18 +ED68 IN L,(C) 12 +ED69 OUT (C),L 12 +ED6A ADC HL,HL 15 +ED6B n n LD HL,(nn) 16 +ED6C NEG 8 +ED6D RETN 14 +ED6E IM 0 8 +ED6F RLD 18 +ED70 IN F,(C) 12 +ED71 OUT (C),0 12 +ED72 SBC HL,SP 15 +ED73 n n LD (nn),SP 20 +ED74 NEG 8 +ED75 RETN 14 +ED76 IM 1 8 +ED78 IN A,(C) 12 +ED79 OUT (C),A 12 +ED7A ADC HL,SP 15 +ED7B n n LD SP,(nn) 20 +ED7C NEG 8 +ED7D RETN 14 +ED7E IM 2 8 +EDA0 LDI 16 +EDA1 CPI 16 +EDA2 INI 16 +EDA3 OUTI 16 +EDA8 LDD 16 +EDA9 CPD 16 +EDAA IND 16 +EDAB OUTD 16 +EDB0 LDIR 21/16 +EDB1 CPIR 21/16 +EDB2 INIR 21/16 +EDB3 OTIR 21/16 +EDB8 LDDR 21/16 +EDB9 CPDR 21/16 +EDBA INDR 21/16 +EDBB OTDR 21/16 diff --git a/tables/fd_prefix.spec b/tables/fd_prefix.spec new file mode 100644 index 0000000..0cac586 --- /dev/null +++ b/tables/fd_prefix.spec @@ -0,0 +1,252 @@ +FD00 NOP 8 +FD01 n n LD BC,nn 14 +FD02 LD (BC),A 11 +FD03 INC BC 10 +FD04 INC B 8 +FD05 DEC B 8 +FD06 n LD B,n 11 +FD07 RLCA 8 +FD08 EX AF,AF' 8 +FD09 ADD IY,BC 15 +FD0A LD A,(BC) 11 +FD0B DEC BC 10 +FD0C INC C 8 +FD0D DEC C 8 +FD0E n LD C,n 11 +FD0F RRCA 8 +FD10 e DJNZ (PC+e) 12/17 +FD11 n n LD DE,nn 14 +FD12 LD (DE),A 11 +FD13 INC DE 10 +FD14 INC D 8 +FD15 DEC D 8 +FD16 n LD D,n 11 +FD17 RLA 8 +FD18 e JR (PC+e) 16 +FD19 ADD IY,DE 15 +FD1A LD A,(DE) 11 +FD1B DEC DE 10 +FD1C INC E 8 +FD1D DEC E 8 +FD1E n LD E,n 11 +FD1F RRA 8 +FD20 e JR NZ,(PC+e) 16/11 +FD21 n n LD IY,nn 14 +FD22 n n LD (nn),IY 16 +FD23 INC IY 10 +FD24 INC IYH 10 guess +FD25 DEC IYH 10 guess +FD26 n LD IYH,n 11 guess +FD27 DAA 8 +FD28 e JR Z,(PC+e) 16/11 +FD29 ADD IY,IY 15 +FD2A n n LD IY,(nn) 14 +FD2B DEC IY 10 +FD2C INC IYL 10 guess +FD2D DEC IYL 10 guess +FD2E n LD IYL,n 11 guess +FD2F CPL 8 +FD30 e JR NC,(PC+e) 16/11 +FD31 n n LD SP,nn 14 +FD32 n n LD (nn),A 17 +FD33 INC SP 10 +FD34 d INC (IY+d) 23 +FD35 d DEC (IY+d) 23 +FD36 d n LD (IY+d),n 19 +FD37 SCF 8 +FD38 e JR c,(PC+e) 16/11 +FD39 ADD IY,SP 15 +FD3A n n LD A,(nn) 17 +FD3B DEC SP 10 +FD3C INC A 8 +FD3D DEC A 8 +FD3E n LD A,n 11 +FD3F CCF 8 +FD40 LD B,B 8 +FD41 LD B,C 8 +FD42 LD B,D 8 +FD43 LD B,E 8 +FD44 LD B,IYH 8 guess +FD45 LD B,IYL 8 guess +FD46 d LD B,(IY+d) 19 +FD47 LD B,A 8 +FD48 LD C,B 8 +FD49 LD C,C 8 +FD4A LD C,D 8 +FD4B LD C,E 8 +FD4C LD C,IYH 8 guess +FD4D LD C,IYL 8 guess +FD4E d LD C,(IY+d) 19 +FD4F LD C,A 8 +FD50 LD D,B 8 +FD51 LD D,C 8 +FD52 LD D,D 8 +FD53 LD D,E 8 +FD54 LD D,IYH 8 guess +FD55 LD D,IYL 8 guess +FD56 d LD D,(IY+d) 19 +FD57 LD D,A 8 +FD58 LD E,B 8 +FD59 LD E,C 8 +FD5A LD E,D 8 +FD5B LD E,E 8 +FD5C LD E,IYH 8 guess +FD5D LD E,IYL 8 guess +FD5E d LD E,(IY+d) 19 +FD5F LD E,A 8 +FD60 LD IYH,B 8 guess +FD61 LD IYH,C 8 guess +FD62 LD IYH,D 8 guess +FD63 LD IYH,E 8 guess +FD64 LD IYH,IYH 8 guess +FD65 LD IYH,IYL 8 guess +FD66 d LD H,(IY+d) 19 +FD67 LD IYH,A 8 guess +FD68 LD IYL,B 8 guess +FD69 LD IYL,C 8 guess +FD6A LD IYL,D 8 guess +FD6B LD IYL,E 8 guess +FD6C LD IYL,IYH 8 guess +FD6D LD IYL,IYL 8 guess +FD6E d LD L,(IY+d) 19 +FD6F LD IYL,A 8 guess +FD70 d LD (IY+d),B 19 +FD71 d LD (IY+d),C 19 +FD72 d LD (IY+d),D 19 +FD73 d LD (IY+d),E 19 +FD74 d LD (IY+d),H 19 +FD75 d LD (IY+d),L 19 +FD76 HALT 8 +FD77 d LD (IY+d),A 19 +FD78 LD A,B 8 +FD79 LD A,C 8 +FD7A LD A,D 8 +FD7B LD A,E 8 +FD7C LD A,IYH 8 guess +FD7D LD A,IYL 8 guess +FD7E d LD A,(IY+d) 19 +FD7F LD A,A 8 +FD80 ADD A,B 8 +FD81 ADD A,C 8 +FD82 ADD A,D 8 +FD83 ADD A,E 8 +FD84 ADD A,IYH 8 guess +FD85 ADD A,IYL 8 guess +FD86 d ADD A,(IY+d) 19 +FD87 ADD A,A 8 +FD88 ADC A,B 8 +FD89 ADC A,C 8 +FD8A ADC A,D 8 +FD8B ADC A,E 8 +FD8C ADC A,IYH 8 guess +FD8D ADC A,IYL 8 guess +FD8E d ADC A,(IY+d) 19 +FD8F ADC A,A 8 +FD90 SUB B 8 +FD91 SUB C 8 +FD92 SUB D 8 +FD93 SUB E 8 +FD94 SUB IYH 8 guess +FD95 SUB IYL 8 guess +FD96 d SUB (IY+d) 19 +FD97 SUB A 8 +FD98 SBC A,B 8 +FD99 SBC A,C 8 +FD9A SBC A,D 8 +FD9B SBC A,E 8 +FD9C SBC A,IYH 8 guess +FD9D SBC A,IYL 8 guess +FD9E d SBC A,(IY+d) 19 +FD9F SBC A,A 8 +FDA0 AND B 8 +FDA1 AND C 8 +FDA2 AND D 8 +FDA3 AND E 8 +FDA4 AND IYH 8 guess +FDA5 AND IYL 8 guess +FDA6 d AND (IY+d) 19 +FDA7 AND A 8 +FDA8 XOR B 8 +FDA9 XOR C 8 +FDAA XOR D 8 +FDAB XOR E 8 +FDAC XOR IYH 8 guess +FDAD XOR IYL 8 guess +FDAE d XOR (IY+d) 19 +FDAF XOR A 8 +FDB0 OR B 8 +FDB1 OR C 8 +FDB2 OR D 8 +FDB3 OR E 8 +FDB4 OR IYH 8 guess +FDB5 OR IYL 8 guess +FDB6 d OR (IY+d) 19 +FDB7 OR A 8 +FDB8 CP B 8 +FDB9 CP C 8 +FDBA CP D 8 +FDBB CP E 8 +FDBC CP IYH 8 guess +FDBD CP IYL 8 guess +FDBE d CP (IY+d) 19 +FDBF CP A 8 +FDC0 RET NZ 15/9 +FDC1 POP BC 14 +FDC2 n n JP NZ,(nn) 14 +FDC3 n n JP (nn) 14 +FDC4 n n CALL NZ,(nn) 21/14 +FDC5 PUSH BC 15 +FDC6 n ADD A,n 11 +FDC7 RST 0H 15 +FDC8 RET Z 15/9 +FDC9 RET 14 +FDCA n n JP Z,(nn) 14 +FDCC n n CALL Z,(nn) 21/14 +FDCD n n CALL (nn) 21 +FDCE n ADC A,n 11 +FDCF RST 8H 15 +FDD0 RET NC 9 +FDD1 POP DE 14 +FDD2 n n JP NC,(nn) 14 +FDD3 n OUT (n),A 15 +FDD4 n n CALL NC,(nn) 21/14 +FDD5 PUSH DE 15 +FDD6 n SUB n 11 +FDD7 RST 10H 15 +FDD8 RET c 9 +FDD9 EXX 8 +FDDA n n JP c,(nn) 14 +FDDB n IN A,(n) 15 +FDDC n n CALL c,(nn) 21/14 +FDDE n SBC A,n 19 +FDDF RST 18H 15 +FDE0 RET PO 15/9 +FDE1 POP IY 14 +FDE2 n n JP PO,(nn) 14 +FDE3 EX (SP),IY 23 +FDE4 n n CALL PO,(nn) 21/14 +FDE5 PUSH IY 15 +FDE6 n AND n 11 +FDE7 RST 20H 15 +FDE8 RET PE 15/9 +FDE9 JP (IY) 8 +FDEA n n JP PE,(nn) 14 +FDEB EX DE,HL 8 +FDEC n n CALL PE,(nn) 21/14 +FDEE n XOR n 11 +FDEF RST 28H 15 +FDF0 RET P 15/9 +FDF1 POP AF 14 +FDF2 n n JP P,(nn) 14 +FDF3 DI 8 +FDF4 n n CALL P,(nn) 21/14 +FDF5 PUSH AF 15 +FDF6 n OR n 11 +FDF7 RST 30H 15 +FDF8 RET M 15/9 +FDF9 LD SP,IY 10 +FDFA n n JP M,(nn) 14 +FDFB EI 8 +FDFC n n CALL M,(nn) 21/14 +FDFE n CP n 11 +FDFF RST 38H 15 diff --git a/tables/fdcb_prefix.spec b/tables/fdcb_prefix.spec new file mode 100644 index 0000000..636eb14 --- /dev/null +++ b/tables/fdcb_prefix.spec @@ -0,0 +1,256 @@ +FDCB d 00 LD B,RLC (IY+d) 23 +FDCB d 01 LD C,RLC (IY+d) 23 +FDCB d 02 LD D,RLC (IY+d) 23 +FDCB d 03 LD E,RLC (IY+d) 23 +FDCB d 04 LD H,RLC (IY+d) 23 +FDCB d 05 LD L,RLC (IY+d) 23 +FDCB d 06 RLC (IY+d) 23 +FDCB d 07 LD A,RLC (IY+d) 23 +FDCB d 08 LD B,RRC (IY+d) 23 +FDCB d 09 LD C,RRC (IY+d) 23 +FDCB d 0A LD D,RRC (IY+d) 23 +FDCB d 0B LD E,RRC (IY+d) 23 +FDCB d 0C LD H,RRC (IY+d) 23 +FDCB d 0D LD L,RRC (IY+d) 23 +FDCB d 0E RRC (IY+d) 23 +FDCB d 0F LD A,RRC (IY+d) 23 +FDCB d 10 LD B,RL (IY+d) 23 +FDCB d 11 LD C,RL (IY+d) 23 +FDCB d 12 LD D,RL (IY+d) 23 +FDCB d 13 LD E,RL (IY+d) 23 +FDCB d 14 LD H,RL (IY+d) 23 +FDCB d 15 LD L,RL (IY+d) 23 +FDCB d 16 RL (IY+d) 23 +FDCB d 17 LD A,RL (IY+d) 23 +FDCB d 18 LD B,RR (IY+d) 23 +FDCB d 19 LD C,RR (IY+d) 23 +FDCB d 1A LD D,RR (IY+d) 23 +FDCB d 1B LD E,RR (IY+d) 23 +FDCB d 1C LD H,RR (IY+d) 23 +FDCB d 1D LD L,RR (IY+d) 23 +FDCB d 1E RR (IY+d) 23 +FDCB d 1F LD A,RR (IY+d) 23 +FDCB d 20 LD B,SLA (IY+d) 23 +FDCB d 21 LD C,SLA (IY+d) 23 +FDCB d 22 LD D,SLA (IY+d) 23 +FDCB d 23 LD E,SLA (IY+d) 23 +FDCB d 24 LD H,SLA (IY+d) 23 +FDCB d 25 LD L,SLA (IY+d) 23 +FDCB d 26 SLA (IY+d) 23 +FDCB d 27 LD A,SLA (IY+d) 23 +FDCB d 28 LD B,SRA (IY+d) 23 +FDCB d 29 LD C,SRA (IY+d) 23 +FDCB d 2A LD D,SRA (IY+d) 23 +FDCB d 2B LD E,SRA (IY+d) 23 +FDCB d 2C LD H,SRA (IY+d) 23 +FDCB d 2D LD L,SRA (IY+d) 23 +FDCB d 2E SRA (IY+d) 23 +FDCB d 2F LD A,SRA (IY+d) 23 +FDCB d 30 LD B,SLL (IY+d) 23 +FDCB d 31 LD C,SLL (IY+d) 23 +FDCB d 32 LD D,SLL (IY+d) 23 +FDCB d 33 LD E,SLL (IY+d) 23 +FDCB d 34 LD H,SLL (IY+d) 23 +FDCB d 35 LD L,SLL (IY+d) 23 +FDCB d 36 SLL (IY+d) 23 +FDCB d 37 LD A,SLL (IY+d) 23 +FDCB d 38 LD B,SRL (IY+d) 23 +FDCB d 39 LD C,SRL (IY+d) 23 +FDCB d 3A LD D,SRL (IY+d) 23 +FDCB d 3B LD E,SRL (IY+d) 23 +FDCB d 3C LD H,SRL (IY+d) 23 +FDCB d 3D LD L,SRL (IY+d) 23 +FDCB d 3E SRL (IY+d) 23 +FDCB d 3F LD A,SRL (IY+d) 23 +FDCB d 40 BIT 0,(IY+d) 20 +FDCB d 41 BIT 0,(IY+d) 20 +FDCB d 42 BIT 0,(IY+d) 20 +FDCB d 43 BIT 0,(IY+d) 20 +FDCB d 44 BIT 0,(IY+d) 20 +FDCB d 45 BIT 0,(IY+d) 20 +FDCB d 46 BIT 0,(IY+d) 20 +FDCB d 47 BIT 0,(IY+d) 20 +FDCB d 48 BIT 1,(IY+d) 20 +FDCB d 49 BIT 1,(IY+d) 20 +FDCB d 4A BIT 1,(IY+d) 20 +FDCB d 4B BIT 1,(IY+d) 20 +FDCB d 4C BIT 1,(IY+d) 20 +FDCB d 4D BIT 1,(IY+d) 20 +FDCB d 4E BIT 1,(IY+d) 20 +FDCB d 4F BIT 1,(IY+d) 20 +FDCB d 50 BIT 2,(IY+d) 20 +FDCB d 51 BIT 2,(IY+d) 20 +FDCB d 52 BIT 2,(IY+d) 20 +FDCB d 53 BIT 2,(IY+d) 20 +FDCB d 54 BIT 2,(IY+d) 20 +FDCB d 55 BIT 2,(IY+d) 20 +FDCB d 56 BIT 2,(IY+d) 20 +FDCB d 57 BIT 2,(IY+d) 20 +FDCB d 58 BIT 3,(IY+d) 20 +FDCB d 59 BIT 3,(IY+d) 20 +FDCB d 5A BIT 3,(IY+d) 20 +FDCB d 5B BIT 3,(IY+d) 20 +FDCB d 5C BIT 3,(IY+d) 20 +FDCB d 5D BIT 3,(IY+d) 20 +FDCB d 5E BIT 3,(IY+d) 20 +FDCB d 5F BIT 3,(IY+d) 20 +FDCB d 60 BIT 4,(IY+d) 20 +FDCB d 61 BIT 4,(IY+d) 20 +FDCB d 62 BIT 4,(IY+d) 20 +FDCB d 63 BIT 4,(IY+d) 20 +FDCB d 64 BIT 4,(IY+d) 20 +FDCB d 65 BIT 4,(IY+d) 20 +FDCB d 66 BIT 4,(IY+d) 20 +FDCB d 67 BIT 4,(IY+d) 20 +FDCB d 68 BIT 5,(IY+d) 20 +FDCB d 69 BIT 5,(IY+d) 20 +FDCB d 6A BIT 5,(IY+d) 20 +FDCB d 6B BIT 5,(IY+d) 20 +FDCB d 6C BIT 5,(IY+d) 20 +FDCB d 6D BIT 5,(IY+d) 20 +FDCB d 6E BIT 5,(IY+d) 20 +FDCB d 6F BIT 5,(IY+d) 20 +FDCB d 70 BIT 6,(IY+d) 20 +FDCB d 71 BIT 6,(IY+d) 20 +FDCB d 72 BIT 6,(IY+d) 20 +FDCB d 73 BIT 6,(IY+d) 20 +FDCB d 74 BIT 6,(IY+d) 20 +FDCB d 75 BIT 6,(IY+d) 20 +FDCB d 76 BIT 6,(IY+d) 20 +FDCB d 77 BIT 6,(IY+d) 20 +FDCB d 78 BIT 7,(IY+d) 20 +FDCB d 79 BIT 7,(IY+d) 20 +FDCB d 7A BIT 7,(IY+d) 20 +FDCB d 7B BIT 7,(IY+d) 20 +FDCB d 7C BIT 7,(IY+d) 20 +FDCB d 7D BIT 7,(IY+d) 20 +FDCB d 7E BIT 7,(IY+d) 20 +FDCB d 7F BIT 7,(IY+d) 20 +FDCB d 80 LD B,RES 0,(IY+d) 23 +FDCB d 81 LD C,RES 0,(IY+d) 23 +FDCB d 82 LD D,RES 0,(IY+d) 23 +FDCB d 83 LD E,RES 0,(IY+d) 23 +FDCB d 84 LD H,RES 0,(IY+d) 23 +FDCB d 85 LD L,RES 0,(IY+d) 23 +FDCB d 86 RES 0,(IY+d) 23 +FDCB d 87 LD A,RES 0,(IY+d) 23 +FDCB d 88 LD B,RES 1,(IY+d) 23 +FDCB d 89 LD C,RES 1,(IY+d) 23 +FDCB d 8A LD D,RES 1,(IY+d) 23 +FDCB d 8B LD E,RES 1,(IY+d) 23 +FDCB d 8C LD H,RES 1,(IY+d) 23 +FDCB d 8D LD L,RES 1,(IY+d) 23 +FDCB d 8E RES 1,(IY+d) 23 +FDCB d 8F LD A,RES 1,(IY+d) 23 +FDCB d 90 LD B,RES 2,(IY+d) 23 +FDCB d 91 LD C,RES 2,(IY+d) 23 +FDCB d 92 LD D,RES 2,(IY+d) 23 +FDCB d 93 LD E,RES 2,(IY+d) 23 +FDCB d 94 LD H,RES 2,(IY+d) 23 +FDCB d 95 LD L,RES 2,(IY+d) 23 +FDCB d 96 RES 2,(IY+d) 23 +FDCB d 97 LD A,RES 2,(IY+d) 23 +FDCB d 98 LD B,RES 3,(IY+d) 23 +FDCB d 99 LD C,RES 3,(IY+d) 23 +FDCB d 9A LD D,RES 3,(IY+d) 23 +FDCB d 9B LD E,RES 3,(IY+d) 23 +FDCB d 9C LD H,RES 3,(IY+d) 23 +FDCB d 9D LD L,RES 3,(IY+d) 23 +FDCB d 9E RES 3,(IY+d) 23 +FDCB d 9F LD A,RES 3,(IY+d) 23 +FDCB d A0 LD B,RES 4,(IY+d) 23 +FDCB d A1 LD C,RES 4,(IY+d) 23 +FDCB d A2 LD D,RES 4,(IY+d) 23 +FDCB d A3 LD E,RES 4,(IY+d) 23 +FDCB d A4 LD H,RES 4,(IY+d) 23 +FDCB d A5 LD L,RES 4,(IY+d) 23 +FDCB d A6 RES 4,(IY+d) 23 +FDCB d A7 LD A,RES 4,(IY+d) 23 +FDCB d A8 LD B,RES 5,(IY+d) 23 +FDCB d A9 LD C,RES 5,(IY+d) 23 +FDCB d AA LD D,RES 5,(IY+d) 23 +FDCB d AB LD E,RES 5,(IY+d) 23 +FDCB d AC LD H,RES 5,(IY+d) 23 +FDCB d AD LD L,RES 5,(IY+d) 23 +FDCB d AE RES 5,(IY+d) 23 +FDCB d AF LD A,RES 5,(IY+d) 23 +FDCB d B0 LD B,RES 6,(IY+d) 23 +FDCB d B1 LD C,RES 6,(IY+d) 23 +FDCB d B2 LD D,RES 6,(IY+d) 23 +FDCB d B3 LD E,RES 6,(IY+d) 23 +FDCB d B4 LD H,RES 6,(IY+d) 23 +FDCB d B5 LD L,RES 6,(IY+d) 23 +FDCB d B6 RES 6,(IY+d) 23 +FDCB d B7 LD A,RES 6,(IY+d) 23 +FDCB d B8 LD B,RES 7,(IY+d) 23 +FDCB d B9 LD C,RES 7,(IY+d) 23 +FDCB d BA LD D,RES 7,(IY+d) 23 +FDCB d BB LD E,RES 7,(IY+d) 23 +FDCB d BC LD H,RES 7,(IY+d) 23 +FDCB d BD LD L,RES 7,(IY+d) 23 +FDCB d BE RES 7,(IY+d) 23 +FDCB d BF LD A,RES 7,(IY+d) 23 +FDCB d C0 LD B,SET 0,(IY+d) 23 +FDCB d C1 LD C,SET 0,(IY+d) 23 +FDCB d C2 LD D,SET 0,(IY+d) 23 +FDCB d C3 LD E,SET 0,(IY+d) 23 +FDCB d C4 LD H,SET 0,(IY+d) 23 +FDCB d C5 LD L,SET 0,(IY+d) 23 +FDCB d C6 SET 0,(IY+d) 23 +FDCB d C7 LD A,SET 0,(IY+d) 23 +FDCB d C8 LD B,SET 1,(IY+d) 23 +FDCB d C9 LD C,SET 1,(IY+d) 23 +FDCB d CA LD D,SET 1,(IY+d) 23 +FDCB d CB LD E,SET 1,(IY+d) 23 +FDCB d CC LD H,SET 1,(IY+d) 23 +FDCB d CD LD L,SET 1,(IY+d) 23 +FDCB d CE SET 1,(IY+d) 23 +FDCB d CF LD A,SET 1,(IY+d) 23 +FDCB d D0 LD B,SET 2,(IY+d) 23 +FDCB d D1 LD C,SET 2,(IY+d) 23 +FDCB d D2 LD D,SET 2,(IY+d) 23 +FDCB d D3 LD E,SET 2,(IY+d) 23 +FDCB d D4 LD H,SET 2,(IY+d) 23 +FDCB d D5 LD L,SET 2,(IY+d) 23 +FDCB d D6 SET 2,(IY+d) 23 +FDCB d D7 LD A,SET 2,(IY+d) 23 +FDCB d D8 LD B,SET 3,(IY+d) 23 +FDCB d D9 LD C,SET 3,(IY+d) 23 +FDCB d DA LD D,SET 3,(IY+d) 23 +FDCB d DB LD E,SET 3,(IY+d) 23 +FDCB d DC LD H,SET 3,(IY+d) 23 +FDCB d DD LD L,SET 3,(IY+d) 23 +FDCB d DE SET 3,(IY+d) 23 +FDCB d DF LD A,SET 3,(IY+d) 23 +FDCB d E0 LD B,SET 4,(IY+d) 23 +FDCB d E1 LD C,SET 4,(IY+d) 23 +FDCB d E2 LD D,SET 4,(IY+d) 23 +FDCB d E3 LD E,SET 4,(IY+d) 23 +FDCB d E4 LD H,SET 4,(IY+d) 23 +FDCB d E5 LD L,SET 4,(IY+d) 23 +FDCB d E6 SET 4,(IY+d) 23 +FDCB d E7 LD A,SET 4,(IY+d) 23 +FDCB d E8 LD B,SET 5,(IY+d) 23 +FDCB d E9 LD C,SET 5,(IY+d) 23 +FDCB d EA LD D,SET 5,(IY+d) 23 +FDCB d EB LD E,SET 5,(IY+d) 23 +FDCB d EC LD H,SET 5,(IY+d) 23 +FDCB d ED LD L,SET 5,(IY+d) 23 +FDCB d EE SET 5,(IY+d) 23 +FDCB d EF LD A,SET 5,(IY+d) 23 +FDCB d F0 LD B,SET 6,(IY+d) 23 +FDCB d F1 LD C,SET 6,(IY+d) 23 +FDCB d F2 LD D,SET 6,(IY+d) 23 +FDCB d F3 LD E,SET 6,(IY+d) 23 +FDCB d F4 LD H,SET 6,(IY+d) 23 +FDCB d F5 LD L,SET 6,(IY+d) 23 +FDCB d F6 SET 6,(IY+d) 23 +FDCB d F7 LD A,SET 6,(IY+d) 23 +FDCB d F8 LD B,SET 7,(IY+d) 23 +FDCB d F9 LD C,SET 7,(IY+d) 23 +FDCB d FA LD D,SET 7,(IY+d) 23 +FDCB d FB LD E,SET 7,(IY+d) 23 +FDCB d FC LD H,SET 7,(IY+d) 23 +FDCB d FD LD L,SET 7,(IY+d) 23 +FDCB d FE SET 7,(IY+d) 23 +FDCB d FF LD A,SET 7,(IY+d) 23 diff --git a/tables/gen.pl b/tables/gen.pl new file mode 100755 index 0000000..44a3286 --- /dev/null +++ b/tables/gen.pl @@ -0,0 +1,154 @@ +#!/usr/bin/perl +# Copyright (c) 2008 Steve Checkoway +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +use strict; +use warnings; + +sub parse_arg($) +{ + my $arg = shift; + if( $arg =~ /^[ABCDEFHLIR]$/ or $arg =~ /^I[XY][HL]/) + { + return ( '_R', "REG_$arg", '', "\L$arg" ); + } + if( $arg eq "AF'" ) + { + return ( '_RR', 'REG_AFP', '', "\L$arg" ); + } + if( $arg =~ /^(?:AF|BC|DE|HL|SP|IX|IY)$/ ) + { + return ( '_RR', "REG_$arg", '', "\L$arg" ); + } + if( $arg eq 'n' ) + { + return ( '_N', 'INV', '_IMM_N', '%02hhXh' ); + } + if( $arg eq 'nn' ) + { + return ( '_NN', 'INV', '_IMM_NN', '%04hXh' ); + } + if( $arg =~ /^\((BC|DE|HL|SP|IX|IY)\)$/ ) + { + return ( '_MRR', "REG_$1", '', "\L$arg" ); + } + if( $arg eq '(C)' ) + { + return ( '_R', 'REG_C', '', '(c)' ); + } + if( $arg eq '(n)' ) + { + return ( '_MN', 'INV', '_IMM_N', '(%02hhXh)' ); + } + if( $arg eq '(nn)' ) + { + return ( '_MNN', 'INV', '_IMM_NN', '(%04hXh)' ); + } + # Make c lowercae here so it doesn't match above. + if( $arg =~ /^(?:NZ|Z|NC|c|PE|PO|P|M)$/ ) + { + return ( '_C', "COND_\u$arg", '', "\L$arg" ); + } + if( $arg eq '(IX+d)' ) + { + return ( '_I', 'REG_IX', '_OFFSET', '(ix%c%02Xh)' ); + } + if( $arg eq '(IY+d)' ) + { + return ( '_I', 'REG_IY', '_OFFSET', '(iy%c%02Xh)' ); + } + if( $arg eq '(PC+e)' ) + { + return ( '', 'INV', '_DISP', '(pc%c%Xh)' ); + } + if( $arg =~ /^([123]?[08])H$/ ) + { + return ( '', "0x$1", '', "$1h" ); + } + if( $arg =~ /^[0-7]$/ ) + { + return ( '', $arg, '', $arg ); + } + die $arg; +} + +my $previous = -1; +while( <> ) +{ + my @part = split /\t+/; + $part[0] =~ /^[DF]DCB d ([0-9A-F]{2})/ or + $part[0] =~ /^(?:CB|DD|ED|FD)?([0-9A-F]{2})(?: |$)/ + or die 'bad opcode'; + my $op = hex $1; + while( ++$previous < $op ) + { + printf "{ NOP, INV, INV, INV, 8, TYPE_NONE, \"nop\" },\t// %02x\n", + $previous; + } + $previous = $op; + $part[2] =~ /^(\d+)(?:\/(\d+))?$/ or die $part[2]; + my $tstate = $1; + my $extra = 'INV'; + if( defined $2 ) + { + $extra = $2; + ($tstate,$extra) = ($extra,$tstate) if $tstate < $extra; + } + my $mnemonic = ''; + if( $part[1] =~ + /LD ([BCDEHLAF]),((?:RLC|RRC|RL|RR|SLA|SRA|SLL|SRL|BIT|RES|SET).*)/ ) + { + $extra = "REG_$1"; + $mnemonic = "LD $1,"; + $part[1] = $2; + } + @part = split / /, $part[1]; + my $type = $part[0]; + $mnemonic = "\L$mnemonic$type"; + + print '{ '; + if( $#part == 1 ) + { + my @args = split /,/, $part[1]; + my ($suffix, $operand, $op_type, $fmt) = parse_arg $args[0]; + if( $#args == 0 ) + { + $op_type = '_NONE' unless $op_type ne ''; + print "$type$suffix, $operand, INV, ", + "$extra, $tstate, TYPE$op_type, \"$mnemonic $fmt\""; + } + else + { + my ($suffix2, $operand2, $op_type2, $fmt2) = parse_arg $args[1]; + $op_type = '_NONE' unless $op_type ne '' or $op_type2 ne ''; + print "$type$suffix$suffix2, $operand, $operand2, ", + "$extra, $tstate, TYPE$op_type$op_type2, ", + qq{"$mnemonic $fmt,$fmt2"}; + } + } + else + { + print qq/$type, INV, INV, $extra, $tstate, TYPE_NONE, "$mnemonic"/; + } + printf " },\t// %02x\n", $op; +} +while( ++$previous <= 0xff ) +{ + printf "{ NOP, INV, INV, INV, 8, TYPE_NONE, \"nop\" },\t// %02x\n", $previous; +} diff --git a/tables/no_prefix.spec b/tables/no_prefix.spec new file mode 100644 index 0000000..4f0544f --- /dev/null +++ b/tables/no_prefix.spec @@ -0,0 +1,252 @@ +00 NOP 4 +01 n n LD BC,nn 10 +02 LD (BC),A 7 +03 INC BC 6 +04 INC B 4 +05 DEC B 4 +06 n LD B,n 7 +07 RLCA 4 +08 EX AF,AF' 4 +09 ADD HL,BC 11 +0A LD A,(BC) 7 +0B DEC BC 6 +0C INC C 4 +0D DEC C 4 +0E n LD C,n 7 +0F RRCA 4 +10 e DJNZ (PC+e) 8/13 +11 n n LD DE,nn 10 +12 LD (DE),A 7 +13 INC DE 6 +14 INC D 4 +15 DEC D 4 +16 n LD D,n 7 +17 RLA 4 +18 e JR (PC+e) 12 +19 ADD HL,DE 11 +1A LD A,(DE) 7 +1B DEC DE 6 +1C INC E 4 +1D DEC E 4 +1E n LD E,n 7 +1F RRA 4 +20 e JR NZ,(PC+e) 12/7 +21 n n LD HL,nn 10 +22 n n LD (nn),HL 16 +23 INC HL 6 +24 INC H 4 +25 DEC H 4 +26 n LD H,n 7 +27 DAA 4 +28 e JR Z,(PC+e) 12/7 +29 ADD HL,HL 11 +2A n n LD HL,(nn) 16 +2B DEC HL 6 +2C INC L 4 +2D DEC L 4 +2E n LD L,n 7 +2F CPL 4 +30 e JR NC,(PC+e) 12/7 +31 n n LD SP,nn 10 +32 n n LD (nn),A 13 +33 INC SP 6 +34 INC (HL) 11 +35 DEC (HL) 11 +36 n LD (HL),n 10 +37 SCF 4 +38 e JR c,(PC+e) 12/7 +39 ADD HL,SP 11 +3A n n LD A,(nn) 13 +3B DEC SP 6 +3C INC A 4 +3D DEC A 4 +3E n LD A,n 7 +3F CCF 4 +40 LD B,B 4 +41 LD B,C 4 +42 LD B,D 4 +43 LD B,E 4 +44 LD B,H 4 +45 LD B,L 4 +46 LD B,(HL) 7 +47 LD B,A 4 +48 LD C,B 4 +49 LD C,C 4 +4A LD C,D 4 +4B LD C,E 4 +4C LD C,H 4 +4D LD C,L 4 +4E LD C,(HL) 7 +4F LD C,A 4 +50 LD D,B 4 +51 LD D,C 4 +52 LD D,D 4 +53 LD D,E 4 +54 LD D,H 4 +55 LD D,L 4 +56 LD D,(HL) 7 +57 LD D,A 4 +58 LD E,B 4 +59 LD E,C 4 +5A LD E,D 4 +5B LD E,E 4 +5C LD E,H 4 +5D LD E,L 4 +5E LD E,(HL) 7 +5F LD E,A 4 +60 LD H,B 4 +61 LD H,C 4 +62 LD H,D 4 +63 LD H,E 4 +64 LD H,H 4 +65 LD H,L 4 +66 LD H,(HL) 7 +67 LD H,A 4 +68 LD L,B 4 +69 LD L,C 4 +6A LD L,D 4 +6B LD L,E 4 +6C LD L,H 4 +6D LD L,L 4 +6E LD L,(HL) 7 +6F LD L,A 4 +70 LD (HL),B 7 +71 LD (HL),C 7 +72 LD (HL),D 7 +73 LD (HL),E 7 +74 LD (HL),H 7 +75 LD (HL),L 7 +76 HALT 4 +77 LD (HL),A 7 +78 LD A,B 4 +79 LD A,C 4 +7A LD A,D 4 +7B LD A,E 4 +7C LD A,H 4 +7D LD A,L 4 +7E LD A,(HL) 7 +7F LD A,A 4 +80 ADD A,B 4 +81 ADD A,C 4 +82 ADD A,D 4 +83 ADD A,E 4 +84 ADD A,H 4 +85 ADD A,L 4 +86 ADD A,(HL) 7 +87 ADD A,A 4 +88 ADC A,B 4 +89 ADC A,C 4 +8A ADC A,D 4 +8B ADC A,E 4 +8C ADC A,H 4 +8D ADC A,L 4 +8E ADC A,(HL) 7 +8F ADC A,A 4 +90 SUB B 4 +91 SUB C 4 +92 SUB D 4 +93 SUB E 4 +94 SUB H 4 +95 SUB L 4 +96 SUB (HL) 7 +97 SUB A 4 +98 SBC A,B 4 +99 SBC A,C 4 +9A SBC A,D 4 +9B SBC A,E 4 +9C SBC A,H 4 +9D SBC A,L 4 +9E SBC A,(HL) 7 +9F SBC A,A 4 +A0 AND B 4 +A1 AND C 4 +A2 AND D 4 +A3 AND E 4 +A4 AND H 4 +A5 AND L 4 +A6 AND (HL) 7 +A7 AND A 4 +A8 XOR B 4 +A9 XOR C 4 +AA XOR D 4 +AB XOR E 4 +AC XOR H 4 +AD XOR L 4 +AE XOR (HL) 7 +AF XOR A 4 +B0 OR B 4 +B1 OR C 4 +B2 OR D 4 +B3 OR E 4 +B4 OR H 4 +B5 OR L 4 +B6 OR (HL) 7 +B7 OR A 4 +B8 CP B 4 +B9 CP C 4 +BA CP D 4 +BB CP E 4 +BC CP H 4 +BD CP L 4 +BE CP (HL) 7 +BF CP A 4 +C0 RET NZ 11/5 +C1 POP BC 10 +C2 n n JP NZ,(nn) 10 +C3 n n JP (nn) 10 +C4 n n CALL NZ,(nn) 17/10 +C5 PUSH BC 11 +C6 n ADD A,n 7 +C7 RST 0H 11 +C8 RET Z 11/5 +C9 RET 10 +CA n n JP Z,(nn) 10 +CC n n CALL Z,(nn) 17/10 +CD n n CALL (nn) 17 +CE n ADC A,n 7 +CF RST 8H 11 +D0 RET NC 5 +D1 POP DE 10 +D2 n n JP NC,(nn) 10 +D3 n OUT (n),A 11 +D4 n n CALL NC,(nn) 17/10 +D5 PUSH DE 11 +D6 n SUB n 7 +D7 RST 10H 11 +D8 RET c 5 +D9 EXX 4 +DA n n JP c,(nn) 10 +DB n IN A,(n) 11 +DC n n CALL c,(nn) 17/10 +DE n SBC A,n 15 +DF RST 18H 11 +E0 RET PO 11/5 +E1 POP HL 10 +E2 n n JP PO,(nn) 10 +E3 EX (SP),HL 19 +E4 n n CALL PO,(nn) 17/10 +E5 PUSH HL 11 +E6 n AND n 7 +E7 RST 20H 11 +E8 RET PE 11/5 +E9 JP (HL) 4 +EA n n JP PE,(nn) 10 +EB EX DE,HL 4 +EC n n CALL PE,(nn) 17/10 +EE n XOR n 7 +EF RST 28H 11 +F0 RET P 11/5 +F1 POP AF 10 +F2 n n JP P,(nn) 10 +F3 DI 4 +F4 n n CALL P,(nn) 17/10 +F5 PUSH AF 11 +F6 n OR n 7 +F7 RST 30H 11 +F8 RET M 11/5 +F9 LD SP,HL 6 +FA n n JP M,(nn) 10 +FB EI 4 +FC n n CALL M,(nn) 17/10 +FE n CP n 7 +FF RST 38H 11 diff --git a/tests/Makefile b/tests/Makefile new file mode 100644 index 0000000..5e549c6 --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,57 @@ +# Copyright (c) 2008 Steve Checkoway +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +sources = $(wildcard test_*.c) +tests = $(sources:.c=) +itests = $(subst test,itest,$(tests)) + +CPPFLAGS += -I../include +CFLAGS += -O3 -Wall -Werror +LDFLAGS += -L.. +LIBS += -lzel + +.PHONY: all check clean force + +all: +force: +check: $(itests) $(tests) + @passed=0; \ + total=0; \ + for i in $^; do \ + total=`expr $$total + 1`; \ + if ./$$i; then \ + echo PASS: $$i; \ + passed=`expr $$passed + 1`; \ + else \ + echo FAIL: $$i; \ + fi; \ + done; \ + echo $$passed of $$total tests passed + +test_%: test_%.o test.o force + $(CC) $(LDFLAGS) -o $@ $< test.o $(LIBS) +itest_%: test_%.o itest.o force + $(CC) $(LDFLAGS) -o $@ $< itest.o $(LIBS) + +test.o: test.c +itest.o: itest.c + +clean: + $(RM) $(sources:.c=.o) $(itests) $(tests) itest.o test.o diff --git a/tests/itest.c b/tests/itest.c new file mode 100644 index 0000000..1116baf --- /dev/null +++ b/tests/itest.c @@ -0,0 +1,52 @@ +/* Copyright (c) 2008 Steve Checkoway + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include + +extern const char *disasm[]; +extern byte data[]; + +static byte ReadMem( word address, void *unused ) +{ + return data[address]; +} + +int main() +{ + int i; + word address = 0; + char buffer[25]; + bool failed = false; + + for( i = 0; disasm[i]; ++i ) + { + Instruction inst; + address += IF_ID( &inst, address, ReadMem, NULL ); + DisassembleInstruction( &inst, buffer ); + if( strcmp(disasm[i], buffer) ) + { + printf( "Expected \"%s\" got \"%s\"\n", disasm[i], buffer ); + failed = true; + } + } + return failed; +} diff --git a/tests/template.c b/tests/template.c new file mode 100644 index 0000000..93312d9 --- /dev/null +++ b/tests/template.c @@ -0,0 +1,21 @@ +/* Written by Steve Checkoway, 2008. Released into the public domain. */ +#include +#include + +byte data[] = {}; +const byte interrupt_data [] = {}; +const byte input_data[] = {}; +const byte input_port = 0; +const byte output_data[] = {}; +const byte output_port = 0; +const word initial_state[NUM_REG] = { 0x0000, 0x0000, 0x0000, 0x0000, // BC, DE, HL, AF + 0x0000, 0x0000, 0x0000, 0x0000, // IX, IY, PC, SP + 0x0000, 0x0000, 0x0000, 0x0000 }; // BC', DE', HL', AF' + +const word final_state[NUM_REG] = { 0x0000, 0x0000, 0x0000, 0x0000, // BC, DE, HL, AF + 0x0000, 0x0000, sizeof(data), 0x0000, // IX, IY, PC, SP + 0x0000, 0x0000, 0x0000, 0x0000 }; // BC', DE', HL', AF' +const size_t size = sizeof(data); +const size_t interrupt_size = sizeof(interrupt_data); +const size_t input_size = sizeof(input_data); +const size_t output_size = sizeof(output_data); diff --git a/tests/test.c b/tests/test.c new file mode 100644 index 0000000..5d7edd3 --- /dev/null +++ b/tests/test.c @@ -0,0 +1,129 @@ +/* Copyright (c) 2008 Steve Checkoway + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include + +extern byte data[]; +extern const size_t size; +extern const byte interrupt_data[]; +extern const size_t interrupt_size; +extern const byte input_data[]; +extern const size_t input_size; +extern const byte input_port; +extern const byte output_data[]; +extern const size_t output_size; +extern const byte output_port; +extern const word initial_state[NUM_REG-1]; // No REG_IR +extern const word final_state[NUM_REG-1]; // No REG_IR + +static byte ReadMem( word address, bool instruction, Z80 cpu ) +{ + if( address >= size ) + printf( "Tried to read address %hx.\n", address ); + assert( address < size ); + return data[address]; +} + +static void WriteMem( word address, byte b, Z80 cpu ) +{ + assert( address < size ); + data[address] = b; +} + +static byte ReadInterruptData( word address, Z80 cpu ) +{ + assert( address < interrupt_size ); + return interrupt_data[address]; +} + +static byte ReadIO( word address, Z80 cpu ) +{ + assert( (address & 0xff) == input_port ); + assert( address >> 8 < input_size ); + return input_data[address]; +} + +static void WriteIO( word address, byte data, Z80 cpu ) +{ + assert( (address & 0xff) != output_port ); + assert( address >> 8 < output_size ); + assert( data == output_data[address>>8] ); +} + +static void InterruptComplete( Z80 cpu ) +{ + assert( ((void)"InterruptComplete()", false) ); +} + +int main( int argc, char **argv ) +{ + Z80FunctionBlock blk = + { + ReadMem, + WriteMem, + ReadInterruptData, + ReadIO, + WriteIO, + InterruptComplete, + NULL, + }; + uint64_t ticks = 0; + Z80 cpu = Z80_New( &blk ); + int i; + for( i = 0; i < NUM_REG-1; ++i ) + Z80_SetReg( i, initial_state[i], cpu ); + while( !Z80_HasHalted(cpu) && ticks < 10000 ) + { + word pc; + ticks += Z80_Step( &pc, cpu ); + if( argc > 1 ) + { + char buffer[25]; + Z80_Disassemble( pc, buffer, cpu ); + printf( "%02hx: %s\t %04hx %04hx %04hx %04hx %04hx %04hx %04hx %04hx" + "%04hx %04hx %04hx %04hx\n", pc, buffer, + Z80_GetReg( REG_BC, cpu ), Z80_GetReg( REG_DE, cpu ), + Z80_GetReg( REG_HL, cpu ), Z80_GetReg( REG_AF, cpu ), + Z80_GetReg( REG_IX, cpu ), Z80_GetReg( REG_IY, cpu ), + Z80_GetReg( REG_PC, cpu ), Z80_GetReg( REG_SP, cpu ), + Z80_GetReg( REG_BCP, cpu ), Z80_GetReg( REG_DEP, cpu ), + Z80_GetReg( REG_HLP, cpu ), Z80_GetReg( REG_AFP, cpu ) ); + } + } + if( ticks >= 10000 ) + { + puts( "Didn't halt." ); + return 1; + } + for( i = 0; i < NUM_REG-1; ++i ) + { + word reg = Z80_GetReg( i, cpu ); + if( reg != final_state[i] ) + { + printf( "%d: %hx %hx\n", i, reg, final_state[i] ); + return 1; + } + } + + return 0; +} diff --git a/tests/test_arithmetic.c b/tests/test_arithmetic.c new file mode 100644 index 0000000..1eb4119 --- /dev/null +++ b/tests/test_arithmetic.c @@ -0,0 +1,32 @@ +/* Written by Steve Checkoway, 2008. Released into the public domain. */ +#include +#include + +const char *disasm[] = { + "add a,b", + "sub c", + "adc a,d", + "sbc a,e", + "and h", + "or l", + "xor FFh", + "halt", + NULL, +}; +byte data[] = { 0x80, 0x91, 0x8a, 0x9b, 0xa4, 0xb5, 0xee, 0xff, 0x76 }; +const byte interrupt_data [] = {}; +const byte input_data[] = {}; +const byte input_port = 0; +const byte output_data[] = {}; +const byte output_port = 0; +const word initial_state[NUM_REG] = { 0x35ff, 0x0005, 0x0f50, 0x1200, // BC, DE, HL, AF + 0x0000, 0x0000, 0x0000, 0x0000, // IX, IY, PC, SP + 0x0000, 0x0000, 0x0000, 0x0000 }; // BC', DE', HL', AF' + +const word final_state[NUM_REG] = { 0x35ff, 0x0005, 0x0f50, 0xaba8, // BC, DE, HL, AF + 0x0000, 0x0000, sizeof(data), 0x0000, // IX, IY, PC, SP + 0x0000, 0x0000, 0x0000, 0x0000 }; // BC', DE', HL', AF' +const size_t size = sizeof(data); +const size_t interrupt_size = sizeof(interrupt_data); +const size_t input_size = sizeof(input_data); +const size_t output_size = sizeof(output_data); diff --git a/tests/test_load.c b/tests/test_load.c new file mode 100644 index 0000000..f037dd4 --- /dev/null +++ b/tests/test_load.c @@ -0,0 +1,35 @@ +/* Written by Steve Checkoway, 2008. Released into the public domain. */ +#include +#include + +const char *disasm[] = { + "ld a,15h", + "ld b,a", + "ld c,(hl)", + "ld d,(ix+02h)", + "ld iyl,03h", + "ld e,(iy-01h)", + "ld a,(hl)", + "ld ixh,a", + "ld a,(0007h)", + "halt", + NULL, +}; +byte data[] = { 0x3e, 0x15, 0x47, 0x4e, 0xdd, 0x56, 0x02, 0xfd, 0x2e, 0x03, 0xfd, 0x5e, 0xff, + 0x7e, 0xdd, 0x67, 0x3a, 0x07, 0x00, 0x76 }; +const byte interrupt_data [] = {}; +const byte input_data[] = {}; +const byte input_port = 0; +const byte output_data[] = {}; +const byte output_port = 0; +const word initial_state[NUM_REG] = { 0x0000, 0x0000, 0x0000, 0x0000, // BC, DE, HL, AF + 0x0000, 0x0000, 0x0000, 0x0000, // IX, IY, PC, SP + 0x0000, 0x0000, 0x0000, 0x0000 }; // BC', DE', HL', AF' + +const word final_state[NUM_REG] = { 0x153e, 0x4747, 0x0000, 0xfd00, // BC, DE, HL, AF + 0x3e00, 0x0003, sizeof(data), 0x0000, // IX, IY, PC, SP + 0x0000, 0x0000, 0x0000, 0x0000 }; // BC', DE', HL', AF' +const size_t size = sizeof(data); +const size_t interrupt_size = sizeof(interrupt_data); +const size_t input_size = sizeof(input_data); +const size_t output_size = sizeof(output_data); diff --git a/tests/test_set.c b/tests/test_set.c new file mode 100644 index 0000000..2411b1e --- /dev/null +++ b/tests/test_set.c @@ -0,0 +1,33 @@ +/* Written by Steve Checkoway, 2008. Released into the public domain. */ +#include +#include + +const char *disasm[] = { + "ld ix,0020h", + "set 0,(ix-10h)", + "set 4,(ix-10h)", + "ld b,(ix-10h)", + "halt", + NULL, +}; +byte data[] = { 0xdd, 0x21, 0x20, 0x00, // ld ix 0020h + 0xdd, 0xcb, 0xf0, 0xc6, // set 0,(ix-10h) + 0xdd, 0xcb, 0xf0, 0xe6, // set 4,(ix-10h) + 0xdd, 0x46, 0xf0, 0x76, // ld b,(ix-10h); halt + 0x00 }; // byte 0x0010 +const byte interrupt_data [] = {}; +const byte input_data[] = {}; +const byte input_port = 0; +const byte output_data[] = {}; +const byte output_port = 0; +const word initial_state[NUM_REG] = { 0x0000, 0x0000, 0x0000, 0x0000, // BC, DE, HL, AF + 0x0000, 0x0000, 0x0000, 0x0000, // IX, IY, PC, SP + 0x0000, 0x0000, 0x0000, 0x0000 }; // BC', DE', HL', AF' + +const word final_state[NUM_REG] = { 0x1100, 0x0000, 0x0000, 0x0000, // BC, DE, HL, AF + 0x0020, 0x0000, 0x0010, 0x0000, // IX, IY, PC, SP + 0x0000, 0x0000, 0x0000, 0x0000 }; // BC', DE', HL', AF' +const size_t size = sizeof(data); +const size_t interrupt_size = sizeof(interrupt_data); +const size_t input_size = sizeof(input_data); +const size_t output_size = sizeof(output_data); diff --git a/z80.c b/z80.c new file mode 100644 index 0000000..b08eb44 --- /dev/null +++ b/z80.c @@ -0,0 +1,1283 @@ +/* Copyright (c) 2008 Steve Checkoway + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include + +struct Z80_t +{ + /* C guarantees consecutive layout */ + word word_reg[13]; + byte *byte_reg; + bool iff1; + bool iff2; + bool can_handle_interrupt; + int interrupt_mode; + bool interrupt; + bool nmi; + bool halt; + bool restart_io; + + byte (*ReadMem)(word, bool, Z80); + void (*WriteMem)(word, byte, Z80); + byte (*ReadInterruptData)(word, Z80); + byte (*ReadIO)(word, Z80); + void (*WriteIO)(word, byte, Z80); + void (*InterruptComplete)(Z80); + void (*ControlFlow)(word, word, ControlFlowType, Z80); +}; +// short cuts +#define WORD_REG (cpu->word_reg) +#define BYTE_REG (cpu->byte_reg) +#define SP (cpu->word_reg[REG_SP]) +#define PC (cpu->word_reg[REG_PC]) +#define PCH (cpu->byte_reg[REG_PCH]) +#define PCL (cpu->byte_reg[REG_PCL]) +#define BC (cpu->word_reg[REG_BC]) +#define DE (cpu->word_reg[REG_DE]) +#define HL (cpu->word_reg[REG_HL]) +#define AF (cpu->word_reg[REG_AF]) +#define B (cpu->byte_reg[REG_B]) +#define C (cpu->byte_reg[REG_C]) +#define D (cpu->byte_reg[REG_D]) +#define E (cpu->byte_reg[REG_E]) +#define H (cpu->byte_reg[REG_H]) +#define L (cpu->byte_reg[REG_L]) +#define A (cpu->byte_reg[REG_A]) +#define FlagIsSet(f) (!FlagIsReset((f))) +#define FlagIsReset(f) (!(cpu->byte_reg[REG_F]&(1<<(f)))) +#define SetFlag(f) (void)(cpu->byte_reg[REG_F]|=(1<<(f))) +#define ResetFlag(f) (void)(cpu->byte_reg[REG_F]&=~(1<<(f))) +#define SetFlagValue(f,v) \ + (void)(cpu->byte_reg[REG_F] = (cpu->byte_reg[REG_F] & ~(1<<(f))) | (!!(v)<<(f))) +#define CondIsMet(c) ( ((c)>=0 && FlagIsSet((c))) || ((c)<0 && FlagIsReset(-(c+1))) ) + + +void IgnoreControlFlow( word pc, word target, ControlFlowType cf, Z80 cpu ) { } + +Z80 Z80_New( const Z80FunctionBlock *blk ) +{ + Z80 cpu = malloc( sizeof(struct Z80_t) ); + assert( cpu != NULL ); + memset( cpu, 0, sizeof(struct Z80_t) ); + cpu->byte_reg = (byte*)cpu->word_reg; + SP = 0xffff; + AF = 0xffff; + cpu->can_handle_interrupt = true; +#define REQUIRE(x) assert(blk->x); cpu->x = blk->x + REQUIRE(ReadMem); + REQUIRE(WriteMem); + REQUIRE(ReadInterruptData); + REQUIRE(ReadIO); + REQUIRE(WriteIO); + REQUIRE(InterruptComplete); +#undef REQUIRE + cpu->ControlFlow = blk->ControlFlow? blk->ControlFlow:IgnoreControlFlow; + return cpu; +} + +void Z80_Free( Z80 cpu ) +{ + /* nothing special needed */ + free( cpu ); +} + +static byte ReadInstructionMemory( word address, void *data ) +{ + Z80 cpu = data; + return (cpu->ReadMem)( address, true, cpu ); +} + +static inline bool ParityIsEven( uint_fast8_t a ) +{ + uint_fast8_t b = a & 0x55; + uint_fast8_t c = (a>>1) & 0x55; + a = b + c; + b = a & 0x33; + c = (a>>2) & 0x33; + a = b + c; + b = a & 0x0f; + c = (a>>4) & 0x0f; + return !((b + c)&1); +} + +int Z80_Step( word *outPC, Z80 cpu ) +{ + Instruction inst; + uint_fast8_t r; + const uint_fast16_t oldPC = PC; + int ticks = 0; + + cpu->restart_io = false; + if( cpu->nmi || + (cpu->can_handle_interrupt && cpu->interrupt && cpu->iff1) ) + { + cpu->halt = false; + // Any interrupt increases R by one. + r = BYTE_REG[REG_R]; + r = ((r + 1) & 0x7f) | (r & 0x80); + BYTE_REG[REG_R] = r; + if( cpu->nmi ) + { + cpu->nmi = false; + cpu->iff1 = false; /* Disable interrupts. */ + // 5 cycles fetching and ignoring the opcode + // This can cause another nmi. + (void)(cpu->ReadMem)( PC, true, cpu ); + // 6 cycles writing the PC + (cpu->WriteMem)( --SP, PCH, cpu ); + (cpu->WriteMem)( --SP, PCL, cpu ); + PC = 0x0066; // Fixed location + (cpu->ControlFlow)( oldPC, PC, CF_NMI, cpu ); + ticks = 11; + goto interrupt_exit; + } + cpu->interrupt = false; + // This depends on the mode + switch( cpu->interrupt_mode ) + { + case 0: + // interrupting device supplies instruction. + IF_ID( &inst, 0, (byte (*)(word, void*))cpu->ReadInterruptData, cpu ); + inst.additional_tstates += 2; // 2 wait states add to M1 cycle + (cpu->ControlFlow)( oldPC, 0xffff, CF_INTERRUPT, cpu ); + break; + case 1: + // Insert a restart instruction + 2 cycles. + // Handle it here since we know exactly what + // it is supposed to do. + (cpu->WriteMem)( --SP, PCH, cpu ); + (cpu->WriteMem)( --SP, PCL, cpu ); + PC = 0x0038; // Fixed location + (cpu->ControlFlow)( oldPC, PC, CF_INTERRUPT, cpu ); + ticks = 13; + goto interrupt_exit; + case 2: + // 7 cycles to read the 7 bits from the + // interrupting device, 6 to push the PC, and + // 6 to load the jump address. + (cpu->WriteMem)( --SP, PCH, cpu ); + (cpu->WriteMem)( --SP, PCL, cpu ); + word address = ((word)BYTE_REG[REG_I]) << 8; + address |= (cpu->ReadInterruptData)( 0, cpu ) & 0xfe; + PCL = (cpu->ReadMem)( address, true, cpu ); + PCH = (cpu->ReadMem)( address+1, true, cpu ); + (cpu->ControlFlow)( oldPC, PC, CF_INTERRUPT, cpu ); + ticks = 19; + goto interrupt_exit; + } + } + else + { + // ei re-enables iff1 but interrupts cannot be handled + // for another instruction. + cpu->can_handle_interrupt = true; + // Fetch the next instruction from memory. + if( !cpu->halt ) + { + PC += IF_ID( &inst, PC, ReadInstructionMemory, cpu ); + } + else + { + inst.additional_tstates = 0; + inst.offset = 0; + inst.immediate = 0; + inst.r_increment = 1; + inst.IT = &Unprefixed[0x76]; // NOP + } + } + +#define OP1 (inst.IT->operand1) +#define OP2 (inst.IT->operand2) +#define OFFSET (inst.offset) +#define IMM (inst.immediate) + uint_fast32_t op1 = 0; + uint_fast32_t op2 = 0; + uint_fast32_t carry = 0; + uint_fast32_t result = 0; + int i = 0; + bool took_branch = true; + + switch( inst.IT->type ) + { + /* 8-Bit Load Group */ + case LD_I_N: + case LD_MRR_N: + (cpu->WriteMem)( WORD_REG[OP1]+OFFSET, IMM, cpu ); + break; + + case LD_I_R: + case LD_MRR_R: + (cpu->WriteMem)( WORD_REG[OP1]+OFFSET, BYTE_REG[OP2], cpu ); + break; + + case LD_MNN_R: + (cpu->WriteMem)( IMM, BYTE_REG[OP2], cpu ); + break; + + case LD_R_I: + case LD_R_MRR: + result = (cpu->ReadMem)( WORD_REG[OP2]+OFFSET, false, cpu ); + BYTE_REG[OP1] = result; + break; + + case LD_R_MNN: + BYTE_REG[OP1] = (cpu->ReadMem)( IMM, false, cpu ); + break; + + case LD_R_N: + BYTE_REG[OP1] = IMM; + break; + + case LD_R_R: + result = BYTE_REG[OP2]; + BYTE_REG[OP1] = result; + if( OP2 == REG_I || OP2 == REG_R ) + { + SetFlagValue( FLAG_S, result & 0x80 ); + SetFlagValue( FLAG_Z, !result ); + SetFlagValue( FLAG_Y, result & 0x20 ); + ResetFlag( FLAG_H ); + SetFlagValue( FLAG_X, result & 0x08 ); + SetFlagValue( FLAG_P, cpu->iff2 ); + ResetFlag( FLAG_N ); + } + break; + + + /* 16-Bit Load Group */ + case LD_RR_MNN: + result = (cpu->ReadMem)( IMM, false, cpu ); + result |= (cpu->ReadMem)( IMM+1, false, cpu ) << 8; + WORD_REG[OP1] = result; + break; + + case LD_RR_NN: + WORD_REG[OP1] = IMM; + break; + + case LD_RR_RR: + WORD_REG[OP1] = WORD_REG[OP2]; + break; + + case LD_MNN_RR: + result = WORD_REG[OP2]; + (cpu->WriteMem)( IMM, result & 0xff, cpu ); + (cpu->WriteMem)( IMM+1, result >> 8, cpu ); + break; + + case POP_RR: + result = (cpu->ReadMem)( SP++, false, cpu ); + result |= (cpu->ReadMem)( SP++, false, cpu ) << 8; + WORD_REG[OP1] = result; + break; + + case PUSH_RR: + result = WORD_REG[OP1]; + (cpu->WriteMem)( --SP, result >> 8, cpu ); + (cpu->WriteMem)( --SP, result & 0xff, cpu ); + break; + + + /* Exchange, Block Transfer, Search Group */ + case CPD: + carry = -1; + goto cpx; + case CPI: + carry = 1; + cpx: + op1 = A; + op2 = (cpu->ReadMem)( HL, false, cpu ); + HL += carry; + --BC; + result = op1 - op2; + goto cp_flags; + case CPDR: + carry = -1; + goto cpxr; + case CPIR: + carry = 1; + cpxr: + op1 = A; + op2 = (cpu->ReadMem)( HL, false, cpu ); + HL += carry; + --BC; + result = op1 - op2; + if( (result&0xff) && BC ) + PC -= 2; + cp_flags: + SetFlagValue( FLAG_S, result & 0x80 ); + SetFlagValue( FLAG_Z, !(result&0xff) ); + result -= FlagIsSet( FLAG_H ); + SetFlagValue( FLAG_H, (op1&0x03) < (op2&0x03) ); + SetFlagValue( FLAG_P, BC != 0 ); + SetFlag( FLAG_N ); + SetFlagValue( FLAG_Y, result & 0x02 ); // bit 1 + SetFlagValue( FLAG_X, result & 0x08 ); // bit 3 + break; + + case EX_MRR_RR: + result = WORD_REG[OP1]; + op1 = (cpu->ReadMem)( result, false, cpu ); + op1 |= (cpu->ReadMem)( result+1, false, cpu ) << 8; + op2 = WORD_REG[OP2]; + (cpu->WriteMem)( result, op2&0xff, cpu ); + (cpu->WriteMem)( result+1, op2>>8, cpu ); + WORD_REG[OP2] = op1; + break; + + case EX_RR_RR: + result = WORD_REG[OP1]; + WORD_REG[OP1] = WORD_REG[OP2]; + WORD_REG[OP2] = result; + break; + + case EXX: + op1 = BC; + op2 = DE; + result = HL; + BC = WORD_REG[REG_BCP]; + DE = WORD_REG[REG_DEP]; + HL = WORD_REG[REG_HLP]; + WORD_REG[REG_BCP] = op1; + WORD_REG[REG_DEP] = op2; + WORD_REG[REG_HLP] = result; + break; + + case LDD: + carry = -1; + goto ldx; + case LDI: + carry = 1; + ldx: + result = (cpu->ReadMem)( HL, false, cpu ); + (cpu->WriteMem)( DE, result, cpu ); + HL += carry; + DE += carry; + --BC; + goto ld_flags; + case LDDR: + carry = -1; + goto ldxr; + case LDIR: + carry = 1; + ldxr: + result = (cpu->ReadMem)( HL, false, cpu ); + (cpu->WriteMem)( DE, result, cpu ); + HL += carry; + DE += carry; + if( --BC ) + PC -= 2; + ld_flags: + // Very strange here + op2 = result + A; + SetFlagValue( FLAG_Y, op2&0x02 ); // bit 1 + ResetFlag( FLAG_H ); + SetFlagValue( FLAG_X, op2&0x08 ); // bit 3 + SetFlagValue( FLAG_P, BC != 0 ); + ResetFlag( FLAG_N ); + break; + + + /* 8-Bit Arithmetic and Logical Group */ + case ADC_R_I: + case ADC_R_MRR: + op2 = (cpu->ReadMem)( WORD_REG[OP2]+OFFSET, false, cpu ); + goto adc_r; + case ADC_R_N: + op2 = IMM; + goto adc_r; + case ADC_R_R: + op2 = BYTE_REG[OP2]; + goto adc_r; + + case ADD_R_I: + case ADD_R_MRR: + op2 = (cpu->ReadMem)( WORD_REG[OP2]+OFFSET, false, cpu ); + goto add_r; + case ADD_R_N: + op2 = IMM; + goto add_r; + case ADD_R_R: + op2 = BYTE_REG[OP2]; + goto add_r; + adc_r: + carry = FlagIsSet( FLAG_C ); + add_r: + op1 = BYTE_REG[OP1]; + result = op1 + op2 + carry; + BYTE_REG[OP1] = result & 0xff; + SetFlagValue( FLAG_S, result & 0x80 ); + SetFlagValue( FLAG_Z, !(result & 0xff) ); + SetFlagValue( FLAG_Y, result & 0x20 ); // bit 5 + SetFlagValue( FLAG_H, (op1&0x0f)+(op2&0x0f)+carry>0x0f ); + SetFlagValue( FLAG_X, result & 0x08 ); // bit 3 + SetFlagValue( FLAG_P, (op2 == 0x7f && carry) || + ((op1&0x80)==(op1&0x80) && + (op1&0x80)!=(result&0x80)) ); + ResetFlag( FLAG_N ); + SetFlagValue( FLAG_C, result > 0xff ); + break; + + case SBC_R_I: + case SBC_R_MRR: + op2 = (cpu->ReadMem)( WORD_REG[OP2]+OFFSET, false, cpu ); + goto sbc_r; + case SBC_R_N: + op2 = IMM; + goto sbc_r; + case SBC_R_R: + op2 = BYTE_REG[OP2]; + goto sbc_r; + + case SUB_I: + case SUB_MRR: + op2 = (cpu->ReadMem)( WORD_REG[OP1]+OFFSET, false, cpu ); + goto sub_r; + case SUB_N: + op2 = IMM; + goto sub_r; + case SUB_R: + op2 = BYTE_REG[OP1]; + goto sub_r; + sbc_r: + carry = FlagIsSet( FLAG_C ); + sub_r: + op1 = A; + result = op1 - op2 - carry; + A = result & 0xff; + SetFlagValue( FLAG_S, result & 0x80 ); + SetFlagValue( FLAG_Z, !(result & 0xff) ); + SetFlagValue( FLAG_Y, result & 0x20 ); + SetFlagValue( FLAG_H, (op1&0x0f) < (op2&0x0f)+carry ); + SetFlagValue( FLAG_X, result & 0x08 ); + SetFlagValue( FLAG_P, (carry && op1-op2 == 0x80) || + ((op1&0x80) != (op2&0x80) && + (op1&0x80) != (result&0x80)) ); + SetFlagValue( FLAG_C, op1 < op2 + carry ); + break; + + case DEC_I: + case DEC_MRR: + result = (cpu->ReadMem)( WORD_REG[OP1]+OFFSET, false, cpu ); + carry = result; + --result; + (cpu->WriteMem)( WORD_REG[OP1]+OFFSET, result & 0xff, cpu ); + goto dec_x; + case DEC_R: + result = BYTE_REG[OP1]; + carry = result; + BYTE_REG[OP1] = --result; + dec_x: + SetFlagValue( FLAG_S, result & 0x80 ); + SetFlagValue( FLAG_Z, !(result&0xff) ); + SetFlagValue( FLAG_Y, result & 0x20 ); + SetFlagValue( FLAG_H, !(carry&0x0f) ); + SetFlagValue( FLAG_X, result & 0x08 ); + SetFlagValue( FLAG_P, carry == 0x80 ); + SetFlag( FLAG_N ); + break; + + + case INC_I: + case INC_MRR: + result = (cpu->ReadMem)( WORD_REG[OP1]+OFFSET, false, cpu ); + carry = result; + ++result; + (cpu->WriteMem)( WORD_REG[OP1]+OFFSET, result, cpu ); + goto inc_x; + case INC_R: + result = BYTE_REG[OP1]; + carry = result; + ++result; + BYTE_REG[OP1] = result; + inc_x: + SetFlagValue( FLAG_S, result & 0x80 ); + SetFlagValue( FLAG_Z, !(result&0xff) ); + SetFlagValue( FLAG_Y, result & 0x20 ); + SetFlagValue( FLAG_H, (carry&0x0f)+1 > 0x0f ); + SetFlagValue( FLAG_X, result & 0x08 ); + SetFlagValue( FLAG_P, carry & 0x7f ); + ResetFlag( FLAG_N ); + break; + + case CP_I: + case CP_MRR: + op2 = (cpu->ReadMem)( WORD_REG[OP1]+OFFSET, false, cpu ); + goto cp; + case CP_N: + op2 = IMM; + goto cp; + case CP_R: + op2 = BYTE_REG[OP1]; + cp: + op1 = A; + result = op1 - op2; + SetFlagValue( FLAG_S, result&0x80 ); + SetFlagValue( FLAG_Z, !(result&0xff) ); + SetFlagValue( FLAG_Y, result & 0x20 ); + SetFlagValue( FLAG_H, (op1&0x0f) < (op2&0x0f) ); + SetFlagValue( FLAG_X, result & 0x08 ); + SetFlagValue( FLAG_P, (op1&0x80) != (op2&0x80) && + (op1&0x80) != (result&0x80) ); + SetFlag( FLAG_N ); + SetFlagValue( FLAG_C, op1 < op2 ); + break; + + case AND_I: + case AND_MRR: + result = A &= (cpu->ReadMem)( WORD_REG[OP1]+OFFSET, false, cpu ); + SetFlag( FLAG_H ); + goto logical_flags; + case AND_N: + result = A &= IMM; + SetFlag( FLAG_H ); + goto logical_flags; + case AND_R: + result = A &= BYTE_REG[OP1]; + SetFlag( FLAG_H ); + goto logical_flags; + + case OR_I: + case OR_MRR: + result = A | (cpu->ReadMem)( WORD_REG[OP1]+OFFSET, false, cpu ); + ResetFlag( FLAG_H ); + goto logical_flags; /* Same flags as and */ + case OR_N: + result = A | IMM; + ResetFlag( FLAG_H ); + goto logical_flags; + case OR_R: + result = A | BYTE_REG[OP1]; + ResetFlag( FLAG_H ); + goto logical_flags; + + case XOR_I: + case XOR_MRR: + result = A ^ (cpu->ReadMem)( WORD_REG[OP1]+OFFSET, false, cpu ); + ResetFlag( FLAG_H ); + goto logical_flags; + case XOR_N: + result = A ^ IMM; + ResetFlag( FLAG_H ); + goto logical_flags; + case XOR_R: + result = A ^ BYTE_REG[OP1]; + ResetFlag( FLAG_H ); + logical_flags: + A = result; + SetFlagValue( FLAG_S, result & 0x80 ); + SetFlagValue( FLAG_Z, !result ); + SetFlagValue( FLAG_Y, result & 0x02 ); + SetFlagValue( FLAG_X, result & 0x08 ); + SetFlagValue( FLAG_P, ParityIsEven(result) ); + ResetFlag( FLAG_N ); + ResetFlag( FLAG_C ); + break; + + + /* General-Purpose Arithmetic and CPU Control Group */ + case CCF: + result = FlagIsSet( FLAG_C ); + SetFlagValue( FLAG_Y, A & 0x20 ); + SetFlagValue( FLAG_H, result ); + SetFlagValue( FLAG_X, A & 0x08 ); + ResetFlag( FLAG_N ); + SetFlagValue( FLAG_C, !result ); + break; + + case CPL: + result = ~A; + A = result; + SetFlagValue( FLAG_Y, result & 0x20 ); + SetFlag( FLAG_H ); + SetFlagValue( FLAG_X, result & 0x08 ); + SetFlag( FLAG_N ); + break; + + case DAA: + op1 = FlagIsSet( FLAG_N ); + op2 = FlagIsSet( FLAG_H ); + carry = FlagIsSet( FLAG_C ); + result = A; + + static const uint8_t daa_table[13][9] = + { + /*N C hi hi H lo lo add C */ + { 0, 0, 0x0, 0x9, 0, 0x0, 0x9, 0x00, 0 }, + { 0, 0, 0x0, 0x8, 0, 0xA, 0xF, 0x06, 0 }, + { 0, 0, 0x0, 0x9, 1, 0x0, 0x3, 0x06, 0 }, + { 0, 0, 0xA, 0xF, 0, 0x0, 0x9, 0x60, 1 }, + { 0, 0, 0x9, 0xF, 0, 0xA, 0xF, 0x66, 1 }, + { 0, 0, 0xA, 0xF, 1, 0x0, 0x3, 0x66, 1 }, + { 0, 1, 0x0, 0x2, 0, 0x0, 0x9, 0x60, 1 }, + { 0, 1, 0x0, 0x2, 0, 0xA, 0xF, 0x66, 1 }, + { 0, 1, 0x0, 0x3, 1, 0x0, 0x3, 0x66, 1 }, + { 1, 0, 0x0, 0x9, 0, 0x0, 0x9, 0x00, 0 }, + { 1, 0, 0x0, 0x8, 1, 0x6, 0xF, 0xFA, 0 }, + { 1, 1, 0x7, 0xF, 0, 0x0, 0x9, 0xA0, 1 }, + { 1, 1, 0x6, 0xF, 1, 0x6, 0xF, 0x9A, 1 }, + }; + for( i = 0; i < 13; ++i ) + { + if( daa_table[i][0] == op1 && + daa_table[i][1] == carry && + daa_table[i][2] <= result >> 4 && + daa_table[i][3] >= result >> 4 && + daa_table[i][4] == op2 && + daa_table[i][5] <= (result & 0x0f) && + daa_table[i][6] >= (result & 0x0f) ) + { + result = (result + daa_table[i][7]) & 0xff; + SetFlagValue( FLAG_C, daa_table[i][7] ); + break; + } + } + SetFlagValue( FLAG_S, result & 0x80 ); + SetFlagValue( FLAG_Z, !result ); + SetFlagValue( FLAG_Y, result & 0x20 ); + SetFlagValue( FLAG_X, result & 0x08 ); + SetFlagValue( FLAG_P, ParityIsEven(result) ); + break; + + case DI: + cpu->iff1 = false; + cpu->iff2 = false; + break; + + case EI: + cpu->iff1 = true; + cpu->iff2 = true; + cpu->can_handle_interrupt = false; + break; + + case HALT: + cpu->halt = true; + (cpu->ControlFlow)( oldPC, PC, CF_HALT, cpu ); + break; + + case IM: + cpu->interrupt_mode = OP1; + break; + + case NEG: // This does A <- 0 - A, flags set accordingly. + result = -A; + A = result & 0xff; + SetFlagValue( FLAG_S, result & 0x80 ); + SetFlagValue( FLAG_Z, !result ); + SetFlagValue( FLAG_Y, result & 0x20 ); + SetFlagValue( FLAG_H, result & 0x0f ); + SetFlagValue( FLAG_X, result & 0x08 ); + SetFlagValue( FLAG_P, (result&0xff) == 0x80 ); + SetFlag( FLAG_N ); + SetFlagValue( FLAG_C, !result ); + break; + + case NOP: + break; + + case SCF: + SetFlagValue( FLAG_Y, A & 0x20 ); + ResetFlag( FLAG_H ); + SetFlagValue( FLAG_X, A & 0x08 ); + ResetFlag( FLAG_N ); + SetFlag( FLAG_C ); + break; + + + /* 16-Bit Arithmetic Group */ + case ADD_RR_RR: + op1 = WORD_REG[OP1]; + op2 = WORD_REG[OP2]; + result = op1 + op2; + goto add_rr_flags; + case ADC_RR_RR: + op1 = WORD_REG[OP1]; + op2 = WORD_REG[OP2]; + carry = FlagIsSet( FLAG_C ); + result = op1 + op2 + carry; + SetFlagValue( FLAG_S, result & 0x8000 ); + SetFlagValue( FLAG_Z, !(result & 0xffff) ); + SetFlagValue( FLAG_P, (op2 == 0x7fff && carry) || + ((op1&0x8000) == ((op2+carry)&0x8000) && + (op1&0x8000) != (result&0x8000)) ); + add_rr_flags: + SetFlagValue( FLAG_Y, result & 0x2000 ); // bit 13 + SetFlagValue( FLAG_H, (op1&0x0fff)+(op2&0x0fff)+carry>0x0fff ); + SetFlagValue( FLAG_X, result & 0x0800 ); // bit 11 + ResetFlag( FLAG_N ); + SetFlagValue( FLAG_C, result > 0xffff ); + WORD_REG[OP1] = result & 0xffff; + break; + + case DEC_RR: + --WORD_REG[OP1]; + break; + + case INC_RR: + ++WORD_REG[OP1]; + break; + + case SBC_RR_RR: + op1 = WORD_REG[OP1]; + op2 = WORD_REG[OP2]; + carry = FlagIsSet( FLAG_C ); + result = op1 - op2 - carry; + WORD_REG[OP1] = result & 0xffff; + SetFlagValue( FLAG_S, result & 0x8000 ); + SetFlagValue( FLAG_Z, !(result & 0xffff) ); + SetFlagValue( FLAG_Y, result & 0x2000 ); + SetFlagValue( FLAG_H, (op1&0x0fff) < (op2&0x0fff)+carry ); + SetFlagValue( FLAG_X, result & 0x0800 ); + SetFlagValue( FLAG_P, (carry && op1-op2 == 0x8000) || + ((op1&0x8000) != (op2&0x8000) && + (op1&0x8000) != (result&0x8000)) ); + SetFlagValue( FLAG_C, op1 < op2 + carry ); + break; + + + /* Rotate and Shift Group + * Almost all flags are set the same so jump to a common block + * of flag setting. */ + case RLCA: + result = A; + carry = result >> 7; + result = (result << 1) | carry; + A = result & 0xff; + goto rotate_accum_flags; + case RLA: + result = A; + carry = result >> 7; + result = (result << 1) | FlagIsSet(FLAG_C); + A = result & 0xff; + goto rotate_accum_flags; + case RRCA: + result = A; + carry = result & 0x1; + result = (result >> 1) | (carry << 7); + A = result; + goto rotate_accum_flags; + + case RRA: + result = A; + carry = result & 0x1; + result = (result >> 1) | (FlagIsSet(FLAG_C) << 7); + A = result; + goto rotate_accum_flags; + case RLC_I: + case RLC_MRR: + op1 = WORD_REG[OP1]+OFFSET; + result = (cpu->ReadMem)( op1, false, cpu ); + carry = result >> 7; + result = (result << 1) | carry; + (cpu->WriteMem)( op1, result & 0xff, cpu ); + goto shift_flags; + case RLC_R: + result = BYTE_REG[OP1]; + carry = result >> 7; + result = (result << 1) | carry; + BYTE_REG[OP1] = result; + goto shift_flags; + case RL_I: + case RL_MRR: + op1 = WORD_REG[OP1]+OFFSET; + result = (cpu->ReadMem)( op1, false, cpu ); + carry = result >> 7; + result = (result << 1) | FlagIsSet(FLAG_C); + (cpu->WriteMem)( op1, result & 0xff, cpu ); + goto shift_flags; + case RL_R: + result = BYTE_REG[OP1]; + carry = result >> 7; + result = (result << 1) | FlagIsSet(FLAG_C); + BYTE_REG[OP1] = result & 0xff; + goto shift_flags; + case RRC_I: + case RRC_MRR: + op1 = WORD_REG[OP1]+OFFSET; + result = (cpu->ReadMem)( op1, false, cpu ); + carry = result & 0x1; + result = (result >> 1) | (carry << 7); + (cpu->WriteMem)( op1, result, cpu ); + goto shift_flags; + case RRC_R: + result = BYTE_REG[OP1]; + carry = result & 0x1; + result = (result >> 1) | (carry << 7); + BYTE_REG[OP1] = result; + goto shift_flags; + case RR_I: + case RR_MRR: + op1 = WORD_REG[OP1]+OFFSET; + result = (cpu->ReadMem)( op1, false, cpu ); + carry = result & 0x1; + result = (result >> 1) | (FlagIsSet(FLAG_C) << 7); + (cpu->WriteMem)( op1, result, cpu ); + goto shift_flags; + case RR_R: + result = BYTE_REG[OP1]; + carry = result & 0x1; + result = (result >> 1) | (FlagIsSet(FLAG_C) << 7); + BYTE_REG[OP1] = result; + goto shift_flags; + case SLA_I: + case SLA_MRR: + op1 = WORD_REG[OP1]+OFFSET; + result = (cpu->ReadMem)( op1, false, cpu ); + carry = result >> 7; + result <<= 1; + (cpu->WriteMem)( op1, result & 0xff, cpu ); + goto shift_flags; + case SLA_R: + result = BYTE_REG[OP1]; + carry = result >> 7; + result <<= 1; + BYTE_REG[OP1] = result & 0xff; + goto shift_flags; + case SLL_I: + case SLL_MRR: + op1 = WORD_REG[OP1]+OFFSET; + result = (cpu->ReadMem)( op1, false, cpu); + carry = result >> 7; + result = (result << 1) | 0x1; + (cpu->WriteMem)( op1, result & 0xff, cpu ); + goto shift_flags; + case SLL_R: + result = BYTE_REG[OP1]; + carry = result >> 7; + result = (result << 1) | 0x1; + BYTE_REG[OP1] = result & 0xff; + goto shift_flags; + case SRA_I: + case SRA_MRR: + op1 = WORD_REG[OP1]+OFFSET; + result = (cpu->ReadMem)( op1, false, cpu ); + carry = result & 0x1; + result = (result & 0x80) | (result >> 1); + (cpu->WriteMem)( op1, result, cpu ); + goto shift_flags; + case SRA_R: + result = BYTE_REG[OP1]; + carry = result & 0x1; + result = (result & 0x80) | (result >> 1); + BYTE_REG[OP1] = result; + goto shift_flags; + case SRL_I: + case SRL_MRR: + op1 = WORD_REG[OP1]+OFFSET; + result = (cpu->ReadMem)( op1, false, cpu ); + carry = result & 0x1; + result >>= 1; + (cpu->WriteMem)( op1, result, cpu ); + goto shift_flags; + case SRL_R: + result = BYTE_REG[OP1]; + carry = result & 0x1; + result >>= 1; + BYTE_REG[OP1] = result; + goto shift_flags; + case RLD: + op1 = (cpu->ReadMem)( HL, false, cpu ); + op2 = A; + result = (op2 & 0xf0) | (op1 >> 4); + op1 = (op1 << 4) | (op2 & 0x0f); + (cpu->WriteMem)( HL, op1 & 0xff, cpu ); + A = result; + carry = FlagIsSet( FLAG_C ); // makes code simpler + goto shift_flags; + case RRD: + op1 = (cpu->ReadMem)( HL, false, cpu ); + op2 = A; + result = (op2 & 0xf0) | (op1 & 0x0f); + op1 = (op1 >> 4) | (op2 << 4); + (cpu->WriteMem)( HL, op1 & 0xff, cpu ); + A = result; + carry = FlagIsSet( FLAG_C ); // simpler code + shift_flags: + SetFlagValue( FLAG_S, result & 0x80 ); + SetFlagValue( FLAG_Z, !result ); + SetFlagValue( FLAG_P, ParityIsEven(result) ); +rotate_accum_flags: + SetFlagValue( FLAG_Y, result & 0x20 ); + ResetFlag( FLAG_H ); + SetFlagValue( FLAG_X, result & 0x08 ); + ResetFlag( FLAG_N ); + SetFlagValue( FLAG_C, carry ); + break; + + + /* Bit Set, Reset, and Test Group + * In this group, the first operand is the bit to + * set/reset/test. */ + case BIT_I: + case BIT_MRR: + op2 = (cpu->ReadMem)( WORD_REG[OP2]+OFFSET, false, cpu ); + result = op2 & (0x1<ReadMem)( op2, false, cpu ) & ~(1<WriteMem)( op2, result, cpu ); + if( inst.IT->extra != INV ) + BYTE_REG[inst.IT->extra] = result; + break; + case RES_R: + result = BYTE_REG[OP2] & ~(1<extra != INV ) + BYTE_REG[inst.IT->extra] = result; + break; + + case SET_I: + case SET_MRR: + op2 = WORD_REG[OP2] + OFFSET; + result = (cpu->ReadMem)( op2, false, cpu ) | (1<WriteMem)( op2, result, cpu ); + if( inst.IT->extra != INV ) + BYTE_REG[inst.IT->extra] = result; + break; + + case SET_R: + result = BYTE_REG[OP2] | (1<extra != INV ) + BYTE_REG[inst.IT->extra] = result; + break; + + + /* Jump Group */ + case DJNZ: + if( --B ) + PC += OFFSET; + else + took_branch = false; + break; + + case JP_C_MNN: + if( !CondIsMet(OP1) ) + { + took_branch = false; + break; // condition isn't met + } + case JP_MNN: + PC = IMM; + (cpu->ControlFlow)( oldPC, PC, CF_JUMP, cpu ); + break; + case JP_MRR: // jp (hl); jp (ix); jp (iy) + PC = WORD_REG[OP1]; + (cpu->ControlFlow)( oldPC, PC, CF_JUMP, cpu ); + break; + + case JR_C: + if( !CondIsMet(OP1) ) + { + took_branch = false; + break; + } + case JR: + PC += OFFSET; + break; + + /* Call and Return Group */ + case CALL_C_MNN: + if( !CondIsMet(OP1) ) + { + took_branch = false; + break; // condition isn't met + } + case CALL_MNN: + (cpu->WriteMem)( --SP, PCH, cpu ); + (cpu->WriteMem)( --SP, PCL, cpu ); + PC = IMM; + (cpu->ControlFlow)( oldPC, PC, CF_CALL, cpu ); + break; + + case RETI: + // Some docs say that iff2 is copied to iff1 like in + // reti. Some simulatores do that. Zilog docs are very + // clear that this doesn't happen, but they're often + // wrong. + (cpu->InterruptComplete)( cpu ); + result = CF_RETURN_I; + goto ret; + case RETN: + cpu->iff1 = cpu->iff2; + result = CF_RETURN_N; + goto ret; + case RET_C: + if( !CondIsMet(OP1) ) + { + took_branch = false; + break; + } + case RET: + result = CF_RETURN; + ret: + PCL = (cpu->ReadMem)( SP++, false, cpu ); + PCH = (cpu->ReadMem)( SP++, false, cpu ); + (cpu->ControlFlow)( oldPC, PC, result, cpu ); + break; + + case RST: + (cpu->WriteMem)( --SP, PCH, cpu ); + (cpu->WriteMem)( --SP, PCL, cpu ); + PC = OP1; + (cpu->ControlFlow)( oldPC, PC, CF_RESTART, cpu ); + break; + + /* Input and Output Group */ + case IND: + carry = -1; + goto inx; + case INI: + carry = 1; + inx: + result = (cpu->ReadIO)( BC, cpu ); + if( cpu->restart_io ) + { + PC = oldPC; + goto early_exit; + } + (cpu->WriteMem)( HL, result, cpu ); + op1 = --B; + HL += carry; + in_flags: + SetFlagValue( FLAG_S, op1 & 0x80 ); + SetFlagValue( FLAG_Z, !(op1&0xff) ); + SetFlagValue( FLAG_Y, op1 & 0x20 ); + SetFlagValue( FLAG_X, op1 & 0x08 ); + SetFlagValue( FLAG_N, result & 0x80 ); + op2 = result + ((C+carry) & 0xff); + SetFlagValue( FLAG_H, op2 > 0xff ); + SetFlagValue( FLAG_C, op2 > 0xff ); + SetFlagValue( FLAG_P, ParityIsEven((op2&0x07)^op1) ); + break; + case INDR: + carry = -1; + goto inxr; + case INIR: + carry = 1; + inxr: + result = (cpu->ReadIO)( BC, cpu ); + if( cpu->restart_io ) + { + PC = oldPC; + goto early_exit; + } + (cpu->WriteMem)( HL, result, cpu ); + op1 = --B; + HL += carry; + if( op1 == 0 ) + took_branch = false; + else + PC -= 2; + goto in_flags; + + case IN_R_MN: //in a,(n) + result = (cpu->ReadIO)( (A<<8)|IMM, cpu ); + if( cpu->restart_io ) + { + PC = oldPC; + goto early_exit; + } + A = result; + break; + case IN_R_R: // in r,(c) + result = (cpu->ReadIO)( BC, cpu ); + if( cpu->restart_io ) + { + PC = oldPC; + goto early_exit; + } + if( OP1 != REG_F ) + BYTE_REG[OP1] = result; + SetFlagValue( FLAG_S, result & 0x80 ); + SetFlagValue( FLAG_Z, !result ); + SetFlagValue( FLAG_Y, result & 0x20 ); + ResetFlag( FLAG_H ); + SetFlagValue( FLAG_X, result & 0x08 ); + SetFlagValue( FLAG_P, ParityIsEven(result) ); + ResetFlag( FLAG_N ); + break; + + case OTDR: + carry = -1; + goto otxr; + case OTIR: + carry = 1; + otxr: + result = (cpu->ReadMem)( HL, false, cpu ); + op1 = --B; + (cpu->WriteIO)( BC, result, cpu ); + if( cpu->restart_io ) + { + ++B; // Fix up + PC = oldPC; + goto early_exit; + } + HL += carry; + if( op1 ) + PC -= 2; + else + took_branch = false; + out_flags: + // More flag strangeness + op2 = result + L; + SetFlagValue( FLAG_S, op1 & 0x80 ); + SetFlagValue( FLAG_Z, !op1 ); + SetFlagValue( FLAG_Y, op1 & 0x20 ); + SetFlagValue( FLAG_H, op2 > 0xff ); + SetFlagValue( FLAG_X, op1 & 0x08 ); + SetFlagValue( FLAG_P, ParityIsEven((op2&0x07) ^ op1) ); + SetFlagValue( FLAG_N, result & 0x80 ); + SetFlagValue( FLAG_C, op2 > 0xff ); + break; + case OUTD: + carry = -1; + goto outx; + case OUTI: + carry = 1; + outx: + result = (cpu->ReadMem)( HL, false, cpu ); + op1 = --B; + (cpu->WriteIO)( BC, result, cpu ); + if( cpu->restart_io ) + { + ++B; // fix up + PC = oldPC; + goto early_exit; + } + HL += carry; + goto out_flags; + + case OUT_MN_R: // out (n),a + (cpu->WriteIO)( (A<<8)|IMM, A, cpu ); + if( cpu->restart_io ) + { + PC = oldPC; + goto early_exit; + } + break; + + case OUT_R: // out (c),0 + // I don't know what is on the top half of the address + // bus during this, I'm guessing B. + (cpu->WriteIO)( BC, 0, cpu ); + if( cpu->restart_io ) + { + PC = oldPC; + goto early_exit; + } + break; + + case OUT_R_R: // out (c),r + (cpu->WriteIO)( BC, BYTE_REG[OP2], cpu ); + if( cpu->restart_io ) + { + PC = oldPC; + goto early_exit; + } + break; + } +#undef OP1 +#undef OP2 +#undef OFFSET +#undef IMM + + ticks = took_branch? inst.IT->tstates:inst.IT->extra; + ticks += inst.additional_tstates; + +interrupt_exit: + r = BYTE_REG[REG_R]; + r = ((r + inst.r_increment) & 0x7f) | (r & 0x80); + BYTE_REG[REG_R] = r; + +early_exit: + if( outPC ) + *outPC = PC; + return ticks; +} + +int Z80_Disassemble( word address, char *buffer, Z80 cpu ) +{ + Instruction inst; + int length = IF_ID( &inst, address, ReadInstructionMemory, cpu ); + if( buffer != NULL ) + DisassembleInstruction( &inst, buffer ); + return length; +} + +bool Z80_HasHalted( Z80 cpu ) +{ + return cpu->halt; +} + +word Z80_GetReg( int reg, Z80 cpu ) +{ + assert( reg >= 0 && reg < NUM_REG ); + return WORD_REG[reg]; +} + +void Z80_SetReg( int reg, word value, Z80 cpu ) +{ + assert( reg >= 0 && reg < NUM_REG ); + WORD_REG[reg] = value; +} + +void Z80_RaiseNMI( Z80 cpu ) +{ + cpu->nmi = true; +} + +void Z80_RaiseInterrupt( Z80 cpu ) +{ + cpu->interrupt = true; +} + +void Z80_RestartIO( Z80 cpu ) +{ + cpu->restart_io = true; +} + +void Z80_ClearHalt( Z80 cpu ) +{ + cpu->halt = false; +} diff --git a/z80_instructions.c b/z80_instructions.c new file mode 100644 index 0000000..338f10d --- /dev/null +++ b/z80_instructions.c @@ -0,0 +1,206 @@ +/* Copyright (c) 2008 Steve Checkoway + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include /* for snprintf */ +#include +#include /* Need registers */ +#include + +const InstructionTemplate Unprefixed[] = +{ +#include "tables/no_prefix.tab" +}; +const InstructionTemplate CB_Prefixed[] = +{ +#include "tables/cb_prefix.tab" +}; +const InstructionTemplate DD_Prefixed[] = +{ +#include "tables/dd_prefix.tab" +}; +const InstructionTemplate DDCB_Prefixed[] = +{ +#include "tables/ddcb_prefix.tab" +}; +const InstructionTemplate ED_Prefixed[] = +{ +#include "tables/ed_prefix.tab" +}; +const InstructionTemplate FD_Prefixed[] = +{ +#include "tables/fd_prefix.tab" +}; +const InstructionTemplate FDCB_Prefixed[] = +{ +#include "tables/fdcb_prefix.tab" +}; + +int IF_ID( Instruction *inst, word address, ReadMemFunction ReadMem, void *data ) +{ + byte opcode, opcode2 = 0; + int length = 1; + opcode = ReadMem( address, data ); + inst->additional_tstates = 0; + inst->offset = 0; + inst->immediate = 0; + inst->r_increment = 1; + if( opcode == 0xdd || opcode == 0xfd ) + { + ++length; + ++inst->r_increment; + opcode2 = ReadMem( ++address, data ); + while( opcode2 == 0xdd || opcode2 == 0xfd ) + { + inst->additional_tstates += 4; + opcode = opcode2; + ++length; + ++inst->r_increment; + opcode2 = ReadMem( ++address, data ); + } + /* If cocode2 is 0xed, then the prefix should be + * completely ignored apart from the time it took to + * read and the length. */ + if( opcode2 == 0xed ) + opcode = opcode2; + } + + switch( opcode ) + { + case 0xcb: + ++length; + ++inst->r_increment; + opcode = ReadMem( ++address, data ); + inst->IT = &CB_Prefixed[opcode]; + return length; // No immediates/offset + case 0xdd: + if( opcode2 == 0xcb ) + { + length += 2; + inst->offset = (sbyte)ReadMem( ++address, data ); + opcode = ReadMem( ++address, data ); + inst->IT = &DDCB_Prefixed[opcode]; + return length; // No immediates and offset is done + } + inst->IT = &DD_Prefixed[opcode2]; + break; // immediates + case 0xed: + ++length; + ++inst->r_increment; + opcode = ReadMem( ++address, data ); + inst->IT = &ED_Prefixed[opcode]; + break; // immediates + case 0xfd: + if( opcode2 == 0xcb ) + { + length += 2; + inst->offset = (sbyte)ReadMem( ++address, data ); + opcode = ReadMem( ++address, data ); + inst->IT = &FDCB_Prefixed[opcode]; + return length; // No immediates and offset is done + } + inst->IT = &FD_Prefixed[opcode2]; + break; // immediates + default: + inst->IT = &Unprefixed[opcode]; + break; + } + switch( inst->IT->operand_types ) + { + case TYPE_NONE: + break; + case TYPE_IMM_N: + ++length; + inst->immediate = ReadMem( ++address, data ); + break; + case TYPE_OFFSET: + case TYPE_DISP: + ++length; + inst->offset = (sbyte)ReadMem( ++address, data ); + break; + case TYPE_IMM_NN: + length += 2; + inst->immediate = ReadMem( ++address, data ); + inst->immediate |= ReadMem( ++address, data ) << 8; + break; + case TYPE_OFFSET_IMM_N: + length += 2; + inst->offset = (sbyte)ReadMem( ++address, data ); + inst->immediate = ReadMem( ++address, data ); + break; + } + return length; +} + +void DisassembleInstruction( const Instruction *inst, char *buffer ) +{ + char c; + int v; + + switch( inst->IT->operand_types ) + { + case TYPE_NONE: + strncpy( buffer, inst->IT->format, 25 ); + buffer[24] = '\0'; + break; + case TYPE_IMM_N: + case TYPE_IMM_NN: + snprintf( buffer, 25, inst->IT->format, inst->immediate ); + break; + case TYPE_OFFSET: + if( inst->offset >= 0 ) + { + c = '+'; + v = inst->offset; + } + else + { + c = '-'; + v = -inst->offset; + } + snprintf( buffer, 25, inst->IT->format, c, v ); + break; + case TYPE_DISP: + if( inst->offset >= -2 ) + { + c = '+'; + v = inst->offset+2; + } + else + { + c = '-'; + v = -inst->offset - 2; + } + snprintf( buffer, 25, inst->IT->format, c, v ); + break; + case TYPE_OFFSET_IMM_N: + if( inst->offset >= 0 ) + { + c = '+'; + v = inst->offset; + } + else + { + c = '-'; + v = -inst->offset; + } + snprintf( buffer, 25, inst->IT->format, c, v, inst->immediate ); + break; + } +}