Z80 Emulator Debugging Standard
This proposal specifies a standard for emulators to integrate breakpoint and tracing debugging features. There are two parts to the standard, an extension to the Z80 instruction set, and a file format that provides similar functionality.
- 1 Overview
- 2 Z80 Emulator Debugging Instruction Set
- 3 File Reference
Previously, emulators required users to manually enter breakpoints, and often had no way to load breakpoints from an external file, preventing them being loaded from an IDE or assembler. This standard specifies ways for emulators to load breakpoints, provide tracing and logging services, and load label names.
There are two parts to this: An extended instruction set that allows breakpoints and tracing to be included in the instruction stream, and a file format that allows names for breakpoints and tracing events to be specified, and also allows breakpoints to be loaded from an external file. An emulator may implement either or both standards. An emulator supporting breakpoint instructions need not support loading them from a file.
Z80 Emulator Debugging Instruction Set
The Z80 Emulator Debugging Instruction Set (ZEDIS) specifies debugging events in the instruction stream. This allows emulators to avoid checking every instruction fetch against a debug event list. Instead, they simply issue the event when they see the instruction.
All instructions occupy unused instruction slots in the
ED xx range. The unused instructions in this range function as 8-cycle NOPs, so software containing these instructions can be run on hardware without ill effect. Emulators MAY choose to count the ZEDIS instructions as 8-cycle NOPs for timing purposes. The following opcodes are USED in the Z80 instruction, and are NOT valid as debugging instructions:
ED 40 -
ED 78 -
ED A0 -
ED A8 -
ED B0 -
ED B8 -
Some instructions take more than one
ED xx instruction. The additional arguments are also always of the form
Software often has many different subsystems, so ZEDIS divides all debugging events into groups. There are 16 defined groups, 0-15. The purpose of each group is up to the user. For example, the user might use group 0 for events in a tile mapping system, and group 1 for events in sprites. Thus, the user can separately debug the two systems. The emulator SHOULD provide a UI means of disabling and enabling groups. Tracing groups and breakpoint groups are the same logical group.
A breakpoint causes the emulator to pause emulation, and open a debugger interface. The emulator pauses and opens the interface after PC has passed the breakpoint instruction.
Tracing provides a means for users to track the execution of software logic without single-stepping. Each tracing event adds an entry to a log, which MUST include the group number and any arguments (e.g. A = 3C), and MAY include the PC address of the event and the time the event happened.
An event is simply a log that the code passed through that point. Event IDs are encoded with a single 8-bit argument. All events IDs are shared between groups. The 8-bit event ID allows the trace log to show, for example, a message saying that a loop was iterated again, instead of just logging register values without any indication about their context. A sufficiently smart assembler MAY allow the user to type a string instead of a number for the event ID, and automatically cross-reference the string into names file.
Instruction Reference (ZEDIS)
Specifying Group Names
It is recommended that assemblers support the following directives to simplify use.
Per the file format specified below, the assembler may emit a file giving names to various groups. The exact syntax may be modified to suit each assembler. For example, changing
., or not requiring parentheses.
||Changes the debugging mode. Valid modes are |
||Defines that group x should be given name.|
||Disables all ZEDIS instructions (except ED 7F)|
||Enables all ZEDIS instructions|
||Disables all events in group x|
||Enables all events in group x|
||Breakpoint in group x|
||Trace event in group x with no arguments|
||Trace event in group x with event ID y, see below for imm8 encoding|
||Trace event in group x, logging the value of reg, see table below|
||Trace event in group x, logging the value of ixreg, where ixreg is IX, IXL, IXH, or (IX)|
||Trace event in group x, logging the value of iyreg, where iyreg is IY, IYL, IYH, or (IY)|
||Trace event in group x, logging the value of all data between reg16 and length, where length is a SIGNED 8-bit number, encoded as below. If length is negative, it logs bytes before the pointer, not after. A value of 0 logs 1 byte, a value of 7F logs 80 bytes.|
||Trace event in group x, recording the value in port imm8 without changing any state, see below for imm8 encoding|
FD can similarly be used with the
ED 3x set.
Imm8 values are encoded prefixed with ED, followed by:
- If imm8 <= 3F or imm8 >= C0, then imm8 is encoded as it is.
- If imm8 >= 40 && imm8 <= BF, then imm8 is encoded as
ED A5 ED imm8+80h. So 40 becomes C0, 50 becomes D0, 7F becomes FF, 80 becomes 00, and BF becomes 3F.
If IX or IY is selected, then only H, L, HL, or (HL) are valid and H becomes IXH or IYH &c. You know the drill with index registers.
Files are formatted like INI files.
- platform=platform, values may be ti8x or ti84pcse
- programname="string", may be used for an app or a program