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.
Overview
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.
Z80 Emulator Debugging Instruction Set
Overview
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 76
, ED 78
- ED 7E
, ED A0
- ED A3
, ED A8
- ED AB
, ED B0
- ED B3
, ED B8
- ED BB
Some instructions take more than one ED xx
instruction. The additional arguments are also always of the form ED xx
.
Groups
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.
Breakpoints
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
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.
Instruction Reference (ZEDIS)
Specifying Group Names
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 #
to .
, or not requiring parentheses.
Macro | Description |
#zedsmode(mode)
|
Changes the debugging mode. Valid modes are off , instr , and file .
|
#brkgroupname(x, name)
|
Defines that breakpoint group x should be given name. |
#tracegroupname(x, name)
|
Defines that trace group x should be given name. |
General Instructions
Instruction | Mnemonic | Description |
ED 77
|
ZEDISOFF
|
Disables all ZEDIS instructions (except ED 7F) |
ED 7F
|
ZEDISON
|
Enables all ZEDIS instructions |
ED Cx
|
GRPOFF x
|
Disables all events in group x |
ED Dx
|
GRPON x
|
Enables all events in group x |
Breakpoint Instructions
Instruction | Mnemonic | Description |
ED Fx
|
BREADK x
|
Breakpoint in group x |
Tracing Instructions
Instruction | Mnemonic | Description | |||||
ED 0x
|
TRACE x
|
Trace event in group x with no arguments | |||||
ED 1x ED yy
|
TRACE x, y
|
Trace event in group x with event ID y, where yy is not a valid ED instruction. | |||||
ED 2x ED yy
|
TRACE x, reg
|
Trace event in group x, logging the value of reg, see table below. | |||||
DD ED 2x ED yy
|
TRACE x, ixreg
|
Trace event in group x, logging the value of ixreg, where ixreg is IX, IXL, IXH, or (IX). | |||||
FD ED 2x ED iyreg
|
TRACE x, IY
|
Trace event in group x, logging the value of iyreg, where iyreg is IY, IYL, IYH, or (IY). | ED 3x ED yy
|
TRACE x, (
|
ED 8x ED port
|
TRACEP x, (port)
|
Records the value in port without changing any state, see below |
Imm8 Values
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 <= 7F, then Imm8 is encoded as
ED A5 ED Imm8 - 40h
- If Imm8 >= 80 && Imm8 <= BF, then Imm8 is encoded as
ED A5 ED Imm8 + 40h
So, if Imm8 is < 40 or >= C0, it is encoded in one byte. If Imm8 >= 40 and < C0, it is encoded as two bytes, with ED A5
as a prefix specifying that there should be an offset
Register Codes
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.
Value | Register | Value | Register |
00
|
B | 10
|
BC |
01
|
C | 11
|
DE |
02
|
D | 12
|
HL |
03
|
E | 13
|
AF |
04
|
H | 14
|
BC' |
05
|
L | 15
|
DE' |
06
|
(HL) | 16
|
HL' |
07
|
A | 17
|
AF' |
08
|
B' | 18
|
(BC) |
09
|
C' | 19
|
(DE) |
0A
|
D' | 1A
|
(BC') |
0B
|
E' | 1B
|
(DE') |
0C
|
H' | 1C
|
SP |
0D
|
L' | 1D
|
(SP) |
0E
|
(HL') | 1E
|
IR |
0F
|
A' | 1F
|
IFF |