FASTZ80, A FAST Z80 EMULATOR

Written by Lajos Kintli, 2007-2008.

Zilog Z80 was a popular 8 bit microprocessor at the late 1970's, early 1980's, which was the heart of many computer at that time, such as TRS-80. TRS-80 clones under different model names existed around the world, VideoGenie (in Europe), PMC-80 (in USA), System-80 (in Australia/New Zealand), TRZ-80 (in South Africa). The Hungarian version of these was HT-1080Z. The first version of HT-1080Z showed the closest relationship with VideoGenie-1 (closest to TRS-80 Model 1 Level II). Small group of enthusiastic people collected all the discoverable information into http://ht.homeserver.hu (unfortunately most of the things only in Hungarian), and Attila Grosz made an emulator about the different versions of TRS-80 clones, including the HT-1080Z.

It was a great pleasure, when I first saw Attila's emulator, as HT-1080Z was the computer which I first met and programmed (both in BASIC language and in Z80 assembly). Not long ago I decided to write my own emulator too, as I was thirsting for a programming, and the emulator seemed to be a challenging area. Simply I wanted to try my capabilities in it, and I was curious how fast and compact emulator I can write, how big work it is. My final result is shared now.

Special thanks to Attila Grosz for his emulator, and to Istvan Majzik, who put the result on the HT-1080Z home page, under the following direct link: http://ht.homeserver.hu/html/emulatorfastz80.html

Main features

System requirements & installation

The program was written and compiled with the "Microsoft Visual C++ 2005 Express Edition" in a special way using only standard WIN32 API, not referring to any external run time library (critical parts have been compiled with Microsoft Macro Assembler Version 8.00 from version V1.01). It runs from Windows 95 to the latest windows releases. The program in standard mode consumes insignificant system resources, however in "full speed" mode it eats up one processor.

No special installation is needed, the files should be extracted from the downloaded zip package into any directory, and FASTZ80.EXE can be run.

Package contains:

FASTZ80.EXE the emulator itself
README.TXT this file
Z80_INST.TXT Z80 instruction set defintions
Z80_CODE.TXT Z80 instruction set table by prefixes and opcode
TRS80.ROM TRS-80 ROM
TRS80E.ROM TRS-80 ROM with extension
HT1.ROM HT-1080Z V1 ROM
HT1E.ROM HT-1080Z V1 ROM with extension
HT2.ROM HT-1080Z V2 ROM
HT2E.ROM HT-1080Z V2 ROM with extension
GALAXY.CMD the famous GALAXY program
TEST.CAS Simple Basic Language program, used for calibration
show_char_map.hex simple program for displaying the character map in intel hex format
show_char_map.cmd simple program for displaying the character map in trs-80 cmd format
char_rom_trs_80.bmp TRS-80 character rom bitmap
char_rom_video_genie.bmp VideoGenie character rom bitmap
char_rom_ht_hu1.bmp Hungarian character rom bitmap 1
char_rom_ht_hu2.bmp Hungarian character rom bitmap 2
kbd_map.txt
Example keyboard definition file

Simulated hardware & selected solution

The basic features of the simulated hardware are coming from the original HT-1080Z version 1

The undocumented Z80

The instruction set of the Z80 processor is published in the "Z80 Family CPU User Manual" by Zilog. Comparing to Intel's 8080 processor Zilog introduced instruction prefixes, but not all prefix / instruction code combinations were defined, although many of the undocumented instructions may have useful functions in certain cases, thus some instructions became widely known. There are several initiatives in surveying the entire instruction set too. One of the best summary of these is "The Undocumented Z80 Documented" by Sean Young, which - beside the "official" document - was taken as a reference for writing this emulator.

File Z80_CODE.TXT lists all the different prefix / instruction code combinations, how those are understood in this emulator. File Z80_INST.TXT gives another view of the same table, adding extra information about the instructions, effect to flag bits. Here are short listed samples about the logic of some undocumented opcode:

