This project features a software emulation of the complete hardware of a Z80 CPU and a VZ200 computer based on that CPU.
I will add more detailed documentation somewhat later, since currently, many things are still changing and it would not make a point to write documentation before the installation process has been stabilized. Also, I am still going to enhance usability (many options are currently hard-wired constants in the code rather than being read from some configuration file), which will also affect building and running. So please, be a little bit patient! At least, I already recorded some YouTube video that demonstrates that the core emulation is already running:
Originally motivated by the desire to archive and keep access to old software that I had written in the 80s and that still resided on magnetic tape cassettes, I implemented most of the Z80 emulation and essential parts of the VZ200 specific components already in 1998, but I did not get it to work due to lack of knowledge on several hardware details. Also, the Z80 emulation was disappointingly slow.
In 2010, I resumed work on the Z80 emulation and sucessfully implemented a much faster instruction instantiation mechanism, using precompiled templates for fast op code decoding and arguments extraction and related bit shifting and masking, thus making the Z80 emulation sufficiently fast. Also, I got the emulation passing most of VZ200's initialization routine. However, near the end of that routine, the CPU got stuck, infinitely waiting for an IRQ of unknown source. I already suspected the video hardware to have to deliver video horizontal / vertical sync information to the CPU via an IRQ, since the video memory has only a single shared access port and the CPU higher access privilege than the video hardware, such that the video hardware will shortly stop producing pixels, while the CPU accesses the video RAM. Therefore, the software wants to know when sync gaps occur to access video RAM only during these gaps in order to not interfere with video output. Though, I still had not enough detail information about the hardware to correctly implement IRQ generation and handling.
Finally, in 2018, I found more detailed hardware information to get video sync IRQ generation and handling correct, such that the emulation now sucessfully passed the initialization routine and entered into BASIC mode. Though, I still found and had to fix lots of bugs in almost all relevant parts of the emulator, until, in late 2018, I got the emulator successfully run its first non-trivial BASIC program.
In early 2021, I made some more tiny bugfixes related to exact timing of the Z80 emulation, such that reading from and writing to a virtual magnetic tape cassette (implemented by reading from / writing to an audio file) now works as expected. Though, I guess, quality of my original tape recordings has decayed beneath the threshold of readability already a long time ago (there is signal crosstalk caused by magnetism from adjacent windings, resulting in kind of echoing effect), such that I probably won't be able to read them in ever again.
For more documentation, see also my talk at GPN 19 at Gulaschprogrammiernacht '19 (GPN19) in Karlsruhe, Germany (in German language) with a short introduction by Prof. Sebastian Ritterbusch, as well as the corresponding set of slides as OpenDocument presentation (.odp) file (in English language).
In foresight of an upcoming, more detailed installation documentation: Currently, for getting the code running, you have to download the source code and compile it by yourself on a system that provides standard Unix tools such as (GNU) make, (ba)sh, etc., and, of course, a Java compiler. Executing "make all" should suffice to create a build directory with (almost) everything needed to run the emulator.
Note that until I can solve all potential copyright issues regarding
the VZ200's ROM memory, I will exclude the 16kB of ROM from this
repository, which is needed to run the VZ200 emulation. With one of
the next commits (still a TODO), you will be able to run the core Z80
emulator without that ROM with just getting a warning instead of an
error, that you are trying to run the emulator without any software.
If you do not have the ROM, you may trying googling for VZ200 and ROM,
and grab that ROM. The ROM should be a file with exactly 16384 bytes.
Put this file as ./emulator/vz200/os.rom
below the build directory.
Then start Java with the main class as parameter, e.g. with
java -cp ../build emulator.vz200.VZ200
from within the source directory.
Here are some screenshots that illustrate the features and GUI of the emulator.
The application frame windows include the VZ200's actual ouput screen window, a virtual keyboard, and a monitor control and debug program.
The screen window currently supports three different zoom factors (1, 2 and 3). There are future plans for a full screen display mode that will mimick a cathode ray tube's specific appearance.
Fig. 1: VZ200 Screen
While most input can be easily done via the standard PC keyboard, the VZ200's original keyboard contained special key combinations for accessing block graphics characters, special editor control keys, but also shortcuts for command keywords. Mapping these special key combinations to a standard PC keyboard may result in unexpected behavior, especially on non-US keyboard layouts. Therefore, key input on the PC's keyboard is mapped to the VZ200's keyboard whenever possible in a reasonable way. Some special characters or functions, however, may be accessible solely by clicking on the VZ200's virtual keyboard.
Fig. 2: VZ200 Keyboard
The monitor control program is a special program that runs in a console window and allows for inspection and manipulation of the CPU's address space as well as all of the CPU's registers. Features include listing of memory contents as either Z80 unassembled menmonics or hexadecimal bytes or ascii characters, as well as entering hexadecimal data bytes. Also, starting and stopping the CPU can be controlled via the monitor, including useful tools for debugging like a trace and single instruction step mode, or running until reaching a breakpoint.
Fig. 3: Monitor Console
The monitor's unassemble feature also allows for limited capabilities of code comments and symbolic addresses and values. For that purpose, one can write a special XML annotation file that contains code comments, code labels and symbolic values. Whenever unassembling machine instructions that match any of these meta information, that information will be printed out along with the unassembled instruction, thus resulting in an assembler listing that comes close to a source code listing. Here is an example snippet of such an annotation file:
<at address="0x7a9d">
<label>fname_buf</label>
<data-bytes length="0x11" />
<header>
---- START file name buffer ----<br />
file name buffer for currently processed cassette file,<br />
max. 16 characters + trailing "\0"
</header>
</at>
<at address="0x7ae6">
<data-bytes length="0x1" />
</at>
<at address="0x7aad">
<footer>---- END file name buffer ----</footer>
</at>
<at address="0x7aae">
<label>next_crs_x</label>
<data-bytes length="0x1" />
<comment>
x coordinate where to place cursor<br />
after next text buffer to screen copy
</comment>
</at>
The idea of such an annotation file is that you can retrofit annotations to assembler instructions of code separately from its binary and source code representation, in particular if you do not own or have access to the source code and thus can not put annotations directly alongside the source code. This is usually the case when you reverse engineer binary code. Of course, if you own the source code, you do not need such retrofit annotations.
The configuration dialogs currently support setting up the target of the VZ200's speaker output and cassette ouput, the source of the cassette input, and some properties of the CPU emulation.
Fig. 4: Speaker Settings
The VZ200's speaker can be mapped to any audio output line that is available via Java's built-in AudioSystem class. Note that the VZ200 produced sound by plucking a speaker's 3-state membrane controlled by two flip-flops, while sound cards as of today expect a stream of sample values. The emulator automatically converts the emulated plucked membrane's state into a continuous stream of samples appropriate for a modern sound card.
Fig. 5: Speaker Line Selection
Fig. 6: Cassette I/O Settings
Technically, the VZ200's cassette output works very much like the speaker output: The binary data output is converted into a stream of samples that the emulator can map on any audio output line that is available via Java's built-in AudioSystem class. Also, thanks to a special function, the output can also directly be written onto disc as an audio file.
Fig. 7: CPU Settings
Beyond the basic control features in the monitor control program, the CPU settings dialog enables the user to set up special CPU parameters, including the emulated speed, and some CPU profiling / logging features. Also, one can decide between a busy waiting model that will produce very exact timing on the micro scale but may challenge the host's CPU power, and a more lazy, but much more host CPU saving mode. Usually, even the more lazy mode will still produce a micro-scale timing good enough for generating sound and graphics without flicker (as compared to the busy waiting model).
Fig. 8: CPU Speed Selection
At least on my Ubuntu 18.04 box, there is a problem with the new
java-11-openjdk-amd64
version: It will find no audio devices. The
emulation will still run, but sound (i.e. audio output and cassette
input / output) will not work. If this problem also affects you, but
you want get running the VZ200's speaker and cassette input/output,
try installing and running the older java-8-openjdk-amd64 version
instead; at least this works for me. That is, on my Ubuntu
box, I am currently using
/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java -cp ../build emulator.vz200.VZ200
to start the emulator.
.vz
FilesThere is limited, experimental support for reading .vz
files. .vz
files are the inofficial quasi standard for storing binary and basic
programs on standard discs. You will find lots of software for the
VZ200 on the internet as .vz
files. However, the support for .vz
files is not yet thread safe. That is why the implementation for that
support is not yet on the Git main
branch, but on a branch called
sloppy_vzfile_support
. If you plan to use .vz
files, you may want
to check out branch sloppy_vzfile_support
. However, since the
implementation is not yet thread safe, you should not try to load in a
.vz
file while the CPU emulation is running (this is possible via
the graphical GUI). In that case, the whole emulator might get stuck
in a dead lock due to some previous race condition.
I will first try to make the implementation on the Git master
branch
thread safe; only then, I will re-integrate the
sloppy_vzfile_support
branch into the master
branch.
If you do not need support for .vz
files, you probably want to stick
to the more stable master
branch.