4E00H - DEBUG Entry Point
Main entry point for the DEBUG monitor overlay. Saves all CPU registers (primary, alternate, and index) to the register save area at 4065H, captures the stack pointer, and adjusts the stack for debugger operation. Called when RST 30H is executed (via the 400FH vector) or when SVC 87H is invoked directly.
4E00
POP AF F1
Remove the first return address from the stack. This discards the overlay loader's internal return address that was pushed during the RST 28H/RST 30H dispatch sequence.
4E01
POP AF F1
Remove a second value from the stack. This retrieves the caller's AF register (containing the error code or SVC parameter) that was saved by the overlay dispatch code in SYS0. Register A now holds the value that was in A when the debug entry was triggered.
4E02
PUSH AF F5
Save the caller's AF back onto the stack. This preserves it as part of the complete register snapshot that will be copied to the save area.
4E03
PUSH IY FD E5
Save Register Pair IY onto the stack.
4E05
PUSH IX DD E5
Save Register Pair IX onto the stack.
4E07
EX AF,AF' 08
Switch to the alternate AF register. The primary AF is now in AF' and the alternate AF is now in AF.
4E08
EXX D9
Switch to the alternate register set (BC', DE', HL' become active as BC, DE, HL). The primary registers are now stored in the alternate set.
4E09
PUSH HL E5
Save the alternate HL' (now active as HL) onto the stack.
4E0A
PUSH DE D5
Save the alternate DE' onto the stack.
4E0B
PUSH BC C5
Save the alternate BC' onto the stack.
4E0C
PUSH AF F5
Save the alternate AF' (currently active as AF) onto the stack.
4E0D
EX AF,AF' 08
Switch back to the primary AF register set.
4E0E
EXX D9
Switch back to the primary register set (BC, DE, HL are primary again).
4E0F
PUSH HL E5
Save the primary HL onto the stack.
4E10
PUSH DE D5
Save the primary DE onto the stack.
4E11
PUSH BC C5
Save the primary BC onto the stack.
4E12
PUSH AF F5
Save the primary AF onto the stack. All 12 register pairs are now on the stack (AF, BC, DE, HL, AF', BC', DE', HL', IX, IY, plus the outer AF from 4E02H).
Copy Registers From Stack to Save Area
The 24 bytes on the stack (12 register pairs x 2 bytes each) are now block-copied to the register save area at 4065H using LDIR. This preserves the complete CPU state for display and modification by the debugger commands.
4E13
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H. This will be used with ADD HL,SP to capture the current stack pointer value.
4E16
ADD HL,SP 39
ADD the stack pointer to HL. Since HL was 0000H, HL now equals the current SP value, pointing to the top of the register data on the stack.
4E17
LD DE,4065H 11 65 40
Point Register Pair DE to the register save area at 4065H. This is the destination for the block copy.
4E1A
LD BC,0018H 01 18 00
Load Register Pair BC with 0018H (24 decimal). This is the byte count for the LDIR: 12 register pairs x 2 bytes = 24 bytes.
4E1D
LDIR ED B0
Block copy 24 bytes from the stack (source HL) to the save area at 4065H (destination DE). After completion, HL points past the copied data on the stack, and DE points to 407DH (past the save area). The register save area at 4065H now contains all 12 register pairs in order: AF, BC, DE, HL, AF', BC', DE', HL', IX, IY, outer-AF, and the return HL.
4E1F
LD (4079H),HL 22 79 40
Store HL (which now points past the copied stack data) into the saved stack pointer location at 4079H. This records the user program's effective stack pointer, adjusted for the register saves, so it can be restored when the Go command resumes execution.
4E22
LD SP,HL F9
Set the stack pointer to HL. The debugger now operates with its own stack positioned above the saved register area, leaving the user program's stack undisturbed below.
Check For and Remove RST 30H Breakpoint Marker
If the program was stopped by a breakpoint (RST 30H = F7H byte), the byte at the current PC minus 1 will be F7H. This check detects that condition and adjusts the saved PC (at 407BH) to point back to the breakpoint location so execution can resume from the correct address.
4E23
LD HL,(407BH) 2A 7B 40
Load Register Pair HL with the saved program counter from 407BH. This is the address where execution was interrupted (or where the RST 30H breakpoint returned to).
4E26
DEC HL 2B
DECrement HL by 1 to point to the byte before the saved PC. If the program hit an RST 30H breakpoint, the PC was advanced past the F7H byte, so decrementing points back to the breakpoint location.
4E27
LD A,(HL) 7E
Fetch the byte at (HL) into Register A. If this byte is F7H, the program was stopped by a breakpoint.
4E28
CP A,0F7H FE F7
Compare Register A against F7H (RST 30H opcode). If equal (Z FLAG set), a breakpoint was hit and the PC needs adjustment.
4E2A
If the byte is NOT F7H (NZ FLAG, no breakpoint), JUMP to 4E2FH to skip the PC adjustment and proceed to breakpoint cleanup.
4E2C
LD (407BH),HL 22 7B 40
Store the adjusted address (pointing to the breakpoint F7H byte) back to the saved PC at 407BH. This ensures that when execution resumes, it will start from the breakpoint location rather than the byte after it.
4E2FH - Breakpoint Cleanup and Timer Dequeue
Scans up to 2 breakpoint entries in the 405DH area. For each entry, if the address is non-zero, checks whether the byte at that address is still F7H (RST 30H). If so, restores the original byte that was saved when the breakpoint was inserted. After cleanup, zeroes out the breakpoint entry. This ensures that any breakpoints from a previous Go command are removed before the debugger accepts new commands.
4E2F
LD HL,405DH 21 5D 40
Point Register Pair HL to the breakpoint/work area at 405DH. This area contains up to 2 breakpoint records, each consisting of the original byte value and the breakpoint address.
4E32
LD B,02H 06 02
Load Register B with 02H. Two breakpoint slots are processed.
4E34
XOR A,A AF
Loop Start
Set Register A to 00H and clear all flags. A=00H will be used to zero out the breakpoint entry after processing.
4E35
LD C,02H 0E 02
Load Register C with 02H. This is not directly used in the immediate code but initializes C for the breakpoint record structure.
4E37
LD E,(HL) 5E
Fetch the low byte of the breakpoint address from (HL) into Register E.
4E38
LD (HL),A 77
Store 00H (Register A) over the low byte, clearing the breakpoint entry.
4E39
INC HL 23
INCrement HL to point to the high byte of the breakpoint address.
4E3A
LD D,(HL) 56
Fetch the high byte of the breakpoint address from (HL) into Register D. DE now holds the complete breakpoint address.
4E3B
LD (HL),A 77
Store 00H over the high byte, clearing the rest of the breakpoint entry.
4E3C
INC HL 23
INCrement HL to point to the saved original byte for this breakpoint.
4E3D
LD A,E 7B
Copy the low byte of the breakpoint address from Register E into Register A.
4E3E
OR A,D B2
OR Register A (low byte) with Register D (high byte). If both are zero, the breakpoint address is 0000H, meaning no breakpoint was set in this slot.
4E3F
If the Z FLAG is set (breakpoint address is 0000H), JUMP to 4E48H to skip restoration for this empty slot.
4E41
LD A,(DE) 1A
Fetch the byte currently at the breakpoint address (DE) into Register A. This should be F7H if the breakpoint is still in place.
4E42
CP A,0F7H FE F7
Compare Register A against F7H (RST 30H opcode). If equal, the breakpoint byte is still there and needs to be restored.
4E44
If the byte is NOT F7H (NZ FLAG), the breakpoint has already been removed or the memory was overwritten. JUMP to 4E48H to skip restoration.
4E46
LD A,(HL) 7E
Fetch the saved original byte from the breakpoint record at (HL). This is the instruction byte that was replaced by F7H when the breakpoint was set.
4E47
LD (DE),A 12
Restore the original byte to the breakpoint address (DE), removing the F7H breakpoint marker and restoring the original instruction.
4E48
INC HL 23
INCrement HL to advance past the saved-byte field, pointing to the next breakpoint slot.
4E49
Loop End
DECrement Register B and loop back to 4E34H if not zero. After both breakpoint slots have been processed, fall through to the command loop entry.
4E4BH - Command Loop Entry Point
Main command loop for the DEBUG monitor. Restores the debugger stack pointer, calls the register dump display, reads a command character from the keyboard, and dispatches to the appropriate handler based on ASCII value. Each handler returns to 4E4BH (pushed on the stack at 4E63H) to re-enter the loop. Unrecognized commands invoke RST 28H (which triggers the overlay loader to attempt loading a different overlay, effectively treating the unknown command as an SVC code).
4E4B
LD SP,(4079H) ED 7B 79 40
Restore the stack pointer from the saved value at 4079H. This ensures the debugger always operates with a clean stack, regardless of what the command handlers may have done.
4E4F
GOSUB to the register dump display routine at 4ECFH. This outputs all 12 register pairs with their current values, including flags bit breakdown for AF and AF', to the screen.
4E52
LD HL,3FC0H 21 C0 3F
Load Register Pair HL with 3FC0H, the start of the last line of video RAM (64 columns x 15 rows = offset 3C0H from video base 3C00H). This positions the cursor on the bottom screen line for command input.
4E55
LD (4020H),HL 22 20 40
Store HL (3FC0H) into the cursor position variable at 4020H. This sets the screen output position to the bottom line for command echoing.
4E58
GOSUB to the keyboard input routine at 518AH. This waits for a keypress, echoes it if printable, and returns the ASCII character in Register A.
4E5B
CP A,47H FE 47
Compare Register A against 47H (ASCII 'G' for Go command).
4E5D
If Register A equals 'G' (Z FLAG set), JUMP to the Go command handler at 4F80H.
Command Dispatch
Push the command loop return address (4E4BH) onto the stack. Each command handler terminates with RET, which returns to 4E4BH to re-enter the command loop. The Go command is excluded from this pattern because it does not return to the debugger.
4E60
LD HL,4E4BH 21 4B 4E
Load Register Pair HL with 4E4BH, the command loop entry point address.
4E63
PUSH HL E5
Push the command loop address onto the stack. When any command handler executes RET, it will return to 4E4BH to display registers and accept the next command.
4E64
CP A,53H FE 53
Compare Register A against 53H (ASCII 'S' for Step command).
4E66
If 'S', JUMP to the Step command handler at 4E9AH.
4E68
CP A,3BH FE 3B
Compare Register A against 3BH (ASCII ';' for Scroll Forward).
4E6A
If ';', JUMP to the Scroll Forward handler at 4EAEH.
4E6C
CP A,2DH FE 2D
Compare Register A against 2DH (ASCII '-' for Scroll Backward).
4E6E
If '-', JUMP to the Scroll Backward handler at 4EC6H.
4E70
CP A,41H FE 41
Compare Register A against 41H (ASCII 'A' for Set Address).
4E72
If 'A', JUMP to the Set Address handler at 4ECBH.
4E74
CP A,43H FE 43
Compare Register A against 43H (ASCII 'C' for instruction decode/Continue).
4E76
If 'C', JUMP to 4E82H (which falls through to the JP Z,505DH check for I command).
4E78
CP A,44H FE 44
Compare Register A against 44H (ASCII 'D' for Display memory).
4E7A
If 'D', JUMP to the Display command handler at 4EA8H.
4E7C
CP A,48H FE 48
Compare Register A against 48H (ASCII 'H' for Set Address, alternate key).
4E7E
If 'H', JUMP to the Set Address handler at 4ECBH (same as 'A').
4E80
CP A,49H FE 49
Compare Register A against 49H (ASCII 'I' for Instruction decode).
4E82
If Register A is 'I' (or 'C' which fell through from 4E76H), JUMP to the Instruction Decode handler at 505DH.
4E85
CP A,4DH FE 4D
Compare Register A against 4DH (ASCII 'M' for Modify memory).
4E87
If 'M', JUMP to the Modify Memory handler at 4FDBH.
4E8A
CP A,52H FE 52
Compare Register A against 52H (ASCII 'R' for Register modify).
4E8C
If 'R', JUMP to the Register Modify handler at 5011H.
4E8F
CP A,55H FE 55
Compare Register A against 55H (ASCII 'U' for Wait/pause).
4E91
If 'U', JUMP to the Wait handler at 4E9EH.
4E93
CP A,58H FE 58
Compare Register A against 58H (ASCII 'X' for Exit step mode).
4E95
If 'X', JUMP to the Exit handler at 4E99H.
4E97
RST 28H EF
For any unrecognized command character, invoke RST 28H. This transfers control to the SYS0 overlay loader, which interprets the byte following RST 28H (at 4E98H = C9H) as an SVC code. C9H does not correspond to a valid overlay, so this effectively acts as a no-op that returns control.
4E98
RET C9
Return to the command loop at 4E4BH (the address pushed at 4E63H). If reached directly (not via RST 28H), this simply re-enters the command loop. If RST 28H loaded an overlay, this byte serves as the SVC code parameter.
4E99H - Exit Step Mode (X Command)
Clears the single-step flag and returns to the command loop. The XOR A sets A=00H, which falls through to 4E9AH to store 00H in the step flag, effectively disabling single-step mode.
4E99
XOR A,A AF
Set Register A to 00H. This value will be stored as the step flag, disabling single-step mode.
4E9AH - Step Mode Toggle (S Command)
Stores the command character (53H = 'S' for step, or 00H from X command) into the single-step flag at 405EH. When non-zero, the Go command will insert a single-step breakpoint.
4E9A
LD (405EH),A 32 5E 40
Store Register A into the single-step mode flag at 405EH. For the S command, A=53H (non-zero = step mode active). For the X command fall-through, A=00H (step mode disabled).
4E9D
RET C9
Return to the command loop at 4E4BH.
4E9EH - Wait for Keypress (U Command)
Waits in a tight loop for a non-zero keypress from the keyboard, providing a simple pause function. Useful when single-stepping to pause between steps until the user is ready.
4E9E
Loop Start
GOSUB to the Model I ROM keyboard wait routine at 002BH. This waits for a keypress and returns the ASCII character in Register A (or 00H if no key is pressed).
4EA1
OR A,A B7
Test Register A for zero by ORing it with itself. Sets the Z FLAG if A is 00H (no key pressed).
4EA2
RET NZ C0
If a key was pressed (NZ FLAG, A is non-zero), return to the command loop. The keypress is consumed silently.
4EA3
GOSUB to the register dump display at 4ECFH. This refreshes the register display while waiting, so the user can see the current state.
4EA6
Loop End
LOOP BACK to 4E9EH to check for another keypress.
4EA8H - Display Memory (D Command)
Reads a hex address from the keyboard and displays a hex/ASCII memory dump at that address. Falls through to the scroll forward handler to perform the actual display.
4EA8
GOSUB to the hex number input routine at 51A3H. This reads hex digits from the keyboard and returns the 16-bit value in HL. Returns Z FLAG if Enter pressed (no value entered), or NZ with value in HL.
4EAB
RET Z C8
If the Z FLAG is set (Enter pressed with no address), return to the command loop without changing the display address.
4EAC
JUMP to 4EC2H to store the entered address in the display address variable at 4063H and then display the memory dump.
4EAEH - Scroll Forward (; Command)
Advances the display address by 64 bytes (one screen row of hex dump) or by the configured scroll increment. If the step flag is non-zero, advances by 256 bytes instead.
4EAE
LD BC,0040H 01 40 00
Load Register Pair BC with 0040H (64 decimal). This is the default scroll forward increment: 64 bytes = one screen row of 16-byte hex dump lines (4 lines x 16 bytes).
4EB1
LD HL,(4063H) 2A 63 40
Load Register Pair HL with the current display address from 4063H.
4EB4
LD A,(405EH) 3A 5E 40
Fetch the single-step mode flag from 405EH into Register A.
4EB7
OR A,A B7
Test Register A for zero. If the step flag is zero, use the 64-byte increment. If non-zero, use 256 bytes.
4EB8
If the step flag is 00H (Z FLAG, normal mode), JUMP to 4EC1H to add the 64-byte increment.
4EBA
LD C,00H 0E 00
Set Register C to 00H. BC was 0040H; now BC = 0000H + the adjustment below.
4EBC
LD A,B 78
Load Register A with Register B (currently 00H from the LD BC,0040H).
4EBD
OR A,A B7
Test if B is zero.
4EBE
If B is non-zero, JUMP to 4EC1H.
4EC0
INC B 04
INCrement B to 01H. BC is now 0100H (256 decimal). In step mode, the scroll increment is 256 bytes (one full page).
4EC1
ADD HL,BC 09
ADD BC (scroll increment) to HL (current display address).
4EC2
LD (4063H),HL 22 63 40
Store the new display address in the variable at 4063H.
4EC5
RET C9
Return to the command loop at 4E4BH. The register dump display will be refreshed, showing the new display address context.
4EC6H - Scroll Backward (- Command)
Decrements the display address by 64 bytes by adding the two's complement value FFC0H.
4EC6
LD BC,0FFC0H 01 C0 FF
Load Register Pair BC with FFC0H, which is the two's complement of 0040H (negative 64). Adding this to the display address decrements it by 64 bytes.
4EC9
JUMP to 4EB1H to load the current display address and add BC (FFC0H), effectively subtracting 64 bytes.
4ECBH - Set Address (A/H Command)
Stores the command character ('A' = 41H or 'H' = 48H) into the address variable at 405DH. This variable is used by other commands to determine addressing mode.
4ECB
LD (405DH),A 32 5D 40
Store Register A (the command character, 41H for 'A' or 48H for 'H') into the address mode variable at 405DH.
4ECE
RET C9
Return to the command loop at 4E4BH.
4ECFH - Register Dump Display
Displays all 12 register pairs with their current hex values from the save area at 4065H. For the AF and AF' registers (detected when the loop counter B AND 0BH equals 08H), an additional flags bit breakdown is shown using the flags name table at 4F78H ("SZ1H1PNC"). For non-flags registers, the display includes an "=>" prefix followed by the memory contents at the register pair's address. Two display modes exist: normal mode (step flag = 0) clears the screen and shows 12 lines; step mode (step flag non-zero) shows a compact 16-register display without clearing.
4ECF
LD A,(405EH) 3A 5E 40
Fetch the single-step mode flag from 405EH into Register A.
4ED2
OR A,A B7
Test Register A for zero. If step mode is active (non-zero), use the compact display format.
4ED3
If the step flag is non-zero (NZ FLAG, step mode active), JUMP to 4F45H for the compact step-mode register display.
4ED5
LD A,1CH 3E 1C
Load Register A with 1CH (cursor home / clear screen control code on the TRS-80 Model I). This clears the screen before the full register dump.
4ED7
GOSUB to ROM 0033H to output the clear-screen control code.
4EDA
LD HL,4065H 21 65 40
Point Register Pair HL to the start of the register save area at 4065H. This is the source for register values.
4EDD
PUSH HL E5
Save the register save area pointer onto the stack. It will be swapped with the name table pointer via EX (SP),HL during the display loop.
4EDE
LD HL,4F54H 21 54 4F
Point Register Pair HL to the register name display table at 4F54H. Each entry is 2 bytes: the two ASCII characters of the register pair name.
4EE1
LD B,0CH 06 0C
Load Register B with 0CH (12 decimal). There are 12 register pairs to display: AF, BC, DE, HL, AF', BC', DE', HL', IX, IY, SP, PC.
4EE3
JUMP to 4EEAH to skip the carriage return for the first iteration (the first register pair is displayed at the top of the screen without a preceding line break).
4EE5
LD A,0DH 3E 0D
Load Register A with 0DH (carriage return) to move to the next screen line before displaying the next register pair.
4EE7
GOSUB to ROM 0033H to output the carriage return.
Register Display Loop
For each register pair: print the 2-character name from the table at 4F54H, then read the 2-byte value from the save area at 4065H, display "=" + space + 4-hex-digit value. For AF/AF' registers, also show a flags bit breakdown. For other registers, show "=>" + memory contents at the register pair's address. The name table pointer and save area pointer are kept on the stack and swapped via EX (SP),HL at each transition.
4EEA
GOSUB to the print-two-characters routine at 51F6H. This reads 2 bytes from the name table at (HL), prints them as ASCII characters, and advances HL by 2. For example, the first call prints "AF" and advances HL to the next entry.
4EED
EX (SP),HL E3
Exchange HL with the top of the stack. HL now holds the register save area pointer (was on the stack), and the name table pointer (was in HL) is now on the stack. This swaps between the two data pointers.
4EEE
LD E,(HL) 5E
Fetch the low byte of the saved register value from (HL) into Register E.
4EEF
INC HL 23
INCrement HL to the high byte.
4EF0
LD D,(HL) 56
Fetch the high byte of the saved register value into Register D. DE now holds the register pair's 16-bit value (D=high byte, E=low byte on the Z80 stack push format).
4EF1
INC HL 23
INCrement HL past this register value entry.
4EF2
PUSH HL E5
Save the advanced save area pointer onto the stack for the next iteration.
4EF3
EX DE,HL EB
Exchange DE and HL. HL now holds the register pair value (for display), DE is free.
4EF4
LD A,3DH 3E 3D
Load Register A with 3DH (ASCII '='). This is the separator between the register name and its hex value.
4EF6
GOSUB to ROM 0033H to output the '=' character.
4EF9
GOSUB to the print-space routine at 51F2H to output a space after the '='.
4EFC
LD A,H 7C
Copy the high byte of the register value from Register H into Register A.
4EFD
GOSUB to the hex-byte-with-space routine at 51EFH. This outputs the high byte as two hex digits followed by a space (e.g., "4E ").
4F00
LD A,L 7D
Copy the low byte of the register value from Register L into Register A.
4F01
GOSUB to 51EFH to output the low byte as two hex digits followed by a space.
4F04
LD A,B 78
Copy the loop counter from Register B into Register A. This is used to detect the AF and AF' iterations for the flags breakdown.
4F05
AND A,0BH E6 0B
Mask Register A with 0BH. When B=0CH (first iteration, AF), 0CH AND 0BH = 08H. When B=08H (fifth iteration, AF'), 08H AND 0BH = 08H. All other values of B produce results other than 08H. This efficiently detects both AF and AF' registers.
4F07
CP A,08H FE 08
Compare the masked value against 08H. If equal (Z FLAG set), this is an AF or AF' register that needs the flags bit breakdown.
4F09
If NOT an AF register (NZ FLAG), JUMP to 4F27H to display the "=>" memory contents format for non-flags registers.
Flags Bit Breakdown Display
For AF and AF' registers, the low byte (L, which holds the F register value) is expanded into a visual bit display showing each flag's state. The flags table at 4F78H contains "SZ1H1PNC" (8 characters for the 8 bits, from bit 7 down to bit 0). For each bit, if the bit is set, the corresponding flag letter is displayed; if clear, a '-' is displayed.
4F0B
LD C,L 4D
Copy the flags byte (low byte of AF, currently in Register L) into Register C. The flags bits will be tested by shifting C left.
4F0C
PUSH BC C5
Save Register Pair BC (B=loop counter, C=flags byte) onto the stack.
4F0D
LD HL,4F78H 21 78 4F
Point Register Pair HL to the flags name table at 4F78H. This 8-byte table contains the characters "SZ1H1PNC" representing: S=Sign, Z=Zero, 1=always-1, H=Half-carry, 1=always-1, P=Parity/Overflow, N=Subtract, C=Carry.
4F10
LD B,08H 06 08
Load Register B with 08H (8 decimal). There are 8 flag bits to display.
4F12
SLA C CB 21
Loop Start
Shift Register C left arithmetically. The highest bit (bit 7) shifts into the CARRY FLAG. This tests each flag bit from most-significant (Sign) to least-significant (Carry) in order.
4F14
LD A,(HL) 7E
Fetch the flag name character from the table at (HL) into Register A (e.g., 'S' for the Sign flag).
4F15
If the CARRY FLAG is set (the flag bit was 1), JUMP to 4F19H to display the flag letter. The flag is active.
4F17
LD A,2DH 3E 2D
The flag bit was 0 (not set). Load Register A with 2DH (ASCII '-') to display a dash indicating the flag is inactive.
4F19
GOSUB to ROM 0033H to output the flag character (letter if set, '-' if clear).
4F1C
INC HL 23
INCrement HL to point to the next flag name character in the table.
4F1D
Loop End
DECrement Register B and loop back to 4F12H if not zero. After all 8 flag bits have been displayed.
4F1F
POP BC C1
Restore Register Pair BC (B=outer loop counter, C=flags byte) from the stack.
4F20
LD A,0ECH 3E EC
Load Register A with ECH. On the TRS-80 Model I, this is a semigraphics block character used as a visual separator after the flags display.
4F22
GOSUB to ROM 0033H to output the separator character.
4F25
JUMP to 4F2AH to rejoin the main loop, skipping the non-flags register display path.
Non-Flags Register "=>" Memory Display
For registers other than AF/AF', display "=>" followed by the memory content at the address held in the register pair. This shows what the register is pointing to in memory.
4F27
GOSUB to the memory-at-register display routine at 5131H. This routine saves BC, prints "=>", outputs a space, then displays the 16-byte hex dump at the address in HL (the register pair value). However, due to the B AND 0BH check at 5184H, only the 8th iteration (where B=08H) displays the full dump; other iterations display a shorter format.
4F2A
POP HL E1
Pop the save area pointer from the stack (saved at 4EF2H) back into HL.
4F2B
EX (SP),HL E3
Exchange HL with the top of stack. HL now holds the name table pointer (was on stack), and the save area pointer goes back on the stack for the next iteration.
4F2C
DECrement Register B and loop back to 4EE5H if not zero. After all 12 register pairs have been displayed, fall through.
4F2E
POP HL E1
Remove the remaining save area pointer from the stack (cleanup from the EX (SP),HL swap pattern).
Memory Dump at Display Address
After the register display, show a 4-line hex dump of memory starting at the display address in 4063H. Each line shows the address, hex bytes, and ASCII representation.
4F2F
LD HL,(4063H) 2A 63 40
Load Register Pair HL with the current display address from 4063H. This is the memory dump starting address.
4F32
LD B,04H 06 04
Load Register B with 04H (4 decimal). Four lines of hex dump will be displayed.
4F34
LD A,0C7H 3E C7
Loop Start
Load Register A with C7H. This is a TRS-80 semigraphics block character used as a visual line marker at the start of each dump line.
4F36
GOSUB to ROM 0033H to output the line marker character.
4F39
GOSUB to the 4-digit hex display routine at 51D4H to output the current address in HL as a hexadecimal value.
4F3C
GOSUB to the print-space routine at 51F2H.
4F3F
GOSUB to the memory dump line routine at 5131H. This displays "=>" followed by 16 hex bytes and their ASCII representation at the address in HL, advancing HL by 16.
4F42
Loop End
DECrement Register B and loop back to 4F34H if not zero. After 4 lines (64 bytes total), fall through.
4F44
RET C9
Return to the caller (the command loop at 4E4FH).
4F45H - Step Mode Register Display (Compact Format)
When single-step mode is active, displays a more compact register dump without clearing the screen. Positions the cursor at the bottom of the display area and shows 16 lines of register data in a condensed format suitable for continuous stepping.
4F45
LD HL,3BFFH 21 FF 3B
Load Register Pair HL with 3BFFH. This is one byte before the start of video RAM (3C00H), representing a cursor position that will wrap to the beginning of video RAM on the next output.
4F48
LD (4020H),HL 22 20 40
Store HL into the cursor position variable at 4020H. This effectively positions output at the top of the screen without issuing a clear-screen command.
4F4B
LD HL,(4063H) 2A 63 40
Load Register Pair HL with the display address from 4063H.
4F4E
LD L,00H 2E 00
Clear the low byte of HL to 00H. This page-aligns the display address (rounds down to a 256-byte boundary) for the compact dump format.
4F50
LD B,10H 06 10
Load Register B with 10H (16 decimal). The compact display shows 16 lines of hex dump (16 x 16 = 256 bytes, one full page).
4F52
JUMP to 4F34H to use the same hex dump loop as the normal display, but with 16 iterations instead of 4.
4F54H - Register Name Display Table
Lookup table of 12 two-byte entries, each containing the two ASCII characters of a register pair name. Used by the register dump display loop at 4ECFH to label each register value. The entries are in the same order as the saved register values at 4065H: AF, BC, DE, HL, AF', BC', DE', HL', IX, IY, SP, PC.
4F54
DEFM "AF BC DE HL AF'BC'DE'HL'IX IY SP PC " 41 46 20 42 43 20 44 45 20 48 4C 20 41 46 27 42 43 27 44 45 27 48 4C 27 49 58 20 49 59 20 53 50 20 50 43 20
Register name table (36 bytes, 12 entries of variable format). Each register name is 2 characters, followed by either a space (20H) for primary registers and IX/IY/SP/PC, or an apostrophe (27H) for alternate registers. The display routine at 51F6H reads 2 bytes per call, printing the name characters. Note: the third byte (space or apostrophe) is consumed by the adjacent register value display logic or serves as visual padding in the screen output.
4F78H - Flags Bit Name Table
Eight ASCII characters representing the Z80 flags register bits from bit 7 (most significant) to bit 0 (least significant). Used by the flags breakdown display at 4F0BH.
4F78
DEFM "SZ1H1PNC" 53 5A 31 48 31 50 4E 43
Flags bit names: S=Sign (bit 7), Z=Zero (bit 6), 1=always-1 (bit 5), H=Half-carry (bit 4), 1=always-1 (bit 3), P=Parity/Overflow (bit 2), N=subtract (bit 1), C=Carry (bit 0). Bits 5 and 3 are documented as fixed '1' values in the Z80 architecture but are displayed here for completeness.
4F80H - Go Command (G)
Resumes execution of the user program from the saved PC address. Optionally reads up to 2 breakpoint addresses from the keyboard and inserts RST 30H (F7H) breakpoint markers at those addresses. Patches the BREAK key handler to redirect to the DEBUG entry point. Then restores all saved registers from 4065H and transfers control to the user program via the saved PC at 407BH.
4F80
LD B,02H 06 02
Load Register B with 02H. Up to 2 breakpoint addresses can be specified.
4F82
LD DE,4062H 11 62 40
Point Register Pair DE to the breakpoint save area at 4062H. This is where the breakpoint records (original byte + address) will be stored.
4F85
GOSUB to the hex number input routine at 51A3H. Reads a hex address from the keyboard. Returns Z if Enter pressed (no address), NZ with address in HL, or CARRY if invalid.
4F88
If Enter was pressed with no address (Z FLAG), JUMP to 4F8DH to skip this breakpoint slot.
4F8A
LD (407BH),HL 22 7B 40
Store the entered address as the new program counter at 407BH. If the user enters an address with G, execution starts from that address instead of the saved PC.
4F8D
If the CARRY FLAG is set (input was terminated by Enter or end-of-input), JUMP to 4F99H to finalize breakpoints and resume execution.
4F8F
GOSUB to read another hex address for the breakpoint location.
4F92
PUSH AF F5
Save the flags from the input routine (Z and CARRY status).
4F93
If a valid address was entered (NZ FLAG), GOSUB to the breakpoint insertion routine at 4FCAH. This saves the byte at (HL), writes F7H (RST 30H), and records the breakpoint in the save area at (DE).
4F96
POP AF F1
Restore the flags.
4F97
DECrement Register B and loop back to 4F8DH if not zero. After both breakpoint slots have been processed, fall through.
Patch BREAK Key Handler and Restore Registers
Before resuming execution, the BREAK key handler at 4315H is patched to jump to 400FH (the RST 30H vector, which re-enters DEBUG). This allows the user to break back into the debugger by pressing BREAK. Then all 12 register pairs are restored from the save area and control is transferred to the user program.
4F99
LD HL,400FH 21 0F 40
Load Register Pair HL with 400FH, the RST 30H handler vector address. This is where the BREAK key will redirect to, which is the DEBUG/error handler entry.
4F9C
LD (4316H),HL 22 16 43
Store 400FH into the BREAK key handler target address at 4316H-4317H. This overwrites the BREAK handler destination so that pressing BREAK will jump to 400FH (DEBUG entry).
4F9F
LD A,0C3H 3E C3
Load Register A with C3H (JP opcode). This will be written to 4315H to create a JP 400FH instruction at the BREAK handler location.
4FA1
LD (4315H),A 32 15 43
Store the JP opcode (C3H) at 4315H. Combined with the address at 4316H-4317H (400FH), the BREAK handler is now: JP 400FH. When the BREAK key is pressed, execution jumps to the RST 30H vector, which loads SYS5 and re-enters the debugger.
Register Restoration From Save Area
The following code restores all 12 register pairs from the save area at 4065H-407CH by pushing them onto the stack in reverse order and then popping them back into the CPU registers. The save area pointer at 407AH is read backward (DEC HL pattern) to push the values in the correct order for the POP sequence.
4FA4
LD HL,407AH 21 7A 40
Point Register Pair HL to byte 407AH, which is near the end of the save area. The code reads backward from here to push register values in the correct order.
4FA7
LD B,0BH 06 0B
Load Register B with 0BH (11 decimal). Eleven register pairs will be pushed from the save area onto the stack.
4FA9
LD D,(HL) 56
Loop Start
Fetch the high byte of the register pair from the save area at (HL) into Register D.
4FAA
DEC HL 2B
DECrement HL to point to the low byte.
4FAB
LD E,(HL) 5E
Fetch the low byte of the register pair into Register E.
4FAC
DEC HL 2B
DECrement HL to point to the next register pair (going backward through the save area).
4FAD
PUSH DE D5
Push the register pair value onto the stack.
4FAE
Loop End
DECrement Register B and loop back to 4FA9H. After all 11 pairs are pushed, the stack contains the register values ready for POP restoration.
4FB0
POP AF F1
Restore the primary AF register pair from the stack.
4FB1
POP BC C1
Restore the primary BC register pair.
4FB2
POP DE D1
Restore the primary DE register pair.
4FB3
POP HL E1
Restore the primary HL register pair.
4FB4
EX AF,AF' 08
Switch to the alternate AF register set.
4FB5
EXX D9
Switch to the alternate register set (BC', DE', HL').
4FB6
POP AF F1
Restore the alternate AF' from the stack.
4FB7
POP BC C1
Restore the alternate BC'.
4FB8
POP DE D1
Restore the alternate DE'.
4FB9
POP HL E1
Restore the alternate HL'.
4FBA
EX AF,AF' 08
Switch back to the primary AF.
4FBB
EXX D9
Switch back to the primary register set.
4FBC
POP IX DD E1
Restore Register Pair IX.
4FBE
POP IY FD E1
Restore Register Pair IY.
4FC0
POP HL E1
Pop the saved stack pointer value into HL.
4FC1
LD SP,HL F9
Restore the user program's stack pointer from HL. The debugger's stack is abandoned and the user program's original stack is now active.
4FC2
LD HL,(407BH) 2A 7B 40
Load Register Pair HL with the saved program counter from 407BH. This is the address where execution will resume.
4FC5
PUSH HL E5
Push the resume address onto the user program's stack. This will be used by the RET instruction at 4FC9H to transfer control.
4FC6
LD HL,(406BH) 2A 6B 40
Load Register Pair HL with the saved HL value from the register save area at 406BH. This restores the final register (HL) to its pre-debug value.
4FC9
RET C9
Return to the address pushed at 4FC5H, which is the saved PC from 407BH. This transfers control back to the user program with all registers fully restored. If breakpoints were set, execution will continue until an RST 30H (F7H) byte is encountered, which will re-enter the debugger.
4FCAH - Insert Breakpoint
Saves the original byte at address (HL), writes the RST 30H opcode (F7H) in its place, and records the breakpoint address and saved byte in the breakpoint save area at (DE). Includes a write-verify check to ensure the F7H was successfully written (protecting against ROM or write-protected areas).
4FCA
LD A,(HL) 7E
Fetch the original byte at the breakpoint address (HL) into Register A. This byte will be saved so it can be restored when the breakpoint is removed.
4FCB
LD (DE),A 12
Store the original byte into the breakpoint save area at (DE).
4FCC
DEC DE 1B
DECrement DE to the next position in the save area (building the record backward).
4FCD
LD A,0F7H 3E F7
Load Register A with F7H, the RST 30H opcode. This is the breakpoint instruction that will be written to the target address.
4FCF
LD (HL),A 77
Write F7H (RST 30H) to the breakpoint address at (HL), replacing the original instruction byte.
4FD0
CP A,(HL) BE
Compare Register A (F7H) against the byte at (HL). This read-back verifies that the F7H was successfully written. If the address is in ROM or write-protected memory, the write would have failed and (HL) would still contain the original byte.
4FD1
If the verify failed (NZ FLAG, byte at (HL) does not equal F7H), JUMP to the breakpoint cleanup routine at 4E2FH. The breakpoint could not be set (address is in ROM or unwritable), so the debugger returns to the command loop instead of attempting to execute.
4FD4
LD A,H 7C
Copy the high byte of the breakpoint address from Register H into Register A.
4FD5
LD (DE),A 12
Store the high byte of the breakpoint address into the save area at (DE).
4FD6
DEC DE 1B
DECrement DE.
4FD7
LD A,L 7D
Copy the low byte of the breakpoint address from Register L into Register A.
4FD8
LD (DE),A 12
Store the low byte of the breakpoint address into the save area.
4FD9
DEC DE 1B
DECrement DE to position for the next breakpoint record (if any).
4FDA
RET C9
Return to the Go command handler.
4FDBH - Modify Memory (M Command)
Interactive memory editor. Reads a starting address from the keyboard, then enters a loop displaying the current byte at that address and accepting a new hex value. Pressing Enter without a value advances to the next byte. Pressing Enter at the address prompt returns to the command loop.
4FDB
LD HL,(4060H) 2A 60 40
Load Register Pair HL with the memory modify address from 4060H. This remembers the last-used modify address for convenience.
4FDE
GOSUB to the hex number input routine at 51A3H. If the user enters a hex address, HL is updated. If Enter is pressed with no input, HL retains the previous value.
4FE1
LD (4060H),HL 22 60 40
Store the (possibly updated) address back to the modify address variable at 4060H.
4FE4
RET C D8
If the CARRY FLAG is set (Enter was pressed at address prompt), return to the command loop.
4FE5
PUSH HL E5
Save the current modify address onto the stack.
4FE6
GOSUB to the register dump display at 4ECFH to refresh the screen with current register values and memory context.
4FE9
LD HL,3F40H 21 40 3F
Load HL with 3F40H, a position in the lower portion of video RAM for displaying the modify prompt.
4FEC
LD (4020H),HL 22 20 40
Set the cursor position to 3F40H for the modify display line.
4FEF
LD HL,(4060H) 2A 60 40
Reload the modify address from 4060H.
4FF2
GOSUB to display HL as a 4-digit hex address.
4FF5
PUSH HL E5
Save the modify address.
4FF6
LD HL,3F80H 21 80 3F
Load HL with 3F80H, a position on the next video line for the byte modification display.
4FF9
LD (4020H),HL 22 20 40
Set the cursor position to the byte display line.
4FFC
POP HL E1
Restore the modify address into HL.
4FFD
GOSUB to the display-byte-as-hex routine at 51D0H. This reads the byte at (HL) and displays it as 2 hex digits, then advances HL by 1.
5000
LD A,2DH 3E 2D
Load Register A with 2DH (ASCII '-'). This separator indicates where the user can type a new value.
5002
GOSUB to ROM 0033H to output the '-' separator.
5005
POP DE D1
Restore the original modify address into DE (saved at 4FE5H).
5006
GOSUB to read a hex value from the keyboard. If the user enters a value, HL holds it.
5009
EX DE,HL EB
Exchange DE and HL. HL now holds the original modify address, DE holds the entered value (if any).
500A
If no value was entered (Z FLAG, Enter pressed), JUMP to 500DH to skip the byte write and just advance the address.
500C
LD (HL),E 73
Store the low byte of the entered value (Register E) into memory at the modify address (HL). Only the low byte is written since this is a single-byte modify operation.
500D
RET C D8
If the CARRY FLAG is set (Enter terminated the input), return to the command loop.
500E
INC HL 23
INCrement HL to advance to the next memory address.
500F
LOOP BACK to 4FE1H to store the new address and continue the modify loop for the next byte.
5011H - Register Modify (R Command)
Reads a two-character register name from the keyboard, searches the register name table at 4F54H for a match, and if found, reads a new 16-bit hex value and stores it in the corresponding position in the register save area at 4065H. Supports an optional third character for the alternate register apostrophe.
5011
GOSUB to the keyboard input routine at 518AH. Read the first character of the register name.
5014
RET Z C8
If Enter was pressed (Z FLAG), return to the command loop without modifying any register.
5015
LD C,A 4F
Store the first character in Register C.
5016
Read the second character of the register name.
5019
RET Z C8
If Enter, return.
501A
LD D,A 57
Store the second character in Register D.
501B
LD E,20H 1E 20
Set Register E to 20H (space) as the default third character. Primary registers have a space separator; alternate registers have an apostrophe.
501D
Read an optional third character (space, apostrophe, or Enter).
5020
RET C D8
If CARRY is set (Enter), return without modification.
5021
If Z FLAG (Enter pressed), JUMP to 5029H to search with default space separator.
5023
LD E,A 5F
Store the third character (apostrophe for alternate registers) in Register E.
5024
Read one more character (should be Enter or comma to confirm).
5027
RET NZ C0
If not Enter (NZ), return (unexpected character, abort).
5028
RET C D8
If CARRY (Enter), return without modification.
Search Register Name Table
Search the 12 entries in the register name table at 4F54H for a match against the 3-character key (C, D, E). Each table entry is checked against the first 2 characters, and the third byte (space or apostrophe) is checked to distinguish primary from alternate registers.
5029
LD HL,4F54H 21 54 4F
Point Register Pair HL to the register name table at 4F54H.
502C
LD B,0CH 06 0C
Load Register B with 0CH (12 entries to search).
502E
LD A,(HL) 7E
Loop Start
Fetch the first character of the current table entry.
502F
CP A,C B9
Compare against the user's first character (Register C).
5030
If first character matches (Z), JUMP to 5038H to check the second character.
5032
INC HL 23
Skip to the next table entry (advance by 3 bytes total).
5033
INC HL 23
Second byte skip.
5034
INC HL 23
Third byte skip. HL now points to the next entry.
5035
DECrement B and loop. If all 12 entries checked with no match, fall through.
5037
RET C9
No matching register found. Return to the command loop without modification.
5038
INC HL 23
Advance past the first character to the second character of the table entry.
5039
LD A,(HL) 7E
Fetch the second character from the table entry.
503A
CP A,D BA
Compare against the user's second character (Register D).
503B
If second character does not match (NZ), JUMP to 5034H to skip to the next entry.
503D
INC HL 23
Advance to the third byte (space or apostrophe).
503E
LD A,(HL) 7E
Fetch the third byte.
503F
CP A,E BB
Compare against the user's third character (Register E, space or apostrophe).
5040
If third character does not match (NZ), JUMP to 5034H to try the next entry.
Register Found - Calculate Save Area Offset
The register name was found. Calculate the offset into the save area at 4065H based on the entry position in the table. Each table entry is 3 bytes, and each register value in the save area is 2 bytes, so the offset is (12 - B) * 2.
5042
LD A,18H 3E 18
Load Register A with 18H (24 decimal, which is 12 entries * 2 bytes).
5044
SUB A,B 90
SUBtract Register B (remaining count) from A. A = 24 - remaining_count.
5045
SUB A,B 90
SUBtract B again. A = 24 - 2*remaining_count. Since B counts down from 12, when the Nth entry (0-based) matches, B = 12-N, so A = 24 - 2*(12-N) = 2*N. This gives the byte offset into the 2-byte-per-entry save area.
5046
LD C,A 4F
Copy the offset into Register C.
5047
LD B,00H 06 00
Clear Register B. BC = offset as a 16-bit value.
5049
LD HL,4065H 21 65 40
Point HL to the start of the register save area.
504C
ADD HL,BC 09
ADD the offset to HL. HL now points to the specific register pair's saved value in the save area.
504D
PUSH HL E5
Save the save area pointer for later use.
504E
LD A,1EH 3E 1E
Load Register A with 1EH (cursor down control code on Model I). This moves the cursor down one line for the value entry prompt.
5050
GOSUB to ROM 0033H to output the cursor-down code.
5053
POP DE D1
Pop the save area pointer into DE (was saved at 504DH).
5054
GOSUB to read a new hex value from the keyboard.
5057
RET Z C8
If Enter was pressed with no value (Z), return without modifying the register.
5058
EX DE,HL EB
Exchange DE and HL. HL = save area pointer, DE = entered value.
5059
LD (HL),E 73
Store the low byte of the new value into the save area.
505A
INC HL 23
INCrement HL to the high byte position.
505B
LD (HL),D 72
Store the high byte of the new value into the save area.
505C
RET C9
Return to the command loop. The register will take effect when the Go command restores registers from the save area.
505DH - Instruction Decode (C/I Command)
Decodes and displays the Z80 instruction at the current saved PC address. Uses the opcode classification table at 50E0H-512EH to determine the instruction's length and addressing mode based on the first (and optionally second) opcode byte. Handles prefix bytes DDH (IX), FDH (IY), and EDH (extended instructions) by selecting different sub-tables within the classification data. The complete instruction decode system displays the instruction address, raw bytes, and formatted operands.
505D
PUSH AF F5
Save Register AF (containing the command character 'C' or 'I') onto the stack. The command character is checked later at 50AFH to determine whether this is a C (continue/step) or I (inspect only) invocation.
505E
LD DE,(407BH) ED 5B 7B 40
Load Register Pair DE with the saved program counter from 407BH. This is the address of the instruction to decode.
5062
LD A,(DE) 1A
Fetch the first opcode byte from the instruction at (DE) into Register A.
5063
LD HL,5115H 21 15 51
Point Register Pair HL to the DD/FD prefix classification sub-table at 5115H. This is the default table for IX/IY-prefixed instructions.
5066
CP A,0DDH FE DD
Compare Register A against DDH (IX prefix byte).
5068
If DDH prefix found (Z), JUMP to 5078H to read the next byte and classify using the DD/FD sub-table.
506A
CP A,0FDH FE FD
Compare Register A against FDH (IY prefix byte).
506C
If FDH prefix found (Z), JUMP to 5078H.
506E
LD HL,50E0H 21 E0 50
Point HL to the main (unprefixed) opcode classification table at 50E0H.
5071
CP A,0EDH FE ED
Compare Register A against EDH (extended instruction prefix).
5073
If NOT EDH (NZ), use the main table. JUMP to 507BH to begin classification.
5075
LD HL,510EH 21 0E 51
Point HL to the ED-prefix classification sub-table at 510EH.
5078
INC DE 13
INCrement DE to point to the second byte of the instruction (past the prefix byte).
5079
LD A,(DE) 1A
Fetch the second opcode byte from (DE) into Register A.
507A
DEC DE 1B
DECrement DE back to the start of the instruction (the prefix byte). DE still points to the full instruction start for length/display purposes.
Opcode Classification Loop
Search the selected classification table for an entry that matches the opcode byte. Each table entry is 3 bytes: a mask byte, a match byte, and a length/type byte. For each entry: (opcode AND mask) is compared against the match byte. If equal, the entry matches. The length/type byte encodes the instruction length in bits 0-3 and the operand display mode in bits 4-7.
507B
LD C,A 4F
Save the opcode byte in Register C for repeated comparison.
507C
LD A,(HL) 7E
Loop Start
Fetch the mask byte from the current table entry at (HL).
507D
AND A,C A1
AND the opcode (Register C) with the mask. This isolates the significant bits for comparison.
507E
INC HL 23
Advance HL to the match byte.
507F
CP A,(HL) BE
Compare the masked opcode against the match byte. If equal (Z), this table entry matches the instruction.
5080
INC HL 23
Advance HL to the length/type byte.
5081
If the entry matches (Z FLAG), JUMP to 5089H to extract the length and type information.
5083
INC HL 23
Skip past the length/type byte to the next table entry.
5084
LD A,(HL) 7E
Peek at the next mask byte. If it is less than 05H, this is a sentinel marking the end of the table.
5085
CP A,05H FE 05
Compare against 05H. Valid mask bytes are 05H or greater. Values below 05H serve as end-of-table markers or default entries.
5087
Loop End
If the next mask is >= 05H (NC FLAG), LOOP BACK to 507CH to check this entry. If < 05H, fall through to use the current byte as a default length/type.
5089
LD A,(HL) 7E
Fetch the length/type byte from the matched table entry (or default entry).
508A
LD B,A 47
Save the full length/type byte in Register B for later use. The high nibble (bits 4-7) encodes the operand display mode, and the low nibble (bits 0-3) encodes the total instruction length in bytes.
508B
AND A,0FH E6 0F
Mask to get the instruction length (bits 0-3) in Register A.
508D
LD L,A 6F
Copy the instruction length into Register L.
508E
LD H,00H 26 00
Clear Register H. HL = instruction length (1-4 bytes).
5090
ADD HL,DE 19
ADD DE (instruction start address) to HL (instruction length). HL now points to the byte AFTER the current instruction - the address of the next instruction.
5091
PUSH DE D5
Save the instruction start address.
5092
LD DE,4062H 11 62 40
Point DE to the breakpoint save area at 4062H.
5095
GOSUB to the breakpoint insertion routine at 4FCAH. This inserts an RST 30H (F7H) at the next instruction address (HL), creating a single-step breakpoint that will halt execution after the current instruction completes.
5098
POP HL E1
Restore the instruction start address into HL.
5099
LD A,B 78
Copy the length/type byte from Register B into Register A.
509A
AND A,0F0H E6 F0
Mask to get the operand display mode (bits 4-7) in the high nibble of A.
509C
If the display mode is 00H (no special operand display), JUMP to 50B4H to proceed to the register restoration and resume execution.
509E
INC HL 23
INCrement HL past the opcode byte to the first operand byte.
509F
CP A,20H FE 20
Compare the display mode against 20H. Mode 10H = immediate byte display. Mode 20H = immediate word or register display. Mode 30H-60H = other addressing modes.
50A1
If mode < 20H (i.e., mode 10H = immediate byte), JUMP to 50D8H to display the operand as a single byte from the saved HL register.
50A3
If mode = 20H (immediate word), JUMP to 50CCH to display the operand as a 16-bit value.
50A5
CP A,40H FE 40
Compare against 40H.
50A7
If mode < 40H (i.e., mode 30H = signed relative branch), JUMP to 50C0H to display the branch offset.
50A9
If mode = 40H (read from stack pointer area), JUMP to 50BAH.
50AB
CP A,60H FE 60
Compare against 60H.
50AD
If mode < 60H (i.e., mode 50H = read from saved SP area), JUMP to 50B7H.
50AF
POP AF F1
Restore the command character ('C' or 'I') from the stack (saved at 505DH).
50B0
CP A,49H FE 49
Compare against 49H (ASCII 'I'). If the command was 'I' (inspect only), do not resume execution.
50B2
If 'I' command (Z), JUMP to 50BAH to just display without stepping.
50B4
JUMP to the register restoration code at 4FA4H. This restores all registers and resumes execution at the saved PC. The single-step breakpoint at the next instruction will halt execution after one instruction.
50B7
LD HL,(4079H) 2A 79 40
Load HL with the saved stack pointer from 4079H. This addresses the user program's stack for reading stack-relative operands.
50BA
LD A,(HL) 7E
Fetch the low byte from the address in HL.
50BB
INC HL 23
INCrement HL.
50BC
LD H,(HL) 66
Fetch the high byte from the next address into H.
50BD
LD L,A 6F
Move the low byte into L. HL now holds the 16-bit value read from the operand location.
50BE
JUMP to 50DBH to store this address as a breakpoint target and continue execution.
50C0
LD C,(HL) 4E
Fetch the signed displacement byte from the instruction operand at (HL) into Register C.
50C1
XOR A,A AF
Clear Register A to 00H.
50C2
BIT 7,C CB 79
Test bit 7 of the displacement byte (sign bit). If set, the displacement is negative.
50C4
If the displacement is positive (bit 7 clear), JUMP to 50C7H.
50C6
CPL 2F
Complement Register A (00H becomes FFH). This sign-extends the negative displacement: B=FFH combined with the negative displacement in C gives the correct 16-bit signed offset.
50C7
LD B,A 47
Copy the sign extension byte into Register B. BC now holds the signed 16-bit displacement.
50C8
INC HL 23
INCrement HL past the displacement byte to point to the next instruction (the branch base address for relative offset calculation).
50C9
ADD HL,BC 09
ADD the signed displacement (BC) to the base address (HL). HL now holds the computed branch target address.
50CA
JUMP to 50DBH to use this computed address as the step-to breakpoint target.
50CC
LD HL,(4075H) 2A 75 40
Load HL with the saved IX register value from the save area at 4075H. This is the default for mode 20H.
50CF
BIT 5,C CB 69
Test bit 5 of the opcode byte (saved in Register C). This distinguishes between IX-indexed (bit 5 = 0) and IY-indexed (bit 5 = 1) instructions when used with DD/FD prefixes.
50D1
If bit 5 is clear (IX), JUMP to 50DBH with the IX value in HL.
50D3
LD HL,(4077H) 2A 77 40
Load HL with the saved IY register value from the save area at 4077H.
50D6
JUMP to 50DBH with the IY value in HL.
50D8
LD HL,(406BH) 2A 6B 40
Load HL with the saved HL register value from the save area at 406BH. This is used for mode 10H (display the value that HL points to).
50DB
GOSUB to the breakpoint insertion routine at 4FCAH. This inserts an RST 30H breakpoint at the computed target address in HL, providing a second breakpoint for branch instructions (the first breakpoint was placed at the sequential next instruction at 5095H).
50DE
JUMP to 50B4H to restore registers and resume execution. The user program will run until it hits either the sequential or branch-target breakpoint.
50E0H - Z80 Opcode Classification Table
Lookup table used by the instruction decoder at 505DH to classify Z80 opcodes. Each entry is 3 bytes: a mask, a match value, and a length/type byte. The decoder applies (opcode AND mask) == match to find the matching entry. The length/type byte encodes: bits 0-3 = total instruction length in bytes, bits 4-7 = operand display/addressing mode (00=none, 10=HL-indirect, 20=IX/IY, 30=relative branch, 40=stack-read, 50=SP-indirect, 60=execute/step). Three sub-tables exist: main table at 50E0H for unprefixed opcodes, ED-prefix table at 510EH, and DD/FD-prefix table at 5115H.
50E0-512EH
DEFB (opcode classification data, 79 bytes) C7 C0 51 FF C9 51 FF E9 11 CF 01 03 E7 22 03 C7 C2 43 FF C3 43 C7 C4 63 FF CD 63 C7 06 02 F7 D3 02 C7 C6 02 FF CB 02 F7 10 32 E7 20 32 01 C7 43 04 F7 45 52 02 FE 34 03 C0 40 03 FF 21 04 FF 22 04 FF 2A 04 FF 36 04 FF CB 04 FF E9 22 02 C5 3E 3D
Main opcode classification table (50E0H), ED-prefix table (510EH), and DD/FD-prefix table (5115H). Each 3-byte entry specifies mask, match, and length/type for a class of Z80 instructions. The table entries classify instructions into groups such as: single-byte instructions (length 1), 2-byte immediate instructions (length 2), 3-byte address instructions (length 3), relative branch instructions (length 2 + relative offset handling), and prefixed instructions (length 2-4 with IX/IY or ED prefix handling). The exact encoding of each entry requires cross-referencing against the Z80 instruction set architecture.
5131H - Memory Dump Line Display
Displays a line of hex dump: saves BC, prints "=>" separator, space, then 16 hex bytes from (HL) with ASCII character representation. After the hex bytes, displays the corresponding ASCII characters (replacing non-printable bytes with '.'). Advances HL by 16 bytes. Used by both the register dump (showing memory at register addresses) and the main memory dump display.
5131
PUSH BC C5
Save Register Pair BC (preserving the outer loop counter).
5132
LD A,3DH 3E 3D
Load Register A with 3DH (ASCII '=').
5134
GOSUB to ROM 0033H to output '='.
5137
LD A,3EH 3E 3E
Load Register A with 3EH (ASCII '>').
5139
GOSUB to ROM 0033H to output '>'.
513C
GOSUB to print a space.
513F
LD B,10H 06 10
Load Register B with 10H (16 decimal). Display 16 hex bytes per line.
5141
Loop Start
GOSUB to the byte display routine at 5165H. This reads a byte from (HL) via 51D0H, displaying it as 2 hex digits. It also checks if the current address matches the saved PC (4060H) and highlights it.
5144
LD A,(405DH) 3A 5D 40
Fetch the address mode variable from 405DH. If set to 'A' (41H), the display shows ASCII characters alongside the hex bytes.
5147
CP A,41H FE 41
Compare against 41H (ASCII 'A').
5149
If not 'A' mode (NZ), JUMP to 515EH to skip the ASCII character display for this byte.
514B
GOSUB to print a space before the ASCII character.
514E
LD A,(HL) 7E
Fetch the byte at the current memory address (HL).
514F
CP A,20H FE 20
Compare against 20H (space). If below 20H, the character is a control code and not printable.
5151
If A < 20H (CARRY set), JUMP to 5157H to substitute a dot.
5153
CP A,0C0H FE C0
Compare against C0H. Characters C0H and above are TRS-80 semigraphics blocks which could disrupt the display.
5155
If A < C0H (printable range 20H-BFH), JUMP to 5159H to display the character as-is.
5157
LD A,2EH 3E 2E
Load Register A with 2EH (ASCII '.'). This dot substitutes for non-printable characters in the ASCII column.
5159
GOSUB to ROM 0033H to output the ASCII character (or dot substitute).
515C
INC HL 23
INCrement HL to the next memory address.
515D
XOR A,A AF
Clear Register A (set to 00H). This resets the NZ flag so that the CALL NZ below is skipped on the next iteration's hex display.
515E
If NZ (not in ASCII mode, or first pass), GOSUB to the hex byte display at 51D0H. In non-ASCII mode, this displays the byte as hex.
5161
Loop End
DECrement Register B and loop back to 5141H. After 16 bytes displayed.
5163
POP BC C1
Restore the outer loop counter from the stack.
5164
RET C9
Return to the caller.
5165H - Byte Display With PC Highlight
Displays a single byte from memory at (HL) as hex, with special highlighting when the address matches the saved program counter at 4060H. The PC byte is displayed with a special marker character (95H = inverse block) instead of a leading space.
5165
LD DE,(4060H) ED 5B 60 40
Load DE with the current memory pointer from 4060H (used for PC tracking in the display).
5169
INC DE 13
INCrement DE (adjusting for the comparison offset).
516A
PUSH HL E5
Save HL (current display address).
516B
XOR A,A AF
Clear Register A and the carry flag for the subtraction.
516C
SBC HL,DE ED 52
SUBtract DE from HL to compare the addresses. If HL == DE, the result is zero.
516E
LD A,95H 3E 95
Load Register A with 95H (a TRS-80 inverse/highlighted block character). This will be used as the leading marker if this byte is at the PC address.
5170
If the addresses match (Z FLAG), JUMP to 5180H to display the PC marker and the byte.
5172
GOSUB to check if this is the 8th byte position (B=08H) for potential line formatting.
5175
INC HL 23
INCrement HL (restored below, this adjusts the comparison result).
5176
LD A,L 7D
Copy Register L into A.
5177
OR A,H B4
OR H into A. Tests if the incremented comparison result is zero.
5178
POP HL E1
Restore the original display address into HL.
5179
LD A,0AAH 3E AA
Load A with AAH (a TRS-80 specific character used as a secondary marker).
517B
If the previous comparison was zero (Z), output the marker character and return.
517E
JUMP to 5188H to output a regular space and continue.
5180
Output the PC marker character (95H) that was loaded at 516EH.
5183
POP HL E1
Restore the display address into HL.
5184
LD A,B 78
Copy the byte counter from Register B into A.
5185
CP A,08H FE 08
Compare against 08H (the 8th byte in a 16-byte line). This creates a visual gap in the middle of the hex dump line.
5187
RET NZ C0
If not at the 8th position (NZ), return normally.
5188
JUMP to the print-space routine at 51F2H. This adds an extra space at the midpoint of the hex dump line for visual separation, or outputs a regular space separator.
518AH - Keyboard Input With Echo
Reads a single character from the keyboard using ROM 0049H (non-blocking scan), waiting in a loop until a key is pressed. Printable characters (20H and above) are echoed to the screen. Returns with A=character, Z FLAG set if Enter (0DH), CARRY set if Enter with comma or space preceding.
518A
PUSH DE D5
Save Register Pair DE.
518B
Loop Start
GOSUB to the ROM keyboard scan routine at 0049H. Returns A=character if a key is pressed, A=00H if no key.
518E
CP A,0DH FE 0D
Compare against 0DH (Enter key).
5190
If Enter (Z), JUMP to 51A0H to set carry and return.
5192
CP A,20H FE 20
Compare against 20H (space). Characters below 20H are control codes and are not echoed.
5194
If A < 20H (CARRY set, control character that is not Enter), loop back to scan again. Control keys other than Enter are ignored.
5196
GOSUB to ROM 0033H to echo the printable character on screen.
5199
POP DE D1
Restore Register Pair DE.
519A
CP A,2CH FE 2C
Compare A against 2CH (comma). Comma serves as a field separator in some debug commands.
519C
RET Z C8
If comma (Z), return. The Z FLAG indicates a field separator was entered.
519D
CP A,20H FE 20
Compare A against 20H (space). Space also serves as a field separator.
519F
RET C9
Return. Z FLAG is set if the character was a space (acting as separator). NZ and no CARRY for normal printable characters.
51A0
POP DE D1
Restore Register Pair DE.
51A1
SCF 37
Set the CARRY FLAG to indicate that Enter was pressed.
51A2
RET C9
Return with CARRY set (Enter), A=0DH.
51A3H - Read Hexadecimal Number
Reads hex digits from the keyboard and builds a 16-bit value in HL. Each digit shifts HL left by 4 bits and ORs in the new digit value. Continues reading until a non-hex character is entered. Returns Z FLAG if Enter pressed with no digits, CARRY if Enter pressed, NZ with value in HL if valid hex entered.
51A3
GOSUB to read a character from the keyboard.
51A6
RET Z C8
If the first character is a separator (Z FLAG from comma/space), return with Z=no value.
51A7
LD HL,0000H 21 00 00
Initialize HL to 0000H. This is the accumulator for the hex value being built.
51AA
Loop Start
GOSUB to the hex digit converter at 51BFH. Converts the ASCII hex character in A to a binary value 0-15. Sets CARRY if the character is not a valid hex digit.
51AD
If CARRY is set (invalid hex digit), JUMP to the command loop at 4E4BH. This aborts the hex input and returns to the debugger prompt.
51B0
ADD HL,HL 29
Shift HL left by 1 bit (multiply by 2).
51B1
ADD HL,HL 29
Shift HL left again (total x4).
51B2
ADD HL,HL 29
Shift HL left again (total x8).
51B3
ADD HL,HL 29
Shift HL left again (total x16). HL has been shifted left by 4 bits, making room for the new hex digit in the low nibble.
51B4
OR A,L B5
OR the hex digit value (0-15 in A) with Register L. This inserts the new digit into the low nibble of L.
51B5
LD L,A 6F
Store the updated low byte back into Register L.
51B6
GOSUB to read the next character from the keyboard.
51B9
Loop End
If the character is not a separator (NZ), LOOP BACK to 51AAH to convert and add the next hex digit.
51BB
RRA 1F
Rotate A right. This shifts bit 0 into CARRY. Since A=0DH (Enter) or 20H/2CH (separator), this sets specific carry states.
51BC
ADC A,81H CE 81
ADD 81H plus CARRY to A. This arithmetic operation sets the flags to produce: NZ (a value was entered) and CARRY if Enter was the terminator. The specific result depends on whether the terminator was Enter (0DH), comma (2CH), or space (20H).
51BE
RET C9
Return with: HL = hex value entered, NZ = value is valid, CARRY = Enter was pressed (no more input expected).
51BFH - Hex Digit Converter
Converts an ASCII hex digit character in Register A to its binary value (0-15). Returns with A = digit value (0-15) and CARRY clear if valid, or CARRY set if the character is not a hex digit (0-9, A-F).
51BF
SUB A,30H D6 30
SUBtract 30H (ASCII '0') from A. If A was '0'-'9', result is 0-9. If A was below '0', CARRY is set.
51C1
RET C D8
If CARRY (A was below '0'), return with CARRY set indicating invalid digit.
51C2
ADD A,0E9H C6 E9
ADD E9H to A. For digits 0-9, this produces: E9H-F2H (no carry). For 'A'-'F' (after -30H = 11H-16H), this produces: FAH-FFH then wraps. This step checks if the value exceeds 9.
51C4
RET C D8
If CARRY (value was in the gap between '9'+1 and 'A'-1), return invalid.
51C5
ADD A,06H C6 06
ADD 06H. For digits 0-9, this restores the original 0-9 range. For letters A-F, this adjusts the value.
51C7
If CARRY (digit was 0-9 range), JUMP to 51CCH to finalize.
51C9
ADD A,07H C6 07
ADD 07H for hex letter adjustment. This converts 'A'-'F' (after the subtractions) to the values 10-15.
51CB
RET C D8
If CARRY (character was above 'F'), return invalid.
51CC
ADD A,0AH C6 0A
ADD 0AH to finalize the digit value. For '0'-'9', A is now 0-9. For 'A'-'F', A is now 10-15.
51CE
OR A,A B7
Clear the CARRY FLAG (the digit is valid) by ORing A with itself. The NZ flag is also set since valid digits produce non-zero intermediate results (except for digit 0, but OR A,A handles flags correctly).
51CF
RET C9
Return with A = binary digit value (0-15), CARRY clear (valid hex digit).
51D0H - Display Byte From Memory as Hex
Reads a byte from (HL), displays it as 2 hex digits, and increments HL.
51D0
LD A,(HL) 7E
Fetch the byte at (HL) into Register A.
51D1
INC HL 23
INCrement HL to the next address.
51D2
JUMP to the hex byte output routine at 51D9H to display A as 2 hex digits.
51D4H - Display HL as 4-Digit Hexadecimal
Outputs the 16-bit value in HL as 4 hex digits (H byte first, then L byte).
51D4
LD A,H 7C
Copy Register H into A for hex display.
51D5
GOSUB to display the high byte as 2 hex digits.
51D8
LD A,L 7D
Copy Register L into A for hex display. Falls through to 51D9H.
51D9H - Hex Byte Output
Converts a byte in Register A to two hexadecimal ASCII characters and outputs them via ROM 0033H. High nibble first, then low nibble. Uses the standard hex conversion algorithm: nibble + 30H, adjust by +7 if >= 3AH.
51D9
PUSH AF F5
Save the full byte for later processing of the low nibble.
51DA
RRA 1F
Rotate A right through carry (shift high nibble toward low nibble).
51DB
RRA 1F
Second rotation.
51DC
RRA 1F
Third rotation.
51DD
RRA 1F
Fourth rotation. The high nibble is now in bits 0-3.
51DE
GOSUB to the nibble-to-ASCII converter at 51E2H to output the high nibble as a hex character.
51E1
POP AF F1
Restore the original byte. The low nibble will be processed by falling through to 51E2H.
51E2
AND A,0FH E6 0F
Mask to keep only the low nibble (bits 0-3).
51E4
ADD A,30H C6 30
ADD 30H to convert to ASCII. Values 0-9 become '0'-'9' (30H-39H).
51E6
CP A,3AH FE 3A
Compare against 3AH. If A >= 3AH, the digit is A-F and needs letter adjustment.
51E8
If A < 3AH (digit 0-9), JUMP to 51ECH to output as-is.
51EA
ADD A,07H C6 07
ADD 07H to adjust from ':'-'?' range to 'A'-'F' range.
51EC
JUMP to ROM 0033H to output the hex character. Returns to the caller of this routine.
51EFH - Hex Byte Output With Trailing Space
Outputs a byte as 2 hex digits followed by a space. Used in the register dump display.
51EF
GOSUB to the hex byte output routine to display A as 2 hex digits. Falls through to 51F2H to print a trailing space.
51F2H - Print Space
Outputs a single ASCII space character (20H) via ROM 0033H.
51F2
LD A,20H 3E 20
Load Register A with 20H (ASCII space).
51F4
JUMP to 51ECH (JP 0033H) to output the space character.
51F6H - Print Two Characters From Table
Reads and prints two consecutive bytes from the address in HL, advancing HL by 2. Used by the register dump display to output register pair names from the name table.
51F6
GOSUB to read and print one character from (HL), advancing HL by 1.
51F9
GOSUB to read and print a second character from (HL), advancing HL by 1.
51FCH - Print Character From Table
Reads a single byte from (HL), increments HL, and outputs the byte as a character via ROM 0033H.
51FC
LD A,(HL) 7E
Fetch the byte at (HL) into Register A.
51FD
INC HL 23
INCrement HL to the next byte.
51FE
JUMP to 51ECH (JP 0033H) to output the character and return to the caller.