Opcode Originally Prefixed Rule
DD 7C LD A,H LD A,XH H is replaced with XH, high byte of IX
FD 7C LD A,H LD A,YH H is replaced with YH, high byte of IY
DD 7D LD A,L LD A,XL L is replaced with XL, low byte of IX
FD 7D LD A,L LD A,YL L is replaced with YL, low byte of IY
DD 6C LD L,H LD XL,XH both registers are replaced
DD 6E d LD L,(HL) LD L,(IX+d) (HL) is replaced with (IX+d), but L is NOT replaced with XL (documented)
DD 78 LD A,B LD A,B prefix is skipped, as H, L or HL are not used in the instruction
DD FD 7D LD A,L LD A,YL first prefix is skipped, second prefix is used
DD CB d C0 SET 0,B SET 0,(IX+d),B bit 0 of memory of (IX+d) is set, additionally it is loaded into B
DD CB d 00 RLC B RLC (IX+d),B rotate (IX+d) and load the result into B
ED 7C - NEG same as the 'ED 44' NEG (multiple opcode of an instruction)
ED FF - NOP undefined opcode, nothing is done (like NOP is executed)
CB 30 - SLL B 'Shift Logic Left' (similar to SLA, except bit 0 becomes 1)
ED 70 - IN F,(C) Port read, set flags based on it
ED 71 - OUT (C),0 Writes 0 to port

Undocumented flag bits:

Bit 3 and 5 of flag register (often indicated as X and Y bits) are unspecified, however most of the instructions modifies them, which adjust the flag register. Generally bit 3 and 5 of the result are copied into the corresponding bit of flag register. However there are exceptions when these bits (or some other flag bits) are generated in a very special way, these are:

Emulator from version 1.01 contains an entirely rewritten Z80 engine, where the development process was started by creating several test patterns for testing the instruction set of a Z80 including the undocumented features, which were first executed on a vintage mother board equipped with a Zilog Z80 CPU. Later these test patterns were used as a validation of the written emulator. This way a list of instructions (but not all) was extensively tested. However if you found some differences between the original Zilog's Z80 and in this Z80 implementation, please let me know. Thanks.

Video display

HT-1080Z/TRS-80 is featured with a text mode display. 1 kByte video RAM (seated at 0x3C00-0x3FFF) is organized into 16 line 64 characters in each. Graphics mode is simulated by subdividing a single character into 3*2 pixels, which results 128*48 dot matrix (in fact character codes 0x80-0xBF give all combinations of pixels). So called "Video cut" feature makes it possible to zoom into one half of the video by displaying only the first or second 32 columns in double sized horizontally, a separate "page button" controls it, which half is shown. The emulator makes it possible to show the display in two different size. The smaller resolution uses 512*384 sized window client area, which is increased to 1024*768 if the "window magnifier" is turned on. You can control these features from the "Machine" menu. Be careful, if both the "video cut" and "page" is turned on, you may get empty screen (e.g. at bootup), when only short messages are written into the display memory.

The content of the character generator ROM can be loaded from file. Only 2 colors monochrome bitmap files are supported. In the package there are examples, however the entire bitmap should be 128*192 pixel sized (16 * 16 characters, each of them are 8*12 pixel sized). If you would like to create a new one, it is recommended, that you copy an example, then you edit it, and load it into the emulator by using the "Load Character Bitmap" menu point.

The "Reset Character ROM" menu point returns back the character generator status to the one, which is compiled into the emulator.

Sound generation

The emulator supports two kinds of sound generation. First versions of TRS-80 machines used the tape output for gaining sound effects (controlled by bit 0-1 on port 0xFF). Additionally the Hungarian HT-1080Z contained an extra card built with the popular General Instruments AY-3-8910 sound chip (Yamaha YM2149 was compatible with it too), which had 3 channels 12 bit controlled square wave output sound with 16 level logarithmical amplitude control and with a noise generator. Both sound generators can be independently switched on and off from the "Machine" menu. The sound is implemented internally in the emulator with 16 bit one channel 44.1 KHz samples.

