v0.2-alpha

This commit is contained in:
redcode
2022-05-17 12:53:52 +02:00
parent b60d21889e
commit 028f50cbde
47 changed files with 7210 additions and 2335 deletions

View File

@@ -6,3 +6,13 @@ end_of_line = lf
indent_size = 8
indent_style = tab
trim_trailing_whitespace = true
[*.{md,rst}]
trim_trailing_whitespace = false
[*.rc]
charset = utf-8-bom
[*.{cff,yml}]
indent_size = 2
indent_style = space

4
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,4 @@
github: redcode
ko_fi: redcode
liberapay: redcode
patreon: redcode

7
.github/pull_request_template.md vendored Normal file
View File

@@ -0,0 +1,7 @@
Thank you for your contribution to the Z80 library. It is required that contributors assign copyright to the original author so that he retains full ownership of the project.
This makes it easier for other entities to use the software because they only have to deal with one copyright holder. It also gives the original author assurance that he will be able to make decisions in the future without gathering and consulting all contributors.
By submitting this PR, you agree to the following:
> You hereby assign copyright in this PR's code to the Z80 library and its copyright holder, Manuel Sainz de Baranda y Goñi, to be licensed under the same terms as the rest of the code. You agree to relinquish any and all copyright interest in the software, to the detriment of your heirs and successors.

72
.github/workflows/documentation-ci.yml vendored Normal file
View File

@@ -0,0 +1,72 @@
name: Documentation CI
on:
push:
paths:
- '.github/**'
- 'API/**'
- 'CMake/FindBreathe.cmake'
- 'CMake/FindSphinx.cmake'
- 'documentation/**'
- 'CMakeLists.txt'
pull_request:
paths:
- '.github/**'
- 'API/**'
- 'CMake/FindBreathe.cmake'
- 'CMake/FindSphinx.cmake'
- 'documentation/**'
- 'CMakeLists.txt'
env:
BUILD_SHARED_LIBS: NO
CMAKE_BUILD_TYPE: Release
CMAKE_VERBOSE_MAKEFILE: YES
Z80_DOWNLOAD_TEST_FILES: NO
Z80_WITH_CMAKE_SUPPORT: NO
Z80_WITH_HTML_DOCUMENTATION: YES
Z80_WITH_PDF_DOCUMENTATION: YES
Z80_WITH_PKGCONFIG_SUPPORT: NO
Z80_WITH_STANDARD_DOCUMENTS: NO
Z80_WITH_TESTS: NO
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Build Tools
run: |
sudo apt-get update
sudo apt-get -y install doxygen
sudo apt-get -y install python3-pip
sudo apt-get -y install texlive-full
pip3 install --user sphinx
pip3 install --user breathe
- name: Install Dependencies
run: |
mkdir -p ${{github.workspace}}/build
curl -L http://zeta.st/downloads/Zeta-latest.tar.xz | xz -cd | tar -C ${{github.workspace}}/build --strip-components=2 -xvf - Zeta/API/Z
- name: Configure CMake
run: >
cmake -B ${{github.workspace}}/build
-DBUILD_SHARED_LIBS=${{env.BUILD_SHARED_LIBS}}
-DCMAKE_BUILD_TYPE=${{env.CMAKE_BUILD_TYPE}}
-DCMAKE_VERBOSE_MAKEFILE=${{env.CMAKE_VERBOSE_MAKEFILE}}
-DZ80_DOWNLOAD_TEST_FILES=${{env.Z80_DOWNLOAD_TEST_FILES}}
-DZ80_WITH_CMAKE_SUPPORT=${{env.Z80_WITH_CMAKE_SUPPORT}}
-DZ80_WITH_HTML_DOCUMENTATION=${{env.Z80_WITH_HTML_DOCUMENTATION}}
-DZ80_WITH_PDF_DOCUMENTATION=${{env.Z80_WITH_PDF_DOCUMENTATION}}
-DZ80_WITH_PKGCONFIG_SUPPORT=${{env.Z80_WITH_PKGCONFIG_SUPPORT}}
-DZ80_WITH_STANDARD_DOCUMENTS=${{env.Z80_WITH_STANDARD_DOCUMENTS}}
-DZ80_WITH_TESTS=${{env.Z80_WITH_TESTS}}
- name: Build HTML Documentation
run: cmake --build ${{github.workspace}}/build --config ${{env.CMAKE_BUILD_TYPE}} --target Documentation-HTML
- name: Build PDF Documentation
run: cmake --build ${{github.workspace}}/build --config ${{env.CMAKE_BUILD_TYPE}} --target Documentation-PDF

92
.github/workflows/library-ci.yml vendored Normal file
View File

@@ -0,0 +1,92 @@
name: Library CI
on:
push:
paths:
- '.github/**'
- 'API/**'
- 'CMake/FindZeta.cmake'
- 'sources/**'
- 'support/*.sha512sum'
- 'CMakeLists.txt'
pull_request:
paths:
- '.github/**'
- 'API/**'
- 'CMake/FindZeta.cmake'
- 'sources/**'
- 'support/*.sha512sum'
- 'CMakeLists.txt'
env:
BUILD_SHARED_LIBS: YES
CMAKE_BUILD_TYPE: Release
CMAKE_VERBOSE_MAKEFILE: YES
Z80_DOWNLOAD_TEST_FILES: YES
Z80_NOSTDLIB_FLAGS: Auto
Z80_WITH_CMAKE_SUPPORT: NO
Z80_WITH_HTML_DOCUMENTATION: NO
Z80_WITH_PDF_DOCUMENTATION: NO
Z80_WITH_PKGCONFIG_SUPPORT: NO
Z80_WITH_STANDARD_DOCUMENTS: NO
Z80_WITH_TESTS: YES
Z80_WITH_EXECUTE: YES
Z80_WITH_FULL_IM0: YES
Z80_WITH_Q: YES
Z80_WITH_RESET_SIGNAL: YES
Z80_WITH_SPECIAL_RESET_SIGNAL: NO
Z80_WITH_UNOFFICIAL_RETI: NO
Z80_WITH_ZILOG_NMOS_LD_A_IR_BUG: YES
jobs:
build:
runs-on: ${{matrix.os}}
strategy:
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@v3
- name: Install Dependencies (POSIX)
if: startsWith(matrix.os, 'macos') || startsWith(matrix.os, 'ubuntu')
run: |
mkdir -p ${{github.workspace}}/build
curl -L http://zeta.st/downloads/Zeta-latest.tar.xz | xz -cd | tar -C ${{github.workspace}}/build --strip-components=2 -xvf - Zeta/API/Z
- name: Install Dependencies (Windows)
if: startsWith(matrix.os, 'windows')
shell: cmd
run: |
mkdir ${{github.workspace}}\build
curl -L http://zeta.st/downloads/Zeta-latest.tar.xz | 7z x -txz -si -so | 7z x -si -ttar -o${{github.workspace}}\build Zeta/API/Z
- name: Configure CMake
run: >
cmake -B ${{github.workspace}}/build
-DBUILD_SHARED_LIBS=${{env.BUILD_SHARED_LIBS}}
-DCMAKE_BUILD_TYPE=${{env.CMAKE_BUILD_TYPE}}
-DCMAKE_VERBOSE_MAKEFILE=${{env.CMAKE_VERBOSE_MAKEFILE}}
-DZ80_DOWNLOAD_TEST_FILES=${{env.Z80_DOWNLOAD_TEST_FILES}}
-DZ80_NOSTDLIB_FLAGS=${{env.Z80_NOSTDLIB_FLAGS}}
-DZ80_WITH_CMAKE_SUPPORT=${{env.Z80_WITH_CMAKE_SUPPORT}}
-DZ80_WITH_HTML_DOCUMENTATION=${{env.Z80_WITH_HTML_DOCUMENTATION}}
-DZ80_WITH_PDF_DOCUMENTATION=${{env.Z80_WITH_PDF_DOCUMENTATION}}
-DZ80_WITH_PKGCONFIG_SUPPORT=${{env.Z80_WITH_PKGCONFIG_SUPPORT}}
-DZ80_WITH_STANDARD_DOCUMENTS=${{env.Z80_WITH_STANDARD_DOCUMENTS}}
-DZ80_WITH_TESTS=${{env.Z80_WITH_TESTS}}
-DZ80_WITH_EXECUTE=${{env.Z80_WITH_EXECUTE}}
-DZ80_WITH_FULL_IM0=${{env.Z80_WITH_FULL_IM0}}
-DZ80_WITH_Q=${{env.Z80_WITH_Q}}
-DZ80_WITH_RESET_SIGNAL=${{env.Z80_WITH_RESET_SIGNAL}}
-DZ80_WITH_SPECIAL_RESET_SIGNAL=${{env.Z80_WITH_SPECIAL_RESET_SIGNAL}}
-DZ80_WITH_UNOFFICIAL_RETI=${{env.Z80_WITH_UNOFFICIAL_RETI}}
-DZ80_WITH_ZILOG_NMOS_LD_A_IR_BUG=${{env.Z80_WITH_ZILOG_NMOS_LD_A_IR_BUG}}
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.CMAKE_BUILD_TYPE}}
- name: Test
working-directory: ${{github.workspace}}/build
run: ctest --output-on-failure -C ${{env.CMAKE_BUILD_TYPE}}

3
.gitignore vendored
View File

@@ -1,3 +1,4 @@
.directory
.DS_Store
.directory
Thumbs.db
build/

4
.vimrc Normal file
View File

@@ -0,0 +1,4 @@
set noexpandtab
set shiftwidth=8
set tabstop=8
autocmd BufWritePre * %s/\s\+$//e

672
API/Z80.h Normal file
View File

@@ -0,0 +1,672 @@
/* Z80 API
______ ______ ______
/\___ \/\ __ \\ __ \
____ \/__/ /\_\ __ \\ \/\ \ ________________________________________________
| /\_____\\_____\\_____\ |
| Zilog \/_____//_____//_____/ CPU Emulator |
| Copyright (C) 1999-2022 Manuel Sainz de Baranda y Goñi. |
| |
| This emulator is free software: you can redistribute it and/or modify it |
| under the terms of the GNU Lesser General Public License as published by |
| the Free Software Foundation, either version 3 of the License, or (at your |
| option) any later version. |
| |
| This emulator is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
| License for more details. |
| |
| You should have received a copy of the GNU Lesser General Public License |
| along with this emulator. If not, see <http://www.gnu.org/licenses/>. |
| |
'=============================================================================*/
#ifndef Z80_H
/** @file Z80.h
* @brief Zilog Z80 CPU emulator.
*
* @details The Z80 library implements a fast, small and accurate emulator
* of the Zilog Z80. It emulates all that is known to date about this CPU,
* including the undocumented flags and instructions, MEMPTR, Q, and the
* special RESET.
*
* @version 0.2
* @date 2022-05-29
* @author Manuel Sainz de Baranda y Goñi. */
#ifdef Z80_DEPENDENCIES_HEADER
# define Z80_H
# include Z80_DEPENDENCIES_HEADER
# undef Z80_H
#else
# include <Z/macros/language.h>
# include <Z/types/bitwise.h>
#endif
#ifndef Z80_API
# if defined(Z80_STATIC) || defined(__DOXYGEN__)
# define Z80_API
# else
# define Z80_API Z_API_IMPORT
# endif
#endif
/** @brief The major version number of the Z80 library. */
#define Z80_LIBRARY_VERSION_MAJOR 0
/** @brief The minor version number of the Z80 library. */
#define Z80_LIBRARY_VERSION_MINOR 2
/** @brief The micro version number of the Z80 library. */
#define Z80_LIBRARY_VERSION_MICRO 0
/** @brief A string literal with the version number of the Z80 library. */
#define Z80_LIBRARY_VERSION_STRING "0.2"
/** @brief The maximum number of clock cycles that the @ref z80_run and @ref
* z80_execute functions can emulate per call. */
#define Z80_CYCLE_LIMIT (Z_USIZE_MAXIMUM - Z_USIZE(30))
#define Z80_CYCLES_PER_RESET 5
/** @brief The 8-bit value interpreted as a hook by the Z80 emulator, which
* corresponds to the <tt>ld h,h</tt> opcode in the Z80 ISA. */
#define Z80_HOOK Z_UINT8(0x64)
/** @brief Defines a pointer to a callback function used by the Z80 emulator
* to read a byte.
*
* @param context The value of the @ref Z80.context member variable of the
* object invoking the callback.
* @param address The memory address or I/O port to read from.
* @return The byte read. */
typedef zuint8 (* Z80Read)(void *context, zuint16 address);
/** @brief Defines a pointer to a callback function used by the Z80 emulator
* to write a byte.
*
* @param context The value of the @ref Z80.context member variable of the
* object invoking the callback.
* @param address The memory address or I/O port to write to.
* @param value The byte to write. */
typedef void (* Z80Write)(void *context, zuint16 address, zuint8 value);
/** @brief Defines a pointer to a callback function used by the Z80 emulator
* to notify the change of state of the HALT line.
*
* @param context The value of the @ref Z80.context member variable of the
* object invoking the callback.
* @param state
* @c TRUE if the HALT line goes low (the CPU enters the HALT state);
* @c FALSE if the HALT line goes high (the CPU exits the HALT state). */
typedef void (* Z80HALT)(void *context, zboolean state);
/** @brief Defines a pointer to a callback function used by the Z80 emulator
* to notify an event.
*
* @param context The value of the @ref Z80.context member variable of the
* object invoking the callback. */
typedef void (* Z80Notify)(void *context);
typedef zusize (* Z80Reset)(void *context, zuint16 address);
/** @struct Z80 Z80.h
*
* @brief A Z80 CPU emulator.
*
* @details @c Z80 contains the state of an emulated Z80 CPU
* and the callback pointers needed to interconnect it with the external logic.
* Before using an object of this type, some of its members
* must be initialized. In particular the following (in alphabetical order):
* @ref Z80.context, @ref Z80.fetch, @ref Z80.fetch_opcode, @ref Z80.halt_nop,
* @ref Z80.in, @ref Z80.out, @ref Z80.read, @ref Z80.write, @ref Z80.read_bus,
* @ref Z80.halt, @ref Z80.inta, @ref Z80.reti @ref Z80.hook and @ref
* Z80.model.
*
* Callback | Mandatory
* --------------------- | ---------
* @ref Z80.fetch_opcode | yes
* @ref Z80.fetch | yes
* @ref Z80.read | yes
* @ref Z80.write | yes
* @ref Z80.in | yes
* @ref Z80.out | yes
* @ref Z80.halt | no
* @ref Z80.halt_nop | no
* @ref Z80.nmia | yes
* @ref Z80.inta | yes
* @ref Z80.int_fetch | no
* @ref Z80.ld_i_a | no
* @ref Z80.ld_r_a | no
* @ref Z80.reti | no
* @ref Z80.retn | no
* @ref Z80.hook | no
*/
typedef struct {
/** @brief Clock cycle counter.
*
* This clock cycle counter is updated as the emulator executes
* instructions and responds to different signals. */
zusize cycles;
/** @brief Maximum number of clock cycles to be executed in the current
* invokation of @ref z80_run. */
zusize cycle_limit;
/** @brief Pointer passed as the first argument to the callbacks.
*
* @details This member variable can be used to maintain a reference to
* the object or context to which the Z80 emulator object belongs. */
void *context;
/** @brief Callback used to perform opcode fetch operations.
*
* @details This type of operation is used by the CPU to read the first
* byte of an instruction or an instruction prefix. A succession of
* @c DDh and/or @c FDh prefixes will cause multiple consecutive such
* operations until an opcode is fetched. In the instructions with
* double prefix (@c CBDDh or @c CBFDh), only the prefixes are fetched
* with this operation, the remaining 2 bytes are accessed by using
* normal memory read operations.
*
* The emulator always incrementents the R register @b before calling
* this callback, but the value of its most-significant bit (R7) is not
* preserved for speed optimization reasons. In the rare case that the
* callback function needs to access that register, it must take R7
* from the 7th bit of the @c r7 member variable.
*
* Implementations that do not distinguish between opcode fetch and
* memory read operations should use the same callback function for
* both.
*
* @attention This callback is mandatory, initializing it to @c Z_NULL
* will cause the emulator to crash. */
Z80Read fetch_opcode;
/** @brief Callback used to perform memory read operations on instruction data.
*
* @attention This callback is mandatory, initializing it to @c Z_NULL
* will cause the emulator to crash. */
Z80Read fetch;
/** @brief Callback used to perform a memory read operation.
*
* @details This type of operation is used by the CPU to read a byte
* from a memory address.
*
* @attention This callback is mandatory, initializing it to @c Z_NULL
* will cause the emulator to crash. */
Z80Read read;
/** @brief Callback used to perform a memory write operation.
*
* @details This type of operation is used by the CPU to write a byte
* to a memory address.
*
* @attention This callback is mandatory, initializing it to @c Z_NULL
* will cause the emulator to crash. */
Z80Write write;
/** @brief Callback used to perform an I/O read operation.
*
* @details This type of operation is used by the CPU to read a byte
* from an I/O port.
*
* @attention This callback is mandatory, initializing it to @c Z_NULL
* will cause the emulator to crash. */
Z80Read in;
/** @brief Callback used to perform an I/O write operation.
*
* @details This type of operation is used by the CPU to write a byte
* to an I/O port.
*
* @attention This callback is mandatory, initializing it to @c Z_NULL
* will cause the emulator to crash. */
Z80Write out;
/** @brief Callback used to notify that the state of the HALT output
* line has changed.
*
* @details The @c HALT instruction halts the CPU by not incrementing
* the PC register, so the instruction is re-executed until an
* interrupt is accepted. Only then the PC register is incremented
* again and the next instruction is executed. The HALT output line is
* active (low) during the HALT state.
*
* The emulator invokes this callback after changing the value of the
* @c halt_line member variable and, when exiting the HALT state,
* immediately before executing the interrupt response.
*
* @attention This callback is optional and @b must be initialized to
* @c Z_NULL if not used. */
Z80HALT halt;
/** @brief Callback invoked... */
Z80Read nop;
/** @brief Callback invoked... */
Z80Read nmia;
/** @brief Callback used to notify a maskable interrupt acknowledge
* (INTA).
*
* @details When a maskable interrupt (INT) is accepted, the CPU
* generates a special M1 cycle to indicate that the interrupting I/O
* device can write to the data bus. Two wait clock cycles are added
* to this M1 cycle, allowing sufficient time to identify which device
* must insert the data.
*
* The emulator invokes this callback during the execution of the INT
* response. It should be used to identify and prepare the context of
* the interrupting device, so that subsequent invocations of the @c
* read_bus callback can read the interrupt response vector or the
* instruction to be executed.
*
* @note This callback is optional and @b must be initialized to @c
* Z_NULL if not used.
* @details When a maskable interrupt (INT) is accepted, the CPU reads
* the interrupt response data provided by the interrupting device via
* the data bus. Usually only one data bus read operation is performed
* during the INT acknowledge cycle, but when the CPU responds to the
* interrupt in mode 0, it will perform as many such operations as
* needed to read the byte sequence of the instruction to be executed.
*
* The emulator invokes this callback during the execution of the INT
* response. The return value is ignored in interrupt mode 1. In mode
* 0, the emulator invokes this callback as many times as needed to
* read a complete instruction. Illegal instructions and instruction
* prefix sequences are fully supported.
*
* @attention This callback is optional and @b must be initialized to
* @c Z_NULL if not used, in which case the emulator will assume that
* the byte read from the data bus is always @c FFh. */
Z80Read inta;
/** @brief Callback used to perform a data bus read operation during a
* maskable interrupt (INT) response.
**/
Z80Read int_fetch;
Z80Reset reset;
/** @brief Callback invoked before executing the <tt>ld i,a</tt>
* instruction. */
Z80Notify ld_i_a;
/** @brief Callback invoked before executing the <tt>ld r,a</tt>
* instruction.
*
* @attention This callback is optional and @b must be initialized to
* @c Z_NULL if not used. */
Z80Notify ld_r_a;
/** @brief Callback invoked before executing the @c reti instruction.
*
* The Z80 Counter/Timer Circuit (CTC) detects the two-byte @c reti
* opcode when it is fetched by the CPU. This instruction is used to
* return from an ISR and signal that the computer should initialize
* the daisy-chain enable lines for control of nested priority
* interrupt handling.
*
* Although the Z80 CTC is not part of the CPU, the emulator can signal
* the execution of a @c reti instruction by invoking this callback in
* order to simplify the emulation of machines that use daisy-chain
* interrupt servicing, thus avoiding having to implement the detection
* of this instruction externally, which is not optimal and would cause
* a speed penalty.
*
* @attention This callback is optional and @b must be initialized to
* @c Z_NULL if not used. */
Z80Notify reti;
/** @brief Callback invoked before executing the @c retn instruction.
* @attention This callback is optional and @b must be initialized to
* @c Z_NULL if not used. */
Z80Notify retn;
/** @brief Callback invoked...
*
* @attention This callback is optional and @b must be initialized to
* @c Z_NULL if not used. */
Z80Read hook;
/** @brief Temporary storage used for instruction fetch. */
ZInt32 data;
/** @brief Temporay IX/IY register. */
ZInt16 xy;
ZInt16 memptr; /**< @brief MEMPTR register. */
ZInt16 pc; /**< @brief PC register. */
ZInt16 sp; /**< @brief SP register. */
ZInt16 ix; /**< @brief IX register. */
ZInt16 iy; /**< @brief IY register. */
ZInt16 af; /**< @brief AF register. */
ZInt16 bc; /**< @brief BC register. */
ZInt16 de; /**< @brief DE register. */
ZInt16 hl; /**< @brief HL register. */
ZInt16 af_; /**< @brief AF' register. */
ZInt16 bc_; /**< @brief BC' register. */
ZInt16 de_; /**< @brief DE' register. */
ZInt16 hl_; /**< @brief HL' register. */
zuint8 r; /**< @brief R register. */
zuint8 i; /**< @brief I register. */
/** @brief The most significant bit of the R register (R7).
*
* @details The R register is incremented during each M1 cycle, but its
* most significant bit (R7) is not affected. For optimization reasons,
* this behavior is not emulated in every M1 cycle, so successive
* increments of R corrupt R7. @c z80_run keeps the value of R7 in this
* temporary member variable while executing operations and copies it
* back to R before returning. Since this variable is a snapshot of the
* R register at a given time, the value of the 7 least significant
* bits must be considered garbage. */
zuint8 r7;
/** @brief Maskable interrup mode.
*
* @details Contains the number of the maskable interrupt mode in use:
* `0`, `1` or `2`. */
zuint8 im;
/** @brief Number of signals pending to be processed. */
zuint8 request;
/** @brief TODO */
zuint8 resume;
zuint8 iff1; /**< @brief Interrupt flip-flop 1 (IFF1). */
zuint8 iff2; /**< @brief Interrupt flip-flop 2 (IFF2). */
zuint8 q; /**< @brief Q register. */
/** @brief CPU model.
*
* @details todo... */
zuint8 options;
/** @brief State of the INT line.
*
* @details Contains @c TRUE if the INT line is active, or @c FALSE
* otherwise. */
zuint8 int_line;
/** @brief State of the HALT line.
*
* @details Contains @c TRUE if the HALT line is active, or @c FALSE
* otherwise. The emulator always modifies this variable before
* invoking the @ref Z80.halt callback. */
zuint8 halt_line;
} Z80;
#define Z80_MEMPTR(self) (self).memptr.uint16_value
#define Z80_MEMPTRH(self) (self).memptr.uint8_values.at_1
#define Z80_MEMPTRL(self) (self).memptr.uint8_values.at_0
#define Z80_PC(self) (self).pc.uint16_value
#define Z80_SP(self) (self).sp.uint16_value
#define Z80_XY(self) (self).xy.uint16_value
#define Z80_IX(self) (self).ix.uint16_value
#define Z80_IY(self) (self).iy.uint16_value
#define Z80_AF(self) (self).af.uint16_value
#define Z80_BC(self) (self).bc.uint16_value
#define Z80_DE(self) (self).de.uint16_value
#define Z80_HL(self) (self).hl.uint16_value
#define Z80_AF_(self) (self).af_.uint16_value
#define Z80_BC_(self) (self).bc_.uint16_value
#define Z80_DE_(self) (self).de_.uint16_value
#define Z80_HL_(self) (self).hl_.uint16_value
#define Z80_PCH(self) (self).pc.uint8_values.at_1
#define Z80_PCL(self) (self).pc.uint8_values.at_0
#define Z80_SPH(self) (self).sp.uint8_values.at_1
#define Z80_SPL(self) (self).sp.uint8_values.at_0
#define Z80_XYH(self) (self).xy.uint8_values.at_1
#define Z80_XYL(self) (self).xy.uint8_values.at_0
#define Z80_IXH(self) (self).ix.uint8_values.at_1
#define Z80_IXL(self) (self).ix.uint8_values.at_0
#define Z80_IYH(self) (self).iy.uint8_values.at_1
#define Z80_IYL(self) (self).iy.uint8_values.at_0
#define Z80_A(self) (self).af.uint8_values.at_1
#define Z80_F(self) (self).af.uint8_values.at_0
#define Z80_B(self) (self).bc.uint8_values.at_1
#define Z80_C(self) (self).bc.uint8_values.at_0
#define Z80_D(self) (self).de.uint8_values.at_1
#define Z80_E(self) (self).de.uint8_values.at_0
#define Z80_H(self) (self).hl.uint8_values.at_1
#define Z80_L(self) (self).hl.uint8_values.at_0
#define Z80_A_(self) (self).af_.uint8_values.at_1
#define Z80_F_(self) (self).af_.uint8_values.at_0
#define Z80_B_(self) (self).bc_.uint8_values.at_1
#define Z80_C_(self) (self).bc_.uint8_values.at_0
#define Z80_D_(self) (self).de_.uint8_values.at_1
#define Z80_E_(self) (self).de_.uint8_values.at_0
#define Z80_H_(self) (self).hl_.uint8_values.at_1
#define Z80_L_(self) (self).hl_.uint8_values.at_0
#define Z80_SF 128
#define Z80_ZF 64
#define Z80_YF 32
#define Z80_HF 16
#define Z80_XF 8
#define Z80_PF 4
#define Z80_NF 2
#define Z80_CF 1
#define Z80_OPTION_LD_A_IR_BUG 1
#define Z80_OPTION_OUT_VC_255 2
#define Z80_OPTION_XQ 8
#define Z80_OPTION_HALT_SKIP 16
#define Z80_OPTION_YQ 32
/** @brief Zilog Z80 NMOS version. */
#define Z80_MODEL_ZILOG_NMOS \
(Z80_OPTION_LD_A_IR_BUG | Z80_OPTION_XQ | Z80_OPTION_YQ)
/** @brief Zilog Z80 CMOS version. */
#define Z80_MODEL_ZILOG_CMOS \
(Z80_OPTION_OUT_VC_255 | Z80_OPTION_XQ | Z80_OPTION_YQ)
#define Z80_MODEL_NEC_NMOS \
Z80_OPTION_LD_A_IR_BUG
#define Z80_MODEL_ST_CMOS \
(Z80_OPTION_LD_A_IR_BUG | Z80_OPTION_YQ)
#define Z80_REQUEST_RESET 3
#define Z80_REQUEST_REJECT_NMI 4
#define Z80_REQUEST_NMI 8 /**< NMI pending. */
#define Z80_REQUEST_CLEAR_PC 16
#define Z80_REQUEST_SPECIAL_RESET 32
#define Z80_REQUEST_INT 64 /**< INT pending. */
#define Z80_REQUEST_ANY_RESET 35
#define Z80_REQUEST_RESET 3
#define Z80_REQUEST_INTERRUPT 5
#define Z80_RESUME_HALT 1 /**< Resume the execution of the HALT state. */
#define Z80_RESUME_XY 2 /**< Resume at opcode decode stage in INT mode 0. */
#define Z80_RESUME_IM0_XY 3 /**< Resume at opcode decode stage. */
#define Z80_RESUME_NORMAL_RESET 4
#define Z80_RESUME_SPECIAL_RESET_XY 5
#define Z80_RESUME_SPECIAL_RESET_NOP 6
Z_EXTERN_C_BEGIN
/** @brief Sets the power state of a Z80 emulator.
*
* @param self Pointer to the object on which the function is called.
* @param state
* @c TRUE = power ON;
* @c FALSE = power OFF. */
Z80_API void z80_power(Z80 *self, zboolean state);
/** @brief Performs a normal RESET on a Z80 emulator.
*
* @param self Pointer to the object on which the function is called. */
Z80_API void z80_instant_reset(Z80 *self);
/** @brief Sends a normal RESET signal to a Z80 emulator.
*
* @details todo
*
* @param self Pointer to the object on which the function is called. */
Z80_API void z80_reset(Z80 *self);
/** @brief Sends a special RESET signal to a Z80 emulator.
*
* @details todo
*
* @sa
* - http://www.primrosebank.net/computers/z80/z80_special_reset.htm
* - US Patent 4486827
*
* @param self Pointer to the object on which the function is called. */
Z80_API void z80_special_reset(Z80 *self);
/** @brief Sets the state of the INT line of a Z80 emulator.
*
* @param self Pointer to the object on which the function is called.
* @param state
* @c TRUE = ON (line low);
* @c FALSE = OFF (line high). */
Z80_API void z80_int(Z80 *self, zboolean state);
/** @brief Sends a NMI signal to a Z80 emulator.
*
* @param self Pointer to the object on which the function is called. */
Z80_API void z80_nmi(Z80 *self);
Z80_API void z80_busreq(Z80 *self, zboolean state);
/** @brief Runs a Z80 emulator for a given number of clock @p cycles, executing
* only instructions without responding to signals.
*
* @details Given the fact that one Z80 instruction takes between 4 and 23
* cycles to be executed, it is not always possible to run the CPU the exact
* number of @p cycles specfified.
*
* @param self Pointer to the object on which the function is called.
* @param cycles Number of clock cycles to be emulated.
* @return The actual number of clock cycles emulated. */
Z80_API zusize z80_execute(Z80 *self, zusize cycles);
/** @brief Runs a Z80 emulator for a given number of clock @p cycles.
*
* @details Given the fact that one Z80 instruction takes between 4 and 23
* cycles to be executed, it is not always possible to run the CPU the exact
* number of @p cycles specfified.
*
* @param self Pointer to the object on which the function is called.
* @param cycles Number of clock cycles to be emulated.
* @return The actual number of clock cycles emulated. */
Z80_API zusize z80_run(Z80 *self, zusize cycles);
/** @brief Obtains the refresh address of the M1 cycle being executed by a Z80
* emulator.
*
* @details todo
*
* @param self Pointer to the object on which the function is called.
* @return todo */
static Z_INLINE zuint16 z80_refresh_address(Z80 *self)
{return ((zuint16)self->i << 8) | ((self->r - 1) & 127);}
/** @brief Computes the clock cycle, relative to the start of the instruction,
* at which the I/O read M-cycle being executed by a Z80 emulator begins.
*
* @details todo
*
* @param self Pointer to the object on which the function is called.
* @return todo */
static Z_INLINE zuint8 z80_in_cycle(Z80 *self)
{
return self->data.uint8_array[0] == 0xDB
? /* in a,(BYTE) : 4+3 */
7
: /* in J,(c) / in (c) : 4+4 */
8
+ /* ini / ind / inir / indr : 4+5 */
(self->data.uint8_array[1] >> 7);
}
/** @brief Computes the clock cycle, relative to the start of the instruction,
* at which the I/O write M-cycle being executed by a Z80 emulator begins.
*
* @details todo
*
* @param self Pointer to the object on which the function is called.
* @return todo */
static Z_INLINE zuint8 z80_out_cycle(Z80 *self)
{
return self->data.uint8_array[0] == 0xD3
? /* out (BYTE),a : 4+3 */
7
: /* out (c),J / out (c),0 : 4+4 */
8
+ /* outi / outd / otir / otdr : 4+5+3 */
((self->data.uint8_array[1] >> 7) << 2);
}
Z_EXTERN_C_END
#endif /* Z80_H */

