34 KiB

Zilog Z80 CPU Emulator
Introduction
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.
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.
Emulation accuracy
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.
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.
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
This set of programs 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 with Zilog Z80 CPU, and reports any deviations detected.
Results
z80full.tap Tests all flags and registers. |
z80doc.tap Tests all registers, but only officially documented flags. |
|
|
z80flags.tap Tests all flags, ignores registers. |
z80docflags.tap Tests documented flags only, ignores registers. |
|
|
z80ccf.tap Tests all flags after executing ccf after each instruction tested.
|
z80memptr.tap Tests all flags after executing bit n,(hl) after each instruction tested.
|
|
|
Z80 Test Suite, by Mark Woodmass
This suite performs a series of tests to verify the MEMPTR documents (English, Russian), 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 CPU, but Simon Conway kindly tested several other Z80 clones, confirming the same results.
Results
z80tests.tap |
|
|
|
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 (Yet Another Z80 Emulator). It is often difficult to track down, so Jonathan Graham Harston put it together here, as well as some conversions. The latest release of YAZE is available at Andreas Gerlich's website.
Results
zexdoc.tap Tests officially documented flag effects. |
zexall.tap Tests all flags changes. |
|
|
zexall2.tap Patrik Rak's modification with MEMPTR testing. |
|
|
Installation
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, 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.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.
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.md> [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:
-
Build the project as a shared library rather than a static one.
The default isNO. -
-DCMAKE_BUILD_TYPE=(Debug|Release|RelWithDebInfo)
Choose the type of build (configuration) to generate.
The default isRelease. -
-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 isNO. -
-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 isAuto(autoconfigure flags). If you get linker errors, set this option to"". -
Build the project as a shared library rather than a static one.
This option takes precedence overBUILD_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 isNO. -
-DZ80_WITH_HTML_DOCUMENTATION=(YES|NO)
Build and install the documentation in HTML format.
It requires Doxygen, Sphinx and Breathe.
The default isNO. -
-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 isNO. -
-DZ80_WITH_PKGCONFIG_SUPPORT=(YES|NO)
Generate and install the pkg-config file.
The default isNO. -
-DZ80_WITH_STANDARD_DOCUMENTS=(YES|NO)
Install the standard text documents distributed with the package:AUTHORS,COPYING,COPYING.LESSER,HISTORY,READMEandTHANKS.
The default isNO. -
-DZ80_WITH_TESTS=(YES|NO)
Build the testing tool.
The default isNO.
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 thez80_executefunction.
The default isNO. -
-DZ80_WITH_FULL_IM0=(YES|NO)
Build the full implementation of the interrupt mode 0 rather than the reduced one.
The default isNO. -
-DZ80_WITH_Q=(YES|NO)
Build the implementation of the Q "register".
The default isNO. -
-DZ80_WITH_RESET_SIGNAL=(YES|NO)
Build the implementation of the normal RESET signal.
The default isNO. -
-DZ80_WITH_SPECIAL_RESET_SIGNAL=(YES|NO)
Build the implementation of the special RESET signal.
The default isNO. -
-DZ80_WITH_UNOFFICIAL_RETI=(YES|NO)
Configure theED5Dh,ED6DhandED7Dhundocumented instructions asretiinstead ofretn.
The default isNO. -
-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 theld a,{i|r}instructions.
The default isNO.
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
Running the tests
The package includes a tool called test-Z80 capable of running all CP/M and ZX Spectrum versions of the major test suites. Configure the build system with -DZ80_WITH_TESTS=YES to enable its compilation and -DZ80_DOWNLOAD_TEST_FILES=YES to download the firmware and software required. Also note that the Z80 library must be built with -DZ80_WITH_Q=YES to be able to pass Patrik Rak's tests.
Once you have built the package, type the following to run all tests:
./test-Z80 -p downloads/firmware -p downloads/software/POSIX -p "downloads/software/ZX Spectrum" -a
The tool supports options and can run the tests individually. Type ./test-Z80 -h for help. If you prefer to run all tests through Make, just type make tests. For CTest, use ctest or ctest -V instead.
These are the complete logs generated by test-Z80 emulating the different CPU variants:
The CRC errors in the latter two are normal and match the values obtained on real hardware.
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:
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:
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:
-
#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 theZ80.hheader. -
#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 theZ80.hheader. -
#define Z80_WITH_LOCAL_HEADER
TellsZ80.cto#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.
Showcase
This emulator has been used by the following projects (listed in alphabetical order):
- Augmentinel, by Simon Owen - GitHub
- CPM-Emulator, by Marc Sibert - GitHub
- tihle: a unique TI calculator emulator, by Peter Marheine - GitHub, GitLab
- TileMap, by Simon Owen - GitHub
- Zemu, by Jay Valentine - GitHub, RubyGems
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
- For validating tests on real hardware. 1
- For his research on the unstable flag behavior of the
ccf/scfinstructions. - For his invaluable help.
- Banks, David (hoglet)
- 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
- Brady, Stuart
- For his research on the flag behavior of the
ccf/scfinstructions. 10
- For his research on the flag behavior of the
- Brewer, Tony
- Bystrov, Dmitry (Alone Coder)
- For validating tests on real hardware. 4
- Chunin, Roman (CHRV)
- Conway, Simon (BadBeard)
- For validating the "Z80 Test Suite" on several Z80 clones. 13
- Cooke, Simon
- For finding out how the
out (c),0instruction behaves on the Zilog Z80 CMOS. 14
- For finding out how the
- 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
- goodboy
- Greenway, Ian
- Harston, Jonathan Graham
- Helcmanovsky, Peter (Ped7g)
- icebear
- Kladov, Vladimir
- Krook, Magnus
- For validating tests on real hardware. 28
- London, Matthew
- For validating tests on real hardware.
- Martínez Cantero, Ricardo (Kyp)
- For validating tests on real hardware.
- Molodtsov, Aleksandr
- 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/scfinstructions.
- For helping me to research the unstable flag behavior of the
- Ortega Sosa, Sofía
- For her support.
- Owen, Simon
- For the idea of the hooking method used in this emulator.
- Rak, Patrik
- 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)
- Stevenson, Dave
- Weissflog, Andre (Floh)
- Wilkinson, Oli (evolutional)
- For validating tests on real hardware. 26
- Wlodek
- Woodmass, Mark (Woody)
- Young, Sean
- ZXGuesser
- For validating tests on real hardware.
References
- https://spectrumcomputing.co.uk/forums/viewtopic.php?p=83384#p83384
- https://stardot.org.uk/forums/viewtopic.php?t=15464
- Banks, David (2018-08-21). "Undocumented Z80 Flags" revision 1.0.
- https://spectrumcomputing.co.uk/forums/viewtopic.php?p=83041#p83041
- http://wizard.ae.krakow.pl/~jb/qaop/tests.html
- https://zxpress.ru/zxnet/zxnet.pc/5909
- https://zx-pk.ru/threads/2506-komanda-bit-n-(hl).html
- https://zx-pk.ru/threads/2586-prosba-realshchikam-ot-emulyatorshchikov.html
- boo_boo; Kladov, Vladimir (2006-03-29). "MEMPTR, Esoteric Register of the Zilog Z80 CPU".
- https://sourceforge.net/p/fuse-emulator/mailman/message/6929573
- Brewer, Tony (2014-12). "Z80 Special Reset".
- https://mtxworld.dk/memorum/viewtopic.php?p=1352#p1352
- https://worldofspectrum.org/forums/discussion/20345
- https://groups.google.com/g/comp.os.cpm/c/HfSTFpaIkuU/m/KotvMWu3bZoJ
- 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
- https://baltazarstudios.com/zilog-z80-undocumented-behavior
- Flammenkamp, Achim. "Interrupt Behaviour of the Z80 CPU".
- Young, Sean (1998-10). "Z80 Undocumented Features (in Software Behaviour)" v0.3.
- https://elmundodelspectrum.com/desenterrando-el-primer-emulador-de-spectrum
- https://elmundodelspectrum.com/con-vosotros-el-emulador-de-pedro-gimeno-1989
- https://sourceforge.net/p/fuse-emulator/mailman/message/4502844
- Harston, Jonathan Graham (2008). "Full Z80 Opcode List Including Undocumented Opcodes" v0.11 (revised).
- Harston, Jonathan Graham (2012). "Z80 Microprocessor Undocumented Instructions" v0.15.
- Harston, Jonathan Graham (2014). "Z80 Opcode Map" v0.10 (revised).
- https://mdfs.net/Software/Z80/Exerciser/Spectrum
- https://spectrumcomputing.co.uk/forums/viewtopic.php?t=6102
- https://github.com/MrKWatkins/ZXSpectrumNextTests
- https://spectrumcomputing.co.uk/forums/viewtopic.php?p=83157#p83157
- https://worldofspectrum.org/forums/discussion/41704
- https://worldofspectrum.org/forums/discussion/41834
- https://worldofspectrum.org/forums/discussion/34574
- https://worldofspectrum.org/forums/discussion/comment/668760/#Comment_668760
- https://jisanchez.com/test-a-dos-placas-de-zx-spectrum
- https://stardot.org.uk/forums/viewtopic.php?p=212360#p212360
- https://floooh.github.io/2021/12/17/cycle-stepped-z80.html
- https://github.com/floooh/v6502r
- http://groups.google.co.uk/group/comp.sys.sinclair/msg/56dd1fd4ccb5fb3b
- Young, Sean (1997-09-21). "Zilog Z80 CPU Specifications".
- Young, Sean (2005-09-18). "Undocumented Z80 Documented, The" v0.91.
License
Copyright © 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 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.