When the emulator is used in slow or high speed, the sound is shifted by two octaves, however in full mode the sound is disabled (anyway inaudible sound would be generated).

Tuning the emulator

The Z80 processor of the original TRS-80 / HT-1080Z computer is running at 1.774 or 1.747 MHz (CPU clock is derived by dividing the 10.644 or 10.48 MHz XTAL frequency of video circuit with 6). There are four running speeds configured into the emulator beside the paused state. "Slow", "standard" and "fast" give 25 %, 100 % and 400 % in speed of the original computer. Additionally "full speed" can be selected and one processor of the system is exhausted as much as possible. The speed is depending on the system and the code, which the emulator executes, but it runs around 250 times faster (25000 %) on a 2.4 GHz Celeron processor than the original machine ran, which means, that the standard speed consumes very small system resource (processor load remains far under 1 %). Parallel execution of simultaneously started emulators is also supported.

You can select the appropriate speed from the "Machine" menu. Additionally you can mark the "Paused at focus lost" menu point, which means, that the emulator suspends the execution if the emulator window is deactivated. Also by selecting the switchable "Run" menu point, the emulator can be placed into suspended or running state at any time (escape is hotkey for it [be careful, if menu is active, first one or two escapes deactivate the menu, next escapes toggle the running state of the emulator]).

You can have the possibility to use two different Z80 engine. As experienced, the ROM and generally the programs are implemented in a way, that the ROM memory area (which is write protected in the real hardware) is newer written (no sense to write it). For the accurate emulation of this write protection each time a comparison has to be done on the memory address, which is typically unnecessary. If the "Simplified Machine" is marked (recommended), this check is eliminated from the emulator. As a further simplification the word read/write is executed as real word read/write operation. This has the side effect, that word operation at the highest address would not access the high byte from location 0 (e.g. ld hl,(0xFFFF) would read the high byte from the nonexistent 0x10000 address, and not from 0x0000). This is kept as theoretical problem, as address 0 contains the code executed after reset. However by these two simplifications significant improvement can be reached in speed. E.g. the following BASIC language code runs around 20-40% faster in full mode:

10 I=I+1
20 PRINT I
30 GOTO 10

Note: if you have a doubt, that the program overwrites the ROM, switch this feature off. Note: the "Cold Reset" reinitialize the ROM (also the entire memory is cleared), while "Warm Reset" just resets the processor, e.g. clears the PC register.

It is possible to switch off the video refreshment by unmarking the "Video Refresh" point. In this case the emulator is still running, just the screen is not refreshed. (Not recommended to use, as practically this does not give really perceptible improvement in speed.)

Port controlled timer / event counter

For tuning programs a timer and an event control have been implemented into the emulator, which can be controlled through port output operations from address range 0x51-0x55 in hexadecimal, 81-85 in decimal. The value written to the port is ignored. The ports have the following control:

Out 81 does not change the running state of the timer. If it were started earlier, the out 81,any instruction clears and restarts the timer. Also out 82 does not clear the previously accumulated time, instead it continues the measurement.

Recommended sequence to measure e.g. a subroutine in assembly

out (83),a ; stops the timer (it may run beforehand)
out (81),a ; clears the timer
...
out (82),a ; starts the timer
call routine ; calls the routine
out (83),a ; stops the timer
...

Note: you must calculate with the time of the out instructions too. E.g. the example above gives 11 additional cycles, the execution time of the out (n),a instruction. This must be taken into account as many times the timer is started.

The following BASIC language example illustrates the function of event counter. At first the event counter is cleared, then every execution of the "FOR" loop is counted as an event by the emulator.

OUT 84,0:FOR I=1 TO 100:OUT 85,0:NEXT

Keyboard layout

The original keyboard matrix is embedded into the memory on the address of 3800-3BFF. It is implemented as a 8*8 matrix, the processors A0-A7 address lines are driven through logic gates plus the D0-D7 data lines are fetched through latches, and any of the pressed buttons connects the relevant address and data lines together. The matrix is usually scanned by reading specific addresses, where only one of the address bit is high out of the A0-A7, however the matrix itself implements 'wired or gates'. Thus e.g. by reading address 38FF results nonzero value, if any of the buttons is pressed.