View File

@@ -1,201 +0,0 @@
/* ______ ______ ______
/\___ \ /\ __ \/\ __ \
\/__/ /_\ \ __ \ \ \/\ \
/\_____\ \_____\ \_____\
Zilog \/_____/\/_____/\/_____/ CPU Emulator ----------------------------------
Copyright (C) 1999-2018 Manuel Sainz de Baranda y Goñi.
This emulator is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
This emulator is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this emulator. If not, see <http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------- */
#ifndef _emulation_CPU_Z80_H_
#define _emulation_CPU_Z80_H_
#ifdef CPU_Z80_DEPENDENCIES_H
# include CPU_Z80_DEPENDENCIES_H
#else
# include <Z/hardware/CPU/architecture/Z80.h>
#endif
/** Z80 emulator instance.
* @details This structure contains the state of the emulated CPU and callback
* pointers necessary to interconnect the emulator with external logic. There
* is no constructor function, so, before using an object of this type, some
* of its members must be initialized, in particular the following:
* @c context, @c read, @c write, @c in, @c out, @c int_data and @c halt. */
typedef struct {
/** Number of cycles executed in the current call to @c z80_run.
* @details @c z80run sets this variable to @c 0 before starting
* to execute instructions and its value persists after returning.
* The callbacks can use this variable to know during what cycle
* they are being called. */
zusize cycles;
/** The value used as the first argument when calling a callback.
* @details This variable should be initialized before using the
* emulator and can be used to reference the context/instance of
* the machine being emulated. */
void *context;
/** Callback: Called when the CPU needs to read 8 bits from memory.
* @param context The value of the member @c context.
* @param address The memory address to read from.
* @return The 8 bits read from memory. */
zuint8 (* read)(void *context, zuint16 address);
/** Callback: Called when the CPU needs to write 8 bits to memory.
* @param context The value of the member @c context.
* @param address The memory address to write to.
* @param value The value to write. */
void (* write)(void *context, zuint16 address, zuint8 value);
/** Callback: Called when the CPU needs to read 8 bits from an I/O port.
* @param context The value of the member @c context.
* @param port The number of the I/O port to read from.
* @return The 8 bits read from the I/O port. */
zuint8 (* in)(void *context, zuint16 port);
/** Callback: Called when the CPU needs to write 8 bits to an I/O port.
* @param context The value of the member @c context.
* @param port The number of the I/O port to write to.
* @param value The value to write. */
void (* out)(void *context, zuint16 port, zuint8 value);
/** Callback: Called when the CPU needs to read one instruction from
* the data bus to service a maskable interrupt (INT) in mode 0.
* @param context The value of the member @c context.
* @return A 32-bit value containing the bytes of one instruction. The
* instruction must begin at the most significant byte (big endian). */
zuint32 (* int_data)(void *context);
/** Callback: Called when the CPU enters or exits the halt state.
* @param context The value of the member @c context.
* @param state @c TRUE if halted; @c FALSE otherwise.
* @note This callback is optional and must be set to @c NULL if not
* used. */
void (* halt)(void *context, zboolean state);
/** CPU registers and internal bits.
* @details It contains the state of the registers, as well as the
* interrupt flip-flops, variables related to interrupts and other
* necessary flags. This is what a debugger should use as its data
* source. */
ZZ80State state;
/** Backup of the 7th bit of the R register.
* @details The value of the R register is incremented as instructions
* are executed, but its most significant bit remains unchanged. For
* optimization reasons, this bit is saved at the beginning of the
* execution of @c z80_run and restored before returning. If an
* instruction directly affects the R register, this variable is also
* updated accordingly. */
zuint8 r7;
/** Temporay IX/IY register for instructions with @c DDh/FDh prefix.
* @details Since instructions with prefix @c DDh and @c FDh behave
* similarly, differing only in the use of register IX or IY, for
* reasons of size optimization, a single register is used that acts
* as both. During opcode analysis, the IX or IY register is copied
* to this variable and, once the instruction emulation is complete,
* its contents are copied back to the appropriate register. */
Z16Bit xy;
/** Temporary storage for opcode fetching.
* @details This is an internal private variable. */
Z32Bit data;
} Z80;
Z_C_SYMBOLS_BEGIN
#ifndef CPU_Z80_API
# ifdef CPU_Z80_STATIC
# define CPU_Z80_API
# else
# define CPU_Z80_API Z_API
# endif
#endif
/** Changes the CPU power status.
* @param object A pointer to a Z80 emulator instance.
* @param state @c TRUE = power ON; @c FALSE = power OFF. */
CPU_Z80_API void z80_power(Z80 *object, zboolean state);
/** Resets the CPU.
* @details This is equivalent to a pulse on the RESET line of a real Z80.
* @param object A pointer to a Z80 emulator instance. */
CPU_Z80_API void z80_reset(Z80 *object);
/** Runs the CPU for a given number of @p cycles.
* @param object A pointer to a Z80 emulator instance.
* @param cycles The number of cycles to be executed.
* @return The number of cycles executed.
* @note Given the fact that one Z80 instruction needs between 4 and 23 cycles
* to be executed, it's not always possible to run the CPU the exact number of
* @p cycles specfified. */
CPU_Z80_API zusize z80_run(Z80 *object, zusize cycles);
/** Performs a non-maskable interrupt (NMI).
* @details This is equivalent to a pulse on the NMI line of a real Z80.
* @param object A pointer to a Z80 emulator instance. */
CPU_Z80_API void z80_nmi(Z80 *object);
/** Changes the state of the maskable interrupt (INT).
* @details This is equivalent to a change on the INT line of a real Z80.
* @param object A pointer to a Z80 emulator instance.
* @param state @c TRUE = line high; @c FALSE = line low. */
CPU_Z80_API void z80_int(Z80 *object, zboolean state);
Z_C_SYMBOLS_END
#ifdef CPU_Z80_WITH_ABI
# ifndef CPU_Z80_DEPENDENCIES_H
# include <Z/ABIs/generic/emulation.h>
# endif
Z_C_SYMBOLS_BEGIN
# ifndef CPU_Z80_ABI
# ifdef CPU_Z80_STATIC
# define CPU_Z80_ABI
# else
# define CPU_Z80_ABI Z_API
# endif
# endif
CPU_Z80_ABI extern ZCPUEmulatorABI const abi_emulation_cpu_z80;
Z_C_SYMBOLS_END
#endif
#endif /* _emulation_CPU_Z80_H_ */

22
CITATION.cff Normal file
View File

@@ -0,0 +1,22 @@
abstract: "Zilog Z80 CPU emulator."
authors:
- family-names: "Sainz de Baranda y Goñi"
given-names: "Manuel"
orcid: "https://orcid.org/0000-0001-6326-3519"
email: "manuel@zxe.io"
website: "https://zxe.io"
cff-version: 1.2.0
date-released: "2022-05-29"
keywords:
- CPU
- LLE
- Z80
- Zilog
- emulator
license: LGPL-3.0-or-later
message: "If you use this software, please cite it using these metadata."
repository-code: "https://github.com/redcode/Z80"
title: "Z80"
type: software
version: 0.2
url: "https://zxe.io/software/Z80"

29
CMake/FindBreathe.cmake Normal file
View File

@@ -0,0 +1,29 @@
# FindBreathe.cmake
# Copyright (C) 2021 Manuel Sainz de Baranda y Goñi.
# This "find module" is DISTRIBUTED AS PUBLIC DOMAIN. No restrictions apply.
include(FindPackageHandleStandardArgs)
find_program(
BREATHE_APIDOC_EXECUTABLE
NAMES breathe-apidoc
DOC "Breathe extension for Sphinx")
if(BREATHE_APIDOC_EXECUTABLE)
execute_process(
COMMAND ${BREATHE_APIDOC_EXECUTABLE} --version
OUTPUT_VARIABLE _output)
if("${_output}" MATCHES ".* ([^\n]+)\n")
set(BREATHE_APIDOC_VERSION "${CMAKE_MATCH_1}")
endif()
endif()
find_package_handle_standard_args(
Breathe
REQUIRED_VARS BREATHE_APIDOC_EXECUTABLE
VERSION_VAR BREATHE_APIDOC_VERSION)
mark_as_advanced(BREATHE_APIDOC_EXECUTABLE)
# FindBreathe.cmake EOF

29
CMake/FindSphinx.cmake Normal file
View File

@@ -0,0 +1,29 @@
# FindSphinx.cmake
# Copyright (C) 2021 Manuel Sainz de Baranda y Goñi.
# This "find module" is DISTRIBUTED AS PUBLIC DOMAIN. No restrictions apply.
include(FindPackageHandleStandardArgs)
find_program(
SPHINX_BUILD_EXECUTABLE
NAMES sphinx-build
DOC "Sphinx Documentation Builder")
if(SPHINX_BUILD_EXECUTABLE)
execute_process(
COMMAND ${SPHINX_BUILD_EXECUTABLE} --version
OUTPUT_VARIABLE _output)
if("${_output}" MATCHES ".* ([^\n]+)\n")
set(SPHINX_BUILD_VERSION "${CMAKE_MATCH_1}")
endif()
endif()
find_package_handle_standard_args(
Sphinx
REQUIRED_VARS SPHINX_BUILD_EXECUTABLE
VERSION_VAR SPHINX_BUILD_VERSION)
mark_as_advanced(SPHINX_BUILD_EXECUTABLE)
# FindSphinx.cmake EOF

50
CMake/FindZ80.cmake Normal file
View File

@@ -0,0 +1,50 @@
# Z80 - FindZ80.cmake
# ______ ______ ______
# /\___ \/\ __ \\ __ \
# \/__/ /\_\ __ \\ \/\ \
# /\_____\\_____\\_____\
# Zilog \/_____//_____//_____/ CPU Emulator
# Copyright (C) 1999-2022 Manuel Sainz de Baranda y Goñi.
# Released under the terms of the GNU Lesser General Public License v3.
# This "find module" is DISTRIBUTED AS PUBLIC DOMAIN. No restrictions apply.
include(FindPackageHandleStandardArgs)
find_path(
Z80_INCLUDE_DIR
"Z80.h"
HINTS ${PROJECT_BINARY_DIR}
${PROJECT_SOURCE_DIR}
PATH_SUFFIXES
"deps/Z80/API"
"dependencies/Z80/API"
"extern/Z80/API"
"external/Z80/API"
"externals/Z80/API"
"kits/Z80/API/"
"Z80/API"
"../Z80/API"
)
if(Z80_INCLUDE_DIR)
file(READ "${Z80_INCLUDE_DIR}/Z80.h" _h)
if(${_h} MATCHES ".*Z80_LIBRARY_VERSION_STRING \"([^\n]*)\".*")
set(Z80_VERSION ${CMAKE_MATCH_1})
endif()
endif()
find_package_handle_standard_args(
Z80
REQUIRED_VARS Z80_INCLUDE_DIR
VERSION_VAR Z80_VERSION
)
if(Z80_FOUND AND NOT TARGET Z80)
add_library(Z80 IMPORTED)
target_include_directories(Z80 INTERFACE ${Z80_INCLUDE_DIR})
endif()
mark_as_advanced(Z80_INCLUDE_DIR)
# FindZ80.cmake EOF

60
CMake/FindZeta.cmake Normal file
View File

@@ -0,0 +1,60 @@
# Zeta - FindZeta.cmake
# ______ ____________ ___
# |__ /| ___|__ __|/ \
# / /_| __| | | / * \
# /_____|_____| |__|/__/ \__\
# Copyright (C) 2006-2022 Manuel Sainz de Baranda y Goñi.
# # Released under the terms of the GNU Lesser General Public License v3.
# This "find module" is DISTRIBUTED AS PUBLIC DOMAIN. No restrictions apply.
include(FindPackageHandleStandardArgs)
find_path(
Zeta_INCLUDE_DIR "Z/version.h"
PATHS "${PROJECT_BINARY_DIR}/Zeta/API"
"${PROJECT_BINARY_DIR}"
"${PROJECT_SOURCE_DIR}/Zeta/API"
"${PROJECT_SOURCE_DIR}"
"${PROJECT_SOURCE_DIR}/dependencies/Zeta/API"
"${PROJECT_SOURCE_DIR}/dependencies"
"${PROJECT_SOURCE_DIR}/deps/Zeta/API"
"${PROJECT_SOURCE_DIR}/deps"
"${PROJECT_SOURCE_DIR}/extern/Zeta/API"
"${PROJECT_SOURCE_DIR}/extern"
"${PROJECT_SOURCE_DIR}/external/Zeta/API"
"${PROJECT_SOURCE_DIR}/external"
"${PROJECT_SOURCE_DIR}/externals/Zeta/API"
"${PROJECT_SOURCE_DIR}/externals"
"${PROJECT_SOURCE_DIR}/kits/Zeta/API"
"${PROJECT_SOURCE_DIR}/kits"
"${PROJECT_SOURCE_DIR}/../Zeta/API"
"${PROJECT_SOURCE_DIR}/.."
ENV CPATH
ENV C_INCLUDE_PATH
ENV CPLUS_INCLUDE_PATH
ENV OBJC_INCLUDE_PATH)
if(Zeta_INCLUDE_DIR AND EXISTS "${Zeta_INCLUDE_DIR}/Z/version.h")
file(READ "${Zeta_INCLUDE_DIR}/Z/version.h" _)
if(_ MATCHES ".*Z_LIBRARY_VERSION_STRING \"([^\n]*)\".*")
set(Zeta_VERSION ${CMAKE_MATCH_1})
endif()
unset(_)
endif()
find_package_handle_standard_args(
Zeta
FOUND_VAR Zeta_FOUND
REQUIRED_VARS Zeta_INCLUDE_DIR Zeta_VERSION
VERSION_VAR Zeta_VERSION)
if(Zeta_FOUND AND NOT (TARGET Zeta))
add_library(Zeta INTERFACE IMPORTED)
target_include_directories(Zeta INTERFACE ${Zeta_INCLUDE_DIR})
endif()
mark_as_advanced(Zeta_INCLUDE_DIR)
# FindZeta.cmake EOF

373
CMakeLists.txt Normal file
View File

@@ -0,0 +1,373 @@
# Z80 - CMakeLists.txt
# ______ ______ ______
# /\___ \/\ __ \\ __ \
# \/__/ /\_\ __ \\ \/\ \
# /\_____\\_____\\_____\
# Zilog \/_____//_____//_____/ CPU Emulator
# Copyright (C) 1999-2022 Manuel Sainz de Baranda y Goñi.
# Released under the terms of the GNU Lesser General Public License v3.
cmake_minimum_required(VERSION 3.14)
if( CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR AND
NOT CMAKE_BUILD_TYPE AND
NOT CMAKE_CONFIGURATION_TYPES
)
set(CMAKE_BUILD_TYPE Release)
endif()
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/API/Z80.h" _)
string(REGEX MATCH ".*Z80_LIBRARY_VERSION_STRING \"([^\n]*)\".*" _ ${_})
project(Z80
VERSION ${CMAKE_MATCH_1}
LANGUAGES C
DESCRIPTION "Zilog Z80 CPU emulator")
unset(_)
message("${PROJECT_NAME} v${PROJECT_VERSION}")
include(GNUInstallDirs)
if(DEFINED ${PROJECT_NAME}_SHARED_LIBS)
set(BUILD_SHARED_LIBS "${${PROJECT_NAME}_SHARED_LIBS}")
endif()
option(${PROJECT_NAME}_DOWNLOAD_TEST_FILES
"Download the firmware and software used by the testing tool."
NO)
set(${PROJECT_NAME}_INSTALL_CMAKEDIR
"${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" CACHE STRING
"Specify the directory in which to install the CMake config-file package.")
set(${PROJECT_NAME}_INSTALL_PKGCONFIGDIR
"${CMAKE_INSTALL_LIBDIR}/pkgconfig" CACHE STRING
"Specify the directory in which to install the pkg-config file.")
set(${PROJECT_NAME}_NOSTDLIB_FLAGS
"Auto" CACHE STRING
"Specify the linker flags used to avoid linking against system libraries.")
set(${PROJECT_NAME}_SPHINX_HTML_THEME
"" CACHE STRING
"Specify the Sphinx theme for the documentation in HTML format.")
option(${PROJECT_NAME}_WITH_CMAKE_SUPPORT
"Generate and install the CMake config-file package."
NO)
option(${PROJECT_NAME}_WITH_HTML_DOCUMENTATION
"Build and install the documentation in HTML format."
NO)
option(${PROJECT_NAME}_WITH_PDF_DOCUMENTATION
"Build and install the documentation in PDF format."
NO)
option(${PROJECT_NAME}_WITH_PKGCONFIG_SUPPORT
"Generate and install the pkg-config file."
NO)
option(${PROJECT_NAME}_WITH_STANDARD_DOCUMENTS
"Install the standard text documents distributed with the package: \
AUTHORS, COPYING, COPYING.LESSER, HISTORY, README and THANKS."
NO)
option(${PROJECT_NAME}_WITH_TESTS
"Build the testing tool."
NO)
option(${PROJECT_NAME}_WITH_EXECUTE
"Build the implementation of the z80_execute function."
NO)
option(${PROJECT_NAME}_WITH_FULL_IM0
"Build the full implementation of the interrupt mode 0 rather than the \
reduced one."
NO)
option(${PROJECT_NAME}_WITH_Q
"Build the implementation of the Q \"register\"."
NO)
option(${PROJECT_NAME}_WITH_RESET_SIGNAL
"Build the implementation of the normal RESET signal."
NO)
option(${PROJECT_NAME}_WITH_SPECIAL_RESET_SIGNAL
"Build the implementation of the special RESET signal."
NO)
option(${PROJECT_NAME}_WITH_UNOFFICIAL_RETI
"Configure the ED5Dh, ED6Dh and ED7Dh undocumented instructions as \"reti\" \
instead of \"retn\"."
NO)
option(${PROJECT_NAME}_WITH_ZILOG_NMOS_LD_A_IR_BUG
"Build the implementation of the bug affecting the Zilog Z80 NMOS, which \
causes the P/V flag to be reset when a maskable interrupt is accepted \
during the execution of the \"ld a,{i|r}\" instructions."
NO)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake")
find_package(Zeta REQUIRED)
add_library(
${PROJECT_NAME}
"${CMAKE_CURRENT_SOURCE_DIR}/API/Z80.h"
"${CMAKE_CURRENT_SOURCE_DIR}/sources/Z80.c")
set_target_properties(
${PROJECT_NAME} PROPERTIES
C_STANDARD 99
C_STANDARD_REQUIRED NO
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
DEBUG_POSTFIX "-debug"
PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/API/Z80.h")
target_link_libraries(${PROJECT_NAME} PUBLIC Zeta)
target_include_directories(
${PROJECT_NAME} PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/API>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
if(BUILD_SHARED_LIBS)
if(WIN32)
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/sources/Z80.rc.in"
"${PROJECT_BINARY_DIR}/Z80.rc"
@ONLY)
target_sources(${PROJECT_NAME} PRIVATE "${PROJECT_BINARY_DIR}/Z80.rc")
endif()
if (${PROJECT_NAME}_NOSTDLIB_FLAGS STREQUAL "Auto")
if(MSVC)
target_compile_definitions(${PROJECT_NAME} PRIVATE Z80_WITH_WINDOWS_DLL_MAIN)
target_link_options(${PROJECT_NAME} PRIVATE "/NODEFAULTLIB")
elseif(APPLE)
if(CMAKE_C_COMPILER_ID MATCHES "^(AppleClang|Clang)$")
target_link_options(${PROJECT_NAME} PRIVATE "LINKER:-dead_strip_dylibs")
elseif(CMAKE_C_COMPILER_ID MATCHES "GNU")
target_link_options(${PROJECT_NAME} PRIVATE "LINKER:-dead_strip_dylibs;-nolibc")
endif()
elseif(CMAKE_C_COMPILER_ID MATCHES "^(ARMClang|Clang|GNU|Intel|TinyCC|XL|XLClang)$")
target_link_options(${PROJECT_NAME} PRIVATE "-nostdlib")
elseif(CMAKE_C_COMPILER_ID MATCHES "PGI")
target_link_options(${PROJECT_NAME} PRIVATE "-Mnostdlib")
elseif(CMAKE_C_COMPILER_ID MATCHES "SunPro")
target_link_options(${PROJECT_NAME} PRIVATE "-xnolib")
endif()
elseif(NOT ${PROJECT_NAME}_NOSTDLIB_FLAGS STREQUAL "")
target_link_options(${PROJECT_NAME} PRIVATE ${${PROJECT_NAME}_NOSTDLIB_FLAGS})
endif()
else()
target_compile_definitions(${PROJECT_NAME} PUBLIC Z80_STATIC)
endif()
if(${PROJECT_NAME}_WITH_EXECUTE)
target_compile_definitions(${PROJECT_NAME} PRIVATE Z80_WITH_EXECUTE)
endif()
if(${PROJECT_NAME}_WITH_FULL_IM0)
target_compile_definitions(${PROJECT_NAME} PRIVATE Z80_WITH_FULL_IM0)
endif()
if(${PROJECT_NAME}_WITH_Q)
target_compile_definitions(${PROJECT_NAME} PRIVATE Z80_WITH_Q)
endif()
if(${PROJECT_NAME}_WITH_RESET_SIGNAL)
target_compile_definitions(${PROJECT_NAME} PRIVATE Z80_WITH_RESET_SIGNAL)
endif()
if(${PROJECT_NAME}_WITH_SPECIAL_RESET_SIGNAL)
target_compile_definitions(${PROJECT_NAME} PRIVATE Z80_WITH_SPECIAL_RESET_SIGNAL)
endif()
if(${PROJECT_NAME}_WITH_UNOFFICIAL_RETI)
target_compile_definitions(${PROJECT_NAME} PRIVATE Z80_WITH_UNOFFICIAL_RETI)
endif()
if(${PROJECT_NAME}_WITH_ZILOG_NMOS_LD_A_IR_BUG)
target_compile_definitions(${PROJECT_NAME} PRIVATE Z80_WITH_ZILOG_NMOS_LD_A_IR_BUG)
endif()
install(TARGETS ${PROJECT_NAME}
EXPORT "${PROJECT_NAME}_Targets"
RUNTIME COMPONENT "${PROJECT_NAME}_Runtime"
LIBRARY COMPONENT "${PROJECT_NAME}_Runtime"
DESTINATION "${CMAKE_INSTALL_LIBDIR}"
NAMELINK_COMPONENT "${PROJECT_NAME}_Development"
ARCHIVE COMPONENT "${PROJECT_NAME}_Development"
PUBLIC_HEADER
COMPONENT "${PROJECT_NAME}_Development"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
if(${PROJECT_NAME}_WITH_CMAKE_SUPPORT OR ${PROJECT_NAME}_WITH_PKGCONFIG_SUPPORT)
include(CMakePackageConfigHelpers)
if(${PROJECT_NAME}_WITH_CMAKE_SUPPORT)
if (BUILD_SHARED_LIBS)
set(_type Shared)
else()
set(_type Static)
endif()
install(EXPORT "${PROJECT_NAME}_Targets"
DESTINATION ${${PROJECT_NAME}_INSTALL_CMAKEDIR}
FILE ${PROJECT_NAME}${_type}Targets.cmake
COMPONENT ${PROJECT_NAME}_Development)
unset(_type)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMajorVersion)
configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/support/${PROJECT_NAME}Config.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
INSTALL_DESTINATION ${${PROJECT_NAME}_INSTALL_CMAKEDIR})
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
DESTINATION ${${PROJECT_NAME}_INSTALL_CMAKEDIR}
COMPONENT ${PROJECT_NAME}_Development)
endif()
if(${PROJECT_NAME}_WITH_PKGCONFIG_SUPPORT)
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/support/${PROJECT_NAME}.pc.in"
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}.pc"
@ONLY)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc"
DESTINATION ${${PROJECT_NAME}_INSTALL_PKGCONFIGDIR}
COMPONENT ${PROJECT_NAME}_Development)
endif()
endif()
if(${PROJECT_NAME}_WITH_STANDARD_DOCUMENTS)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/AUTHORS"
"${CMAKE_CURRENT_SOURCE_DIR}/COPYING"
"${CMAKE_CURRENT_SOURCE_DIR}/COPYING.LESSER"
"${CMAKE_CURRENT_SOURCE_DIR}/HISTORY"
"${CMAKE_CURRENT_SOURCE_DIR}/README"
"${CMAKE_CURRENT_SOURCE_DIR}/THANKS"
DESTINATION ${CMAKE_INSTALL_DOCDIR})
endif()
if(${PROJECT_NAME}_WITH_HTML_DOCUMENTATION OR ${PROJECT_NAME}_WITH_PDF_DOCUMENTATION)
add_subdirectory(documentation)
endif()
if(${PROJECT_NAME}_WITH_TESTS)
include(CTest)
find_package(ZLIB QUIET)
find_package(libzip QUIET)
add_executable("test-${PROJECT_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/sources/test-Z80.c")
target_link_libraries("test-${PROJECT_NAME}" PRIVATE ${PROJECT_NAME})
if(ZLIB_FOUND AND libzip_FOUND)
target_link_libraries("test-${PROJECT_NAME}" PRIVATE z libzip::zip)
target_compile_definitions("test-${PROJECT_NAME}" PRIVATE TEST_Z80_WITH_ARCHIVE_EXTRACTION)
endif()
if(${PROJECT_NAME}_WITH_EXECUTE)
target_compile_definitions("test-${PROJECT_NAME}" PRIVATE TEST_Z80_WITH_EXECUTE)
endif()
if(${PROJECT_NAME}_DOWNLOAD_TEST_FILES)
function(_download_files sha512sum_file base_url downloads_dir)
file(STRINGS "${sha512sum_file}" _lines)
foreach(_line ${_lines})
string(STRIP ${_line} _line)
string(SUBSTRING ${_line} 0 128 _sha512)
string(SUBSTRING ${_line} 130 -1 _file_path)
get_filename_component(_file_full_name ${_file_path} NAME)
set(_file_url "${base_url}/${_file_path}")
message(STATUS "Downloading \"${_file_full_name}\"")
string(REPLACE " " "%20" _file_url ${_file_url})
string(REPLACE "!" "%21" _file_url ${_file_url})
string(REPLACE "(" "%28" _file_url ${_file_url})
string(REPLACE ")" "%29" _file_url ${_file_url})
string(REPLACE "[" "%5B" _file_url ${_file_url})
string(REPLACE "]" "%5D" _file_url ${_file_url})
file( DOWNLOAD
"${_file_url}"
"${downloads_dir}/${_file_path}"
EXPECTED_HASH SHA512=${_sha512})
if ( NOT "${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 3.18 AND
(NOT ZLIB_FOUND OR NOT libzip_FOUND)
)
get_filename_component(_file_extension ${_file_full_name} LAST_EXT)
if(_file_extension STREQUAL ".gz" OR _file_extension STREQUAL ".zip")
get_filename_component(_subdirectory ${_file_path} DIRECTORY)
if(_file_extension STREQUAL ".gz")
set(_extract_pattern "*zex*.com")
else()
set(_extract_pattern "*.tap")
endif()
file( ARCHIVE_EXTRACT
INPUT "${downloads_dir}/${_file_path}"
DESTINATION "${downloads_dir}/${_subdirectory}"
PATTERNS ${_extract_pattern}
VERBOSE)
endif()
endif()
endforeach()
endfunction()
_download_files(
"${CMAKE_CURRENT_SOURCE_DIR}/support/firmware.sha512sum"
"http://zxe.io/downloads/support/firmware"
"${CMAKE_CURRENT_BINARY_DIR}/downloads/firmware")
_download_files(
"${CMAKE_CURRENT_SOURCE_DIR}/support/software.sha512sum"
"http://zxe.io/downloads/support/software"
"${CMAKE_CURRENT_BINARY_DIR}/downloads/software")
if ( "${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 3.18 AND
(NOT ZLIB_FOUND OR NOT libzip_FOUND)
)
message(WARNING
"libzip or zlib was not found on your system, which will cause the "
"test-Z80 tool to be built without archive extraction support. When "
"this happens, the build script extracts those downloaded tests that "
"are compressed so that test-Z80 can use them later, but this has "
"failed because the version of CMake you are using is too old and "
"does not support archive extraction either.\n"
"To fix this, extract all files with \".tar.gz\" or \".zip\" "
"extension located in "
"\"${CMAKE_CURRENT_BINARY_DIR}/downloads/software/**\" "
"to the same directory.")
endif()
endif()
add_test(
NAME "test-${PROJECT_NAME}"
COMMAND "test-${PROJECT_NAME}"
--path "${CMAKE_CURRENT_BINARY_DIR}/downloads/firmware"
--path "${CMAKE_CURRENT_BINARY_DIR}/downloads/software/POSIX"
--path "${CMAKE_CURRENT_BINARY_DIR}/downloads/software/ZX Spectrum"
--all
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
endif()
# CMakeLists.txt EOF

165
COPYING.LESSER Normal file
View File

@@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

101
HISTORY
View File

@@ -1,3 +1,100 @@
Z80 v0.1 (2018-11-10)
Z80 v0.2 (2022-XX-XX)
=====================
+ Initial release.
This is an important update that addresses a number of issues and also includes
new features. Please note that the changes introduced in this release break the
binary compatibility with the previous version.
Changes:
1. Changed the license from GPL to LGPL (by popular request).
2. Moved the public header from <emulation/CPU/Z80.h> to <Z80.h>.
3. Removed the Xcode project.
4. Switched the build system from Premake to CMake.
5. Switched to Zeta v0.1.
6. Added pkg-config support.
7. Added the .vimrc dotfile.
8. Added the CITATION.cff file.
9. Added the file_id.diz file.
10. Added the THANKS file.
11. Added detailed documentation.
12. Added tests.
13. Added public macros for checking the library version.
14. Added public macros with bit masks for working with flags.
15. Added public macros for accessing the 16-bit registers.
16. Added the z80_execute function to run a simplified emulation without RESET
and interrupts.
17. Added the z80_refresh_address function to get the refresh address of the
current M1 cycle.
18. Added the z80_in_cycle and z80_out_cycle functions to get the clock cycle on
which the I/O M-cycle occurs, relative to the start of the instruction.
19. Fixed a bug in the "sll" instruction.
20. Fixed a bug in the INX and OUTX macros affecting the S and N flags.
21. Fixed a bug in the OUTX macro affecting the MSByte of the port number.
22. Fixed the clock cycles of the "dec XY" and "in (c)" instructions.
23. Fixed the read_16 function so that the order in which the compiler evaluates
expressions does not affect the order of the memory read operations.
24. Fixed the order in which the memory write operations are performed when the
SP register is involved. This affects the NMI response, the INT response in
modes 1 and 2, and the following instructions: "ex (sp),{hl|XY}", "push TT",
"push XY", "call WORD", "call Z,WORD" and "rst N".
25. Fixed the handling of illegal instructions to avoid stack overflows in long
sequences of DDh/FDh prefixes.
26. Fixed several implicit conversions to avoid warnings about loss of sign and
precision.
27. Fixed some bitwise operations to avoid undefined behavior and arithmetic
right shifts on signed integers.
28. Fixed violations of the C standard in several identifiers.
29. Renamed the 8-bit register lists: X/Y to J/K; J/K and P/Q to O/P.
30. Replaced all P/V overflow computation functions with a single, faster macro.
31. Replaced all register resolution functions with macros.
32. Replaced all "ld {J,K|O,P}" instructions that have the same destination and
source register with NOPs.
33. Reimplemented the HALT state. The emulation should now be fully accurate.
HALTskip is also supported.
34. Added optional emulation of the normal and special RESET signals, along with
the new z80_reset and z80_special_reset functions to emit them. The old
z80_reset function is now called z80_instant_reset.
35. Added emulation of the NMI acknowledge M-cycle through the new Z80::nmia
callback.
36. Added emulation of the INT acknowledge M-cycle through the new Z80::inta
callback, which replaces Z80::int_data.
37. Added optional full emulation of the interrupt mode 0, along with the new
Z80::int_fetch callback to perform bus read operations on instruction data.
If not enabled at compile-time, the old simplified emulation is built, which
supports only the most typical instructions.
38. Added accurate flag behavior in the following instructions: "ldir", "lddr",
"cpir", "cpdr", "inir", "indr", "otir" and "otdr".
39. Added emulation of the interrupt acceptance deferral that occurs during the
"reti" and "retn" instructions.
40. Added MEMPTR emulation. The "bit N,(hl)" instruction now produces a correct
value of F.
41. Added optional emulation of the Q "register". If enabled at compile-time,
the "ccf" and "scf" instructions produce a correct value of F.
42. Added emulation options that can be configured at runtime.
43. Added emulation of the "out (c),255" instruction (Zilog Z80 CMOS).
44. Added optional emulation of the bug affecting the "ld a,{i|r}" instructions
(Zilog Z80 NMOS). If enabled at compile-time, the P/V flag is reset when an
INT is accepted during the execution of these instructions.
45. Added the Z80::fetch_opcode and Z80::fetch callbacks to perform opcode fetch
operations and memory read operations on instruction data respectively.
46. Added hooking functionality through the "ld h,h" instruction and the new
Z80::hook callback.
47. Added the Z80::nop callback to perform disregarded opcode fetch operations
during internal NOP M-cycles.
48. Added four callbacks to notify the execution of important instructions:
Z80::ld_i_a, Z80::ld_r_a, Z80::reti and Z80::retn.
49. Removed Z80::state. Replaced with individual members for the registers, the
interrupt enable flip-flops and the interrupt mode.
50. Removed the superfluous EI flag. The previous opcode is checked instead,
which is faster and makes the Z80 object smaller.
51. Removed all module-related stuff.
52. Optimizations in flag computation and condition evaluation.
53. New source code comments and improvements to existing ones.
54. Improved code aesthetics.
55. Other improvements, optimizations and minor changes.
Z80 v0.1 (2018-11-10)
=====================
Initial public release.

377
README
View File

@@ -1,84 +1,319 @@
______ ______ ______
/\___ \ /\ __ \/\ __ \
\/__/ /_\ \ __ \ \ \/\ \
/\_____\ \_____\ \_____\
Zilog \/_____/\/_____/\/_____/ CPU Emulator v0.1
Copyright (C) 1999-2018 Manuel Sainz de Baranda y Goñi <manuel@zxe.io>
This is a Zilog Z80 CPU emulator that I wrote many years ago. It is fast, small,
easy to understand, and the code is profusely commented.
________________ ________________ _________________
| /\ | || |
|_______ / / | ____ || ____ |
\_____/ / / | |____| || |___/| |
/ / / | || | | | |
/ / / | ____ || | | | |
/ /_/_____| |____| || |__|_| |
/ || || |
/_______________||________________||________________|
\________________\\______________//________________/
______________________________________________________________________________
| |
| Zilog Z80 CPU Emulator |
| version 0.2 |
| |
| Copyright (C) 1999-2022 Manuel Sainz de Baranda y Goñi |
| Released under the terms of the GNU Lesser General Public License v3 |
| |
| https://zxe.io/software/Z80 |
| |
'=============================================================================='
Building
========
1. Introduction
================
You must first install Z <http://zeta.st>, a header-only library that provides
types and macros. This is the only dependency, the emulator does not use the C
standard library or its headers. Then add Z80.h and Z80.c to your project and
configure its build system so that CPU_Z80_STATIC and CPU_Z80_USE_LOCAL_HEADER
are predefined when compiling the sources.
The Z80 library implements a fast, small and accurate emulator of the Zilog Z80.
It emulates all that is known to date about this CPU, including the undocumented
behaviour, MEMPTR, Q and the special RESET. It also has the honor of having been
the first open source project to provide full emulation of the interrupt mode 0.
If you preffer to build the emulator as a library, you can use premake4:
$ cd building
$ premake4 gmake # generate Makefile
$ make help # list available targets
$ make [config=<configuration>] [target] # build the emulator
There is also an Xcode project in "development/Xcode" with several targets:
Z80 (dynamic)
Shared library.
Z80 (dynamic module)
Shared library with a generic module ABI to be used in modular multi-machine
emulators.
Z80 (static)
Static library.
Z80 (static module)
Static library with a generic CPU emulator ABI to be used in monolithic
multi-machine emulators.
The source code is written in ANSI C for maximum portability and is extensively
commented. The aim has been to write a well-structured, easy to understand piece
of software; something solid and elegant that can stand the test of time with no
need for major changes.
Code configuration
==================
2. Emulation accuracy
======================
There are some predefined macros that control the compilation:
The Zilog Z80 emulator has a classic design with instruction-level granularity.
This provides the best performance when speed is a critical factor, while still
offering a reasonable flexibility to achieve precision down to the T-state level
when accuracy is imperative.
CPU_Z80_DEPENDENCIES_H
If defined, it replaces the inclusion of any external header with this one.
If you don't want to use Z, you can provide your own header with the types
and macros used by the emulator.
Instruction-level granularity implies that, except in a few well-defined cases,
the execution of a given instruction cannot stop until all its internal M-cycles
are completed. This kind of emulation is also carried out in an efficient way:
the pertinent registers are modified only once per instruction and the T-state
counter is updated only after a whole instruction is executed.
CPU_Z80_HIDE_ABI
Makes the generic CPU emulator ABI private.
CPU_Z80_HIDE_API
Makes the public functions private.
CPU_Z80_STATIC
You need to define this to compile or use the emulator as a static library
or if you have added Z80.h and Z80.c to your project.
CPU_Z80_USE_LOCAL_HEADER
Use this if you have imported Z80.h and Z80.c to your project. Z80.c will
#include "Z80.h" instead of <emulation/CPU/Z80.h>.
CPU_Z80_WITH_ABI
Builds the generic CPU emulator ABI and declares its prototype in Z80.h.
CPU_Z80_WITH_MODULE_ABI
Builds the generic module ABI. This macro also enables CPU_Z80_WITH_ABI, so
the generic CPU emulator ABI will be built too. This option is intended to
be used when building a true module loadable at runtime with dlopen(),
LoadLibrary() or similar. The ABI module can be accessed via the weak symbol
__module_abi__.
That said, instructions, flags, memory accesses, interrupt and reset responses,
clock cycles, etc. are accurately emulated as far as is known, according to the
technical documentation available, the findings made after decades of research
on the Z80 and electronic simulations. And, of course, the emulator passes the
most exhaustive tests written to date such as Patrik Rak's "Zilog Z80 CPU Test
Suite", Frank D. Cringle's "Z80 Instruction Set Exerciser", Mark Woodmass' "Z80
Test Suite" and Peter Helcmanovsky's "Z80 Block Flags Test", to name a few.
Use in Proprietary Software
===========================
3. Installation
================
This library is released under the terms of the GNU General Public License v3,
but I can license it for non-free/propietary projects if you contact me.
You will need CMake v3.14 or later to build the package and, optionally, recent
versions of Doxygen, Sphinx and Breathe to compile the documentation. Also make
sure you have LaTeX with PDF support installed on your system in case you want
to generate the documentation in PDF format.
The emulator requires some types and macros included in Zeta (https://zeta.st),
a dependency-free, header-only library used to retain compatibility with most C
compilers. Install Zeta or extract its official source code package to the same
directory of this README or its parent directory. Zeta is the sole dependency;
the emulator is a freestanding implementation and as such does not depend on the
C standard library.
Once all requirements are met, create a directory and run cmake from there to
prepare the build system:
$ mkdir build
$ cd build
$ cmake <directory of this README> [options]
The resulting build files can be configured by passing options to cmake. To show
a complete list of those available along with their current settings, type the
following:
$ cmake -LAH
If in doubt, read the CMake documentation for more information on configuration
options. The following are some of the most relevant standard options of CMake:
-DBUILD_SHARED_LIBS=(YES|NO)
Build the project as a shared library rather than a static one.
The default is NO.
-DCMAKE_BUILD_TYPE=(Debug|Release|RelWithDebInfo)
Choose the type of build (configuration) to generate.
The default is Release.
-DCMAKE_INSTALL_PREFIX="<path>"
Specify the installation prefix on UNIX and UNIX-like operating systems.
The default is "/usr/local".
Package-specific options are prefixed with "Z80_" and can be divided into two
groups. The first one controls aspects not related to the source code of the
library:
-DZ80_DOWNLOAD_TEST_FILES=(YES|NO)
Download the firmware and software used by the testing tool.
The default is NO.
-DZ80_INSTALL_CMAKEDIR="<path>"
Specify the directory in which to install the CMake config-file package.
The default is "${CMAKE_INSTALL_LIBDIR}/cmake/Z80".
-DZ80_INSTALL_PKGCONFIGDIR="<path>"
Specify the directory in which to install the pkg-config file.
The default is "${CMAKE_INSTALL_LIBDIR}/pkgconfig".
-DZ80_NOSTDLIB_FLAGS=(Auto|[<flag>[;<flag>...]])
Specify the linker flags used to avoid linking against system libraries.
The default is Auto (autoconfigure flags). If you get linker errors, set
this option to "".
-DZ80_SHARED_LIBS=(YES|NO)
Build the project as a shared library rather than a static one.
This option takes precedence over "BUILD_SHARED_LIBS".
Not defined by default.
-DZ80_SPHINX_HTML_THEME="[<name>]"
Specify the Sphinx theme for the documentation in HTML format.
The default is "" (use the default theme).
-DZ80_WITH_CMAKE_SUPPORT=(YES|NO)
Generate and install the CMake config-file package.
The default is NO.
-DZ80_WITH_HTML_DOCUMENTATION=(YES|NO)
Build and install the documentation in HTML format.
It requires Doxygen, Sphinx and Breathe.
The default is NO.
-DZ80_WITH_PDF_DOCUMENTATION=(YES|NO)
Build and install the documentation in PDF format.
It requires Doxygen, Sphinx, Breathe and LaTeX with PDF support.
The default is NO.
-DZ80_WITH_PKGCONFIG_SUPPORT=(YES|NO)
Generate and install the pkg-config file.
The default is NO.
-DZ80_WITH_STANDARD_DOCUMENTS=(YES|NO)
Install the standard text documents distributed with the package:
AUTHORS, COPYING, COPYING.LESSER, HISTORY, README and THANKS.
The default is NO.
-DZ80_WITH_TESTS=(YES|NO)
Build the testing tool.
The default is NO.
The second group of package-specific options configures the source code of the
library by predefining macros that enable optional implementations:
-DZ80_WITH_EXECUTE=(YES|NO)
Build the implementation of the z80_execute function.
The default is NO.
-DZ80_WITH_FULL_IM0=(YES|NO)
Build the full implementation of the interrupt mode 0 rather than the
reduced one.
The default is NO.
-DZ80_WITH_Q=(YES|NO)
Build the implementation of the Q "register".
The default is NO.
-DZ80_WITH_RESET_SIGNAL=(YES|NO)
Build the implementation of the normal RESET signal.
The default is NO.
-DZ80_WITH_SPECIAL_RESET_SIGNAL=(YES|NO)
Build the implementation of the special RESET signal.
The default is NO.
-DZ80_WITH_UNOFFICIAL_RETI=(YES|NO)
Configure the ED5Dh, ED6Dh and ED7Dh undocumented instructions as "reti"
instead of "retn".
The default is NO.
-DZ80_WITH_ZILOG_NMOS_LD_A_IR_BUG=(YES|NO)
Build the implementation of the bug affecting the Zilog Z80 NMOS, which
causes the P/V flag to be reset when a maskable interrupt is accepted
during the execution of the "ld a,{i|r}" instructions.
The default is NO.
Package maintainers should use at least the following options for both shared and
static library targets:
-DZ80_WITH_EXECUTE=YES
-DZ80_WITH_FULL_IM0=YES
-DZ80_WITH_Q=YES
-DZ80_WITH_RESET_SIGNAL=YES
-DZ80_WITH_ZILOG_NMOS_LD_A_IR_BUG=YES
Finally, once the build system is configured according to your needs, build and
install the package:
$ make
# make install/strip
4. Integration
===============
4.1. As an external dependency in CMake-based projects
The Z80 library includes find-modules and a config-file package for integration
into CMake-based projects. It is recommended to always copy the FindZ80.cmake
and FindZeta.cmake files into the CMake modules directory of projects that use
the library as an external dependency. This will allow CMake to find the library
if the necessary config-file packages are not installed on the system.
Both the config-file package and the find-module support dual installations of
the shared and static versions of the Z80 library. You can specify the linking
method by using the component mechanism of "find_package".
Example:
find_package(Z80 REQUIRED [Shared|Static])
target_link_libraries(your-target Z80)
Omitting the linking method will select the "Shared" version of the library or,
if not installed, the "Static" version instead.
4.2. As a CMake subproject
To embed the library as a CMake subproject, just place its entire source tree
into a subdirectory of your project.
It is advisable to configure the library in the CMakeLists.txt of your project.
This will prevent the user from having to specify configuration options of the
Z80 subproject through the CMake command line when building the main project.
As noted in the "Installation" section of this document, all package-specific
options are prefixed with "Z80_", so, in a normal scenario, there should be no
risk of name collision with the options and variables of the parent project.
Example:
set(Z80_SHARED_LIBS NO CACHE BOOL "")
set(Z80_WITH_Q YES CACHE BOOL "")
set(Z80_WITH_ZILOG_NMOS_LD_A_IR_BUG YES CACHE BOOL "")
add_subdirectory(dependencies/Z80)
target_link_libraries(your-target Z80)
It is important to set the "Z80_SHARED_LIBS" option. Otherwise CMake will build
the library type indicated by "BUILD_SHARED_LIBS", which may not be the desired
one.
4.3. Manual integration
There are several macros that can be used to configure the source code of the
library. You can define those you need in your build system or at the beginning
of the Z80.c file. The following ones allow you to configure the integration of
Z80.h and Z80.c into the project:
#define Z80_DEPENDENCIES_HEADER "header name.h"
Specifies the only external header to #include, replacing those of Zeta.
If used, it must also be defined before including the Z80.h header.
#define Z80_STATIC
Needed for compiling and/or using the emulator as a static library or as
an internal part of other project.
If used, it must also be defined before including the Z80.h header.
#define Z80_WITH_LOCAL_HEADER
Tells Z80.c to #include "Z80.h" instead of <Z80.h>.
The second group of package-specific options, explained in the "Installation"
section of this document, activates various optional implementations in the
source code by predefining the following macros:
#define Z80_WITH_EXECUTE
#define Z80_WITH_FULL_IM0
#define Z80_WITH_Q
#define Z80_WITH_RESET_SIGNAL
#define Z80_WITH_SPECIAL_RESET_SIGNAL
#define Z80_WITH_UNOFFICIAL_RETI
#define Z80_WITH_ZILOG_NMOS_LD_A_IR_BUG
Please note that the activation of some these optional implementations affects
the speed of the emulator due to various factors (read the documentation for
more details).
As a final note, except for "Z80_DEPENDENCIES_HEADER", the above macros do not
need to be set to a particular token when used, as the source code only checks
whether or not they are defined.
5. License
===========
This library is free software: you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option) any
later version.
This library is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this library. If not, see <http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------
Last update: 2022-05-16 README EOF

790
README.md
View File

@@ -1,229 +1,633 @@
![al-tag](http://upload.wikimedia.org/wikipedia/commons/1/19/Zilog_Z80.jpg)
<h1 align="center">
<img src="http://zxe.io/software/Z80/images/Z80.svg"><br>
<b>Zilog Z80 CPU Emulator</b>
</h1>
<p align="center">
<a href="https://github.com/redcode/Z80-mainline/actions/workflows/library-ci.yml">
<img src="https://github.com/redcode/Z80-mainline/actions/workflows/library-ci.yml/badge.svg">
</a>
<a href="https://github.com/redcode/Z80-mainline/actions/workflows/documentation-ci.yml">
<img src="https://github.com/redcode/Z80-mainline/actions/workflows/documentation-ci.yml/badge.svg">
</a>
<a href="https://discord.gg/zU4dkzp8Mv"><img alt="Discord" src="https://img.shields.io/discord/848534208129138738?color=5865F2&label=Discord&logo=discord&logoColor=white"/></a>
</p>
<br>
# Introduction
# Zilog Z80 CPU Emulator
Copyright © 1999-2018 Manuel Sainz de Baranda y Goñi.
Released under the terms of the [GNU General Public License v3](http://www.gnu.org/copyleft/gpl.html).
The [Z80 library](https://zxe.io/software/Z80) implements a fast, small and accurate [emulator](https://en.wikipedia.org/wiki/Emulator) of the [Zilog Z80](https://en.wikipedia.org/wiki/Zilog_Z80). It emulates all that is known to date about this CPU, including the undocumented behaviour, [MEMPTR](https://zxpress.ru/zxnet/zxnet.pc/5909), [Q](https://worldofspectrum.org/forums/discussion/41704) and the [special RESET](http://www.primrosebank.net/computers/z80/z80_special_reset.htm). It also has the honor of having been the first open source project to provide full emulation of the interrupt mode 0.
This is a very accurate [Z80](http://en.wikipedia.org/wiki/Zilog_Z80) [emulator](http://en.wikipedia.org/wiki/Emulator) I wrote many years ago. It has been used in several machine emulators by other people and it has been extensivelly tested. It is fast, small (33 KB when compiled as a x86-64 dynamic library), easy to understand, and **the code is profusely commented**.
The source code is written in [ANSI C](https://en.wikipedia.org/wiki/ANSI_C) for maximum portability and is extensively commented. The aim has been to write a well-structured, easy to understand piece of software; something solid and elegant that can stand the test of time with no need for major changes.
If you are looking for a Zilog Z80 CPU emulator for your project maybe you have found the correct one. I use this core in the [ZX Spectrum emulator](http://github.com/redcode/MicroZX) I started as hobby.
<br>
# Emulation Accuracy
## Building
The Zilog Z80 emulator has a classic design with instruction-level granularity. This provides the best performance when speed is a critical factor, while still offering a reasonable flexibility to achieve precision down to the T-state level when accuracy is imperative.
You must first install [Z](http://zeta.st), a **header-only** library that provides types and macros. This is the only dependency, the emulator does not use the C standard library or its headers. Then add `Z80.h` and `Z80.c` to your project and configure its build system so that `CPU_Z80_STATIC` and `CPU_Z80_USE_LOCAL_HEADER` are predefined when compiling the sources.
Instruction-level granularity implies that, except in a few well-defined cases, the execution of a given instruction cannot stop until all its internal M-cycles are completed. This kind of emulation is also carried out in an efficient way: the pertinent registers are modified only once per instruction and the T-state counter is updated only after a whole instruction is executed.
If you preffer to build the emulator as a library, you can use [premake4](http://premake.github.io):
```console
$ cd building
$ premake4 gmake # generate Makefile
$ make help # list available targets
$ make [config=<configuration>] [target] # build the emulator
That said, instructions, flags, memory accesses, interrupt and reset responses, clock cycles, etc. are accurately emulated as far as is known, according to the technical documentation available, the findings made after decades of research on the Z80 and electronic simulations. And, of course, the emulator passes the most exhaustive tests written to date:
### Zilog Z80 CPU Test Suite, by [Patrik Rak](https://github.com/raxoft)
[This set of programs](https://github.com/raxoft/z80test) is intended to help the emulator authors to reach the desired level of the CPU emulation authenticity. Each of the included programs performs an exhaustive computation using each of the tested Z80 instructions, compares the results with values obtained from a real [Sinclair ZX Spectrum 48K](https://en.wikipedia.org/wiki/ZX_Spectrum) with Zilog Z80 CPU, and reports any deviations detected.
<details>
<summary>Results</summary>
<table>
<tr>
<td align="center" valign="top" align="center">
<a href="http://zxds.raxoft.cz/taps/misc/z80test-1.0.zip">
<img src="http://zxe.io/software/Z80/images/TAP.png"/>
<br>
<b>z80full.tap</b>
</a>
<br>
Tests all flags and registers.
</td>
<td align="center" valign="top">
<a href="http://zxds.raxoft.cz/taps/misc/z80test-1.0.zip">
<img src="http://zxe.io/software/Z80/images/TAP.png"/>
<br>
<b>z80doc.tap</b>
</a>
<br>
Tests all registers, but only officially documented flags.
</td>
</tr>
<tr>
<td align="center" valign="top">
<img src="http://zxe.io/software/Z80/images/tests/z80full.gif"/>
</td>
<td align="center" valign="top">
<img src="http://zxe.io/software/Z80/images/tests/z80doc.gif"/>
</td>
</tr>
<tr>
<td align="center" valign="top">
<a href="http://zxds.raxoft.cz/taps/misc/z80test-1.0.zip">
<img src="http://zxe.io/software/Z80/images/TAP.png"/>
<br>
<b>z80flags.tap</b>
</a>
<br>
Tests all flags, ignores registers.
</td>
<td align="center" valign="top">
<a href="http://zxds.raxoft.cz/taps/misc/z80test-1.0.zip">
<img src="http://zxe.io/software/Z80/images/TAP.png"/>
<br>
<b>z80docflags.tap</b>
</a>
<br>
Tests documented flags only, ignores registers.
</td>
</tr>
<td align="center" valign="top">
<img src="http://zxe.io/software/Z80/images/tests/z80flags.gif"/>
</td>
<td align="center" valign="top">
<img src="http://zxe.io/software/Z80/images/tests/z80docflags.gif"/>
</td>
</tr>
<tr>
<td align="center" valign="top">
<a href="http://zxds.raxoft.cz/taps/misc/z80test-1.0.zip">
<img src="http://zxe.io/software/Z80/images/TAP.png"/>
<br>
<b>z80ccf.tap</b>
</a>
<br>
Tests all flags after executing <code>ccf</code> after each instruction tested.
</td>
<td align="center" valign="top">
<a href="http://zxds.raxoft.cz/taps/misc/z80test-1.0.zip">
<img src="http://zxe.io/software/Z80/images/TAP.png"/>
<br>
<b>z80memptr.tap</b>
</a>
<br>
Tests all flags after executing <code>bit n,(hl)</code> after each instruction tested.
</td>
</tr>
<tr>
<td align="center" valign="top">
<img src="http://zxe.io/software/Z80/images/tests/z80ccf.gif"/>
</td>
<td align="center" valign="top">
<img src="http://zxe.io/software/Z80/images/tests/z80memptr.gif"/>
</td>
</tr>
</table>
</details>
### Z80 Test Suite, by Mark Woodmass
This suite performs a series of tests to verify the MEMPTR documents _([English](http://zx.pk.ru/attachment.php?attachmentid=2989), [Russian](http://zx.pk.ru/attachment.php?attachmentid=2984))_, which are spot on, as well as a brief run through several of the `CBh`/`DDh`/`FDh` opcode ranges. The test results in the program are compared against those from a [NEC D780C-1](https://www.cpu-world.com/CPUs/Z80/NEC-D780C-1.html) CPU, but Simon Conway kindly tested several other Z80 clones, confirming the same results.
<details>
<summary>Results</summary>
<table>
<tr>
<td align="center" valign="top" colspan="2">
<a href="https://web.archive.org/web/20130511214919if_/http://homepage.ntlworld.com/mark.woodmass/z80tests.tap">
<img src="http://zxe.io/software/Z80/images/TAP.png"/>
<br>
<b>z80tests.tap</b>
</a>
</td>
</tr>
<tr>
<td align="center" valign="top">
<img src="http://zxe.io/software/Z80/images/tests/z80tests-flags.gif"/>
</td>
<td align="center" valign="top">
<img src="http://zxe.io/software/Z80/images/tests/z80tests-memptr.gif"/>
</td>
</tr>
</table>
</details>
### Z80 Instruction Set Exerciser, by Frank D. Cringle
Frank Cringle's _Z80 Instruction Set Exerciser_ attempts to execute every Z80 opcode, putting them through a cycle of tests and comparing the results to actual results from running the code on a real Z80. The exerciser is supplied with Frank's [YAZE](ftp://ftp.ping.de/pub/misc/emulators/yaze-1.10.tar.gz) (Yet Another Z80 Emulator). It is often difficult to track down, so [Jonathan Graham Harston](http://mdfs.net/User/JGH/) put it together [here](http://mdfs.net/Software/Z80/Exerciser/), as well as [some conversions](http://mdfs.net/Software/Z80/Exerciser/Spectrum/). The latest release of YAZE is available at [Andreas Gerlich's website](http://www.mathematik.uni-ulm.de/users/ag/yaze-ag/).
<details>
<summary>Results</summary>
<table>
<tr>
<td align="center" valign="top">
<a href="http://mdfs.net/Software/Z80/Exerciser/Spectrum/zexdoc.tap">
<img src="http://zxe.io/software/Z80/images/TAP.png"/>
<br>
<b>zexdoc.tap</b>
</a>
<br>
Tests officially documented flag effects.
</td>
</td>
<td align="center" valign="top">
<a href="http://mdfs.net/Software/Z80/Exerciser/Spectrum/zexall.tap">
<img src="http://zxe.io/software/Z80/images/TAP.png"/>
<br>
<b>zexall.tap</b>
</a>
<br>
Tests all flags changes.
</td>
</tr>
<tr>
<td align="center" valign="top">
<img src="http://zxe.io/software/Z80/images/tests/zexdoc.gif"/>
</td>
<td align="center" valign="top">
<img src="http://zxe.io/software/Z80/images/tests/zexall.gif"/>
</td>
</tr>
<tr>
<td align="center" valign="top">
<a href="http://zxds.raxoft.cz/taps/misc/zexall2.zip">
<img src="http://zxe.io/software/Z80/images/TAP.png"/>
<br>
<b>zexall2.tap</b>
</a>
<br>
Patrik Rak's modification with MEMPTR testing.
</td>
<td></td>
</tr>
<tr>
<td align="center" valign="top">
<img src="http://zxe.io/software/Z80/images/tests/zexall2.gif"/>
</td>
<td></td>
</tr>
</table>
</details>
# Installation
You will need [CMake](https://cmake.org) v3.14 or later to build the package and, optionally, recent versions of [Doxygen](https://www.doxygen.nl), [Sphinx](https://www.sphinx-doc.org) and [Breathe](https://github.com/michaeljones/breathe) to compile the documentation. Also make sure you have [LaTeX](https://www.latex-project.org) with PDF support installed on your system in case you want to generate the documentation in PDF format.
The emulator requires some types and macros included in [Zeta](https://github.com/redcode/Zeta), a dependency-free, [header-only](https://en.wikipedia.org/wiki/Header-only) library used to retain compatibility with most C compilers. Install Zeta or extract its official source code package to the same directory of this `README.md` or its parent directory. Zeta is the sole dependency; the emulator is a freestanding implementation and as such does not depend on the [C standard library](https://en.wikipedia.org/wiki/C_standard_library).
Once all requirements are met, create a directory and run `cmake` from there to prepare the build system:
```shell
mkdir build
cd build
cmake <directory of this README.md> [options]
```
There is also an Xcode project in `development/Xcode` with several targets:
The resulting build files can be configured by passing options to `cmake`. To show a complete list of those available along with their current settings, type the following:
Target | Description
--- | ---
Z80 (dynamic) | Shared library.
Z80 (dynamic module) | Shared library with a generic module ABI to be used in modular multi-machine emulators.
Z80 (static) | Static library.
Z80 (static module) | Static library with a generic CPU emulator ABI to be used in monolithic multi-machine emulators.
<br>
## Code configuration
There are some predefined macros that control the compilation:
Name | Description
--- | ---
`CPU_Z80_DEPENDENCIES_H` | If defined, it replaces the inclusion of any external header with this one. If you don't want to use Z, you can provide your own header with the types and macros used by the emulator.
`CPU_Z80_HIDE_ABI` | Makes the generic CPU emulator ABI private.
`CPU_Z80_HIDE_API` | Makes the public functions private.
`CPU_Z80_STATIC` | You need to define this to compile or use the emulator as a static library or if you have added `Z80.h` and `Z80.c` to your project.
`CPU_Z80_USE_LOCAL_HEADER` | Use this if you have imported `Z80.h` and `Z80.c` to your project. `Z80.c` will `#include "Z80.h"` instead of `<emulation/CPU/Z80.h>`.
`CPU_Z80_WITH_ABI` | Builds the generic CPU emulator ABI and declares its prototype in `Z80.h`.
`CPU_Z80_WITH_MODULE_ABI` | Builds the generic module ABI. This macro also enables `CPU_Z80_WITH_ABI`, so the generic CPU emulator ABI will be built too. This option is intended to be used when building a true module loadable at runtime with `dlopen()`, `LoadLibrary()` or similar. The ABI module can be accessed via the [weak symbol](http://en.wikipedia.org/wiki/Weak_symbol) `__module_abi__`.
<br>
## API: `Z80` emulator instance
This structure contains the state of the emulated CPU and callback pointers necessary to interconnect the emulator with external logic. There is no constructor function, so, before using an object of this type, some of its members must be initialized, in particular the following: `context`, `read`, `write`, `in`, `out`, `int_data` and `halt`.
```C
zusize cycles;
```shell
cmake -LAH
```
**Description**
Number of cycles executed in the current call to `z80_run`.
**Details**
`z80run` sets this variable to `0` before starting to execute instructions and its value persists after returning. The callbacks can use this variable to know during what cycle they are being called.
```C
void *context;
If in doubt, read the [CMake documentation](https://cmake.org/documentation/) for more information on configuration options. The following are some of the most relevant standard options of CMake:
* **`-DBUILD_SHARED_LIBS=(YES|NO)`**
Build the project as a shared library rather than a static one.
The default is `NO`.
* **`-DCMAKE_BUILD_TYPE=(Debug|Release|RelWithDebInfo)`**
Choose the type of build (configuration) to generate.
The default is `Release`.
* **`-DCMAKE_INSTALL_PREFIX="<path>"`**
Specify the installation prefix on [UNIX](https://en.wikipedia.org/wiki/Unix) and [UNIX-like](https://en.wikipedia.org/wiki/Unix-like) operating systems.
The default is `"/usr/local"`.
Package-specific options are prefixed with `Z80_` and can be divided into two groups. The first one controls aspects not related to the source code of the library:
* **`-DZ80_DOWNLOAD_TEST_FILES=(YES|NO)`**
Download the firmware and software used by the testing tool.
The default is `NO`.
* **`-DZ80_INSTALL_CMAKEDIR="<path>"`**
Specify the directory in which to install the CMake [config-file package](https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html#config-file-packages).
The default is `"${CMAKE_INSTALL_LIBDIR}/cmake/Z80"`.
* **`-DZ80_INSTALL_PKGCONFIGDIR="<path>"`**
Specify the directory in which to install the [pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config) [file](https://people.freedesktop.org/~dbn/pkg-config-guide.html).
The default is `"${CMAKE_INSTALL_LIBDIR}/pkgconfig"`.
* **`-DZ80_NOSTDLIB_FLAGS=(Auto|[<flag>[;<flag>...]])`**
Specify the linker flags used to avoid linking against system libraries.
The default is `Auto` (autoconfigure flags). If you get linker errors, set this option to `""`.
* **`-DZ80_SHARED_LIBS=(YES|NO)`**
Build the project as a shared library rather than a static one.
This option takes precedence over `BUILD_SHARED_LIBS`.
Not defined by default.
* **`-DZ80_SPHINX_HTML_THEME="[<name>]"`**
Specify the Sphinx theme for the documentation in HTML format.
The default is `""` (use the default theme).
* **`-DZ80_WITH_CMAKE_SUPPORT=(YES|NO)`**
Generate and install the CMake [config-file package](https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html#config-file-packages).
The default is `NO`.
* **`-DZ80_WITH_HTML_DOCUMENTATION=(YES|NO)`**
Build and install the documentation in HTML format.
It requires Doxygen, Sphinx and Breathe.
The default is `NO`.
* **`-DZ80_WITH_PDF_DOCUMENTATION=(YES|NO)`**
Build and install the documentation in PDF format.
It requires Doxygen, Sphinx, Breathe and LaTeX with PDF support.
The default is `NO`.
* **`-DZ80_WITH_PKGCONFIG_SUPPORT=(YES|NO)`**
Generate and install the [pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config) [file](https://people.freedesktop.org/~dbn/pkg-config-guide.html).
The default is `NO`.
* **`-DZ80_WITH_STANDARD_DOCUMENTS=(YES|NO)`**
Install the standard text documents distributed with the package: `AUTHORS`, `COPYING`, `COPYING.LESSER`, `HISTORY`, `README` and `THANKS`.
The default is `NO`.
* **`-DZ80_WITH_TESTS=(YES|NO)`**
Build the testing tool.
The default is `NO`.
The second group of package-specific options configures the source code of the library by predefining macros that enable optional implementations:
* **`-DZ80_WITH_EXECUTE=(YES|NO)`**
Build the implementation of the `z80_execute` function.
The default is `NO`.
* **`-DZ80_WITH_FULL_IM0=(YES|NO)`**
Build the full implementation of the interrupt mode 0 rather than the reduced one.
The default is `NO`.
* **`-DZ80_WITH_Q=(YES|NO)`**
Build the implementation of the [Q "register"](https://worldofspectrum.org/forums/discussion/41704).
The default is `NO`.
* **`-DZ80_WITH_RESET_SIGNAL=(YES|NO)`**
Build the implementation of the normal RESET signal.
The default is `NO`.
* **`-DZ80_WITH_SPECIAL_RESET_SIGNAL=(YES|NO)`**
Build the implementation of the [special RESET](http://www.primrosebank.net/computers/z80/z80_special_reset.htm) signal.
The default is `NO`.
* **`-DZ80_WITH_UNOFFICIAL_RETI=(YES|NO)`**
Configure the `ED5Dh`, `ED6Dh` and `ED7Dh` undocumented instructions as `reti` instead of `retn`.
The default is `NO`.
* **`-DZ80_WITH_ZILOG_NMOS_LD_A_IR_BUG=(YES|NO)`**
Build the implementation of the bug affecting the Zilog Z80 NMOS, which causes the P/V flag to be reset when a maskable interrupt is accepted during the execution of the `ld a,{i|r}` instructions.
The default is `NO`.
Package maintainers should use at least the following options for both shared and static library targets:
```shell
-DZ80_WITH_EXECUTE=YES
-DZ80_WITH_FULL_IM0=YES
-DZ80_WITH_Q=YES
-DZ80_WITH_RESET_SIGNAL=YES
-DZ80_WITH_ZILOG_NMOS_LD_A_IR_BUG=YES
```
**Description**
The value used as the first argument when calling a callback.
**Details**
This variable should be initialized before using the emulator and can be used to reference the context/instance of the machine being emulated.
```C
zuint8 (* read)(void *context, zuint16 address);
Finally, once the build system is configured according to your needs, build and install the package:
```shell
make
make install/strip
```
**Description**
Callback: Called when the CPU needs to read 8 bits from memory.
**Parameters**
`context` → The value of the member `context`.
`address` → The memory address to read from.
**Returns**
The 8 bits read from memory.
```C
void (* write)(void *context, zuint16 address, zuint8 value);
# Integration
### As an external dependency in CMake-based projects
The Z80 library includes find-modules and a config-file package for integration into CMake-based projects. It is recommended to always copy the `FindZ80.cmake` and `FindZeta.cmake` files into the CMake modules directory of projects that use the library as an external dependency. This will allow CMake to find the library if the necessary config-file packages are not installed on the system.
Both the config-file package and the find-module support dual installations of the shared and static versions of the Z80 library. You can specify the linking method by using the component mechanism of `find_package`.
Example:
```cmake
find_package(Z80 REQUIRED [Shared|Static])
target_link_libraries(your-target Z80)
```
**Description**
Callback: Called when the CPU needs to write 8 bits to memory.
**Parameters**
`context` → The value of the member `context`.
`address` → The memory address to write to.
`value` → The value to write.
```C
zuint8 (* in)(void *context, zuint16 port);
Omitting the linking method will select the `Shared` version of the library or, if not installed, the `Static` version instead.
### As a CMake subproject
To embed the library as a CMake subproject, just place its entire source tree into a subdirectory of your project.
It is advisable to configure the library in the CMakeLists.txt of your project. This will prevent the user from having to specify configuration options of the Z80 subproject through the CMake command line when building the main project. As noted in the "Installation" section of this document, all package-specific options are prefixed with `Z80_`, so, in a normal scenario, there should be no risk of name collision with the options and variables of the parent project.
Example:
```cmake
set(Z80_SHARED_LIBS NO CACHE BOOL "")
set(Z80_WITH_Q YES CACHE BOOL "")
set(Z80_WITH_ZILOG_NMOS_LD_A_IR_BUG YES CACHE BOOL "")
add_subdirectory(dependencies/Z80)
target_link_libraries(your-target Z80)
```
**Description**
Callback: Called when the CPU needs to read 8 bits from an I/O port.
**Parameters**
`context` → The value of the member `context`.
`port` → The number of the I/O port to read from.
**Returns**
The 8 bits read from the I/O port.
```C
void (* out)(void *context, zuint16 port, zuint8 value);
```
**Description**
Callback: Called when the CPU needs to write 8 bits to an I/O port.
**Parameters**
`context` → The value of the member `context`.
`port` → The number of the I/O port to write to.
`value` → The value to write.
It is important to set the `Z80_SHARED_LIBS` option. Otherwise CMake will build the library type indicated by `BUILD_SHARED_LIBS`, which may not be the desired one.
```C
zuint32 (* int_data)(void *context);
```
**Description**
Callback: Called when the CPU needs to read one instruction from the data bus to service a maskable interrupt (`INT`) in mode 0.
**Parameters**
`context` → The value of the member `context`.
**Returns**
A 32-bit value containing the bytes of an instruction. The instruction must begin at the most significant byte (big endian).
### Manual integration
```C
void (* halt)(void *context, zboolean state);
```
**Description**
Callback: Called when the CPU enters or exits the halt state.
**Note**
This callback is **optional** and must be set to `NULL` if not used.
**Parameters**
`context` → The value of the member `context`.
`state``TRUE` if halted; `FALSE` otherwise.
There are several macros that can be used to configure the source code of the library. You can define those you need in your build system or at the beginning of the `Z80.c` file. The following ones allow you to configure the integration of `Z80.h` and `Z80.c` into the project:
```C
ZZ80State state;
```
**Description**
CPU registers and internal bits.
**Details**
It contains the state of the registers, as well as the interrupt flip-flops, variables related to interrupts and other necessary flags. This is what a debugger should use as data source.
* **`#define Z80_DEPENDENCIES_HEADER "header name.h"`**
Specifies the only external header to `#include`, replacing those of Zeta.
If used, it must also be defined before including the `Z80.h` header.
```C
zuint8 r7;
```
**Description**
Backup of the 7th bit of the R register.
**Details**
The value of the R register is incremented as instructions are executed, but its most significant bit remains unchanged. For optimization reasons, this bit is saved at the beginning of the execution of `z80_run` and restored before returning. If an instruction directly affects the R register, this variable is also updated accordingly.
* **`#define Z80_STATIC`**
Needed for compiling and/or using the emulator as a static library or as an internal part of other project.
If used, it must also be defined before including the `Z80.h` header.
```C
Z16Bit xy;
```
**Description**
Temporay IX/IY register for instructions with `DDh`/`FDh` prefix.
**Details**
Since instructions with prefix `DDh` and `FDh` behave similarly, differing only in the use of register IX or IY, for reasons of size optimization, a single register is used that acts as both. During opcode analysis, the IX or IY register is copied to this variable and, once the instruction emulation is complete, its contents are copied back to the appropriate register.
* **`#define Z80_WITH_LOCAL_HEADER`**
Tells `Z80.c` to `#include "Z80.h"` instead of `<Z80.h>`.
```C
Z32Bit data;
```
**Description**
Temporary storage for opcode fetching.
**Details**
This is an internal private variable.
The second group of package-specific options, explained in the "Installation" section of this document, activates various optional implementations in the source code by predefining the following macros:
<br>
* **`#define Z80_WITH_EXECUTE`**
* **`#define Z80_WITH_FULL_IM0`**
* **`#define Z80_WITH_Q`**
* **`#define Z80_WITH_RESET_SIGNAL`**
* **`#define Z80_WITH_SPECIAL_RESET_SIGNAL`**
* **`#define Z80_WITH_UNOFFICIAL_RETI`**
* **`#define Z80_WITH_ZILOG_NMOS_LD_A_IR_BUG`**
## API: Public Functions
Please note that the activation of some these optional implementations affects the speed of the emulator due to various factors (read the documentation for more details).
```C
void z80_power(Z80 *object, zboolean state);
```
**Description**
Changes the CPU power status.
**Parameters**
`object` → A pointer to a Z80 emulator instance.
`state``TRUE` = power ON; `FALSE` = power OFF.
As a final note, except for `Z80_DEPENDENCIES_HEADER`, the above macros do not need to be set to a particular token when used, as the source code only checks whether or not they are defined.
```C
void z80_reset(Z80 *object);
```
**Description**
Resets the CPU.
**Details**
This is equivalent to a pulse on the `RESET` line of a real Z80.
**Parameters**
`object` → A pointer to a Z80 emulator instance.
# Showcase
```C
zusize z80_run(Z80 *object, zusize cycles);
```
**Description**
Runs the CPU for a given number of `cycles`.
**Note**
Given the fact that one Z80 instruction needs between 4 and 23 cycles to be executed, it's not always possible to run the CPU the exact number of `cycles` specfified.
**Parameters**
`object` → A pointer to a Z80 emulator instance.
`cycles` → The number of cycles to be executed.
**Returns**
The number of cycles executed.
This emulator has been used by the following projects (listed in alphabetical order):
```C
void z80_nmi(Z80 *object);
```
**Description**
Performs a non-maskable interrupt (NMI).
**Details**
This is equivalent to a pulse on the `NMI` line of a real Z80.
**Parameters**
`object` → A pointer to a Z80 emulator instance.
* [Augmentinel](https://simonowen.com/spectrum/augmentinel/), _by [Simon Owen](https://simonowen.com/)_ - [GitHub](https://github.com/simonowen/augmentinel)
* CPM-Emulator, _by [Marc Sibert](https://github.com/Marcussacapuces91)_ - [GitHub](https://github.com/Marcussacapuces91/CPM-Emulator)
* [tihle: a unique TI calculator emulator](https://www.taricorp.net/2020/introducing-tihle/), _by [Peter Marheine](https://www.taricorp.net/about/)_ - [GitHub](https://github.com/tari/tihle), [GitLab](https://gitlab.com/taricorp/tihle)
* [TileMap](https://simonowen.com/spectrum/tilemap/), _by [Simon Owen](https://simonowen.com/)_ - [GitHub](https://github.com/simonowen/tilemap)
* [Zemu](https://github.com/jayvalentine/zemu), _by [Jay Valentine](https://jayvalentine.github.io/)_ - [GitHub](https://github.com/jayvalentine/zemu), [RubyGems](https://rubygems.org/gems/zemu)
* Others...
```C
void z80_int(Z80 *object, zboolean state);
```
**Description**
Changes the state of the maskable interrupt (INT).
**Details**
This is equivalent to a change on the `INT` line of a real Z80.
**Parameters**
`object` → A pointer to a Z80 emulator instance.
`state``TRUE` = line high; `FALSE` = line low.
# Thanks
<br>
Many thanks to the following individuals (in alphabetical order):
## Use in Proprietary Software
This library is released under the terms of the [GNU General Public License v3](http://www.gnu.org/copyleft/gpl.html), but I can license it for non-free/propietary projects if you contact [me](mailto:contact@zxe.io?subject=Z80%20non-free%20licensing).
* **Akimov, Vadim (lvd)**
* For testing the library on many different platforms and CPU architectures.
* **azesmbog**
1. For validating tests on real hardware <sup>[[1](#r1)]</sup>.
2. For his research on the unstable flag behavior of the `ccf/scf` instructions.
3. For his invaluable help.
* **Banks, David (hoglet)**
1. For cracking the flag behavior of the block instructions <sup>[[2](#r2), [3](#r3)]</sup>.
2. For his research on the flag behavior of the `ccf/scf` instructions <sup>[[3](#r3)]</sup>.
* **Beliansky, Anatoly (Tolik_Trek)**
* For validating tests on real hardware <sup>[[4](#r4)]</sup>.
* **Bobrowski, Jan**
* For fixing the _"Z80 Full Instruction Set Exerciser for Spectrum"_ <sup>[[5](#r5)]</sup>.
* **boo_boo**
* For cracking the behavior of the MEMPTR register <sup>[[6](#r6), [7](#r7), [8](#r8), [9](#r9)]</sup>.
* **Brady, Stuart**
* For his research on the flag behavior of the `ccf/scf` instructions <sup>[[10](#r10)]</sup>.
* **Brewer, Tony**
1. For his research on the special RESET <sup>[[11](#r11)]</sup>.
2. For sharing information about the RESET signal <sup>[[12](#r12)]</sup>.
3. For helping to crack the flag behavior of the block instructions <sup>[[2](#r2)]</sup>.
4. For performing low-level tests on real hardware <sup>[[2](#r2)]</sup>.
5. For helping me to test different undocumented behaviors of the Zilog Z80.
* **Bystrov, Dmitry (Alone Coder)**
* For validating tests on real hardware <sup>[[4](#r4)]</sup>.
* **Chunin, Roman (CHRV)**
* For testing the behavior of the MEMPTR register on real Z80 chips <sup>[[6](#r6), [7](#r7), [8](#r8), [9](#r9)]</sup>.
* **Conway, Simon (BadBeard)**
* For validating the _"Z80 Test Suite"_ on several Z80 clones <sup>[[13](#r13)]</sup>.
* **Cooke, Simon**
* For finding out how the `out (c),0` instruction behaves on the Zilog Z80 CMOS <sup>[[14](#r14)]</sup>.
* **Cringle, Frank D.**
* For writing the _"Z80 Instruction Set Exerciser"_ <sup>[[15](#r15)]</sup>.
* **Devic, Goran**
* For his research on undocumented behaviors of the Z80 CPU <sup>[[16](#r16)]</sup>.
* **Flammenkamp, Achim**
* For his article on Z80 interrupts <sup>[[17](#r17)]</sup>.
* **Gimeno Fortea, Pedro**
1. For his research work <sup>[[18](#r18)]</sup>.
2. For writing the first-ever ZX Spectrum emulator <sup>[[19](#r19), [20](#r20)]</sup>.
* **goodboy**
* For testing the behavior of the MEMPTR register on real Z80 chips <sup>[[6](#r6), [7](#r7), [8](#r8), [9](#r9)]</sup>.
* **Greenway, Ian**
* For testing the flag behavior of the `ccf/scf` instructions on real hardware <sup>[[10](#r10), [21](#r21)]</sup>.
* **Harston, Jonathan Graham**
1. For his technical documents about the Zilog Z80 <sup>[[22](#r22), [23](#r23), [24](#r24)]</sup>.
2. For porting the _"Z80 Instruction Set Exerciser"_ to the ZX Spectrum <sup>[[25](#r25)]</sup>.
* **Helcmanovsky, Peter (Ped7g)**
1. For helping me to write the _"IN-MEMPTR"_ test.
2. For writing the _"Z80 Block Flags Test"_ <sup>[[26](#r26), [27](#r27)]</sup>.
3. For writing the _"Z80 CCF SCF Outcome Stability"_ test <sup>[[27](#r27)]</sup>.
4. For writing the _"Z80 INT Skip"_ test <sup>[[27](#r27)]</sup>.
5. For his research on the unstable flag behavior of the `ccf/scf` instructions.
6. For his invaluable help.
* **icebear**
* For testing the behavior of the MEMPTR register on real Z80 chips <sup>[[6](#r6), [7](#r7), [8](#r8), [9](#r9)]</sup>.
* **Kladov, Vladimir**
* For cracking the behavior of the MEMPTR register <sup>[[6](#r6), [7](#r7), [8](#r8), [9](#r9)]</sup>.
* **Krook, Magnus**
* For validating tests on real hardware <sup>[[28](#r28)]</sup>.
* **London, Matthew**
* For validating tests on real hardware.
* **Molodtsov, Aleksandr**
* For testing the behavior of the MEMPTR register on real Z80 chips <sup>[[6](#r6), [7](#r7), [8](#r8), [9](#r9)]</sup>.
* **Nair, Arjun**
* For validating tests on real hardware <sup>[[26](#r26)]</sup>.
* **Nicolás-González, César**
* For helping me to research the unstable flag behavior of the `ccf/scf` instructions.
* **Ortega Sosa, Sofía**
* For her support.
* **Owen, Simon**
* For the idea of the hooking method used in this emulator.
* **Rak, Patrik**
1. For improving the _"Z80 Instruction Set Exerciser for Spectrum"_ <sup>[[29](#r29)]</sup>.
2. For cracking the flag behavior of the `ccf/scf` instructions <sup>[[13](#r13), [29](#r29)]</sup>.
3. For writing the _"Zilog Z80 CPU Test Suite"_ <sup>[[29](#r29), [30](#r30)]</sup>.
4. For his research on the unstable flag behavior of the `ccf/scf` instructions.
* **Rodríguez Jódar, Miguel Ángel (mcleod_ideafix)**
* For his reseach on the state of the registers after POWER/RESET <sup>[[31](#r31)]</sup>.
* **Rodríguez Palomino, Mario (r-lyeh)**
* For teaching me how emulators work.
* **Sainz de Baranda y Romero, Manuel**
* For teaching me programming and giving me my first computer.
* **Sánchez Ordiñana, José Ismael (Vaporatorius)**
* For validating tests on real hardware <sup>[[32](#r32), [33](#r33)]</sup>.
* **Stevenson, Dave**
1. For testing the special RESET on real hardware <sup>[[11](#r11)]</sup>.
2. For performing low-level tests on real hardware <sup>[[34](#r34)]</sup>.
* **Weissflog, Andre (Floh)**
1. For finding out that the "reti/retn" instructions defer the acceptance of the maskable interrupt <sup>[[35](#r35)]</sup>.
2. For writing the "Visual Z80 Remix" simulator <sup>[[36](#r36)]</sup>.
* **Wilkinson, Oli (evolutional)**
* For validating tests on real hardware <sup>[[26](#r26)]</sup>.
* **Wlodek**
* For testing the behavior of the MEMPTR register on real Z80 chips <sup>[[6](#r6), [7](#r7), [8](#r8), [9](#r9)]</sup>.
* **Woodmass, Mark (Woody)**
1. For his invaluable contributions to the emuscene.
2. For writing the _"Z80 Test Suite"_ <sup>[[13](#r13)]</sup>.
3. For his research on the flag behavior of the `ccf/scf` instructions <sup>[[37](#r37)]</sup>.
4. For writing the _"HALT2INT"_ test.
5. For writing the _"EIHALT"_ test.
* **Young, Sean**
1. For his research work.
2. For his technical documents about the Zilog Z80 <sup>[[18](#r18), [38](#r38)]</sup>.
* **ZXGuesser**
* For validating tests on real hardware.
### References
1. <span id="r1">https://spectrumcomputing.co.uk/forums/viewtopic.php?p=83384#p83384</span>
2. <span id="r2">https://stardot.org.uk/forums/viewtopic.php?t=15464</span>
* https://stardot.org.uk/forums/viewtopic.php?p=211042#p211042
* https://stardot.org.uk/forums/viewtopic.php?p=212021#p212021
3. <span id="r3">Banks, David (2018-08-21). _"Undocumented Z80 Flags"_.</span>
* https://github.com/hoglet67/Z80Decoder/wiki/Undocumented-Flags
* https://stardot.org.uk/forums/download/file.php?id=39831
4. <span id="r4">https://spectrumcomputing.co.uk/forums/viewtopic.php?p=83041#p83041</span>
5. <span id="r5">http://wizard.ae.krakow.pl/~jb/qaop/tests.html</span>
6. <span id="r6">https://zxpress.ru/zxnet/zxnet.pc/5909</span>
7. <span id="r7">https://zx-pk.ru/threads/2506-komanda-bit-n-(hl).html</span>
8. <span id="r8">https://zx-pk.ru/threads/2586-prosba-realshchikam-ot-emulyatorshchikov.html</span>
9. <span id="r9">boo_boo; Kladov, Vladimir (2006-03-29). _"MEMPTR: esoteric register of the Zilog Z80 CPU"_.</span>
* http://zx.pk.ru/showpost.php?p=43688
* http://zx.pk.ru/attachment.php?attachmentid=2984
* http://zx.pk.ru/showpost.php?p=43800
* http://zx.pk.ru/attachment.php?attachmentid=2989
10. <span id="r10">https://sourceforge.net/p/fuse-emulator/mailman/message/6929573</span>
11. <span id="r11">Brewer, Tony (2014-12). _"Z80 Special Reset"_.</span>
* http://primrosebank.net/computers/z80/z80_special_reset.htm
12. <span id="r12">https://mtxworld.dk/memorum/viewtopic.php?p=1352#p1352</span>
13. <span id="r13">https://worldofspectrum.org/forums/discussion/20345</span>
14. <span id="r14">https://groups.google.com/g/comp.os.cpm/c/HfSTFpaIkuU/m/KotvMWu3bZoJ</span>
15. <span id="r15">Cringle, Frank D. (1998-01-28). _"Yaze - Yet Another Z80 Emulator"_ v1.10.</span>
* ftp://ftp.ping.de/pub/misc/emulators/yaze-1.10.tar.gz
16. <span id="r16">https://baltazarstudios.com/zilog-z80-undocumented-behavior</span>
17. <span id="r17">Flammenkamp, Achim. _"Interrupt Behaviour of the Z80 CPU"_.</span>
* http://z80.info/interrup.htm
18. <span id="r18">Young, Sean (1998-10). _"Z80 Undocumented Features (in Software Behaviour)"_.</span>
19. <span id="r19">https://elmundodelspectrum.com/desenterrando-el-primer-emulador-de-spectrum</span>
20. <span id="r20">https://elmundodelspectrum.com/con-vosotros-el-emulador-de-pedro-gimeno-1989</span>
21. <span id="r21">https://sourceforge.net/p/fuse-emulator/mailman/message/4502844</span>
22. <span id="r22">Harston, Jonathan Graham (1997-09-09). _"Z80 Opcode Map"_.</span>
* https://mdfs.net/Docs/Comp/Z80/OpCodeMap
23. <span id="r23">Harston, Jonathan Graham (1997-12-18). _"Z80 Microprocessor Undocumented Instructions"_.</span>
* https://mdfs.net/Docs/Comp/Z80/UnDocOps
24. <span id="r24">Harston, Jonathan Graham (1998-04-15). _"Full Z80 Opcode List Including Undocumented Opcodes"_.</span>
* https://mdfs.net/Docs/Comp/Z80/OpList
25. <span id="r25">https://mdfs.net/Software/Z80/Exerciser/Spectrum</span>
26. <span id="r26">https://spectrumcomputing.co.uk/forums/viewtopic.php?t=6102</span>
27. <span id="r27">https://github.com/MrKWatkins/ZXSpectrumNextTests</span>
28. <span id="r28">https://spectrumcomputing.co.uk/forums/viewtopic.php?p=83157#p83157</span>
29. <span id="r29">https://worldofspectrum.org/forums/discussion/41704</span>
* http://zxds.raxoft.cz/taps/misc/zexall2.zip
30. <span id="r30">https://worldofspectrum.org/forums/discussion/41834</span>
* http://zxds.raxoft.cz/taps/misc/z80test-1.0.zip
* https://github.com/raxoft/z80test
31. <span id="r31">https://worldofspectrum.org/forums/discussion/34574</span>
32. <span id="r32">https://worldofspectrum.org/forums/discussion/comment/668760/#Comment_668760</span>
33. <span id="r33">https://jisanchez.com/test-a-dos-placas-de-zx-spectrum</span>
34. <span id="r34">https://stardot.org.uk/forums/viewtopic.php?p=212360#p212360</span>
35. <span id="r35">https://floooh.github.io/2021/12/17/cycle-stepped-z80.html</span>
36. <span id="r36">https://github.com/floooh/v6502r</span>
37. <span id="r37">http://groups.google.co.uk/group/comp.sys.sinclair/msg/56dd1fd4ccb5fb3b</span>
38. <span id="r38">Young, Sean (2005-09-18). _"Undocumented Z80 Documented, The"_.</span>
* http://www.myquest.nl/z80undocumented
* http://www.myquest.nl/z80undocumented/z80-documented-v0.91.pdf
# Thanks
Alexander Molodtsov,
boo_boo,
CHRV,
Dave Stevenson,
Frank D. Cringle,
goodboy,
Goran Devic,
[Ian Greenway](http://www.lasernet.plus.com),
icebear,
Manuel Sainz de Baranda y Romero,
[Mario Rodríguez Palomino](https://github.com/r-lyeh),
Mark Woodmass,
[Miguel Ángel Rodríguez Jódar](https://github.com/mcleod-ideafix),
[Patrik Rak](https://github.com/raxoft),
[Pedro Gimeno Fortea](http://www.formauri.es/personal/pgimeno/),
Sean Young,
Simon Conway,
Simon Cooke,
Simon Owen,
[Sofía Ortega Sosa](https://github.com/agaxia),
Stuart Brady,
Tony Brewer,
Vladimir Kladov,
Wlodek
Read the [THANKS](THANKS) file for details.
# License
Copyright © 1999-2022 Manuel Sainz de Baranda y Goñi.
<img src="http://zxe.io/software/Z80/images/lgplv3-147x51.png" align="right">
This emulator is [free software](https://www.gnu.org/philosophy/free-sw.html): you can redistribute it and/or modify it under the terms of the **[GNU Lesser General Public License](https://www.gnu.org/licenses/lgpl-3.0.en.html)** as published by the [Free Software Foundation](https://www.fsf.org), either version 3 of the License, or (at your option) any later version.
This emulator is distributed in the hope that it will be useful, but **WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE**. See the GNU Lesser General Public License for more details.
You should have received a [copy](COPYING.LESSER) of the GNU Lesser General Public License along with this emulator. If not, see <https://www.gnu.org/licenses/>.
# Special licensing
Projects where the terms of the GNU Lesser General Public License prevent the use of this library, or require unwanted publication of the source code of commercial products, may [apply for a special license](mailto:manuel@zxe.io?subject=Z80).

180
THANKS Normal file
View File

@@ -0,0 +1,180 @@
Many thanks to the following individuals (in alphabetical order):
* Akimov, Vadim (lvd)
For testing the library on many different platforms and CPU architectures.
* azesmbog
1. For validating tests on real hardware [1].
2. For his research on the unstable flag behavior of the "ccf/scf"
instructions.
3. For his invaluable help.
* Banks, David (hoglet)
1. For cracking the flag behavior of the block instructions [2,3].
2. For his research on the flag behavior of the "ccf/scf" instructions [3].
* Beliansky, Anatoly (Tolik_Trek)
For validating tests on real hardware [4].
* Bobrowski, Jan
For fixing the "Z80 Full Instruction Set Exerciser for Spectrum" [5].
* boo_boo
For cracking the behavior of the MEMPTR register [6,7,8,9].
* Brady, Stuart
For his research on the flag behavior of the "ccf/scf" instructions [10].
* Brewer, Tony
1. For his research on the special RESET [11].
2. For sharing information about the RESET signal [12].
3. For helping to crack the flag behavior of the block instructions [2].
4. For performing low-level tests on real hardware [2].
5. For helping me to test different undocumented behaviors of the Zilog Z80.
* Bystrov, Dmitry (Alone Coder)
For validating tests on real hardware [4].
* Chunin, Roman (CHRV)
For testing the behavior of the MEMPTR register on real Z80 chips [6,7,8,9].
* Conway, Simon (BadBeard)
For validating the "Z80 Test Suite" on several Z80 clones [13].
* Cooke, Simon
For finding out how the "out (c),0" instruction behaves on the Zilog Z80
CMOS [14].
* Cringle, Frank D.
For writing the "Z80 Instruction Set Exerciser" [15].
* Devic, Goran
For his research on undocumented behaviors of the Z80 CPU [16].
* Flammenkamp, Achim
* For his article on Z80 interrupts [17].
* Gimeno Fortea, Pedro
1. For his research work [18].
2. For writing the first-ever ZX Spectrum emulator [19,20].
* goodboy
For testing the behavior of the MEMPTR register on real Z80 chips [6,7,8,9].
* Greenway, Ian
For testing the flag behavior of the "ccf/scf" instructions on real hardware
[10,21].
* Harston, Jonathan Graham
1. For his technical documents about the Zilog Z80 [22,23,24].
2. For porting the "Z80 Instruction Set Exerciser" to the ZX Spectrum [25].
* Helcmanovsky, Peter (Ped7g)
1. For helping me to write the "IN-MEMPTR" test.
2. For writing the "Z80 Block Flags Test" [26,27].
3. For writing the "Z80 CCF SCF Outcome Stability" test [27].
4. For writing the "Z80 INT Skip" test [27].
5. For his research on the unstable flag behavior of the "ccf/scf"
instructions.
6. For his invaluable help.
* icebear
For testing the behavior of the MEMPTR register on real Z80 chips [6,7,8,9].
* Kladov, Vladimir
For cracking the behavior of the MEMPTR register [6,7,8,9].
* Krook, Magnus
For validating tests on real hardware [28].
* London, Matthew
For validating tests on real hardware.
* Molodtsov, Aleksandr
For testing the behavior of the MEMPTR register on real Z80 chips [6,7,8,9].
* Nair, Arjun
For validating tests on real hardware [26].
* Nicolás-González, César
For helping me to research the unstable flag behavior of the "ccf/scf"
instructions.
* Ortega Sosa, Sofía
For her support.
* Owen, Simon
For the idea of the hooking method used in this emulator.
* Rak, Patrik
1. For improving the "Z80 Instruction Set Exerciser for Spectrum" [29].
2. For cracking the flag behavior of the "ccf/scf" instructions [13,29].
3. For writing the "Zilog Z80 CPU Test Suite" [29,30].
4. For his research on the unstable flag behavior of the "ccf/scf"
instructions.
* Rodríguez Jódar, Miguel Ángel (mcleod_ideafix)
For his reseach on the state of the registers after POWER/RESET [31].
* Rodríguez Palomino, Mario (r-lyeh)
For teaching me how emulators work.
* Sainz de Baranda y Romero, Manuel
For teaching me programming and giving me my first computer.
* Sánchez Ordiñana, José Ismael (Vaporatorius)
For validating tests on real hardware [32,33].
* Stevenson, Dave
1. For testing the special RESET on real hardware [11].
2. For performing low-level tests on real hardware [34].
* Weissflog, Andre (Floh)
1. For finding out that the "reti/retn" instructions defer the acceptance of
the maskable interrupt [35].
2. For writing the "Visual Z80 Remix" simulator [36].
* Wilkinson, Oli (evolutional)
For validating tests on real hardware [26].
* Wlodek
For testing the behavior of the MEMPTR register on real Z80 chips [6,7,8,9].
* Woodmass, Mark (Woody)
1. For his invaluable contributions to the emuscene.
2. For writing the "Z80 Test Suite" [13].
3. For his research on the flag behavior of the "ccf/scf" instructions [37].
4. For writing the "HALT2INT" test.
5. For writing the "EIHALT" test.
* Young, Sean
1. For his research work.
2. For his technical documents about the Zilog Z80 [18,38].
* ZXGuesser
For validating tests on real hardware.
References
==========
1. https://spectrumcomputing.co.uk/forums/viewtopic.php?p=83384#p83384
2. https://stardot.org.uk/forums/viewtopic.php?t=15464
* https://stardot.org.uk/forums/viewtopic.php?p=211042#p211042
* https://stardot.org.uk/forums/viewtopic.php?p=212021#p212021
3. Banks, David (2018-08-21). "Undocumented Z80 Flags".
* https://github.com/hoglet67/Z80Decoder/wiki/Undocumented-Flags
* https://stardot.org.uk/forums/download/file.php?id=39831
4. https://spectrumcomputing.co.uk/forums/viewtopic.php?p=83041#p83041
5. http://wizard.ae.krakow.pl/~jb/qaop/tests.html
6. https://zxpress.ru/zxnet/zxnet.pc/5909
7. https://zx-pk.ru/threads/2506-komanda-bit-n-(hl).html
8. https://zx-pk.ru/threads/2586-prosba-realshchikam-ot-emulyatorshchikov.html
9. boo_boo; Kladov, Vladimir (2006-03-29). "MEMPTR: esoteric register of the
Zilog Z80 CPU".
* http://zx.pk.ru/showpost.php?p=43688
* http://zx.pk.ru/attachment.php?attachmentid=2984
* http://zx.pk.ru/showpost.php?p=43800
* http://zx.pk.ru/attachment.php?attachmentid=2989
10. https://sourceforge.net/p/fuse-emulator/mailman/message/6929573
11. Brewer, Tony (2014-12). "Z80 Special Reset".
* http://primrosebank.net/computers/z80/z80_special_reset.htm
12. https://mtxworld.dk/memorum/viewtopic.php?p=1352#p1352
13. https://worldofspectrum.org/forums/discussion/20345
14. https://groups.google.com/g/comp.os.cpm/c/HfSTFpaIkuU/m/KotvMWu3bZoJ
15. Cringle, Frank D. (1998-01-28). "Yaze - Yet Another Z80 Emulator" v1.10.
* ftp://ftp.ping.de/pub/misc/emulators/yaze-1.10.tar.gz
16. https://baltazarstudios.com/zilog-z80-undocumented-behavior
17. Flammenkamp, Achim. "Interrupt Behaviour of the Z80 CPU".
* http://z80.info/interrup.htm
18. Young, Sean (1998-10). "Z80 Undocumented Features (in Software Behaviour)".
19. https://elmundodelspectrum.com/desenterrando-el-primer-emulador-de-spectrum
20. https://elmundodelspectrum.com/con-vosotros-el-emulador-de-pedro-gimeno-1989
21. https://sourceforge.net/p/fuse-emulator/mailman/message/4502844
22. Harston, Jonathan Graham (1997-09-09). "Z80 Opcode Map".
* https://mdfs.net/Docs/Comp/Z80/OpCodeMap
23. Harston, Jonathan Graham (1997-12-18). "Z80 Microprocessor Undocumented
Instructions".
* https://mdfs.net/Docs/Comp/Z80/UnDocOps
24. Harston, Jonathan Graham (1998-04-15). "Full Z80 Opcode List Including
Undocumented Opcodes".
* https://mdfs.net/Docs/Comp/Z80/OpList
25. https://mdfs.net/Software/Z80/Exerciser/Spectrum
26. https://spectrumcomputing.co.uk/forums/viewtopic.php?t=6102
27. https://github.com/MrKWatkins/ZXSpectrumNextTests
28. https://spectrumcomputing.co.uk/forums/viewtopic.php?p=83157#p83157
29. https://worldofspectrum.org/forums/discussion/41704
* http://zxds.raxoft.cz/taps/misc/zexall2.zip
30. https://worldofspectrum.org/forums/discussion/41834
* http://zxds.raxoft.cz/taps/misc/z80test-1.0.zip
* https://github.com/raxoft/z80test
31. https://worldofspectrum.org/forums/discussion/34574
32. https://worldofspectrum.org/forums/discussion/comment/668760/#Comment_668760
33. https://jisanchez.com/test-a-dos-placas-de-zx-spectrum
34. https://stardot.org.uk/forums/viewtopic.php?p=212360#p212360
35. https://floooh.github.io/2021/12/17/cycle-stepped-z80.html
36. https://github.com/floooh/v6502r
37. http://groups.google.co.uk/group/comp.sys.sinclair/msg/56dd1fd4ccb5fb3b
38. Young, Sean (2005-09-18). "Undocumented Z80 Documented, The".
* http://www.myquest.nl/z80undocumented
* http://www.myquest.nl/z80undocumented/z80-documented-v0.91.pdf

4
building/.gitignore vendored
View File

@@ -1,4 +0,0 @@
**
!.gitignore
!premake4.lua
!premake5.lua

View File

@@ -1,33 +0,0 @@
solution "Z80"
configurations {
"release-dynamic", "release-dynamic-module", "release-static", "release-static-module",
"debug-dynamic", "debug-dynamic-module", "debug-static", "debug-static-module"
}
project "Z80"
language "C"
flags {"ExtraWarnings"}
files {"../sources/**.c"}
includedirs {"../API"}
--buildoptions {"-std=c89 -pedantic -Wall -Weverything"}
configuration "release*"
targetdir "lib/release"
flags {"Optimize"}
configuration "debug*"
targetdir "lib/debug"
flags {"Symbols"}
configuration "*dynamic*"
kind "SharedLib"
configuration "*dynamic-module"
defines {"CPU_Z80_WITH_MODULE_ABI"}
configuration "*static*"
kind "StaticLib"
defines {"CPU_Z80_STATIC"}
configuration "*static-module"
defines {"CPU_Z80_WITH_ABI"}

View File

@@ -1,3 +0,0 @@
**
!.gitignore
!project.pbxproj

View File

@@ -1,520 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
6428A5751AAFC6DF00634F5D /* Z80.h in Headers */ = {isa = PBXBuildFile; fileRef = 6428A5741AAFC6DF00634F5D /* Z80.h */; settings = {ATTRIBUTES = (Public, ); }; };
6428A5771AAFC72900634F5D /* Z80.c in Sources */ = {isa = PBXBuildFile; fileRef = 6428A5761AAFC72900634F5D /* Z80.c */; };
6428A5801AAFEF1D00634F5D /* Z80.c in Sources */ = {isa = PBXBuildFile; fileRef = 6428A5761AAFC72900634F5D /* Z80.c */; settings = {COMPILER_FLAGS = "-DCPU_Z80_STATIC"; }; };
648C13AF1CCDFA8D00C8DCE1 /* Z80.c in Sources */ = {isa = PBXBuildFile; fileRef = 6428A5761AAFC72900634F5D /* Z80.c */; settings = {COMPILER_FLAGS = "-DCPU_Z80_WITH_MODULE_ABI"; }; };
648C13B21CCDFA8D00C8DCE1 /* Z80.h in Headers */ = {isa = PBXBuildFile; fileRef = 6428A5741AAFC6DF00634F5D /* Z80.h */; settings = {ATTRIBUTES = (Public, ); }; };
648C13C31CCDFBEF00C8DCE1 /* Z80.c in Sources */ = {isa = PBXBuildFile; fileRef = 6428A5761AAFC72900634F5D /* Z80.c */; settings = {COMPILER_FLAGS = "-DCPU_Z80_STATIC -DCPU_Z80_WITH_ABI"; }; };
64F8E3361CD656DA0083A613 /* Z80.h in Headers */ = {isa = PBXBuildFile; fileRef = 6428A5741AAFC6DF00634F5D /* Z80.h */; settings = {ATTRIBUTES = (Public, ); }; };
64F8E3371CD656DB0083A613 /* Z80.h in Headers */ = {isa = PBXBuildFile; fileRef = 6428A5741AAFC6DF00634F5D /* Z80.h */; settings = {ATTRIBUTES = (Public, ); }; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
6428A5691AAFC68700634F5D /* libZ80.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libZ80.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
6428A5741AAFC6DF00634F5D /* Z80.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Z80.h; sourceTree = "<group>"; };
6428A5761AAFC72900634F5D /* Z80.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Z80.c; sourceTree = "<group>"; };
6428A57C1AAFEDED00634F5D /* libZ80.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libZ80.a; sourceTree = BUILT_PRODUCTS_DIR; };
648C13B61CCDFA8D00C8DCE1 /* libZ80.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libZ80.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
648C13C91CCDFBEF00C8DCE1 /* libZ80.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libZ80.a; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
6428A5661AAFC68700634F5D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
6428A5791AAFEDED00634F5D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
648C13B01CCDFA8D00C8DCE1 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
648C13C41CCDFBEF00C8DCE1 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
6428A5601AAFC68700634F5D = {
isa = PBXGroup;
children = (
6428A5711AAFC69A00634F5D /* API */,
6428A5701AAFC69100634F5D /* Sources */,
6428A56A1AAFC68700634F5D /* Products */,
);
sourceTree = "<group>";
};
6428A56A1AAFC68700634F5D /* Products */ = {
isa = PBXGroup;
children = (
6428A5691AAFC68700634F5D /* libZ80.dylib */,
6428A57C1AAFEDED00634F5D /* libZ80.a */,
648C13B61CCDFA8D00C8DCE1 /* libZ80.dylib */,
648C13C91CCDFBEF00C8DCE1 /* libZ80.a */,
);
name = Products;
sourceTree = "<group>";
};
6428A5701AAFC69100634F5D /* Sources */ = {
isa = PBXGroup;
children = (
6428A5761AAFC72900634F5D /* Z80.c */,
);
name = Sources;
path = ../../sources;
sourceTree = "<group>";
};
6428A5711AAFC69A00634F5D /* API */ = {
isa = PBXGroup;
children = (
6428A5741AAFC6DF00634F5D /* Z80.h */,
);
name = API;
path = ../../API/emulation/CPU;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
6428A5671AAFC68700634F5D /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
6428A5751AAFC6DF00634F5D /* Z80.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
6428A57A1AAFEDED00634F5D /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
64F8E3361CD656DA0083A613 /* Z80.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
648C13B11CCDFA8D00C8DCE1 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
648C13B21CCDFA8D00C8DCE1 /* Z80.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
648C13C51CCDFBEF00C8DCE1 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
64F8E3371CD656DB0083A613 /* Z80.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
6428A5681AAFC68700634F5D /* Z80 (dynamic) */ = {
isa = PBXNativeTarget;
buildConfigurationList = 6428A56D1AAFC68700634F5D /* Build configuration list for PBXNativeTarget "Z80 (dynamic)" */;
buildPhases = (
6428A5651AAFC68700634F5D /* Sources */,
6428A5661AAFC68700634F5D /* Frameworks */,
6428A5671AAFC68700634F5D /* Headers */,
);
buildRules = (
);
dependencies = (
);
name = "Z80 (dynamic)";
productName = Z80;
productReference = 6428A5691AAFC68700634F5D /* libZ80.dylib */;
productType = "com.apple.product-type.library.dynamic";
};
6428A57B1AAFEDED00634F5D /* Z80 (static) */ = {
isa = PBXNativeTarget;
buildConfigurationList = 6428A57D1AAFEDED00634F5D /* Build configuration list for PBXNativeTarget "Z80 (static)" */;
buildPhases = (
6428A5781AAFEDED00634F5D /* Sources */,
6428A5791AAFEDED00634F5D /* Frameworks */,
6428A57A1AAFEDED00634F5D /* Headers */,
);
buildRules = (
);
dependencies = (
);
name = "Z80 (static)";
productName = "Z80-Static";
productReference = 6428A57C1AAFEDED00634F5D /* libZ80.a */;
productType = "com.apple.product-type.library.static";
};
648C13AD1CCDFA8D00C8DCE1 /* Z80 (dynamic module) */ = {
isa = PBXNativeTarget;
buildConfigurationList = 648C13B31CCDFA8D00C8DCE1 /* Build configuration list for PBXNativeTarget "Z80 (dynamic module)" */;
buildPhases = (
648C13AE1CCDFA8D00C8DCE1 /* Sources */,
648C13B01CCDFA8D00C8DCE1 /* Frameworks */,
648C13B11CCDFA8D00C8DCE1 /* Headers */,
);
buildRules = (
);
dependencies = (
);
name = "Z80 (dynamic module)";
productName = Z80;
productReference = 648C13B61CCDFA8D00C8DCE1 /* libZ80.dylib */;
productType = "com.apple.product-type.library.dynamic";
};
648C13C11CCDFBEF00C8DCE1 /* Z80 (static module) */ = {
isa = PBXNativeTarget;
buildConfigurationList = 648C13C61CCDFBEF00C8DCE1 /* Build configuration list for PBXNativeTarget "Z80 (static module)" */;
buildPhases = (
648C13C21CCDFBEF00C8DCE1 /* Sources */,
648C13C41CCDFBEF00C8DCE1 /* Frameworks */,
648C13C51CCDFBEF00C8DCE1 /* Headers */,
);
buildRules = (
);
dependencies = (
);
name = "Z80 (static module)";
productName = "Z80-Static";
productReference = 648C13C91CCDFBEF00C8DCE1 /* libZ80.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
6428A5611AAFC68700634F5D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0610;
ORGANIZATIONNAME = "Manuel Sainz de Baranda y Goñi";
TargetAttributes = {
6428A5681AAFC68700634F5D = {
CreatedOnToolsVersion = 6.1.1;
};
6428A57B1AAFEDED00634F5D = {
CreatedOnToolsVersion = 6.1.1;
};
};
};
buildConfigurationList = 6428A5641AAFC68700634F5D /* Build configuration list for PBXProject "Z80" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 6428A5601AAFC68700634F5D;
productRefGroup = 6428A56A1AAFC68700634F5D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
6428A5681AAFC68700634F5D /* Z80 (dynamic) */,
648C13AD1CCDFA8D00C8DCE1 /* Z80 (dynamic module) */,
6428A57B1AAFEDED00634F5D /* Z80 (static) */,
648C13C11CCDFBEF00C8DCE1 /* Z80 (static module) */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
6428A5651AAFC68700634F5D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
6428A5771AAFC72900634F5D /* Z80.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
6428A5781AAFEDED00634F5D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
6428A5801AAFEF1D00634F5D /* Z80.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
648C13AE1CCDFA8D00C8DCE1 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
648C13AF1CCDFA8D00C8DCE1 /* Z80.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
648C13C21CCDFBEF00C8DCE1 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
648C13C31CCDFBEF00C8DCE1 /* Z80.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
6428A56B1AAFC68700634F5D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ENABLE_MODULES = YES;
CLANG_WARN_ASSIGN_ENUM = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_FLOAT_CONVERSION = YES;
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
COPY_PHASE_STRIP = NO;
GCC_C_LANGUAGE_STANDARD = c99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_BUILTIN_FUNCTIONS = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
GCC_WARN_SHADOW = YES;
GCC_WARN_SIGN_COMPARE = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNKNOWN_PRAGMAS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_PARAMETER = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"$(inherited)",
/usr/local/include,
../../API,
);
LINK_WITH_STANDARD_LIBRARIES = NO;
LLVM_LTO = YES;
MACOSX_DEPLOYMENT_TARGET = 10.6;
ONLY_ACTIVE_ARCH = YES;
STRIP_STYLE = "non-global";
};
name = Debug;
};
6428A56C1AAFC68700634F5D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ENABLE_MODULES = YES;
CLANG_WARN_ASSIGN_ENUM = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_FLOAT_CONVERSION = YES;
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_C_LANGUAGE_STANDARD = c99;
GCC_ENABLE_BUILTIN_FUNCTIONS = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
GCC_WARN_SHADOW = YES;
GCC_WARN_SIGN_COMPARE = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNKNOWN_PRAGMAS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_PARAMETER = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"$(inherited)",
/usr/local/include,
../../API,
);
LINK_WITH_STANDARD_LIBRARIES = NO;
LLVM_LTO = YES;
MACOSX_DEPLOYMENT_TARGET = 10.6;
STRIP_STYLE = "non-global";
};
name = Release;
};
6428A56E1AAFC68700634F5D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
DYLIB_COMPATIBILITY_VERSION = 0;
DYLIB_CURRENT_VERSION = 0.1.0;
EXECUTABLE_PREFIX = lib;
PRODUCT_NAME = Z80;
PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/emulation/CPU;
};
name = Debug;
};
6428A56F1AAFC68700634F5D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
DYLIB_COMPATIBILITY_VERSION = 0;
DYLIB_CURRENT_VERSION = 0.1.0;
EXECUTABLE_PREFIX = lib;
PRODUCT_NAME = Z80;
PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/emulation/CPU;
};
name = Release;
};
6428A57E1AAFEDED00634F5D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
PRODUCT_NAME = Z80;
PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/emulation/CPU;
};
name = Debug;
};
6428A57F1AAFEDED00634F5D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
PRODUCT_NAME = Z80;
PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/emulation/CPU;
};
name = Release;
};
648C13B41CCDFA8D00C8DCE1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
DYLIB_COMPATIBILITY_VERSION = 0;
DYLIB_CURRENT_VERSION = 0.1.0;
EXECUTABLE_PREFIX = lib;
PRODUCT_NAME = Z80;
PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/emulation/CPU;
};
name = Debug;
};
648C13B51CCDFA8D00C8DCE1 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
DYLIB_COMPATIBILITY_VERSION = 0;
DYLIB_CURRENT_VERSION = 0.1.0;
EXECUTABLE_PREFIX = lib;
PRODUCT_NAME = Z80;
PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/emulation/CPU;
};
name = Release;
};
648C13C71CCDFBEF00C8DCE1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
PRODUCT_NAME = Z80;
PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/emulation/CPU;
};
name = Debug;
};
648C13C81CCDFBEF00C8DCE1 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
PRODUCT_NAME = Z80;
PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/emulation/CPU;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
6428A5641AAFC68700634F5D /* Build configuration list for PBXProject "Z80" */ = {
isa = XCConfigurationList;
buildConfigurations = (
6428A56B1AAFC68700634F5D /* Debug */,
6428A56C1AAFC68700634F5D /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
6428A56D1AAFC68700634F5D /* Build configuration list for PBXNativeTarget "Z80 (dynamic)" */ = {
isa = XCConfigurationList;
buildConfigurations = (
6428A56E1AAFC68700634F5D /* Debug */,
6428A56F1AAFC68700634F5D /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
6428A57D1AAFEDED00634F5D /* Build configuration list for PBXNativeTarget "Z80 (static)" */ = {
isa = XCConfigurationList;
buildConfigurations = (
6428A57E1AAFEDED00634F5D /* Debug */,
6428A57F1AAFEDED00634F5D /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
648C13B31CCDFA8D00C8DCE1 /* Build configuration list for PBXNativeTarget "Z80 (dynamic module)" */ = {
isa = XCConfigurationList;
buildConfigurations = (
648C13B41CCDFA8D00C8DCE1 /* Debug */,
648C13B51CCDFA8D00C8DCE1 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
648C13C61CCDFBEF00C8DCE1 /* Build configuration list for PBXNativeTarget "Z80 (static module)" */ = {
isa = XCConfigurationList;
buildConfigurations = (
648C13C71CCDFBEF00C8DCE1 /* Debug */,
648C13C81CCDFBEF00C8DCE1 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 6428A5611AAFC68700634F5D /* Project object */;
}

View File

@@ -0,0 +1,54 @@
=============
API reference
=============
Macros
------
.. doxygendefine:: Z80_LIBRARY_VERSION_MAJOR
.. doxygendefine:: Z80_LIBRARY_VERSION_MINOR
.. doxygendefine:: Z80_LIBRARY_VERSION_MICRO
.. doxygendefine:: Z80_LIBRARY_VERSION_STRING
.. doxygendefine:: Z80_CYCLE_LIMIT
.. doxygendefine:: Z80_HOOK
.. doxygendefine:: Z80_MODEL_ZILOG_NMOS
.. doxygendefine:: Z80_MODEL_ZILOG_CMOS
.. doxygendefine:: Z80_REQUEST_SPECIAL_RESET
.. doxygendefine:: Z80_REQUEST_RESET
.. doxygendefine:: Z80_REQUEST_NMI
.. doxygendefine:: Z80_REQUEST_INT
.. doxygendefine:: Z80_RESUME_HALT
.. doxygendefine:: Z80_RESUME_XY
.. doxygendefine:: Z80_RESUME_IM0_XY
Callback Types
--------------
.. doxygentypedef:: Z80Read
.. doxygentypedef:: Z80Write
.. doxygentypedef:: Z80HALT
.. doxygentypedef:: Z80Notify
Objects
-------
.. doxygenstruct:: Z80
:members:
Functions
---------
.. doxygenfunction:: z80_in_offset
.. doxygenfunction:: z80_instant_reset
.. doxygenfunction:: z80_out_offset
.. doxygenfunction:: z80_execute
.. doxygenfunction:: z80_int
.. doxygenfunction:: z80_nmi
.. doxygenfunction:: z80_normal_reset
.. doxygenfunction:: z80_power
.. doxygenfunction:: z80_refresh_address
.. doxygenfunction:: z80_run
.. doxygenfunction:: z80_special_reset

View File

@@ -0,0 +1,100 @@
# Z80 - documentation/CMakeLists.txt
# ______ ______ ______
# /\___ \/\ __ \\ __ \
# \/__/ /\_\ __ \\ \/\ \
# /\_____\\_____\\_____\
# Zilog \/_____//_____//_____/ CPU Emulator
# Copyright (C) 1999-2022 Manuel Sainz de Baranda y Goñi.
# Released under the terms of the GNU Lesser General Public License v3.
find_package(Doxygen REQUIRED)
find_package(Sphinx REQUIRED)
find_package(Breathe REQUIRED)
set(DOXYGEN_INPUT_DIR "${PROJECT_SOURCE_DIR}/API" )
set(DOXYGEN_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}" )
set(DOXYGEN_XML_OUTPUT "API-XML" )
set(_doxyfile_in "${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in")
set(_doxyfile "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile" )
get_target_property(DOXYGEN_INCLUDE_PATH Zeta INTERFACE_INCLUDE_DIRECTORIES)
configure_file(${_doxyfile_in} ${_doxyfile} @ONLY)
file(GLOB_RECURSE _public_headers ${DOXYGEN_INPUT_DIR}/*.h)
set(_api_xml_output "${DOXYGEN_OUTPUT_DIR}/${DOXYGEN_XML_OUTPUT}")
add_custom_command(
OUTPUT ${_api_xml_output}
DEPENDS ${_public_headers}
COMMAND ${DOXYGEN_EXECUTABLE} ${_doxyfile}
MAIN_DEPENDENCY ${_doxyfile}
COMMENT "Extracting API reference")
add_custom_target(API-XML ALL DEPENDS ${_api_xml_output})
if(${PROJECT_NAME}_WITH_HTML_DOCUMENTATION)
set(_html_documentation_output "${CMAKE_CURRENT_BINARY_DIR}/HTML")
if(${PROJECT_NAME}_SPHINX_HTML_THEME STREQUAL "")
set(_html_theme_option "")
else()
set(_html_theme_option "-Dhtml_theme=${${PROJECT_NAME}_SPHINX_HTML_THEME}")
endif()
add_custom_command(
OUTPUT ${_html_documentation_output}
COMMAND ${SPHINX_BUILD_EXECUTABLE}
-b html
${_html_theme_option}
"-Dbreathe_projects.${PROJECT_NAME}=${_api_xml_output}"
${CMAKE_CURRENT_SOURCE_DIR}
${_html_documentation_output}
MAIN_DEPENDENCY ${_api_xml_output}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating documentation in HTML format")
add_custom_target(Documentation-HTML ALL DEPENDS ${_html_documentation_output})
add_dependencies(Documentation-HTML API-XML)
install(DIRECTORY "${_html_documentation_output}/"
DESTINATION "${CMAKE_INSTALL_DOCDIR}/documentation")
endif()
if(${PROJECT_NAME}_WITH_PDF_DOCUMENTATION)
find_package(LATEX REQUIRED COMPONENTS PDFLATEX)
set(_latex_documentation_output "${CMAKE_CURRENT_BINARY_DIR}/LaTeX")
add_custom_command(
OUTPUT ${_latex_documentation_output}
COMMAND ${SPHINX_BUILD_EXECUTABLE}
-b latex
"-Dbreathe_projects.${PROJECT_NAME}=${_api_xml_output}"
${CMAKE_CURRENT_SOURCE_DIR}
${_latex_documentation_output}
MAIN_DEPENDENCY ${_api_xml_output}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating documentation in LaTeX format")
add_custom_target(Documentation-LaTeX ALL DEPENDS ${_latex_documentation_output})
add_dependencies(Documentation-LaTeX API-XML)
string(TOLOWER ${PROJECT_NAME} _pdf_documentation_output)
set(_pdf_documentation_output "${_latex_documentation_output}/${_pdf_documentation_output}.pdf")
add_custom_command(
OUTPUT ${_pdf_documentation_output}
COMMAND make
MAIN_DEPENDENCY ${_latex_documentation_output}
WORKING_DIRECTORY ${_latex_documentation_output}
COMMENT "Converting documentation to PDF format")
add_custom_target(Documentation-PDF ALL DEPENDS ${_pdf_documentation_output})
add_dependencies(Documentation-PDF Documentation-LaTeX)
install(FILES ${_pdf_documentation_output}
DESTINATION ${CMAKE_INSTALL_DOCDIR}
RENAME "${PROJECT_NAME} v${PROJECT_VERSION}.pdf")
endif()
# documentation/CMakeLists.txt EOF

376
documentation/Doxyfile.in Normal file
View File

@@ -0,0 +1,376 @@
# Doxyfile 1.8.15
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "@PROJECT_NAME@"
PROJECT_NUMBER =
PROJECT_BRIEF =
PROJECT_LOGO =
OUTPUT_DIRECTORY = "@DOXYGEN_OUTPUT_DIR@"
CREATE_SUBDIRS = NO
ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = English
OUTPUT_TEXT_DIRECTION = None
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF = "The $name class" \
"The $name widget" \
"The $name file" \
is \
provides \
specifies \
contains \
represents \
a \
an \
the
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = YES
STRIP_FROM_PATH = "@DOXYGEN_INPUT_DIR@"
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO
QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 8
ALIASES = "overline="
TCL_SUBST =
OPTIMIZE_OUTPUT_FOR_C = YES
OPTIMIZE_OUTPUT_JAVA = NO
OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
OPTIMIZE_OUTPUT_SLICE = NO
EXTENSION_MAPPING =
MARKDOWN_SUPPORT = YES
TOC_INCLUDE_HEADINGS = 0
AUTOLINK_SUPPORT = NO
BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO
SIP_SUPPORT = NO
IDL_PROPERTY_SUPPORT = YES
DISTRIBUTE_GROUP_DOC = NO
GROUP_NESTED_COMPOUNDS = NO
SUBGROUPING = YES
INLINE_GROUPED_CLASSES = NO
INLINE_SIMPLE_STRUCTS = NO
TYPEDEF_HIDES_STRUCT = NO
LOOKUP_CACHE_SIZE = 0
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = NO
EXTRACT_PRIVATE = YES
EXTRACT_PACKAGE = NO
EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = NO
EXTRACT_ANON_NSPACES = NO
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = NO
HIDE_SCOPE_NAMES = NO
HIDE_COMPOUND_REFERENCE= NO
SHOW_INCLUDE_FILES = YES
SHOW_GROUPED_MEMB_INC = NO
FORCE_LOCAL_INCLUDES = NO
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = NO
SORT_MEMBERS_CTORS_1ST = NO
SORT_GROUP_NAMES = NO
SORT_BY_SCOPE_NAME = NO
STRICT_PROTO_MATCHING = NO
GENERATE_TODOLIST = YES
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_FILES = YES
SHOW_NAMESPACES = YES
FILE_VERSION_FILTER =
LAYOUT_FILE =
CITE_BIB_FILES =
#---------------------------------------------------------------------------
# Configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
WARN_AS_ERROR = NO
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# Configuration options related to the input files
#---------------------------------------------------------------------------
# The INPUT tag is 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. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
INPUT = "@DOXYGEN_INPUT_DIR@"
INPUT_ENCODING = UTF-8
FILE_PATTERNS = *.h
RECURSIVE = YES
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXCLUDE_SYMBOLS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS = *
EXAMPLE_RECURSIVE = NO
IMAGE_PATH =
INPUT_FILTER =
FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
FILTER_SOURCE_PATTERNS =
USE_MDFILE_AS_MAINPAGE =
#---------------------------------------------------------------------------
# Configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = NO
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
REFERENCED_BY_RELATION = NO
REFERENCES_RELATION = NO
REFERENCES_LINK_SOURCE = YES
SOURCE_TOOLTIPS = YES
USE_HTAGS = NO
VERBATIM_HEADERS = YES
#---------------------------------------------------------------------------
# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = YES
COLS_IN_ALPHA_INDEX = 5
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = NO
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
HTML_EXTRA_STYLESHEET =
HTML_EXTRA_FILES =
HTML_COLORSTYLE_HUE = 220
HTML_COLORSTYLE_SAT = 100
HTML_COLORSTYLE_GAMMA = 80
HTML_TIMESTAMP = NO
HTML_DYNAMIC_MENUS = YES
HTML_DYNAMIC_SECTIONS = NO
HTML_INDEX_NUM_ENTRIES = 100
GENERATE_DOCSET = YES
DOCSET_FEEDNAME = "Zilog Z80 CPU Emulator"
DOCSET_BUNDLE_ID = com.redcode.Z80
DOCSET_PUBLISHER_ID = com.redcode
DOCSET_PUBLISHER_NAME = "Manuel Sainz de Baranda y Goñi"
GENERATE_HTMLHELP = NO
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
CHM_INDEX_ENCODING =
BINARY_TOC = NO
TOC_EXPAND = NO
GENERATE_QHP = NO
QCH_FILE =
QHP_NAMESPACE = org.doxygen.Project
QHP_VIRTUAL_FOLDER = doc
QHP_CUST_FILTER_NAME =
QHP_CUST_FILTER_ATTRS =
QHP_SECT_FILTER_ATTRS =
QHG_LOCATION =
GENERATE_ECLIPSEHELP = NO
ECLIPSE_DOC_ID = org.doxygen.Project
DISABLE_INDEX = NO
GENERATE_TREEVIEW = NO
ENUM_VALUES_PER_LINE = 4
TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO
FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES
USE_MATHJAX = NO
MATHJAX_FORMAT = HTML-CSS
MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/
MATHJAX_EXTENSIONS =
MATHJAX_CODEFILE =
SEARCHENGINE = YES
SERVER_BASED_SEARCH = NO
EXTERNAL_SEARCH = NO
SEARCHENGINE_URL =
SEARCHDATA_FILE = searchdata.xml
EXTERNAL_SEARCH_ID =
EXTRA_SEARCH_MAPPINGS =
#---------------------------------------------------------------------------
# Configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = NO
LATEX_OUTPUT = latex
LATEX_CMD_NAME =
MAKEINDEX_CMD_NAME = makeindex
LATEX_MAKEINDEX_CMD = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4
EXTRA_PACKAGES =
LATEX_HEADER =
LATEX_FOOTER =
LATEX_EXTRA_STYLESHEET =
LATEX_EXTRA_FILES =
PDF_HYPERLINKS = YES
USE_PDFLATEX = YES
LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
LATEX_SOURCE_CODE = NO
LATEX_BIB_STYLE = plain
LATEX_TIMESTAMP = NO
LATEX_EMOJI_DIRECTORY =
#---------------------------------------------------------------------------
# Configuration options related to the RTF output
#---------------------------------------------------------------------------
GENERATE_RTF = NO
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
RTF_SOURCE_CODE = NO
#---------------------------------------------------------------------------
# Configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = NO
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_SUBDIR =
MAN_LINKS = NO
#---------------------------------------------------------------------------
# Configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = YES
XML_OUTPUT = "@DOXYGEN_XML_OUTPUT@"
XML_PROGRAMLISTING = YES
XML_NS_MEMB_FILE_SCOPE = NO
#---------------------------------------------------------------------------
# Configuration options related to the DOCBOOK output
#---------------------------------------------------------------------------
GENERATE_DOCBOOK = NO
DOCBOOK_OUTPUT = docbook
DOCBOOK_PROGRAMLISTING = NO
#---------------------------------------------------------------------------
# Configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# Configuration options related to the Perl module output
#---------------------------------------------------------------------------
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH = "@DOXYGEN_INCLUDE_PATH@"
INCLUDE_FILE_PATTERNS =
PREDEFINED = Z80_API=
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = NO
#---------------------------------------------------------------------------
# Configuration options related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
EXTERNAL_PAGES = YES
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = YES
MSCGEN_PATH =
DIA_PATH =
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = NO
DOT_NUM_THREADS = 0
DOT_FONTNAME = Helvetica
DOT_FONTSIZE = 10
DOT_FONTPATH =
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = NO
UML_LIMIT_NUM_FIELDS = 10
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = NO
CALLER_GRAPH = NO
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
DOT_IMAGE_FORMAT = png
INTERACTIVE_SVG = NO
DOT_PATH =
DOTFILE_DIRS =
MSCFILE_DIRS =
DIAFILE_DIRS =
PLANTUML_JAR_PATH =
PLANTUML_CFG_FILE =
PLANTUML_INCLUDE_PATH =
DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 0
DOT_TRANSPARENT = NO
DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
DOT_CLEANUP = YES

View File

@@ -0,0 +1,3 @@
==================
Emulation accuracy
==================

View File

@@ -0,0 +1,170 @@
============
Installation
============
.. only:: html
.. |br| raw:: html
<br />
.. only:: latex
.. |nl| raw:: latex
\newline
You will need `CMake <https://cmake.org>`_ v3.14 or later to build the package and, optionally, recent versions of `Doxygen <https://www.doxygen.nl>`_, `Sphinx <https://www.sphinx-doc.org>`_ and `Breathe <https://github.com/michaeljones/breathe>`_ to compile the documentation. Also make sure you have `LaTeX <https://www.latex-project.org>`_ with PDF support installed on your system in case you want to generate the documentation in PDF format.
The emulator requires some types and macros included in `Zeta <https://zeta.st>`_, a dependency-free, `header-only <https://en.wikipedia.org/wiki/Header-only>`_ library used to retain compatibility with most C compilers. Install Zeta or extract its official source code package to the directory of the Z80 project or its parent directory. Zeta is the sole dependency; the emulator is a freestanding implementation and as such does not depend on the
`C standard library <https://en.wikipedia.org/wiki/C_standard_library>`_.
Once all requirements are met, create a directory and run ``cmake`` from there to prepare the build system:
.. code-block:: sh
mkdir build
cd build
cmake <path to the Z80 project> [options]
The resulting build files can be configured by passing options to ``cmake``. To show a complete list of those available along with their current settings, type the following:
.. code-block:: sh
cmake -LAH
If in doubt, read the `CMake documentation <https://cmake.org/documentation/>`_ for more information on configuration options. The following are some of the most relevant standard options of CMake:
.. option:: -DBUILD_SHARED_LIBS=(YES|NO)
Build the project as a shared library rather than a static one. |br| |nl|
The default is ``NO``.
.. option:: -DCMAKE_BUILD_TYPE=(Debug|Release|RelWithDebInfo)
Choose the type of build (configuration) to generate. |br| |nl|
The default is ``Release``.
.. option:: -DCMAKE_INSTALL_PREFIX="<path>"
Specify the installation prefix on `UNIX <https://en.wikipedia.org/wiki/Unix>`_ and `UNIX-like <https://en.wikipedia.org/wiki/Unix-like>`_ operating systems. |br| |nl|
The default is ``"/usr/local"``.
Package-specific options are prefixed with ``Z80_`` and can be divided into two groups. The first one controls aspects not related to the source code of the library:
.. option:: -DZ80_DOWNLOAD_TEST_FILES=(YES|NO)
Download the firmware and software used by the testing tool. |br| |nl|
The default is ``NO``.
.. option:: -DZ80_INSTALL_CMAKEDIR="<path>"
Specify the directory in which to install the CMake `config-file package <https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html#config-file-packages>`_. |br| |nl|
The default is ``"${CMAKE_INSTALL_LIBDIR}/cmake/Z80"``.
.. option:: -DZ80_INSTALL_PKGCONFIGDIR="<path>"
Specify the directory in which to install the `pkg-config <https://www.freedesktop.org/wiki/Software/pkg-config>`_ `file <https://people.freedesktop.org/~dbn/pkg-config-guide.html>`_. |br| |nl|
The default is ``"${CMAKE_INSTALL_LIBDIR}/pkgconfig"``.
.. option:: -DZ80_NOSTDLIB_FLAGS=(Auto|[<flag>[;<flag>...]])
Specify the linker flags used to avoid linking against system libraries. |br| |nl|
The default is ``Auto`` (autoconfigure flags). If you get linker errors, set this option to ``""``.
.. option:: -DZ80_SHARED_LIBS=(YES|NO)
Build the project as a shared library rather than a static one. |br| |nl|
This option takes precedence over ``BUILD_SHARED_LIBS``. |br| |nl|
Not defined by default.
.. option:: -DZ80_SPHINX_HTML_THEME="[<name>]"
Specify the Sphinx theme for the documentation in HTML format. |br| |nl|
The default is ``""`` (use the default theme).
.. option:: -DZ80_WITH_CMAKE_SUPPORT=(YES|NO)
Generate and install the CMake `config-file package <https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html#config-file-packages>`_. |br| |nl|
The default is ``NO``.
.. option:: -DZ80_WITH_HTML_DOCUMENTATION=(YES|NO)
Build and install the documentation in HTML format. |br| |nl|
It requires Doxygen, Sphinx and Breathe. |br| |nl|
The default is ``NO``.
.. option:: -DZ80_WITH_PDF_DOCUMENTATION=(YES|NO)
Build and install the documentation in PDF format. |br| |nl|
It requires Doxygen, Sphinx, Breathe and LaTeX with PDF support. |br| |nl|
The default is ``NO``.
.. option:: -DZ80_WITH_PKGCONFIG_SUPPORT=(YES|NO)
Generate and install the `pkg-config <https://www.freedesktop.org/wiki/Software/pkg-config>`_ `file <https://people.freedesktop.org/~dbn/pkg-config-guide.html>`_. |br| |nl|
The default is ``NO``.
.. option:: -DZ80_WITH_STANDARD_DOCUMENTS=(YES|NO)
Install the standard text documents distributed with the package: ``AUTHORS``, ``COPYING``, ``COPYING.LESSER``, ``HISTORY``, ``README`` and ``THANKS``. |br| |nl|
The default is ``NO``.
.. option:: -DZ80_WITH_TESTS=(YES|NO)
Build the testing tool. |br| |nl|
The default is ``NO``.
The second group of package-specific options configures the source code of the library by predefining macros that enable optional implementations:
.. option:: -DZ80_WITH_EXECUTE=(YES|NO)
Build the implementation of the ``z80_execute`` function. |br| |nl|
The default is ``NO``.
.. option:: -DZ80_WITH_FULL_IM0=(YES|NO)
Build the full implementation of the interrupt mode 0 rather than the reduced one. |br| |nl|
The default is ``NO``.
.. option:: -DZ80_WITH_Q=(YES|NO)
Build the implementation of the `Q "register" <https://worldofspectrum.org/forums/discussion/41704>`_. |br| |nl|
The default is ``NO``.
.. option:: -DZ80_WITH_RESET_SIGNAL=(YES|NO)
Build the implementation of the normal RESET signal. |br| |nl|
The default is ``NO``.
.. option:: -DZ80_WITH_SPECIAL_RESET_SIGNAL=(YES|NO)
Build the implementation of the `special RESET <http://www.primrosebank.net/computers/z80/z80_special_reset.htm>`_ signal. |br| |nl|
The default is ``NO``.
.. option:: -DZ80_WITH_UNOFFICIAL_RETI=(YES|NO)
Configure the ``ED5Dh``, ``ED6Dh`` and ``ED7Dh`` undocumented instructions as ``reti`` instead of ``retn``. |br| |nl|
The default is ``NO``.
.. option:: -DZ80_WITH_ZILOG_NMOS_LD_A_IR_BUG=(YES|NO)
Build the implementation of the bug affecting the Zilog Z80 NMOS, which causes the P/V flag to be reset when a maskable interrupt is accepted during the execution of the ``ld a,{i|r}`` instructions. |br| |nl|
The default is ``NO``.
Package maintainers should use at least the following options for both shared and static library targets:
.. code-block:: sh
-DZ80_WITH_EXECUTE=YES
-DZ80_WITH_FULL_IM0=YES
-DZ80_WITH_Q=YES
-DZ80_WITH_RESET_SIGNAL=YES
-DZ80_WITH_ZILOG_NMOS_LD_A_IR_BUG=YES
Finally, once the build system is configured according to your needs, build and install the package:
.. code-block:: sh
make
make install/strip

View File

@@ -0,0 +1,82 @@
===========
Integration
===========
.. only:: html
.. |br| raw:: html
<br />
.. only:: latex
.. |nl| raw:: latex
\newline
As an external dependency in CMake-based projects
-------------------------------------------------
The Z80 library includes find-modules and a config-file package for integration into CMake-based projects. It is recommended to always copy the ``FindZ80.cmake`` and ``FindZeta.cmake`` files into the CMake modules directory of projects that use the library as an external dependency. This will allow CMake to find the library if the necessary config-file packages are not installed on the system.
Both the config-file package and the find-module support dual installations of the shared and static versions of the Z80 library. You can specify the linking method by using the component mechanism of ``find_package``.
Example:
.. code-block:: cmake
find_package(Z80 REQUIRED [Shared|Static])
target_link_libraries(your-target Z80)
Omitting the linking method will select the ``Shared`` version of the library or, if not installed, the ``Static`` version instead.
As a CMake subproject
---------------------
To embed the library as a CMake subproject, just place its entire source tree into a subdirectory of your project.
It is advisable to configure the library in the ``CMakeLists.txt`` of your project. This will prevent the user from having to specify configuration options of the Z80 subproject through the CMake command line when building the main project. As noted in the Installation section of this document, all package-specific options are prefixed with ``Z80_``, so, in a normal scenario, there should be no risk of name collision with the options and variables of the parent project.
Example:
.. code-block:: cmake
set(Z80_SHARED_LIBS NO CACHE BOOL "")
set(Z80_WITH_Q YES CACHE BOOL "")
set(Z80_WITH_ZILOG_NMOS_LD_A_IR_BUG YES CACHE BOOL "")
add_subdirectory(dependencies/Z80)
target_link_libraries(your-target Z80)
It is important to set the ``Z80_SHARED_LIBS`` option. Otherwise CMake will build the library type indicated by ``BUILD_SHARED_LIBS``, which may not be the desired one.
Manual integration
------------------
There are several macros that can be used to configure the source code of the library. You can define those you need in your build system or at the beginning of the ``Z80.c`` file. The following ones allow you to configure the integration of ``Z80.h`` and ``Z80.c`` into the project:
.. c:macro:: Z80_DEPENDENCIES_HEADER
Specifies the only external header to ``#include``, replacing those of Zeta. |br| |nl|
If used, it must also be defined before including the ``Z80.h`` header.
.. c:macro:: Z80_STATIC
Needed for compiling and/or using the emulator as a static library or as an internal part of other project. |br| |nl|
If used, it must also be defined before including the ``Z80.h`` header.
.. c:macro:: Z80_WITH_LOCAL_HEADER
Tells ``Z80.c`` to ``#include Z80.h`` instead of ``<Z80.h>``.
The second group of package-specific options, explained in the "Installation" section of this document, activates various optional implementations in the source code by predefining the following macros:
.. c:macro:: Z80_WITH_EXECUTE
.. c:macro:: Z80_WITH_FULL_IM0
.. c:macro:: Z80_WITH_Q
.. c:macro:: Z80_WITH_RESET_SIGNAL
.. c:macro:: Z80_WITH_SPECIAL_RESET_SIGNAL
.. c:macro:: Z80_WITH_UNOFFICIAL_RETI
.. c:macro:: Z80_WITH_ZILOG_NMOS_LD_A_IR_BUG
Except for ``Z80_DEPENDENCIES_HEADER``, the above macros do not need to be set to a particular token when used, as the source code only checks whether or not they are defined.

View File

@@ -0,0 +1,9 @@
=======
License
=======
This emulator is `free software <https://www.gnu.org/philosophy/free-sw.html>`_: you can redistribute it and/or modify it under the terms of the `GNU Lesser General Public License <https://www.gnu.org/licenses/lgpl-3.0.en.html>`_ as published by the `Free Software Foundation <https://www.fsf.org>`_, either version 3 of the License, or (at your option) any later version.
This emulator is distributed in the hope that it will be useful, but **WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE**. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with this emulator. If not, see <https://www.gnu.org/licenses/>.

20
documentation/Makefile Normal file
View File

@@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

2
documentation/TODO.txt Normal file
View File

@@ -0,0 +1,2 @@
ST CMOS Z80 no se comporta igual en los flags de las instrucciones de bloque?
https://stardot.org.uk/forums/viewtopic.php?p=212100#p212100

View File

@@ -0,0 +1,3 @@
=======
Testing
=======

214
documentation/Thanks.rst Normal file
View File

@@ -0,0 +1,214 @@
======
Thanks
======
Many thanks to the following individuals (in alphabetical order):
Akimov, Vadim (lvd)
For testing the library on many different platforms and CPU architectures.
azesmbog
1. For validating tests on real hardware [1].
2. For his research on the unstable flag behavior of the "ccf/scf" instructions.
3. For his invaluable help.
Banks, David (hoglet)
1. For cracking the flag behavior of the block instructions [2,3].
2. For his research on the flag behavior of the "ccf/scf" instructions [3].
Beliansky, Anatoly (Tolik_Trek)
For validating tests on real hardware [4].
Bobrowski, Jan
For fixing the "Z80 Full Instruction Set Exerciser for Spectrum" [5].
boo_boo
For cracking the behavior of the MEMPTR register [6,7,8,9].
Brady, Stuart
For his research on the flag behavior of the "ccf/scf" instructions [10].
Brewer, Tony
1. For his research on the special RESET [11].
2. For sharing information about the RESET signal [12].
3. For helping to crack the flag behavior of the block instructions [2].
4. For performing low-level tests on real hardware [2].
5. For helping me to test different undocumented behaviors of the Zilog Z80.
Bystrov, Dmitry (Alone Coder)
For validating tests on real hardware [4].
Chunin, Roman (CHRV)
For testing the behavior of the MEMPTR register on real Z80 chips [6,7,8,9].
Conway, Simon (BadBeard)
For validating the "Z80 Test Suite" on several Z80 clones [13].
Cooke, Simon
For finding out how the "out (c),0" instruction behaves on the Zilog Z80 CMOS [14].
Cringle, Frank D.
For writing the "Z80 Instruction Set Exerciser" [15].
Devic, Goran
For his research on undocumented behaviors of the Z80 CPU [16].
Flammenkamp, Achim
For his article on Z80 interrupts [17].
Gimeno Fortea, Pedro
1. For his research work [18].
2. For writing the first-ever ZX Spectrum emulator [19,20].
goodboy
For testing the behavior of the MEMPTR register on real Z80 chips [6,7,8,9].
Greenway, Ian
For testing the flag behavior of the "ccf/scf" instructions on real hardware [10,21].
Harston, Jonathan Graham
1. For his technical documents about the Zilog Z80 [22,23,24].
2. For porting the "Z80 Instruction Set Exerciser" to the ZX Spectrum [25].
Helcmanovsky, Peter (Ped7g)
1. For helping me to write the "IN-MEMPTR" test.
2. For writing the "Z80 Block Flags Test" [26,27].
3. For writing the "Z80 CCF SCF Outcome Stability" test [27].
4. For writing the "Z80 INT Skip" test [27].
5. For his research on the unstable flag behavior of the "ccf/scf" instructions.
6. For his invaluable help.
icebear
For testing the behavior of the MEMPTR register on real Z80 chips [6,7,8,9].
Kladov, Vladimir
For cracking the behavior of the MEMPTR register [6,7,8,9].
Krook, Magnus
For validating tests on real hardware [28].
London, Matthew
For validating tests on real hardware.
Molodtsov, Aleksandr
For testing the behavior of the MEMPTR register on real Z80 chips [6,7,8,9].
Nair, Arjun
For validating tests on real hardware [26].
Nicolás-González, César
For helping me to research the unstable flag behavior of the "ccf/scf" instructions.
Ortega Sosa, Sofía
For her support.
Owen, Simon
For the idea of the hooking method used in this emulator.
Rak, Patrik
1. For improving the "Z80 Instruction Set Exerciser for Spectrum" [29].
2. For cracking the flag behavior of the "ccf/scf" instructions [13,29].
3. For writing the "Zilog Z80 CPU Test Suite" [29,30].
4. For his research on the unstable flag behavior of the "ccf/scf" instructions.
Rodríguez Jódar, Miguel Ángel (mcleod_ideafix)
For his reseach on the state of the registers after POWER/RESET [31].
Rodríguez Palomino, Mario (r-lyeh)
For teaching me how emulators work.
Sainz de Baranda y Romero, Manuel
For teaching me programming and giving me my first computer.
Sánchez Ordiñana, José Ismael (Vaporatorius)
For validating tests on real hardware [32,33].
Stevenson, Dave
1. For testing the special RESET on real hardware [11].
2. For performing low-level tests on real hardware [34].
Weissflog, Andre (Floh)
1. For finding out that the "reti/retn" instructions defer the acceptance of the maskable interrupt [35].
2. For writing the "Visual Z80 Remix" simulator [36].
Wilkinson, Oli (evolutional)
For validating tests on real hardware [26].
Wlodek
For testing the behavior of the MEMPTR register on real Z80 chips [6,7,8,9].
Woodmass, Mark (Woody)
1. For his invaluable contributions to the emuscene.
2. For writing the "Z80 Test Suite" [13].
3. For his research on the flag behavior of the "ccf/scf" instructions [37].
4. For writing the "HALT2INT" test.
5. For writing the "EIHALT" test.
Young, Sean
1. For his research work.
2. For his technical documents about the Zilog Z80 [18,38].
ZXGuesser
For validating tests on real hardware.
References
==========
1. https://spectrumcomputing.co.uk/forums/viewtopic.php?p=83384#p83384
2. https://stardot.org.uk/forums/viewtopic.php?t=15464
* https://stardot.org.uk/forums/viewtopic.php?p=211042#p211042
* https://stardot.org.uk/forums/viewtopic.php?p=212021#p212021
3. Banks, David (2018-08-21). "Undocumented Z80 Flags".
* https://github.com/hoglet67/Z80Decoder/wiki/Undocumented-Flags
* https://stardot.org.uk/forums/download/file.php?id=39831
4. https://spectrumcomputing.co.uk/forums/viewtopic.php?p=83041#p83041
5. http://wizard.ae.krakow.pl/~jb/qaop/tests.html
6. https://zxpress.ru/zxnet/zxnet.pc/5909
7. https://zx-pk.ru/threads/2506-komanda-bit-n-(hl).html
8. https://zx-pk.ru/threads/2586-prosba-realshchikam-ot-emulyatorshchikov.html
9. boo_boo; Kladov, Vladimir (2006-03-29). "MEMPTR: esoteric register of the Zilog Z80 CPU".
* http://zx.pk.ru/showpost.php?p=43688
* http://zx.pk.ru/attachment.php?attachmentid=2984
* http://zx.pk.ru/showpost.php?p=43800
* http://zx.pk.ru/attachment.php?attachmentid=2989
10. https://sourceforge.net/p/fuse-emulator/mailman/message/6929573
11. Brewer, Tony (2014-12). "Z80 Special Reset".
* http://primrosebank.net/computers/z80/z80_special_reset.htm
12. https://mtxworld.dk/memorum/viewtopic.php?p=1352#p1352
13. https://worldofspectrum.org/forums/discussion/20345
14. https://groups.google.com/g/comp.os.cpm/c/HfSTFpaIkuU/m/KotvMWu3bZoJ
15. Cringle, Frank D. (1998-01-28). "Yaze - Yet Another Z80 Emulator" v1.10.
* ftp://ftp.ping.de/pub/misc/emulators/yaze-1.10.tar.gz
16. https://baltazarstudios.com/zilog-z80-undocumented-behavior
17. Flammenkamp, Achim. "Interrupt Behaviour of the Z80 CPU".
* http://z80.info/interrup.htm
18. Young, Sean (1998-10). "Z80 Undocumented Features (in Software Behaviour)".
19. https://elmundodelspectrum.com/desenterrando-el-primer-emulador-de-spectrum
20. https://elmundodelspectrum.com/con-vosotros-el-emulador-de-pedro-gimeno-1989
21. https://sourceforge.net/p/fuse-emulator/mailman/message/4502844
22. Harston, Jonathan Graham (1997-09-09). "Z80 Opcode Map".
* https://mdfs.net/Docs/Comp/Z80/OpCodeMap
23. Harston, Jonathan Graham (1997-12-18). "Z80 Microprocessor Undocumented Instructions".
* https://mdfs.net/Docs/Comp/Z80/UnDocOps
24. Harston, Jonathan Graham (1998-04-15). "Full Z80 Opcode List Including Undocumented Opcodes".
* https://mdfs.net/Docs/Comp/Z80/OpList
25. https://mdfs.net/Software/Z80/Exerciser/Spectrum
26. https://spectrumcomputing.co.uk/forums/viewtopic.php?t=6102
27. https://github.com/MrKWatkins/ZXSpectrumNextTests
28. https://spectrumcomputing.co.uk/forums/viewtopic.php?p=83157#p83157
29. https://worldofspectrum.org/forums/discussion/41704
* http://zxds.raxoft.cz/taps/misc/zexall2.zip
30. https://worldofspectrum.org/forums/discussion/41834
* http://zxds.raxoft.cz/taps/misc/z80test-1.0.zip
* https://github.com/raxoft/z80test
31. https://worldofspectrum.org/forums/discussion/34574
32. https://worldofspectrum.org/forums/discussion/comment/668760/#Comment_668760
33. https://jisanchez.com/test-a-dos-placas-de-zx-spectrum
34. https://stardot.org.uk/forums/viewtopic.php?p=212360#p212360
35. https://floooh.github.io/2021/12/17/cycle-stepped-z80.html
36. https://github.com/floooh/v6502r
37. http://groups.google.co.uk/group/comp.sys.sinclair/msg/56dd1fd4ccb5fb3b
38. Young, Sean (2005-09-18). "Undocumented Z80 Documented, The".
* http://www.myquest.nl/z80undocumented
* http://www.myquest.nl/z80undocumented/z80-documented-v0.91.pdf

View File

@@ -0,0 +1,71 @@
===============
Version History
===============
v0.2 (2022-XX-XX)
=================
This is an important update that addresses a number of issues and also includes new features. Please note that the changes introduced in this release break the binary compatibility with the previous version.
Changes:
1. Changed the license from GPL to LGPL (by popular request).
2. Moved the public header from ``<emulation/CPU/Z80.h>`` to ``<Z80.h>``.
3. Removed the Xcode project.
4. Switched the build system from Premake to CMake.
5. Switched to Zeta v0.1.
6. Added pkg-config support.
7. Added the ``.vimrc`` dotfile.
8. Added the ``CITATION.cff`` file.
9. Added the ``file_id.diz`` file.
10. Added the ``THANKS`` file.
11. Added detailed documentation.
12. Added tests.
13. Added public macros for checking the library version.
14. Added public macros with bit masks for working with flags.
15. Added public macros for accessing the 16-bit registers.
16. Added the ``z80_execute`` function to run a simplified emulation without RESET and interrupts.
17. Added the ``z80_refresh_address`` function to get the refresh address of the current M1 cycle.
18. Added the ``z80_in_cycle`` and ``z80_out_cycle`` functions to get the clock cycle on which the I/O M-cycle occurs, relative to the start of the instruction.
19. Fixed a bug in the ``sll`` instruction.
20. Fixed a bug in the ``INX`` and ``OUTX`` macros affecting the S and N flags.
21. Fixed a bug in the ``OUTX`` macro affecting the MSByte of the port number.
22. Fixed the clock cycles of the ``dec XY`` and ``in (c)`` instructions.
23. Fixed the ``read_16`` function so that the order in which the compiler evaluates expressions does not affect the order of the memory read operations.
24. Fixed the order in which the memory write operations are performed when the SP register is involved. This affects the NMI response, the INT response in modes 1 and 2, and the following instructions: ``ex (sp),{hl|XY}``, ``push TT``, ``push XY``, ``call WORD``, ``call Z,WORD`` and ``rst N``.
25. Fixed the handling of illegal instructions to avoid stack overflows in long sequences of ``DDh`` / ``FDh`` prefixes.
26. Fixed several implicit conversions to avoid warnings about loss of sign and precision.
27. Fixed some bitwise operations to avoid undefined behavior and arithmetic right shifts on signed integers.
28. Fixed violations of the C standard in several identifiers.
29. Renamed the 8-bit register lists: ``X/Y`` to ``J/K``; ``J/K`` and ``P/Q`` to ``O/P``.
30. Replaced all P/V overflow computation functions with a single, faster macro.
31. Replaced all register resolution functions with macros.
32. Replaced all ``ld {J,K|O,P}`` instructions that have the same destination and source register with NOPs.
33. Reimplemented the HALT state. The emulation should now be fully accurate. HALTskip is also supported.
34. Added optional emulation of the normal and special RESET signals, along with the new ``z80_reset`` and ``z80_special_reset`` functions to emit them. The old ``z80_reset`` function is now called ``z80_instant_reset``.
35. Added emulation of the NMI acknowledge M-cycle through the new ``Z80::nmia`` callback.
36. Added emulation of the INT acknowledge M-cycle through the new ``Z80::inta`` callback, which replaces ``Z80::int_data``.
37. Added optional full emulation of the interrupt mode 0, along with the new ``Z80::int_fetch`` callback to perform bus read operations on instruction data. If not enabled at compile-time, the old simplified emulation is built, which supports only the most typical instructions.
38. Added accurate flag behavior in the following instructions: ``ldir``, ``lddr``, ``cpir``, ``cpdr``, ``inir``, ``indr``, ``otir`` and ``otdr``.
39. Added emulation of the interrupt acceptance deferral that occurs during the ``reti`` and ``retn`` instructions.
40. Added MEMPTR emulation. The ``bit N,(hl)`` instruction now produces a correct value of F.
41. Added optional emulation of the Q "register". If enabled at compile-time, the ``ccf`` and ``scf`` instructions produce a correct value of F.
42. Added emulation options that can be configured at runtime.
43. Added emulation of the ``out (c),255`` instruction (Zilog Z80 CMOS).
44. Added optional emulation of the bug affecting the ``ld a,{i|r}`` instructions (Zilog Z80 NMOS). If enabled at compile-time, the P/V flag is reset when an INT is accepted during the execution of these instructions.
45. Added the ``Z80::fetch_opcode`` and ``Z80::fetch`` callbacks to perform opcode fetch operations and memory read operations on instruction data respectively.
46. Added hooking functionality through the ``ld h,h`` instruction and the new ``Z80::hook`` callback.
47. Added the ``Z80::nop`` callback to perform disregarded opcode fetch operations during internal NOP M-cycles.
48. Added four callbacks to notify the execution of important instructions: ``Z80::ld_i_a``, ``Z80::ld_r_a``, ``Z80::reti`` and ``Z80::retn``.
49. Removed ``Z80::state``. Replaced with individual members for the registers, the interrupt enable flip-flops and the interrupt mode.
50. Removed the superfluous EI flag. The previous opcode is checked instead, which is faster and makes the ``Z80`` object smaller.
51. Removed all module-related stuff.
52. Optimizations in flag computation and condition evaluation.
53. New source code comments and improvements to existing ones.
54. Improved code aesthetics.
55. Other improvements, optimizations and minor changes.
v0.1 (2018-11-10)
=================
Initial public release.

55
documentation/conf.py Normal file
View File

@@ -0,0 +1,55 @@
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
# -- Project information -----------------------------------------------------
project = 'Z80'
copyright = '1999-2022 Manuel Sainz de Baranda y Goñi'
author = 'Manuel Sainz de Baranda y Goñi'
# -- General configuration ---------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ['breathe']
# Breathe Configuration.
breathe_default_project = 'Z80'
breathe_domain_by_extension = {"h": "c"}
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
#html_theme = 'haiku'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

27
documentation/index.rst Normal file
View File

@@ -0,0 +1,27 @@
.. Z80 documentation master file, created by
sphinx-quickstart on Wed Feb 24 06:49:20 2021.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Zilog Z80 CPU Emulator
======================
.. toctree::
:maxdepth: 2
:caption: Contents:
EmulationAccuracy
Installation
Integration
APIReference
Testing
Thanks
VersionHistory
License
Indices and tables
==================
* :ref:`genindex`
* :ref:`search`

35
documentation/make.bat Normal file
View File

@@ -0,0 +1,35 @@
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
:end
popd

5
file_id.diz Normal file
View File

@@ -0,0 +1,5 @@
Z80 v0.2 - Fast, small and accurate emulator
of the Zilog Z80. Version 0.2 implements all
that is known to date about this CPU, passes
all test suites and is carefully designed to
fit most use cases.

File diff suppressed because it is too large Load Diff

32
sources/Z80.rc.in Normal file
View File

@@ -0,0 +1,32 @@
1 VERSIONINFO
FILEVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,0,0
PRODUCTVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,0,0
FILEFLAGSMASK 0x3FL
#ifdef NDEBUG
FILEFLAGS 0x0L
#else
FILEFLAGS 0x1L
#endif
FILEOS 0x4L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904B0"
BEGIN
VALUE "CompanyName", "Manuel Sainz de Baranda y Goñi"
VALUE "FileDescription", "@PROJECT_DESCRIPTION@"
VALUE "FileVersion", "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@"
VALUE "InternalName", "@PROJECT_NAME@"
VALUE "LegalCopyright", "Copyright © 1999-2022 Manuel Sainz de Baranda y Goñi"
VALUE "OriginalFilename", "@PROJECT_NAME@.dll"
VALUE "ProductName", "@PROJECT_NAME@"
VALUE "ProductVersion", "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END

812
sources/test-Z80.c Normal file
View File

@@ -0,0 +1,812 @@
/* test-Z80
______ ______ ______
/\___ \/\ __ \\ __ \
____ \/__/ /\_\ __ \\ \/\ \ ________________________________________________
| /\_____\\_____\\_____\ |
| Zilog \/_____//_____//_____/ CPU Emulator Test |
| Copyright (C) 2021-2022 Manuel Sainz de Baranda y Goñi. |
| |
| This program is free software: you can redistribute it and/or modify it |
| under the terms of the GNU General Public License as published by the Free |
| Software Foundation, either version 3 of the License, or (at your option) |
| any later version. |
| |
| This program is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| for more details. |
| |
| You should have received a copy of the GNU General Public License along |
| with this program. If not, see <http://www.gnu.org/licenses/>. |
| |
'=============================================================================*/
#ifdef TEST_Z80_WITH_ARCHIVE_EXTRACTION
# include <zip.h>
# include <zlib.h>
/*-----------------------------------------.
| Z_NULL is also defined by Zeta, so it is |
| undefined to avoid conflicts with zlib. |
'=========================================*/
# ifdef Z_NULL
# undef Z_NULL
# endif
# include <Z/formats/archive/TAR.h>
#endif
#include <Z/constants/pointer.h>
#include <Z/macros/aggregate.h>
#include <Z80.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* MARK: - Constants */
#define OPCODE_NOP 0x00
#define OPCODE_RET 0xC9
#define OPCODE_HALT 0x76
#define OPCODE_CALL_WORD 0xCD
#define OPCODE_JP_WORD 0xC3
/* MARK: - Types */
typedef struct {
/* Name of the archive if the test is compressed; Z_NULL otherwise. */
char const* archive_name;
/* Name of the test program file, or the path to the file inside the
* archive if the file is compressed. */
char const* file_path;
/* Size of the program file. */
zuint16 file_size;
/* Offset of the program code inside the file. */
zuint16 code_offset;
/* Size of the program code. */
zuint16 code_size;
/* Memory address where to jump to start executing the test code. */
zuint16 start_address; /* */
/* Value of the PC register once the test ends. */
zuint16 exit_address;
/* Format of the program file. */
zuint8 format;
/* Total number of lines printed by the test when it passes. */
zuint8 lines_expected;
} Test;
/* CP/M program in COM format. */
#define TEST_FORMAT_CPM 0
/* ZX Spectrum TAP image. Different versions of the Z80 Instruction Set
* Exerciser adapted and improved by Jonathan Graham Harston and others. */
#define TEST_FORMAT_HARSTON 1
/* ZX Spectrum TAP image. Tapes of the Zilog Z80 CPU Test Suite written by
* Patrik Rak. */
#define TEST_FORMAT_RAK 2
/* ZX Spectrum TAP image. Z80 Test Suite, written by Mark Woodmass. */
#define TEST_FORMAT_WOODMASS 3
/* MARK: - Global Variables */
static Test const tests[22] = {
{"Yaze v1.14 (2004-04-23)(Cringle, Frank D.)(Sources)[!].tar.gz", "yaze-1.14/test/zexdoc.com", 8704, 0, 8704, 0x0100, 0, TEST_FORMAT_CPM, 68},
{Z_NULL, "Z80 Documented Instruction Set Exerciser for Spectrum (2018)(Harston, Jonathan Graham)[!].tap", 8716, 91, 8624, 0x8000, 0x803D, TEST_FORMAT_HARSTON, 69},
{"Yaze v1.14 (2004-04-23)(Cringle, Frank D.)(Sources)[!].tar.gz", "yaze-1.14/test/zexall.com", 8704, 0, 8704, 0x0100, 0, TEST_FORMAT_CPM, 68},
{Z_NULL, "Z80 Full Instruction Set Exerciser for Spectrum (2009)(Bobrowski, Jan)[!].tap", 8656, 108, 8547, 0x8000, 0x803D, TEST_FORMAT_HARSTON, 69},
{Z_NULL, "Z80 Full Instruction Set Exerciser for Spectrum (2011)(Bobrowski, Jan)(Narrowed to BIT Instructions)[!].tap", 8656, 108, 8547, 0x8000, 0x803D, TEST_FORMAT_HARSTON, 4},
{Z_NULL, "Z80 Full Instruction Set Exerciser for Spectrum (2017-0x)(Harston, Jonathan Graham)[!].tap", 8704, 91, 8612, 0x8000, 0x803D, TEST_FORMAT_HARSTON, 69},
{Z_NULL, "Z80 Full Instruction Set Exerciser for Spectrum (2018)(Harston, Jonathan Graham)[!].tap", 8716, 91, 8624, 0x8000, 0x803D, TEST_FORMAT_HARSTON, 69},
{"Z80 Instruction Set Exerciser for Spectrum 2 v0.1 (2012-11-27)(Rak, Patrik)[!].zip", "zexall2-0.1/zexall2.tap", 9316, 87, 9228, 0x8000, 0x8040, TEST_FORMAT_HARSTON, 76},
{"Zilog Z80 CPU Test Suite v1.0 (2012-12-08)(Rak, Patrik)[!].zip", "z80test-1.0/z80full.tap", 13758, 91, 13666, 0x8000, 0x7003, TEST_FORMAT_RAK, 156},
{"Zilog Z80 CPU Test Suite v1.0 (2012-12-08)(Rak, Patrik)[!].zip", "z80test-1.0/z80doc.tap", 13758, 91, 13666, 0x8000, 0x7003, TEST_FORMAT_RAK, 156},
{"Zilog Z80 CPU Test Suite v1.0 (2012-12-08)(Rak, Patrik)[!].zip", "z80test-1.0/z80flags.tap", 13758, 91, 13666, 0x8000, 0x7003, TEST_FORMAT_RAK, 156},
{"Zilog Z80 CPU Test Suite v1.0 (2012-12-08)(Rak, Patrik)[!].zip", "z80test-1.0/z80docflags.tap", 13758, 91, 13666, 0x8000, 0x7003, TEST_FORMAT_RAK, 156},
{"Zilog Z80 CPU Test Suite v1.0 (2012-12-08)(Rak, Patrik)[!].zip", "z80test-1.0/z80ccf.tap", 14219, 91, 14127, 0x8000, 0x7003, TEST_FORMAT_RAK, 156},
{"Zilog Z80 CPU Test Suite v1.0 (2012-12-08)(Rak, Patrik)[!].zip", "z80test-1.0/z80memptr.tap", 13758, 91, 13666, 0x8000, 0x7003, TEST_FORMAT_RAK, 156},
{"Zilog Z80 CPU Test Suite v1.2 (2022-01-26)(Rak, Patrik)[!].zip", "z80test-1.2/z80full.tap", 14390, 91, 14298, 0x8000, 0x7003, TEST_FORMAT_RAK, 164},
{"Zilog Z80 CPU Test Suite v1.2 (2022-01-26)(Rak, Patrik)[!].zip", "z80test-1.2/z80doc.tap", 14390, 91, 14298, 0x8000, 0x7003, TEST_FORMAT_RAK, 164},
{"Zilog Z80 CPU Test Suite v1.2 (2022-01-26)(Rak, Patrik)[!].zip", "z80test-1.2/z80flags.tap", 14390, 91, 14298, 0x8000, 0x7003, TEST_FORMAT_RAK, 164},
{"Zilog Z80 CPU Test Suite v1.2 (2022-01-26)(Rak, Patrik)[!].zip", "z80test-1.2/z80docflags.tap", 14390, 91, 14298, 0x8000, 0x7003, TEST_FORMAT_RAK, 164},
{"Zilog Z80 CPU Test Suite v1.2 (2022-01-26)(Rak, Patrik)[!].zip", "z80test-1.2/z80ccf.tap", 14875, 91, 14783, 0x8000, 0x7003, TEST_FORMAT_RAK, 164},
{"Zilog Z80 CPU Test Suite v1.2 (2022-01-26)(Rak, Patrik)[!].zip", "z80test-1.2/z80memptr.tap", 14390, 91, 14298, 0x8000, 0x7003, TEST_FORMAT_RAK, 164},
{Z_NULL, "Z80 Test Suite (2008)(Woodmass, Mark)[!].tap", 5573, 120, 5452, 0x8057, 0x80E6, TEST_FORMAT_WOODMASS, 50},
{Z_NULL, "Z80 Test Suite (2008)(Woodmass, Mark)[!].tap", 5573, 120, 5452, 0x8049, 0x80E6, TEST_FORMAT_WOODMASS, 61}
};
static char const *const cpu_model_identifiers[4] = {
"zilog-nmos",
"zilog-cmos",
"nec-nmos",
"st-cmos"
};
static char const cpu_model_keys[4] = {
Z80_MODEL_ZILOG_NMOS,
Z80_MODEL_ZILOG_CMOS,
Z80_MODEL_NEC_NMOS,
Z80_MODEL_ST_CMOS
};
/* Instance of the Z80 Emulator. */
static Z80 cpu;
/* 64 KB of memory needed by the emulator. */
static zuint8 memory[65536];
/* TRUE if the test is completed, or FALSE otherwise. */
static zboolean test_completed;
static zboolean zx_spectrum_tab;
/* X position of the cursor inside ZX Spectrum screen paper
* (in characters). */
static zuint zx_spectrum_column;
/* Number of text lines printed by the current/latest test.
* It is used to know whether the test passed or produced errors. */
static zuint lines;
/* Address where to place a CPU trap to intercept the PRINT */
static zuint16 print_hook_address;
/* */
static zuint8 in_values[2];
static char* path_buffer = Z_NULL;
static char** search_paths = Z_NULL;
static zuint search_path_count = 0;
/* MARK: - CPU Callbacks: Common */
static zuint8 cpu_read(void *context, zuint16 address)
{
Z_UNUSED(context)
return memory[address];
}
static zuint8 cpu_in(void *context, zuint16 port)
{
Z_UNUSED(context)
return in_values[port & 1];
}
static void cpu_out(void *context, zuint16 port, zuint8 value)
{Z_UNUSED(context) Z_UNUSED(port) Z_UNUSED(value)}
static void cpu_halt(void *context, zboolean state)
{
Z_UNUSED(context) Z_UNUSED(state)
cpu.cycles = Z80_CYCLE_LIMIT;
test_completed = TRUE;
}
/* MARK: - CPU Callbacks: CP/M */
static void cpm_cpu_write(void *context, zuint16 address, zuint8 value)
{
Z_UNUSED(context)
memory[address] = value;
}
static zuint8 cpm_cpu_hook(void *context, zuint16 address)
{
Z_UNUSED(context)
if (address != 5) return OPCODE_NOP;
if (Z80_C(cpu) == 2) switch (Z80_E(cpu))
{
case 0x0D:
break;
case 0x0A:
putchar('\n');
lines++;
break;
default:
putchar(Z80_E(cpu));
}
else if (Z80_C(cpu) == 9)
{
zuint16 i = Z80_DE(cpu);
zuint c = 0;
while (memory[i] != '$')
{
zuint8 character;
if (c++ > 100)
{
putchar('\n');
fputs("Error: String to print is too long!\n", stderr);
exit(EXIT_FAILURE);
}
switch ((character = memory[i++]))
{
case 0x0D:
break;
case 0x0A:
putchar('\n');
lines++;
break;
default:
putchar(character);
}
}
}
return OPCODE_RET;
}
/* MARK: - CPU Callbacks: ZX Spectrum */
static void zx_spectrum_cpu_write(void *context, zuint16 address, zuint8 value)
{
Z_UNUSED(context)
if (address > 0x3FFF) memory[address] = value;
}
static zuint8 zx_spectrum_cpu_hook(void *context, zuint16 address)
{
Z_UNUSED(context)
if (address != print_hook_address) return OPCODE_NOP;
if (zx_spectrum_tab)
{
zuint c = (Z80_A(cpu) % 32) - (zx_spectrum_column % 32);
while (c--) putchar(' ');
zx_spectrum_tab = FALSE;
}
else switch (Z80_A(cpu))
{
case 0x0D: /* CR */
putchar('\n');
lines++;
zx_spectrum_column = 0;
break;
case 0x7F: /* © */
printf("©");
zx_spectrum_column++;
break;
case 0x17: /* TAB */
zx_spectrum_tab = TRUE;
break;
default:
if (Z80_A(cpu) >= 32 && Z80_A(cpu) < 127)
{
putchar(Z80_A(cpu));
zx_spectrum_column++;
}
}
return OPCODE_RET;
}
/* Only needed for Woody's Z80 Test Suite. */
static zuint8 zx_spectrum_cpu_fetch_opcode(void *context, zuint16 address)
{
Z_UNUSED(context)
return (address == 0x0D6B /* 0D6B: THE 'CLS' COMMAND ROUTINE */ ||
address == 0x1601 /* 1601: THE 'CHAN_OPEN' SUBROUTINE */
)
? OPCODE_RET : memory[address];
}
static char const *compose_path(char const *base_path, const char *file_path)
{
zusize base_path_size;
if (base_path == Z_NULL) return file_path;
base_path_size = strlen(base_path);
memcpy(path_buffer, base_path, base_path_size);
path_buffer[base_path_size] = '/';
strcpy(path_buffer + base_path_size + 1, file_path);
return path_buffer;
}
static zboolean load_file(
char const* path,
char const* file_path,
zuint32 file_size,
zuint16 offset,
zuint16 size,
void* buffer
)
{
zboolean status = FALSE;
FILE *file = fopen(compose_path(path, file_path), "rb");
if (file != Z_NULL)
{
fseek(file, 0, SEEK_END);
if (ftell(file) == file_size)
{
fseek(file, offset, SEEK_SET);
status = fread(buffer, size, 1, file) == 1;
}
fclose(file);
}
return status;
}
static zboolean load_test(const char *path, Test const *test, void *buffer)
{
# ifdef TEST_Z80_WITH_ARCHIVE_EXTRACTION
zboolean status = load_file(
path, test->file_path, test->file_size,
test->code_offset, test->code_size, buffer);
if (!status && test->archive_name != Z_NULL)
{
path = compose_path(path, test->archive_name);
/* .tar.gz */
if (strrchr(test->archive_name, '.')[1] == 'g')
{
union {zuint8 data[Z_TAR_BLOCK_SIZE]; Z_TARHeader fields;} header;
gzFile gz = gzopen(path, "rb");
if (gz != Z_NULL)
{
while (!gzeof(gz))
{
char *end;
zulong file_size, block_tail_size;
if (gzread(gz, header.data, Z_TAR_BLOCK_SIZE) != Z_TAR_BLOCK_SIZE) break;
file_size = strtoul((char *)header.fields.size, &end, 8);
if (!strcmp(test->file_path, (char *)header.fields.name))
{
status =
file_size == test->file_size &&
gzseek(gz, test->code_offset, SEEK_CUR) != -1 &&
gzread(gz, buffer, test->code_size) == test->code_size;
break;
}
if ( (zuint8 *)end == header.fields.size || *end ||
-1 == gzseek(gz, (block_tail_size = (file_size % Z_TAR_BLOCK_SIZE))
? file_size + (Z_TAR_BLOCK_SIZE - block_tail_size)
: file_size, SEEK_CUR)
)
break;
}
gzclose(gz);
}
}
/* .zip */
else {
int error;
zip_t *zip = zip_open(path, ZIP_RDONLY | ZIP_CHECKCONS, &error);
if (zip != Z_NULL)
{
zip_file_t *file;
zip_stat_t stat;
if ( !zip_stat(zip, test->file_path, ZIP_FL_ENC_STRICT, &stat) &&
(stat.valid & ZIP_STAT_SIZE) && stat.size == test->file_size &&
(file = zip_fopen(zip, test->file_path, 0)) != Z_NULL
)
{
if ( zip_fread(file, buffer, test->code_offset) == test->code_offset &&
zip_fread(file, buffer, test->code_size) == test->code_size
)
status = TRUE;
zip_fclose(file);
}
zip_close(zip);
}
}
}
return status;
# else
return load_file(
path, test->file_path, test->file_size,
test->code_offset, test->code_size, buffer);
# endif
}
static zboolean run_test(zuint test_index)
{
Test const *test = &tests[test_index];
zuint16 start_address = test->start_address;
zuint i = 0;
if (test->archive_name == Z_NULL) printf(
"[%02u] %s\n* Loading program...",
test_index, test->file_path);
else printf(
"[%02u] %s/%s\n* Loading program...",
test_index, test->archive_name, test->file_path);
memset(memory, 0, 65536);
for (; i < search_path_count &&
!load_test(search_paths[i], test, memory + (start_address & 0xFF00));
i++
);
if ( i == search_path_count &&
!load_test(Z_NULL, test, memory + (start_address & 0xFF00))
)
{
puts(" ERROR\nTest skipped.\n");
return FALSE;
}
puts(" OK");
z80_power(&cpu, TRUE);
if (test->format == TEST_FORMAT_CPM)
{
cpu.fetch_opcode = cpu_read;
cpu.write = cpm_cpu_write;
cpu.hook = cpm_cpu_hook;
memory[0] = OPCODE_HALT;
memory[5] = Z80_HOOK; /* PRINT */
}
else {
cpu.write = zx_spectrum_cpu_write;
cpu.hook = zx_spectrum_cpu_hook;
cpu.im = 1;
cpu.i = 0x3F;
if (test->format == TEST_FORMAT_WOODMASS)
{
printf("* Loading firmware...");
for ( i = 0;
i < search_path_count &&
!load_file(search_paths[i], "ZX Spectrum.rom", 16384, 0, 16384, memory);
i++
);
if ( i == search_path_count &&
!load_file(Z_NULL, "ZX Spectrum.rom", 16384, 0, 16384, memory)
)
{
puts(" ERROR\nTest skipped.\n");
return FALSE;
}
puts(" OK");
Z80_SP(cpu) = 0x7FE8;
Z80_AF(cpu) = 0x3222;
cpu.fetch_opcode = zx_spectrum_cpu_fetch_opcode;
/* 0010: THE 'PRINT A CHARACTER' RESTART */
memory[0x0010] = OPCODE_JP_WORD; /* jp PRINT */
memory[0x0011] = 0xF2;
memory[0x0012] = 0x70;
/* 70F2: PRINT */
memory[print_hook_address = 0x70F2] = Z80_HOOK;
}
else {
cpu.fetch_opcode = cpu_read;
/* 0010: THE 'PRINT A CHARACTER' RESTART */
memory[print_hook_address = 0x0010] = Z80_HOOK;
/* 0D6B: THE 'CLS' COMMAND ROUTINE */
memory[0x0D6B] = OPCODE_RET;
/* 1601: THE 'CHAN_OPEN' SUBROUTINE */
memory[0x1601] = OPCODE_RET;
if (test->format == TEST_FORMAT_RAK)
{
/* 7000: START */
memory[0x7000] = OPCODE_CALL_WORD;
memory[0x7001] = (zuint8)start_address;
memory[0x7002] = (zuint8)(start_address >> 8);
/*memory[0x7003] = HALT;*/
start_address = 0x7000;
}
}
}
memory[test->exit_address] = OPCODE_HALT;
Z80_PC(cpu) = start_address;
lines = 0;
zx_spectrum_column = 0;
zx_spectrum_tab = FALSE;
test_completed = FALSE;
puts("* Running program...\n");
do
# ifdef TEST_Z80_WITH_EXECUTE
z80_execute(&cpu, Z80_CYCLE_LIMIT);
# else
z80_run(&cpu, Z80_CYCLE_LIMIT);
# endif
while (!test_completed);
puts(test->format == TEST_FORMAT_RAK ? "" : "\n");
return lines == test->lines_expected;
}
static zboolean is_option(
char const* string,
char const* short_option,
char const* long_option
)
{
return !strcmp(string, short_option) ||
!strcmp(string, long_option);
}
static zboolean byte_value(char const* string, zuint8 maximum_value, zuint8 *byte)
{
char *end;
zulong value = strtoul(string, &end, 0);
if (end == string || *end || value > maximum_value) return FALSE;
if (byte != Z_NULL) *byte = (zuint8)value;
return TRUE;
}
int main(int argc, char **argv)
{
zboolean all = FALSE;
zuint32 tests_run = 0;
zusize longest_search_path_size = 0;
int ii, i = 0, status = 0;
cpu.options = Z80_MODEL_ZILOG_NMOS;
in_values[0] = 191;
in_values[1] = 255;
while (++i < argc && *argv[i] == '-')
{
if (is_option(argv[i], "-h", "--help"))
{
puts( "Usage: test-Z80 [options] (--all | <test>...)\n"
"\n"
"Options:\n"
" -a, --all Run all tests.\n"
" -h, --help Show this help message.\n"
" -e, --in-even <value> Set the 8-bit value to be read from even I/O ports.\n"
" -o, --in-odd <value> Set the 8-bit value to be read from odd I/O ports.\n"
" -m, --model <model> Specify the CPU model to emulate.\n"
" -p, --path <path> Specify a directory where to look for test files.\n"
" -v, --version Show version and copyright.\n"
"\n"
"CPU models:\n"
" zilog-nmos Zilog NMOS (default)\n"
" zilog-cmos Zilog CMOS\n"
" nec-nmos NEC NMOS\n"
" st-cmos SGS-Thomson CMOS\n"
"\n"
"Tests:\n"
" Versions of the Z80 Documented Instruction Set Exerciser:\n"
" 00 CP/M ~ Cringle, Frank D. (2004-04-23).\n"
" 01 ZX Spectrum ~ Harston, Jonathan Graham (2018).\n"
" Versions of the Z80 Full Instruction Set Exerciser:\n"
" 02 CP/M ~ Cringle, Frank D. (2004-04-23).\n"
" 03 ZX Spectrum ~ Bobrowski, Jan (2009).\n"
" 04 ZX Spectrum ~ Bobrowski, Jan (2011). Narrowed to BIT instructions.\n"
" 05 ZX Spectrum ~ Harston, Jonathan Graham (2017).\n"
" 06 ZX Spectrum ~ Harston, Jonathan Graham (2018).\n"
" 07 ZX Spectrum ~ Rak, Patrik (2012-11-27).\n"
" Zilog Z80 CPU Test Suite v1.0 ~ ZX Spectrum ~ Rak, Patrik (2012-12-08):\n"
" 08 Tests all flags and registers.\n"
" 09 Tests all registers, but only officially documented flags.\n"
" 10 Tests all flags, ignores registers.\n"
" 11 Tests documented flags only, ignores registers.\n"
" 12 Tests all flags after executing CCF after each instruction tested.\n"
" 13 Tests all flags after executing BIT N,(HL) after each instruction tested.\n"
" Zilog Z80 CPU Test Suite v1.2 ~ ZX Spectrum ~ Rak, Patrik (2022-01-26):\n"
" 14 Tests all flags and registers.\n"
" 15 Tests all registers, but only officially documented flags.\n"
" 16 Tests all flags, ignores registers.\n"
" 17 Tests documented flags only, ignores registers.\n"
" 18 Tests all flags after executing CCF after each instruction tested.\n"
" 19 Tests all flags after executing BIT N,(HL) after each instruction tested.\n"
" Z80 Test Suite ~ ZX Spectrum ~ Woodmass, Mark (2008):\n"
" 20 Tests flags.\n"
" 21 Tests MEMPTR.\n"
"\n"
"Email bug reports and questions to <manuel@zxe.io>\n"
"Open issues at <https://github.com/redcode/Z80>");
goto exit_without_error;
}
else if (is_option(argv[i], "-v", "--version"))
{
puts( "test-Z80 v" Z80_LIBRARY_VERSION_STRING "\n"
"Copyright (C) 2021-2022 Manuel Sainz de Baranda y Goñi.\n"
"Released under the terms of the GNU General Public License v3.");
goto exit_without_error;
}
else if (is_option(argv[i], "-e", "--in-even"))
{
if (++i == argc) goto incomplete_option;
if (!byte_value(argv[i], 255, &in_values[0])) goto invalid_io_value;
}
else if (is_option(argv[i], "-o", "--in-odd"))
{
if (++i == argc) goto incomplete_option;
if (!byte_value(argv[i], 255, &in_values[1])) goto invalid_io_value;
}
else if (is_option(argv[i], "-m", "--model"))
{
if (++i == argc) goto incomplete_option;
for (ii = 0; ii < 4; ii++) if (!strcmp(argv[i], cpu_model_identifiers[ii])) break;
if (ii == 4)
{
fprintf(stderr, "Invalid CPU model: '%s'\n", argv[i]);
goto bad_syntax;
}
cpu.options = cpu_model_keys[ii];
}
else if (is_option(argv[i], "-p", "--path"))
{
zusize s;
char **p;
if (++i == argc || !(s = strlen(argv[i]))) goto incomplete_option;
if (s > longest_search_path_size) longest_search_path_size = s;
if ((p = realloc(search_paths, (search_path_count + 1) * sizeof(char *))) == Z_NULL)
{
fputs("Error: Not enough memory available.", stderr);
goto exit_with_error;
}
search_paths = p;
search_paths[search_path_count++] = argv[i];
}
else if (is_option(argv[i], "-a", "--all"))
all = TRUE;
else {
fprintf(stderr, "Invalid option: '%s'\n", argv[i]);
goto bad_syntax;
}
}
if (i == argc && !all)
{
fputs("No test specified.\n", stderr);
goto bad_syntax;
}
if (search_path_count) path_buffer = malloc(longest_search_path_size + 110);
/* Configure stdout as unbuffered. */
setvbuf(stdout, Z_NULL, _IONBF, 0);
/* Configure the Z80 emulator */
cpu.context = Z_NULL;
cpu.fetch =
cpu.read =
cpu.nop = cpu_read;
cpu.in = cpu_in;
cpu.out = cpu_out;
cpu.halt = cpu_halt;
cpu.nmia =
cpu.inta =
cpu.int_fetch = Z_NULL;
cpu.reset = Z_NULL;
cpu.ld_i_a =
cpu.ld_r_a =
cpu.reti =
cpu.retn = Z_NULL;
/* Ensure that all specified test numbers are valid. */
for (ii = i; i < argc; i++)
{
char const *string = argv[i];
char *end;
if (strtoul(string, &end, 10) >= Z_ARRAY_SIZE(tests) || end == string || *end)
{
fprintf(stderr, "Invalid test number: '%s'\n", string);
goto bad_syntax;
}
}
while (ii < argc)
{
tests_run |= Z_UINT32(1) << (i = atoi(argv[ii++]));
if (!run_test(i)) status = -1;
}
if (all) for (i = 0; i < Z_ARRAY_SIZE(tests); i++)
if (!(tests_run & (Z_UINT32(1) << i)) && !run_test(i)) status = -1;
exit_without_error:
free(search_paths);
free(path_buffer);
return status;
incomplete_option:
fprintf(stderr, "Incomplete option: '%s'\n", argv[i - 1]);
goto bad_syntax;
invalid_io_value:
fprintf(stderr, "Invalid I/O value: '%s'\n", argv[i]);
bad_syntax:
fputs("Type 'test-Z80 -h' for help.\n", stderr);
exit_with_error:
free(search_paths);
free(path_buffer);
return -1;
}
/* test-Z80.c EOF */

11
support/Z80.pc.in Normal file
View File

@@ -0,0 +1,11 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
Name: @PROJECT_NAME@
Description: @PROJECT_DESCRIPTION@.
URL: https://zxe.io/software/@PROJECT_NAME@
Version: @PROJECT_VERSION@
Libs: -L${libdir} -l@PROJECT_NAME@
Cflags: -I${includedir}

View File

@@ -0,0 +1,61 @@
cmake_minimum_required(VERSION 3.19)
set(@PROJECT_NAME@_known_components Static Shared)
set(@PROJECT_NAME@_component_Static NO)
set(@PROJECT_NAME@_component_Shared NO)
foreach (@PROJECT_NAME@_component IN LISTS ${CMAKE_FIND_PACKAGE_NAME}_FIND_COMPONENTS)
if (@PROJECT_NAME@_component IN_LIST @PROJECT_NAME@_known_components)
set(@PROJECT_NAME@_component_${@PROJECT_NAME@_component} YES)
else()
set(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE
"@PROJECT_NAME@ does not recognize component `${@PROJECT_NAME@_component}`.")
set(${CMAKE_FIND_PACKAGE_NAME}_FOUND FALSE)
return()
endif()
endforeach()
if (@PROJECT_NAME@_component_Static AND @PROJECT_NAME@_component_Shared)
set(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE
"@PROJECT_NAME@ `Static` and `Shared` components are mutually exclusive.")
set(${CMAKE_FIND_PACKAGE_NAME}_FOUND FALSE)
return()
endif()
set(@PROJECT_NAME@_Static_targets "${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@StaticTargets.cmake")
set(@PROJECT_NAME@_Shared_targets "${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@SharedTargets.cmake")
macro(@PROJECT_NAME@_load_targets type)
if (NOT EXISTS "${@PROJECT_NAME@_${type}_targets}")
set(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE
"@PROJECT_NAME@ `${type}` libraries were requested but not found.")
set(${CMAKE_FIND_PACKAGE_NAME}_FOUND FALSE)
return()
endif()
include(CMakeFindDependencyMacro)
find_dependency(Zeta)
include("${@PROJECT_NAME@_${type}_targets}")
endmacro()
if(@PROJECT_NAME@_component_Static)
@PROJECT_NAME@_load_targets(Static)
elseif(@PROJECT_NAME@_component_Shared)
@PROJECT_NAME@_load_targets(Shared)
elseif(DEFINED @PROJECT_NAME@_SHARED_LIBS AND @PROJECT_NAME@_SHARED_LIBS)
@PROJECT_NAME@_load_targets(Shared)
elseif(DEFINED @PROJECT_NAME@_SHARED_LIBS AND NOT @PROJECT_NAME@_SHARED_LIBS)
@PROJECT_NAME@_load_targets(Static)
elseif(BUILD_SHARED_LIBS)
if(EXISTS "${@PROJECT_NAME@_Shared_targets}")
@PROJECT_NAME@_load_targets(Shared)
else()
@PROJECT_NAME@_load_targets(Static)
endif()
else()
if(EXISTS "${@PROJECT_NAME@_Static_targets}")
@PROJECT_NAME@_load_targets(Static)
else()
@PROJECT_NAME@_load_targets(Shared)
endif()
endif()

View File

@@ -0,0 +1 @@
D5394DC919B1820E1956CB227E8DFFDA7887CB3D3A78E802EA690EE6B47EDF35DB3B29EA72E5E824B32B36FB18D79C72688AB7469A3D383A39EA01BA49AFC261 ZX Spectrum.rom

View File

@@ -0,0 +1,10 @@
2254439627B0A513C2E87266C5F57573C1607744FDD72C634329F8F79CAEAE2C4475DDD4C5945434DBF8F2B189BA0BEBA12ADA3C12A34FAE2DDD44E8DDAA528B POSIX/Yaze v1.14 (2004-04-23)(Cringle, Frank D.)(Sources)[!].tar.gz
FD6DF9FF65ED2F6502DE8892601CF803FBBB1D91F3BE43CF314464AADCB6B05E635F1A83A25C72E309EABEADC69975055EFDA6085A9D95B4815C7512801AC00E ZX Spectrum/Z80 Documented Instruction Set Exerciser for Spectrum (2018)(Harston, Jonathan Graham)[!].tap
C8BC407C874D305CA9BB2647A83D726ACB6969FE7525EEAB0BA2C3270FFF94B3D90CFA186F3059F468CF07F651FD8D4D9465C32989B33A5F4FEF1FABCC2DBA23 ZX Spectrum/Z80 Full Instruction Set Exerciser for Spectrum (2009)(Bobrowski, Jan)[!].tap
E4CD187FA712418863A85BD9FF2C2CC11717C0CCE4510686E3BBF367F38DB0A987BADC7CBC6AD22E88859587747FA818CCB04858B163502A870F45847FF9FE69 ZX Spectrum/Z80 Full Instruction Set Exerciser for Spectrum (2011)(Bobrowski, Jan)(Narrowed to BIT Instructions)[!].tap
CD9B552F3F56298FA7EC75B4B7A4A115CA326CBD3B9DED2BE01EC31534B572216E7A95B7AC5EF920E5E28343CE048F33DC163F47B5CE8BB8DED5232CF41F6D91 ZX Spectrum/Z80 Full Instruction Set Exerciser for Spectrum (2017-0x)(Harston, Jonathan Graham)[!].tap
3B4D93D5BEE0F58E187350E5EA90A92EA7F4874F5A7AABA91A944D92DA63B8EBC0B4B9F4AED264863B256C761307EA4EF3D5FD4A2896469A117EF1C676E6F2A6 ZX Spectrum/Z80 Full Instruction Set Exerciser for Spectrum (2018)(Harston, Jonathan Graham)[!].tap
3F8306CC7EDB49DEFC8C2D8A792D970C4681983D46A0B37982432531D5F56F8CDC1850C41038C3EA1C5AF2C4E98994BBD57C039496C783D9D9626F2D2C0B88B2 ZX Spectrum/Z80 Instruction Set Exerciser for Spectrum 2 v0.1 (2012-11-27)(Rak, Patrik)[!].zip
668542FC9965199659F03044F16A9943223A190B8D1BD9CC4699F58B4FF99FA304B8B3281DBD8B179C9AE0B047DA82D741D187F619B5293241BC1185657F7687 ZX Spectrum/Z80 Test Suite (2008)(Woodmass, Mark)[!].tap
28C1F2BB5E523E4F03A23A5BBB70136F01BC06E12C2EC2AF8074FBF4C31218C9E8235BEEACC8A892128204738EC4C0548ACC0C825D6EA30BD393B1AA28C734F6 ZX Spectrum/Zilog Z80 CPU Test Suite v1.0 (2012-12-08)(Rak, Patrik)[!].zip
5DD2F8335C4543D5D920318A526024CD7442E0CC15E208622D466A0CF57579908652A5301FD286A9AC61BA73341E4D8ACA1583635FC9D4204693FCB2C7364386 ZX Spectrum/Zilog Z80 CPU Test Suite v1.2 (2022-01-26)(Rak, Patrik)[!].zip