Additionally the entire matrix multiplied (fits four times) into the given memory range. These features are implemented in the emulator.

The following table summarizes, how the original keyboard is mapped into the memory. The relevant bit is set on the specified memory location, if the button is held down.

Address D0 D1 D2 D3 D4 D5 D6 D7
3801 @ A B C D E F G
3802 H I J K L M N O
3804 P Q R S T U V W
3808 X Y Z - - - - -
3810 0 1/! 2/" 3/# 4/$ 5/% 6/& 7/'
3820 8/( 9/) :/* ;/+ ,/< -/= ./> //?
3840 Enter Clear Break Up Down Left Right Space
3880 Shift - - - - - - -

The standard keyboard layout in English PC keyboard looks like this:

`/~
1/!
2/@
3/#
4/$
5/%
6/^
7/&
8/*
9/(
0/)
-/_
=/+
BackSpace
Tab
Q
W
E
R
T
Y
U
I
O
P
[/{
]/}
\/|
Caps
A
S
D
F
G
H
J
K
L
;/:
'/"
Enter
LShift
Z
X
C
V
B
N
M
./<
./>
//?
RShift
Space

These buttons have the following meaning on the emulated computer:

Up
1/!
2/"
3/#
4/$
5/%
6/&
7/'
8/(
9/)
0/
:/*
-/=
Left
Down
Q
W
E
R
T
Y
U
I
O
P
Left
Right
@
A
S
D
F
G
H
J
K
L
;/+
Clear
Enter
Shift
Z
X
C
V
B
N
M
./<
./>
//?
Shift
Space

In addition to this the emulator maps the arrows buttons of the PC into "Up/Down/Left/Right" arrows too, and the "delete" key is mapped into the Z80 Emulator's "Break" button. Note, the "Left" button behaves as backspace, the "Right" button works similarly to tab key.

It is possible to change the mapping of the PC keyboard. You must create first a text file containing 3 numbers separated by spaces/tabs at a line, which are the scan code of a PC keyboard, the TRS-80 keyboard matrix row (0-7) and column (0-7). You can add remarks, as the rest of the line behind the 3 numbers is ignored. For extended scan codes you must add 256 to the code. If you are unsure about the scan code of a button, you can use the "Find Scan Code" menu function, where a message box appears containing a scan code after pressing a button.

E.g. add "57 6 7" for mapping the space button to row 6 bit 7. You can use and reedit the file "kbd_map.txt" too, which contains a layout preconfigured into the emulator by default. Once you have a list of scan code mappings, you can load it into the emulator with the "Load Keyboard Map" menu point. You have the possibility to return the original keyboard mapping with the "Reset Keyboard Map" menu.

File handling

Loading a file:

Files with different formats can be loaded directly into the memory by selecting the "Load" menu point. The format of the file is detected based on the content of the file, and not on the extension. Loading of Intel Hex Files, TRS-80 style CMD files, CAS files for Basic language and system programs are supported. If "Auto Run After Load" menu point is marked (can be toggled by selecting it), the program is called at the starting address defined by the last record of the file. In case of Intel Hex File, the starting address is accepted, if it is different from 0. Note, using this method from Basic language CAS files is unsafe, as this method just loads the program into the defined memory location, but list of system pointers are not initialized correctly.

Saving a file:

Currently two different file formats are supported:
"Save" menu point saves the basic language program into a CAS files
"Save memory dump" function saves the entire 64 kByte memory into a binary file

Tape emulation:

An internal memory buffer is allocated for emulating the tape recorder for program loading. It must be used in the following way:

Configuring the ROMs

The bottom of the 64 kByte memory is the place for the 12 kByte basic ROM and 2 kByte ROM Extension. The compiled emulator contains a specific ROM and extension, but you have the possibility to load new ROM with the "Load ROM" menupoint. If you have e.g. a 12 kByte basic ROM in file "BASIC.ROM" and 2 kByte extension ROM in file "EXT.ROM" first you have to merge them together (use e.g. DOS COPY command, like "COPY /B BASIC.ROM+EXT.ROM MERGED.ROM"), then you can load them at once (from file "MERGED.ROM"). If shorter binary file is loaded into the memory (e.g. 4 kByte level 1 basic ROM), the rest of the 14 kByte is filled with 0xFF. Loading a ROM will reset the machine.

It is also possible to remove the ROM from the emulator. By selecting the "Remove ROM" menupoint, the entire ROM will be cleared with "0xFF", except the reset address and nmi service routine, where the following short code is added:

0000: di
0001: ld sp,0
0004: jp 0
...
0066: retn
...

This can have meaning, if you liked to test whether a program uses at all the BIOS. After invoking this function the machine gets reset, the memory is cleared and a processor waits in endless loop. A program can be directly loaded into the memory, and it can be started with the "auto run" feature.

If you want, you can return back to the ROM compiled into the emulator by selecting the "Reset ROM" menu point.

Patching new emulator

It is possible to prepare new emulator, changing the

First make a copy of the original emulator's EXE file (e.g. issue the "COPY FASTZ80.EXE NEWZ80.EXE" dos command), then start the original FASTZ80.EXE (and not the NEWZ80.EXE!). Load the new basic ROM & ROM extension with the "Load ROM" menu point, plus the new character generator with the "Load Character Bitmap", and the new keyboard mapping with the "Load Keyboard Map". Adjust the other settings as you liked (initial speed, XTAL frequency, other options...). Then use the "Patch Machine" menu point. In the file open dialog box select the just copied emulator's EXE file (NEWZ80.EXE), and press "Open". The program updates the selected EXE file with the settings/data.

File Formats

Intel Hex Format:

This format is a text file, contains ":" at the beginning of the line and several hexadecimal characters at each line. The carriage return/line feed separated lines have the following general format:

data lines: :NNHHLLTTDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCC

Where:
:: leading character
NN : number of data bytes in the line (00 in the last line)
HHLL: 4 digit hexadecimal address of first byte
TT: record type (00 data, 01 last line)
DD: data bytes
CC: Check Sum (sum of all byte in the line gives 00 result)

Last line may contain the start address of the program, however many program sets it to '00000001FF'.

CMD File Format:

Binary file contains several data blocks and a start address block

data block: 01 02 LL HH DD DD DD ... DD

where:
01 02: signature bytes
HHLL: address of memory
DD DD .. DD: 256 data bytes
last block: 02 02 LL HH
02 02: signature bytes
HHLL: start address of the program

CAS File Format for BASIC programs:

Binary file contains blocks of data:

1st block: header: 256 times '00' and 'A5' synchron byte
2nd block: name: D3 D3 D3 NN
where:
D3 D3 D3: signature bytes for basic program
NN: 1 character name from ASC 'A'-'Z'
program lines: L1 H1 L2 H2 DD DD DD ... DD 00
where:
H1L1 is the address of memory from where the basic program was saved
H2L2 is the basic line number
DD DD .. DD nonzero data bytes
00 terminating zero
last line: 00 00

CAS File Format for SYSTEM programs:

Binary file contains blocks of data

1st block: header: 256 times '00' and 'A5' synchron byte
2nd block: name:
55, and 6 character name from ASC 'A'-'Z'
data block:
3C NN LL HH DD DD DD ... DD CC
where:
3C: signature byte
NN: length of the data block (0 means 256 bytes)
HHLL: address of memory
DD DD .. DD: data bytes
CC: checksum
last block:
78 LL HH
where
HHLL is the start address of the program

References

Revision history

V1.00 (2007.05.16):

V1.01 (2008.03.08):

V1.02 (2008.07.10):

Kintli Lajos (lajos DOT kintli AT gmail DOT com)