4D00H - DEBUG Entry Point: Save CPU State
This is the entry point for the DEBUG overlay. When a breakpoint (RST 30H / F7H) is hit, execution transfers here. The first task is to save the complete CPU state so it can be displayed and later restored. The calling mechanism places the return address on the stack; the EX (SP),HL at 4D00H swaps HL with this return address, effectively saving HL while capturing the PC. All registers are then pushed in a specific order so they can be accessed by offset later.
4D00
EX (SP),HL E3
Exchange HL with the value on top of the stack. The top of the stack contains the return address (the Program Counter at the point of interruption). After this instruction, HL holds the saved PC value, and the original HL value is now on the stack in its place.
4D01
PUSH BC C5
Save Register Pair BC onto the stack.
4D02
PUSH DE D5
Save Register Pair DE onto the stack.
4D03
EX AF,AF' 08
Exchange AF with the alternate AF' register pair. This brings AF' into the active position so it can be saved next, while preserving the main AF in the alternate slot.
4D04
EXX D9
Exchange BC, DE, HL with their alternate counterparts BC', DE', HL'. After this, the alternate registers are in the active position for saving, and the main registers (already pushed to the stack) are safe in the alternate slots.
4D05
PUSH AF F5
Save the alternate AF' (now in active position) onto the stack.
4D06
PUSH BC C5
Save the alternate BC' (now in active position) onto the stack.
4D07
PUSH DE D5
Save the alternate DE' (now in active position) onto the stack.
4D08
PUSH HL E5
Save the alternate HL' (now in active position) onto the stack.
4D09
PUSH IX DD E5
Save Index Register IX onto the stack.
4D0B
PUSH IY FD E5
Save Index Register IY onto the stack.
At this point the stack contains (from top to bottom): IY, IX, HL', DE', BC', AF', and then below that: DE(main), BC(main), HL(main, which holds the saved PC), AF(main). The SP now points to the IY value. We save this stack pointer so we can access any register by offset later.
4D0D
LD (4D44H),SP ED 73 44 4D
Store the current Stack Pointer value into memory at 4D44H. [SELF-MODIFYING CODE] This writes the SP value into the operand of the LD SP,nnnn instruction at 4D43H. This saved SP is the base address from which all register values can be accessed by offset. It also enables restoring SP when DEBUG exits.
Now we need to retrieve the saved Program Counter from the stack. The stack layout from SP upward is: IY(2), IX(2), HL'(2), DE'(2), BC'(2), AF'(2), DE(2), BC(2), HL_saved_PC(2), AF(2). The saved PC (original HL, which was swapped with the return address) is at SP+14H (20 bytes up). We calculate this offset to extract the PC value.
4D11
LD HL,0014H 21 14 00
Load HL with 0014H (20 decimal) - the offset from the current SP to where the saved Program Counter (original return address) is stored on the stack.
4D14
ADD HL,SP 39
ADD SP to HL. HL now points to the stack location containing the saved PC value (the return address that was on the stack when DEBUG was entered).
4D15
LD E,(HL) 5E
Fetch the low byte of the saved Program Counter from the stack into Register E.
4D16
INC HL 23
INCrement HL to point to the high byte.
4D17
LD D,(HL) 56
Fetch the high byte of the saved Program Counter from the stack into Register D. DE now holds the complete saved PC address.
4D18
LD (4DC7H),DE ED 53 C7 4D
Store the saved Program Counter (DE) into memory at 4DC7H. [SELF-MODIFYING CODE] This writes the PC value into the operand of the LD HL,nnnn instruction at 4DC6H, and also serves as the primary PC storage location referenced by the G and Step commands.
The return address on the stack points one byte PAST the F7H (RST 30H) trap opcode. We need to save the address of the stack slot itself (SP+15H, pointing above the PC high byte) so we can modify the return address later when the user changes PC. We also decrement DE to get the actual address of the trap instruction (one byte back from the return address).
4D1C
INC HL 23
INCrement HL to point past the saved PC on the stack. HL now points to the stack location just above the PC, which is the slot for the saved AF (main flags).
4D1D
DEC DE 1B
DECrement DE by 1. Since the return address points to the byte AFTER the RST 30H trap instruction, decrementing gives the actual address of the trap opcode itself.
4D1E
PUSH DE D5
Save the adjusted trap address (pointing to the actual F7H opcode) onto the stack. This will be used later when restoring the original byte at the trap location.
4D1F
LD (4DC3H),HL 22 C3 4D
Store HL (pointer to the AF slot on the stack) into memory at 4DC3H. [SELF-MODIFYING CODE] This writes into the operand of the LD SP,nnnn instruction at 4DC2H, and is also used by the instruction decoder's RET handler (at 51C8H) to find the return address on the saved stack.
Now we call the SYS0 overlay setup routine to initialize the DEBUG workspace. B=80H is the parameter for this initialization.
4D22
LD B,80H 06 80
Load Register B with 80H - parameter for the overlay setup routine at 4C92H.
4D24
GOSUB to SYS0 routine at 4C92H to initialize the overlay environment with parameter B=80H. This sets up the stack and workspace for the DEBUG overlay.
4D27H - Restore Trap Address Contents
After saving the CPU state, DEBUG must restore the original bytes at both trap addresses. When a trap was set, the original byte at the trap address was replaced with F7H (RST 30H). Now that we have entered DEBUG, those original bytes must be put back so that: (1) the memory display shows the actual code, and (2) if the user single-steps through the trap location, the real instruction executes. The trap table at 4052H contains two 3-byte entries: [address_low, address_high, saved_byte]. The loop processes both entries.
4D27
LD HL,4052H 21 52 40
Point HL to 4052H - the start of the trap address table in the DOS workspace. This table has two 3-byte entries: each entry holds a 2-byte address followed by the 1-byte original opcode that was replaced by F7H (RST 30H).
4D2A
LD B,02H 06 02
Load Register B with 02H - loop counter for processing both trap table entries.
[LOOP START] - Process each trap table entry. For each entry: read the 2-byte trap address into DE, check if the byte at that address is still F7H (the trap opcode), and if so, restore the original byte from the table.
4D2C
LD E,(HL) 5E
Fetch the low byte of the trap address from the table entry into Register E.
4D2D
INC HL 23
INCrement HL to point to the high byte of the trap address.
4D2E
LD D,(HL) 56
Fetch the high byte of the trap address into Register D. DE now holds the complete trap address.
4D2F
INC HL 23
INCrement HL to point to the saved original byte in the table entry.
4D30
LD A,(DE) 1A
Fetch the byte currently at the trap address (pointed to by DE) into Register A. If the trap is active, this byte will be F7H (RST 30H).
4D31
CP F7H FE F7
Compare Register A against F7H (the RST 30H opcode used as the trap marker). If Register A equals F7H, the Z FLAG is set, meaning the trap is still active and needs to be restored.
4D33
If the NZ FLAG (Not Zero) has been set (the byte at the trap address is NOT F7H, meaning the trap is not active or has already been restored), JUMP to 4D40H to skip restoration and advance to the next entry.
4D35
LD A,(HL) 7E
Fetch the saved original byte from the trap table entry into Register A. This is the byte that was at the trap address before F7H was written there.
4D36
LD (DE),A 12
Store the original byte (Register A) back to the trap address (DE), restoring the original instruction that was replaced by the F7H trap.
After restoring the original byte, we need to check if this trap address matches the current PC. If the trap was at the exact location where execution was interrupted, then the saved PC (4DC7H) should be updated to point to this address (since the PC was pointing one byte past the F7H).
4D37
EX (SP),HL E3
Exchange HL with the top of stack. HL now holds the adjusted trap address (pushed at 4D1EH), and the trap table pointer is saved on the stack.
4D38
RST 18H DF
Execute RST 18H - this is the BASIC compare routine (at ROM 0018H) which compares HL against DE. If HL equals DE (trap address matches the address we just restored), the Z FLAG is set.
4D39
EX (SP),HL E3
Exchange HL with top of stack again, restoring the trap table pointer to HL and putting the trap address back on the stack.
4D3A
If the NZ FLAG has been set (the trap address does NOT match the current PC), JUMP to 4D40H to skip the PC update.
4D3C
LD (4DC7H),DE ED 53 C7 4D
Store DE (the trap address) into the saved Program Counter at 4DC7H. This corrects the PC to point to the actual trap location rather than one byte past it, since the RST 30H instruction was at this exact address.
4D40
INC HL 23
INCrement HL to advance past the current trap table entry and point to the start of the next entry.
4D41
DECrement B and loop back to 4D2CH if not zero. This processes the second trap table entry. [LOOP END]
4D43H - Command Loop: Stack Reset and Prompt
This is the main command loop restart point. The LD SP instruction at 4D43H is self-modifying: its operand at 4D44H was written with the saved stack pointer during entry. Every time a command completes (or an error occurs), execution jumps back here to reset the stack and redisplay the prompt. After resetting SP, the saved PC is pushed onto the stack as a return address, then the prompt display routine is called, and user input is accepted.
4D43
LD SP,0000H 31 00 00
[SELF-MODIFYING CODE] Load SP with the value at 4D44H-4D45H. The operand 0000H is overwritten at runtime by the LD (4D44H),SP instruction at 4D0DH. This restores the stack pointer to its saved value, giving DEBUG access to all the saved register values on the stack.
Now push the saved PC address onto the stack as a "safety net" return address. Then call the prompt display routine and accept user input.
4D46
LD HL,4D43H 21 43 4D
Load HL with 4D43H - the address of this command loop restart point itself. This will be pushed as a return address so that if a command returns without jumping somewhere specific, execution returns here.
4D49
PUSH HL E5
Save 4D43H onto the stack as a return address. This means a simple RET from any command handler will restart the command loop.
4D4A
GOSUB to 4FC7H to display the DEBUG prompt. This routine clears the screen, shows the prompt string with SZ-H-PNC flag indicators, and displays either a full register dump or compact memory dump depending on the display mode flag at 42C4H.
4D4D
LD HL,3FC0H 21 C0 3F
Load HL with 3FC0H - the start of the bottom line of the video display (row 15, column 0). This is where the command input line will appear.
4D50
LD (4020H),HL 22 20 40
Store HL (3FC0H) into the cursor position pointer at 4020H. This positions the cursor at the beginning of the bottom screen line for user input.
4D53
LD HL,51ECH 21 EC 51
Load HL with 51ECH - the address of the input buffer where the user's command will be stored. This buffer is within the search pattern area (51E8H-51FFH) at an offset of 4 bytes.
4D56
LD B,12H 06 12
Load Register B with 12H (18 decimal) - the maximum number of characters the user can type for a DEBUG command.
4D58
GOSUB to ROM routine at 0040H for line input. B = 12H (max 18 chars), HL = 51ECH (buffer address). The user types a DEBUG command at the bottom of the screen. On return, HL points to the start of the entered text.
After the user enters a command, we check if the first character is a drive number ('2' or '3' in ASCII, which is 32H or 33H). If so, it selects a different FCB entry in the trap table. The default FCB pointer is at 404CH; drives 2 and 3 offset this by 2 or 4 bytes respectively.
4D5B
LD DE,404CH 11 4C 40
Load DE with 404CH - the base address for the FCB pointer. This is the default pointer used for disk operations (Load and Write commands).
4D5E
LD A,(HL) 7E
Fetch the first character of the user's input from the buffer into Register A.
4D5F
SUB 32H D6 32
SUBtract 32H (ASCII 2) from Register A. If the character was '2', A becomes 0; if '3', A becomes 1. This converts drive numbers '2' and '3' to offsets 0 and 1.
4D61
CP 02H FE 02
Compare Register A against 02H. If A is less than 02H (meaning the original character was '2' or '3'), the CARRY FLAG is set. If A >= 02H, NO CARRY is set.
4D63
If the NO CARRY FLAG has been set (the first character was NOT a drive number '2' or '3'), JUMP to 4D6AH to skip drive selection and use the default FCB pointer.
4D65
INC A 3C
INCrement A by 1. A was 0 (for '2') or 1 (for '3'), so now A is 1 or 2.
4D66
ADD A,A 87
Double A. A becomes 2 (for drive '2') or 4 (for drive '3'). This calculates the byte offset into the FCB pointer table, since each FCB pointer entry is 2 bytes.
4D67
ADD A,E 83
ADD E (4CH, the low byte of the base address 404CH) to Register A. This adds the offset to the base, selecting the correct FCB pointer entry.
4D68
LD E,A 5F
Store the adjusted low byte back into Register E. DE now points to the selected FCB pointer (404CH, 404EH, or 4050H depending on drive).
4D69
INC HL 23
INCrement HL to skip past the drive number character and point to the actual command letter.
4D6A
LD (4EBDH),DE ED 53 BD 4E
Store DE (the selected FCB pointer address) into 4EBDH. This saves the FCB pointer for use by the L (Load) and WR (Write) commands later.
Now convert the entire input buffer to uppercase. The loop processes each character from the current position, calling the SYS0 uppercase conversion routine.
4D6E
PUSH HL E5
Save HL (pointer to the start of the command text after any drive number) onto the stack.
4D6F
INC B 04
INCrement B. B was left over from the ROM input call; incrementing it prepares the loop counter for the uppercase conversion. The exact count depends on the input length, but this ensures at least one iteration.
4D70
LD A,(HL) 7E
[LOOP START] Fetch the current character from the input buffer into Register A.
4D71
GOSUB to SYS0 routine at 4548H to convert lowercase to uppercase. If A is 61H-7AH (a-z), it is converted to 41H-5AH (A-Z); otherwise A is unchanged.
4D74
LD (HL),A 77
Store the uppercased character back into the input buffer, replacing the original.
4D75
INC HL 23
INCrement HL to advance to the next character in the input buffer.
4D76
DECrement B and loop back to 4D70H if not zero. Continues converting characters to uppercase until B reaches 0. [LOOP END]
4D78
POP HL E1
Restore HL from the stack. HL again points to the start of the command text (first character after any drive number).
Now dispatch to the appropriate command handler based on the first character of the input.
4D79
LD A,(HL) 7E
Fetch the first command character from the input buffer into Register A.
4D7A
CP 47H FE 47
Compare Register A against 47H (ASCII G). If A equals 47H, the Z FLAG is set.
4D7C
If the NZ FLAG (Not Zero) has been set (command is NOT G), JUMP to 4DCDH to check for the next command letter (R).
4D7EH - G (Go) Command Handler
The G (Go) command resumes execution of the program being debugged. The syntax is: G[addr][,trap1][,trap2]. If an address is specified, it becomes the new PC. Up to two optional trap addresses can be specified (separated by commas); at each trap address, the original byte is replaced with F7H (RST 30H) so that execution will re-enter DEBUG when that address is reached. After setting traps, the code falls through to the exit routine which restores all registers and jumps to the program.
4D7E
GOSUB to 509BH to check if the next character after G is a hex digit. This routine advances HL and tests the character; if valid hex, Carry is set and A contains the digit value.
4D81
If the NO CARRY FLAG has been set (next character is NOT a hex digit, meaning no address was specified), JUMP to 4D8AH to skip address parsing and use the current saved PC.
4D83
GOSUB to 5079H to parse a 16-bit hexadecimal number from the input buffer. The first hex digit was already validated; this routine accumulates all subsequent hex digits. Returns the parsed address in DE.
4D86
LD (4DC7H),DE ED 53 C7 4D
Store the parsed address (DE) into the saved Program Counter at 4DC7H. This sets the new execution address where the program will resume.
4D8A
LD B,02H 06 02
Load Register B with 02H - loop counter for processing up to two trap addresses.
4D8C
LD D,00H 16 00
[LOOP START] Load Register D with 00H. D will accumulate the high byte of the trap address (initialized to 0 for the "no trap" default).
4D8E
LD A,(HL) 7E
Fetch the current character from the input buffer into Register A.
4D8F
CP 2CH FE 2C
Compare Register A against 2CH (ASCII , comma). If A equals 2CH, the Z FLAG is set, indicating a trap address follows.
4D91
If the NZ FLAG has been set (character is NOT a comma), JUMP to 4D9BH to push the default (no trap) value and continue.
4D93
GOSUB to 5078H to skip the comma and parse the hex trap address. Returns the parsed address in DE.
4D96
LD A,D 7A
Load Register A with D (the high byte of the parsed trap address).
4D97
CP 52H FE 52
Compare Register A against 52H. Addresses below 5200H are in the overlay area or ROM; addresses at or above 5200H are in the user's program space. If A < 52H, CARRY is set, indicating the trap address is below the overlay and therefore invalid (would trap inside DEBUG itself).
4D99
If the CARRY FLAG has been set (trap address is below 5200H, which is within the overlay area), JUMP to 4DE9H which jumps to the ERROR handler at 50B9H.
4D9B
PUSH DE D5
Save DE (the trap address, or 00xxH if no trap was specified) onto the stack for later processing.
4D9C
DECrement B and loop back to 4D8CH if not zero. Processes the second trap address parameter. [LOOP END]
Both trap addresses have been parsed and pushed onto the stack. Now call the routine that writes F7H (RST 30H) to each trap address after saving the original byte.
4D9E
GOSUB to 50B5H to verify the input line ends with ENTER (0DH). If not, the command has trailing garbage and the ERROR handler is called.
4DA1H - Set Traps and Prepare for Exit
This routine pops the two trap addresses from the stack, stores them into the trap table at 4052H, saves the original bytes at those addresses, and writes F7H (RST 30H) in their place. This is called both by the G (Go) command and by the single-step logic when setting the next-instruction trap.
4DA1
LD HL,4052H 21 52 40
Point HL to 4052H - the start of the trap address table.
4DA4
LD B,02H 06 02
Load Register B with 02H - loop counter for two trap entries.
[LOOP START] - For each trap address on the stack: pop it, store the address and original byte in the table, then write F7H to the trap location.
4DA6
POP DE D1
Pop a trap address from the stack into DE. The first POP gets the second trap address (LIFO order); the second POP gets the first.
4DA7
LD (HL),E 73
Store the low byte of the trap address into the trap table entry.
4DA8
INC HL 23
INCrement HL to point to the high byte position in the table.
4DA9
LD (HL),D 72
Store the high byte of the trap address into the trap table entry.
4DAA
INC HL 23
INCrement HL to point to the saved-byte position in the table.
4DAB
LD A,(DE) 1A
Fetch the current byte at the trap address (DE) into Register A. This is the original instruction byte that will be saved before being replaced with F7H.
4DAC
LD (HL),A 77
Store the original byte into the trap table entry's saved-byte position.
4DAD
INC HL 23
INCrement HL to advance to the next trap table entry.
4DAE
LD A,F7H 3E F7
Load Register A with F7H - the RST 30H opcode that serves as the trap/breakpoint marker.
4DB0
LD (DE),A 12
Store F7H (RST 30H) at the trap address (DE), replacing the original instruction byte. When the program executes this address, the RST 30H will transfer control back to DEBUG.
4DB1
DECrement B and loop back to 4DA6H if not zero. Processes the second trap entry. [LOOP END]
4DB3H - DEBUG Exit: Restore All Registers
This routine restores the complete CPU state from the stack and returns execution to the debugged program. The registers are popped in reverse order from how they were pushed during entry. After restoration, the self-modifying LD SP at 4DC2H sets SP to point above the saved PC on the stack, and the LD HL at 4DC6H loads the saved PC. The EX (SP),HL swaps the PC onto the stack as a return address, and the JP to 4BC5H (overlay return) completes the exit.
4DB3
POP AF F1
Restore the alternate AF' from the stack (this was the first alternate register pushed, so it is popped last among the alternates group, but first here because we pop in reverse of the exit sequence).
4DB4
POP IY FD E1
Restore Index Register IY from the stack.
4DB6
POP IX DD E1
Restore Index Register IX from the stack.
4DB8
POP HL E1
Restore the alternate HL' from the stack.
4DB9
POP DE D1
Restore the alternate DE' from the stack.
4DBA
POP BC C1
Restore the alternate BC' from the stack.
4DBB
POP AF F1
Pop the saved AF' value (this was pushed as AF after the EX AF,AF' and EXX at entry). This restores the alternate flags.
4DBC
EX AF,AF' 08
Exchange AF with AF'. This moves the just-restored alternate AF back to the alternate slot, and brings the main AF (which was in the alternate slot) back to the active position.
4DBD
EXX D9
Exchange BC, DE, HL with their alternates. The alternate registers are now restored to their original positions, and the main registers are active again.
4DBE
POP DE D1
Restore Register Pair DE (main) from the stack.
4DBF
POP BC C1
Restore Register Pair BC (main) from the stack.
4DC0
POP HL E1
Pop the value at the stack position where HL was saved. Note: at entry, HL was swapped with the return address via EX (SP),HL, so this position holds the original HL value before the swap.
4DC1
POP AF F1
Restore Register Pair AF (main flags and accumulator) from the stack.
All registers have been popped. Now the self-modifying instructions set up for the final return. The LD SP at 4DC2H resets the stack to point to where the return address should be. The LD HL at 4DC6H loads the saved PC.
4DC2
LD SP,0000H 31 00 00
[SELF-MODIFYING CODE] Load SP with the value stored at 4DC3H-4DC4H. This was written during entry at 4D1FH to point to the AF slot on the saved stack (above the PC). This positions SP correctly for the return.
4DC5
PUSH HL E5
Save HL (which holds the restored original HL from the debugged program) onto the stack temporarily.
4DC6
LD HL,0000H 21 00 00
[SELF-MODIFYING CODE] Load HL with the value stored at 4DC7H-4DC8H - the saved Program Counter. This is the address where execution will resume in the debugged program.
4DC9
EX (SP),HL E3
Exchange HL with the top of the stack. The saved PC goes onto the stack (as the return address), and the original HL value is restored to HL. Now the stack has the correct return address on top.
4DCA
JUMP to 4BC5H - the SYS0 overlay return handler. This completes the return to the debugged program. The RET within 4BC5H will pop the saved PC from the stack and resume execution at the debugged program's address.
4DCDH - R (Register) Command Handler
The R (Register) command displays or modifies register values. Syntax: R[name][,value]. If just R is entered followed by ENTER, the display is refreshed. If a register name follows (e.g., RAF, RBC, RHL'), the command parses the name by comparing against a lookup table at 50DBH. Each table entry contains a 2-character register name, a stack offset byte, and a format byte. If a comma and hex value follow the name, the register is set to the new value.
4DCD
CP 52H FE 52
Compare Register A against 52H (ASCII R). If A equals 52H, the Z FLAG is set.
4DCF
If the NZ FLAG has been set (command is NOT R), JUMP to 4E03H to check for the F (Find) command.
4DD1
LD DE,50DBH 11 DB 50
Point DE to 50DBH - the start of the register name lookup table. This table contains entries in the format: [char1][char2][offset+flags][next_entry_offset], with a 00H terminator at the end of each group.
4DD4
LD B,03H 06 03
[OUTER LOOP START] Load Register B with 03H - the number of characters to compare for each register name entry (the table stores 2 name chars + 1 offset byte per entry; B=3 controls the comparison loop).
4DD6
PUSH HL E5
Save HL (pointer to the user's input after the R) onto the stack.
4DD7
INC HL 23
[INNER LOOP START] INCrement HL to advance to the next character in the user's input.
4DD8
LD A,(DE) 1A
Fetch the current byte from the register name table into Register A.
4DD9
CP (HL) BE
Compare the table byte (A) against the user's input character at (HL). If they match, the Z FLAG is set.
4DDA
INC DE 13
INCrement DE to advance to the next byte in the table.
4DDB
If the Z FLAG has been set (characters match), JUMP to 4DECH to continue comparing the next character in this entry.
Characters did not match. Check if the table character was a space (20H), which acts as a wildcard/skip marker for shorter register names (e.g., single-character abbreviations).
4DDD
CP 20H FE 20
Compare Register A (the table byte that didn't match) against 20H (ASCII space). If A equals 20H, the Z FLAG is set, meaning this table position is a space wildcard.
4DDF
If the Z FLAG has been set (table byte was a space, acting as a wildcard), JUMP to 4DF0H to handle the abbreviated match.
No match at all for this table entry. Skip to the end of the current entry and try the next one.
4DE1
INC DE 13
[SKIP LOOP] INCrement DE to advance past the remaining bytes of this table entry.
4DE2
DECrement B and loop back to 4DE1H if not zero. Skips past the rest of the current table entry (B counts remaining bytes).
4DE4
POP HL E1
Restore HL from the stack (pointer to user input after R).
4DE5
LD A,(DE) 1A
Fetch the next byte from the table into Register A. After skipping an entry, this is either the start of the next entry or 00H (end of group marker).
4DE6
OR A B7
OR Register A with itself to set flags based on the value. If A is 00H, the Z FLAG is set (end of table group).
4DE7
If the NZ FLAG has been set (A is not 00H, more table entries exist), JUMP back to 4DD4H to try matching the next register name entry. [OUTER LOOP END - continues if more entries]
4DE9
JUMP to 50B9H - the ERROR handler. No matching register name was found in the lookup table.
Match found. If we're still comparing characters (B > 0), continue comparing. Otherwise, all characters matched and we proceed to handle the register value.
4DEC
DECrement B and loop back to 4DD7H if not zero. Continues comparing the remaining characters of the register name against the table. [INNER LOOP END]
4DEE
INC HL 23
INCrement HL to advance past the matched input characters.
4DEF
INC B 04
INCrement B (which was 0 after DJNZ fell through) to 1. This is used as a flag or counter for subsequent processing.
4DF0
LD A,(HL) 7E
Fetch the current character from the user's input. After a full match, this should be either a comma (for setting a new value) or ENTER (for display only).
4DF1
CP 2CH FE 2C
Compare Register A against 2CH (ASCII , comma). If A equals 2CH, the Z FLAG is set, meaning the user wants to set a new value for this register.
4DF3
If the NZ FLAG has been set (character is NOT a comma), JUMP to 4DE1H. This skips the rest of this table entry and continues searching - the match was incomplete (e.g., user typed RH but meant HL, not H alone).
The user typed a register name followed by a comma and a new value. Parse the value and store it.
4DF5
POP AF F1
Discard the saved HL from the stack (no longer needed since we found the match).
4DF6
LD A,(DE) 1A
Fetch the offset/type byte from the table entry into Register A. This byte encodes the stack offset where this register's value is stored.
4DF7
PUSH AF F5
Save the offset/type byte onto the stack for later use.
4DF8
GOSUB to 50B2H to parse a hex number from the input, then verify the line ends with ENTER (0DH). Returns the parsed value in DE.
4DFB
POP AF F1
Restore the offset/type byte into Register A.
4DFC
GOSUB to 50C9H - the register address calculator. Given the offset in A, this routine computes the memory address where the register value is stored on the DEBUG stack. Returns HL pointing to the storage location.
4DFF
LD (HL),E 73
Store the low byte of the new value (E) into the register storage location pointed to by HL.
4E00
INC HL 23
INCrement HL to point to the high byte of the register storage location.
4E01
LD (HL),D 72
Store the high byte of the new value (D) into the register storage location.
4E02
RET C9
RETURN. Since 4D43H was pushed as a return address at 4D49H, this returns to the command loop to redisplay the prompt with the updated register value.
4E03H - F (Find) Command Handler
The F (Find) command searches memory for a byte pattern. Syntax: F[byte1,byte2,...,byteN]. The hex bytes are stored in a search buffer at 51E8H. The search begins from the address stored at 4E08H (self-modifying, starts at 0001H and increments after each find). When a match is found, the address is displayed. Pressing ENTER alone repeats the search from the last found address to find the next occurrence.
4E03
CP 46H FE 46
Compare Register A against 46H (ASCII F). If A equals 46H, the Z FLAG is set.
4E05
If the NZ FLAG has been set (command is NOT F), JUMP to 4E59H to check for the L (Load) command.
4E07
LD DE,0000H 11 00 00
[SELF-MODIFYING CODE] Load DE with the value at 4E08H-4E09H. On the first call, this is 0000H; on subsequent calls, it holds the address where the last match was found plus one (to search for the next occurrence).
4E0A
INC DE 13
INCrement DE by 1. This advances the search start address past the last match (or from 0001H on the first call).
4E0B
LD B,00H 06 00
[SELF-MODIFYING CODE] Load Register B with the value at 4E0CH. This is the length of the search pattern (number of bytes). On the first call, this is 0; it is overwritten when the user specifies a new pattern.
4E0D
INC HL 23
INCrement HL to advance past the F command character in the input buffer.
4E0E
LD A,(HL) 7E
Fetch the next character from the input buffer into Register A.
4E0F
CP 0DH FE 0D
Compare Register A against 0DH (ENTER/carriage return). If A equals 0DH, the Z FLAG is set, meaning the user pressed ENTER without specifying a new pattern (repeat the last search).
4E11
If the Z FLAG has been set (user just pressed ENTER), JUMP to 4E32H to repeat the search with the existing pattern in the buffer.
The user has entered new search bytes. Parse them and store in the buffer at 51E8H.
4E13
GOSUB to 5079H to parse the first hex byte from the input. Returns the value in DE (low byte in E).
4E16
PUSH DE D5
Save DE (the parsed first byte value) onto the stack. This will be used as the new search start address (from the first byte value).
4E17
LD B,00H 06 00
Load Register B with 00H - initialize the byte counter for the number of search pattern bytes.
4E19
LD DE,51E8H 11 E8 51
Point DE to 51E8H - the search pattern buffer where the bytes to find will be stored.
4E1C
PUSH DE D5
[LOOP START] Save DE (current position in the search buffer) onto the stack.
4E1D
GOSUB to 50AEH - parse a hex number and check for comma delimiter. This parses the next hex byte value and verifies it is followed by a comma (for more bytes) or ENTER (end of pattern).
4E20
GOSUB to 5078H to parse the next hex byte value from the input (skipping the comma). Returns the value in DE.
4E23
LD A,E 7B
Load Register A with E (the low byte of the parsed value, which is the search byte).
4E24
POP DE D1
Restore DE (pointer to the current position in the search buffer) from the stack.
4E25
INC B 04
INCrement B (byte counter) by 1 to count this new search byte.
4E26
LD (DE),A 12
Store the search byte (A) into the search buffer at the current position (DE).
4E27
INC DE 13
INCrement DE to advance to the next position in the search buffer.
4E28
LD A,(HL) 7E
Fetch the current character from the input buffer. After parsing a byte, this should be a comma (more bytes) or ENTER (end of pattern).
4E29
CP 0DH FE 0D
Compare Register A against 0DH (ENTER). If A equals 0DH, the Z FLAG is set, meaning all search bytes have been entered.
4E2B
If the NZ FLAG has been set (more bytes to parse), JUMP back to 4E1CH to parse the next byte. [LOOP END - continues if more bytes]
4E2D
POP DE D1
Pop DE from the stack (this was the initial parsed value pushed at 4E16H, used as the search start address).
4E2E
LD A,B 78
Load Register A with B (the total number of search pattern bytes).
4E2F
LD (4E0CH),A 32 0C 4E
Store the byte count into 4E0CH. [SELF-MODIFYING CODE] This overwrites the operand of the LD B,nn instruction at 4E0BH, so that future searches (without a new pattern) will use this count.
Now begin the search. DE holds the start address, B holds the pattern length, and the pattern bytes are at 51E8H.
4E32
LD HL,51E8H 21 E8 51
Point HL to 51E8H - the search pattern buffer.
4E35
EX DE,HL EB
Exchange DE and HL. Now HL = search start address (in memory to search), DE = pattern buffer pointer.
[SEARCH LOOP START] - Compare the pattern against memory at the current address.
4E36
PUSH BC C5
Save BC (B = pattern length) onto the stack.
4E37
PUSH DE D5
Save DE (pattern buffer pointer) onto the stack.
4E38
PUSH HL E5
Save HL (current memory search address) onto the stack.
4E39
LD A,(DE) 1A
[COMPARE LOOP] Fetch the current pattern byte from the buffer into Register A.
4E3A
CP (HL) BE
Compare the pattern byte (A) against the memory byte at the current search address (HL). If they match, the Z FLAG is set.
4E3B
INC DE 13
INCrement DE to advance to the next pattern byte.
4E3C
INC HL 23
INCrement HL to advance to the next memory byte.
4E3D
If the NZ FLAG has been set (bytes do NOT match), JUMP to 4E41H to break out of the comparison loop.
4E3F
DECrement B and loop back to 4E39H if not zero. Continues comparing the next pattern byte. [COMPARE LOOP END]
4E41
POP HL E1
Restore HL (the memory address where this comparison started) from the stack.
4E42
POP DE D1
Restore DE (pattern buffer pointer) from the stack.
4E43
POP BC C1
Restore BC (B = pattern length) from the stack.
4E44
If the Z FLAG has been set (all bytes matched - the DJNZ at 4E3FH fell through with Z still set from the last CP), JUMP to 4E4BH to report the match.
No match at this address. Advance to the next address and continue searching. If HL wraps around to 0000H, the entire memory has been searched.
4E46
INC HL 23
INCrement HL to advance to the next memory address to check.
4E47
LD A,H 7C
Load Register A with H (high byte of the search address).
4E48
OR L B5
OR A with L. If HL has wrapped around to 0000H (entire 64K searched), the Z FLAG is set.
4E49
If the NZ FLAG has been set (HL is not 0000H, more memory to search), JUMP back to 4E36H to compare at the next address. [SEARCH LOOP END - continues if more memory]
Match found (or wrapped to 0000H). Save the match address and adjust the display.
4E4B
LD (4E08H),HL 22 08 4E
Store HL (the match address) into 4E08H. [SELF-MODIFYING CODE] This overwrites the operand of the LD DE,nnnn instruction at 4E07H so the next F command (with just ENTER) will start searching from this address + 1.
4E4E
LD DE,FFE0H 11 E0 FF
Load DE with FFE0H (-32 decimal). This offset will be added to the match address to position the display so the found address is visible in the middle of the dump.
4E51
ADD HL,DE 19
ADD FFE0H (-32) to HL. This backs up the display start address by 32 bytes so the found byte is visible on screen.
4E52
LD (404CH),HL 22 4C 40
Store the adjusted address into the FCB/display pointer at 404CH. This sets the memory display start address for the prompt redisplay.
4E55
LD A,58H 3E 58
Load Register A with 58H (ASCII X). This value will be used as the command code to set the display mode.
4E57
JUMP to 4ECFH to set the display mode and return to the command loop. The X command code (58H) at 4ECFH will set display mode to "full" (42C4H = 01H).
4E59H - L (Load) Command Handler
The L (Load) command loads a sector from disk into memory using the FCB pointer at (4EBDH). Syntax: L. This calls the disk read setup routine at 4E87H to validate access, then calls 45DBH to execute the read. If the read succeeds (Z flag set), returns to the command loop. If the read fails with error code 06H (end of file), that is also treated as success.
4E59
CP 4CH FE 4C
Compare Register A against 4CH (ASCII L). If A equals 4CH, the Z FLAG is set.
4E5B
If the NZ FLAG has been set (command is NOT L), JUMP to 4E6BH to check for the W (Write) command.
4E5D
GOSUB to 4E87H to validate disk access. This checks that the system is not in read-only mode, parses the sector number, and verifies the FCB.
4E60
XOR A AF
Set Register A to ZERO and clear all flags. The Z flag is set.
4E61
If the Z FLAG is set (always true after XOR A), GOSUB to SYS0 routine at 45DBH to execute a disk sector read. This sets up the FDC Read Sector command (88H) and performs the read operation.
4E64
RET Z C8
If the Z FLAG has been set (read succeeded with no error), RETURN to the command loop.
4E65
CP 06H FE 06
Compare Register A (error code) against 06H (end of file). If A equals 06H, the Z FLAG is set.
4E67
RET Z C8
If the Z FLAG has been set (error was end-of-file, which is acceptable), RETURN to the command loop.
4E68
JUMP to 50B9H - the ERROR handler. The disk read failed with an unrecoverable error.
4E6BH - WR (Write) Command Handler
The WR (Write) command writes a sector from memory to disk. Syntax: WR (the W must be followed by R for confirmation). This requires the disk to not be in read-only mode (bit 7 of 428CH must be clear). The routine reads the current sector first, writes it, then reads it back to verify.
4E6B
CP 57H FE 57
Compare Register A against 57H (ASCII W). If A equals 57H, the Z FLAG is set.
4E6D
If the NZ FLAG has been set (command is NOT W), JUMP to 4EB5H to check for the D (Deposit) command.
4E6F
INC HL 23
INCrement HL to advance past the W to the next character.
4E70
LD A,(HL) 7E
Fetch the next character into Register A. This must be R for the write command to proceed.
4E71
CP 52H FE 52
Compare Register A against 52H (ASCII R). If A equals 52H, the Z FLAG is set.
4E73
If the NZ FLAG has been set (next character is NOT R), JUMP to 4E68H which jumps to the ERROR handler.
4E75
GOSUB to 4E87H to validate disk access (checks read-only flag, parses sector, verifies FCB).
4E78
GOSUB to SYS0 routine at 45DFH to read the sector first (read-before-write for verification). This saves HL, calls 45DBH (read sector), then restores HL.
4E7B
If the Z FLAG has been set (read succeeded), GOSUB to SYS0 routine at 45EBH to write the sector. This sets up the FDC Write Sector command (A8H).
4E7E
If the Z FLAG has been set (write succeeded), JUMP to 4E85H to verify by reading back.
4E80
CP 06H FE 06
Compare Register A (error code) against 06H (end of file).
4E82
If the Z FLAG has been set (error was EOF), GOSUB to SYS0 routine at 45E7H to write with verify (A9H command).
4E85
JUMP back to 4E61H to perform a verification read and check the result.
4E87H - Disk Access Validation Routine
Validates that disk operations are permitted and parses the sector parameters. Checks the system flags at 428CH (bit 7 = read-only), parses the sector number, and calls 4723H to set up the directory sector for reading.
4E87
LD A,(428CH) 3A 8C 42
Fetch the system flags byte from 428CH into Register A. Bit 7 of this byte indicates read-only mode.
4E8A
RLCA 07
Rotate Register A Left Circular. This moves bit 7 into the Carry flag.
4E8B
If the CARRY FLAG has been set (system is in read-only mode), JUMP to 4E68H which jumps to the ERROR handler.
4E8D
GOSUB to 50ABH to parse a hex number from the input and verify the delimiter is a comma. Returns the value in DE.
4E90
LD A,D 7A
Load Register A with D (high byte of the parsed value).
4E91
OR A B7
OR A with itself to test if D is zero. Sector numbers must be single-byte.
4E92
LD A,E 7B
Load Register A with E (the sector number).
4E93
If the Z FLAG has been set (D was 0, value is a valid single-byte sector), GOSUB to SYS0 routine at 4723H to read the directory sector. A = sector number.
4E96
If the NZ FLAG has been set (D was non-zero or read failed), JUMP to 4E68H (ERROR handler).
4E98
INC HL 23
INCrement HL to advance past the parsed sector number in the input.
4E99
LD A,0AH 3E 0A
Load Register A with 0AH (10 decimal) - the numeric base for decimal parsing.
4E9B
GOSUB to 507BH to parse a number using base 10 (decimal). This reads the record count or offset parameter.
4E9E
GOSUB to 50B5H to verify the input line ends with ENTER (0DH).
4EA1
XOR A AF
Set Register A to ZERO.
4EA2
LD (42C4H),A 32 C4 42
Store 00H into the display mode flag at 42C4H, setting compact display mode (memory dump).
4EA5
LD HL,4300H 21 00 43
Load HL with 4300H - the sector buffer address for disk operations.
4EA8
LD (404CH),HL 22 4C 40
Store HL (4300H) into the display pointer at 404CH to show the sector buffer contents.
4EAB
RET C9
RETURN to the caller (L or WR command handler).
4EACH - Q (Quit) Command Handler
The Q (Quit) command exits DEBUG and returns to the NEWDOS/80 DOS Ready prompt via RST 28H with SVC code E3H and sub-function 0CH.
4EAC
CP 51H FE 51
Compare Register A against 51H (ASCII Q). If A equals 51H, the Z FLAG is set.
4EAE
If the NZ FLAG has been set (command is NOT Q), JUMP to 4E68H (ERROR handler).
4EB0
LD A,E3H 3E E3
Load Register A with E3H - the SVC code for "exit to DOS Ready".
4EB2
LD C,0CH 0E 0C
Load Register C with 0CH - sub-function code for the E3H SVC.
4EB4
RST 28H EF
Execute RST 28H (DOS Supervisor Call) with A=E3H, C=0CH. This transfers control to the DOS Ready prompt, terminating DEBUG.
4EB5H - D (Deposit) Command Handler
The D (Deposit) command writes a 16-bit value to a specified memory address. Syntax: Daddr. Parses the hex address, then stores the value.
4EB5
CP 44H FE 44
Compare Register A against 44H (ASCII D). If A equals 44H, the Z FLAG is set.
4EB7
If the NZ FLAG has been set (command is NOT D), JUMP to 4EC3H to check for the M command.
4EB9
GOSUB to 50B2H to parse a hex value from the input and verify the line ends with ENTER. Returns the parsed value in DE.
4EBC
LD HL,0000H 21 00 00
Load HL with 0000H. HL serves as the destination address pointer. The actual target depends on context from the calling routine.
4EBF
LD (HL),E 73
Store the low byte of the parsed value (E) at the address pointed to by HL.
4EC0
INC HL 23
INCrement HL to point to the next byte.
4EC1
LD (HL),D 72
Store the high byte (D) at the next address.
4EC2
RET C9
RETURN to the command loop.
4EC3H - M/X/S/I/C/;/- Command Dispatcher
Handles the remaining DEBUG commands. M sets the memory display address. X sets full register display mode (42C4H=01H). S sets compact memory dump mode (42C4H=00H). I and C are single-step variants. ; scrolls the display forward by 64 bytes (or 256 in compact mode). - scrolls the display backward by 64 bytes (or 256 in compact mode).
4EC3
CP 4DH FE 4D
Compare Register A against 4DH (ASCII M). If A equals 4DH, the Z FLAG is set.
4EC5
If the Z FLAG has been set (command is M), JUMP to 4F0AH to handle the Memory display address command.
4EC7
INC HL 23
INCrement HL to skip past the command character in the input buffer.
4EC8
LD C,A 4F
Save the command character in Register C.
4EC9
GOSUB to 50B5H to verify the input line ends with ENTER (0DH). If trailing characters exist, ERROR is called.
4ECC
LD A,C 79
Restore the command character from Register C into Register A.
4ECD
LD B,00H 06 00
Load Register B with 00H - used as a flag to distinguish between I (B=0) and C (B=1) commands.
4ECF
LD HL,(4DC7H) 2A C7 4D
Load HL with the saved Program Counter from 4DC7H.
4ED2
LD C,(HL) 4E
Fetch the opcode byte at the current PC into Register C.
4ED3
INC HL 23
INCrement HL to point past the opcode byte.
4ED4
CP 49H FE 49
Compare Register A against 49H (ASCII I). If A equals 49H, the Z FLAG is set.
4ED6
If the Z FLAG has been set (command is I), JUMP to 5140H - the instruction decoder for single-stepping.
4ED9
INC B 04
INCrement B from 0 to 1. B=1 flags the C (call trace) command.
4EDA
CP 43H FE 43
Compare Register A against 43H (ASCII C). If A equals 43H, the Z FLAG is set.
4EDC
If the Z FLAG has been set (command is C), JUMP to 4ED6H which jumps to 5140H with B=1.
4EDE
LD HL,(4EBDH) 2A BD 4E
Load HL with the FCB pointer from 4EBDH.
4EE1
LD E,(HL) 5E
Fetch the low byte of the display address from the FCB pointer.
4EE2
INC HL 23
INCrement HL.
4EE3
LD D,(HL) 56
Fetch the high byte. DE = current display address.
4EE4
LD HL,42C4H 21 C4 42
Point HL to the display mode flag at 42C4H.
4EE7
LD B,(HL) 46
Save the current display mode flag in Register B.
4EE8
LD (HL),01H 36 01
Set the display mode flag to 01H (full register display).
4EEA
CP 58H FE 58
Compare Register A against 58H (ASCII X).
4EEC
RET Z C8
If X, RETURN. Display mode is set to 01H (full register display).
4EED
DEC (HL) 35
DECrement the display mode flag from 01H back to 00H (compact mode).
4EEE
CP 53H FE 53
Compare Register A against 53H (ASCII S).
4EF0
RET Z C8
If S, RETURN. Display mode is set to 00H (compact memory dump).
4EF1
LD (HL),B 70
Restore the original display mode (neither X nor S was the command).
4EF2
LD HL,0040H 21 40 00
Load HL with 0040H (+64 decimal) - the scroll offset for ;.
4EF5
CP 3BH FE 3B
Compare Register A against 3BH (ASCII ;).
4EF7
If ;, JUMP to 4F00H to apply the positive offset.
4EF9
LD HL,FFC0H 21 C0 FF
Load HL with FFC0H (-64 decimal) - the scroll offset for -.
4EFC
CP 2DH FE 2D
Compare Register A against 2DH (ASCII -).
4EFE
If NOT -, JUMP back to 4EACH to recheck for Q, then fall through to ERROR.
4F00
LD A,B 78
Load Register A with B (saved display mode: 00H=compact, 01H=full).
4F01
OR A B7
OR A with itself. Z flag set if compact mode (B=0).
4F02
If full display mode (B=1), JUMP to 4F06H (do not multiply).
4F04
ADD HL,HL 29
Double HL. In compact mode, the offset is multiplied by 4 for faster scrolling.
4F05
ADD HL,HL 29
Double HL again. Offset is now ±256 in compact mode.
4F06
ADD HL,DE 19
ADD the current display address (DE) to the scroll offset (HL). Result is the new display address.
4F07
EX DE,HL EB
Exchange DE and HL. DE now holds the new display address.
4F08
JUMP to 4EBCH to store the new display address and return to the command loop.
4F0AH - M (Memory Display/Edit) Command Handler
The M (Memory) command provides an interactive memory display and editor. Syntax: Maddr. It parses a hex address, sets the display start address, and enters an interactive mode where the user can view memory as a formatted hex/ASCII dump. The display shows memory at the specified address with a blinking cursor; the user can type hex values to modify bytes, use arrow-key-like controls to navigate, or press ENTER to exit. The display uses video RAM directly, calculating screen positions from memory addresses.
4F0A
GOSUB to 50B2H to parse a hex address and verify the line ends with ENTER. Returns the parsed address in DE.
4F0D
EX DE,HL EB
Exchange DE and HL. HL now holds the parsed display address.
4F0E
LD B,00H 06 00
Load Register B with 00H - used as a nibble position flag (0 = high nibble, 1 = low nibble) during hex entry.
4F10
LD (404CH),HL 22 4C 40
[DISPLAY REFRESH] Store HL (current memory address) into the display pointer at 404CH. This updates the start address for the memory dump display.
4F13
PUSH HL E5
Save HL (current address) onto the stack.
4F14
LD C,L 4D
Save the low byte of the address in Register C. This is used for screen position calculation.
4F15
XOR A AF
Set Register A to ZERO.
4F16
LD (42C4H),A 32 C4 42
Store 00H into the display mode flag at 42C4H, setting compact mode (memory dump).
4F19
GOSUB to 4FC7H to display the DEBUG prompt with the memory dump.
Calculate the screen position for the cursor. The memory dump display format shows addresses and hex bytes in a grid. We need to find which screen position corresponds to the current byte being edited. The calculation maps the memory address offset to a video RAM position.
4F1C
LD H,00H 26 00
Clear H. H will accumulate row offset.
4F1E
LD D,H 54
Clear D (D = 0).
4F1F
LD E,H 5C
Clear E (E = 0, DE = 0000H).
4F20
LD A,C 79
Load Register A with C (the low byte of the memory address).
4F21
RRA 1F
Rotate A Right through carry. Bit 0 goes into Carry, which determines whether this is an odd or even byte position.
4F22
RL E CB 13
Rotate E Left through carry. The carry bit (odd/even flag) is shifted into bit 0 of E.
4F24
AND 07H E6 07
Mask A to keep only bits 0-2 (column position within a row, 0-7).
4F26
LD L,A 6F
Store the column index in L.
4F27
ADD A,A 87
Double A (multiply column by 2 for hex digit spacing).
4F28
ADD A,E 83
ADD E (odd/even flag) to A.
4F29
ADD A,A 87
Double A again.
4F2A
ADD A,L 85
ADD L (original column index) to A.
4F2B
ADD A,B 80
ADD B (nibble position flag: 0 or 1) to A. This fine-tunes the cursor to the specific hex digit within the byte display.
4F2C
LD E,A 5F
Store the computed column offset in E.
4F2D
LD A,C 79
Load A with C (low byte of address) again for row calculation.
4F2E
AND F0H E6 F0
Mask to keep only the high nibble of the low address byte. This represents which 16-byte row the address is in.
4F30
LD L,A 6F
Store the row indicator in L.
4F31
ADD HL,HL 29
Double HL (multiply row indicator by 2).
4F32
ADD HL,HL 29
Double HL again (multiply by 4 total). Each display row uses 64 bytes of video RAM.
4F33
ADD HL,DE 19
ADD DE (column offset) to HL. HL now holds the relative position within the display.
4F34
LD DE,3C08H 11 08 3C
Load DE with 3C08H - the base video RAM address plus an 8-character offset (to skip past the address display at the start of each line). 3C00H is the start of video RAM; +08H skips the "XXXX " address prefix.
4F37
ADD HL,DE 19
ADD DE to HL. HL now points to the exact video RAM location of the hex digit being edited.
4F38
LD C,(HL) 4E
Save the current character at the cursor position in Register C (to restore when moving away).
4F39
LD (HL),BFH 36 BF
[CURSOR BLINK START] Write BFH (a TRS-80 graphics block character that appears as a solid cursor) to the video RAM position. This shows the user where the cursor is.
4F3B
GOSUB to 4FB7H - the get-key-with-cursor routine. This waits for a keypress while blinking the cursor. Returns the key in A, with Z flag set if the key retry counter expired.
4F3E
LD (HL),C 71
Restore the original character at the cursor position (remove the cursor block).
4F3F
If the Z FLAG has been set (key retry expired without input), GOSUB to 4FB7H again to wait for another key. This creates the blinking effect: cursor on → wait → cursor off → wait → repeat.
4F42
If the Z FLAG has been set (still no key), JUMP back to 4F39H to show the cursor again. [CURSOR BLINK LOOP]
A key has been pressed. Retrieve the address from the stack and process the key.
4F44
POP HL E1
Restore HL (the current memory address being edited) from the stack.
4F45
CP 0DH FE 0D
Compare the keypress (A) against 0DH (ENTER). If A equals 0DH, the Z FLAG is set.
4F47
LD C,A 4F
Save the keypress in Register C for further processing.
4F48
RET Z C8
If ENTER was pressed, RETURN to the command loop. The user is done editing.
Check if the key is a hex digit (0-9, A-F). If so, modify the current nibble of the memory byte.
4F49
GOSUB to 509DH - check if the character in A is a valid hex digit. Adjusts A to the digit value (0-15) and sets Carry if valid.
4F4C
If the NO CARRY FLAG has been set (not a hex digit), JUMP to 4F6BH to check for navigation keys.
The key is a hex digit. Merge it into the appropriate nibble of the byte at the current address.
4F4E
LD E,F0H 1E F0
Load E with F0H - a mask to keep the high nibble (for when we're writing the low nibble).
4F50
BIT 0,B CB 40
Test bit 0 of B (the nibble flag). If bit 0 is 1, we are editing the low nibble; if 0, the high nibble.
4F52
If bit 0 is set (editing low nibble), JUMP to 4F5AH to merge the digit into the low nibble.
4F54
LD E,0FH 1E 0F
Load E with 0FH - a mask to keep the low nibble (for when we're writing the high nibble).
4F56
RLCA 07
Rotate A left (shift hex digit value into high nibble position).
4F57
RLCA 07
Rotate A left.
4F58
RLCA 07
Rotate A left.
4F59
RLCA 07
Rotate A left. A now has the hex digit value in the high nibble (bits 4-7).
4F5A
LD C,A 4F
Save the positioned digit value in C.
4F5B
LD A,(HL) 7E
Fetch the current byte at the memory address being edited.
4F5C
AND E A3
AND with the mask (E). This clears the nibble being written while preserving the other nibble.
4F5D
OR C B1
OR with C (the new digit value). This merges the new digit into the correct nibble.
4F5E
LD (HL),A 77
Store the modified byte back to memory. The nibble has been updated.
4F5F
BIT 0,B CB 40
Test bit 0 of B again to check which nibble was just edited.
4F61
If bit 0 is 0 (just edited the high nibble), JUMP to 4F65H to toggle to the low nibble.
4F63
INC L 2C
INCrement L (advance to the next memory byte) since we just finished the low nibble.
4F64
RET Z C8
If L wrapped to 0 (page boundary crossed), RETURN. This prevents editing beyond the current 256-byte page.
4F65
LD A,B 78
Load Register A with B (current nibble flag).
4F66
XOR 01H EE 01
Toggle bit 0 of A. This switches between high nibble (0) and low nibble (1).
4F68
LD B,A 47
Store the toggled flag back in B.
4F69
JUMP back to 4F10H to refresh the display and continue editing at the new cursor position.
Check for navigation keys: space (advance), TAB (advance), backspace (go back), down arrow, up arrow, and the bracket key.
4F6B
LD A,C 79
Load Register A with C (the keypress character).
4F6C
CP 20H FE 20
Compare A against 20H (ASCII space).
4F6E
If space, JUMP to 4F74H to advance one byte.
4F70
CP 09H FE 09
Compare A against 09H (TAB character).
4F72
If NOT TAB, JUMP to 4F7DH to check for backspace.
4F74
BIT 0,B CB 40
Test bit 0 of B (nibble flag).
4F76
If high nibble (B=0), JUMP to 4F65H to toggle to low nibble (stay on same byte).
4F78
INC L 2C
INCrement L to advance to the next byte.
4F79
If L did not wrap to 0, JUMP to 4F65H to toggle nibble and continue.
4F7B
If L wrapped to 0 (end of page), JUMP to 4F97H to handle page boundary.
4F7D
CP 08H FE 08
Compare A against 08H (backspace).
4F7F
If NOT backspace, JUMP to 4F8CH to check for arrow keys.
4F81
BIT 0,B CB 40
Test nibble flag.
4F83
If low nibble (B=1), JUMP to 4F65H to toggle back to high nibble.
4F85
INC L 2C
INCrement L (this is a test: we INC then DEC to check if we're at the start).
4F86
DEC L 2D
DECrement L back. Z flag is set if L was 00H (start of page).
4F87
If at the start of the page (L=00H), JUMP to 4F69H to refresh without moving.
4F89
DEC L 2D
DECrement L to move back one byte.
4F8A
JUMP to 4F65H to toggle nibble and continue editing at the previous byte.
4F8C
LD E,02H 1E 02
Load E with 02H - a 2-byte offset for horizontal navigation.
4F8E
CP 19H FE 19
Compare A against 19H (down arrow key code on TRS-80).
4F90
If NOT down arrow, JUMP to 4F9DH to check for other keys.
4F92
LD A,L 7D
Load A with L (current position within the page).
4F93
ADD A,E 83
ADD E (2) to A. Move down one row (2 bytes forward in the hex dump layout).
4F94
LD L,A 6F
Store the new position back in L.
4F95
If no carry (position did not wrap past FFH), JUMP to 4F69H to refresh display.
4F97
LD B,01H 06 01
Load B with 01H - set nibble flag to low nibble.
4F99
LD L,FFH 2E FF
Load L with FFH - set position to end of page.
4F9B
JUMP to 4F69H to refresh display at new position.
4F9D
CP 18H FE 18
Compare A against 18H (up arrow key code).
4F9F
If up arrow, JUMP to 4FADH to move up one row.
4FA1
LD E,10H 1E 10
Load E with 10H (16 decimal) - offset for moving down one full display line.
4FA3
CP 0AH FE 0A
Compare A against 0AH (line feed / down-line key).
4FA5
If line-feed, JUMP to 4F92H to move down by 16 bytes.
4FA7
LD C,L 4D
Save L in C before checking the bracket key.
4FA8
CP 5BH FE 5B
Compare A against 5BH (ASCII [ left bracket).
4FAA
If NOT [, JUMP to 50B9H - the ERROR handler. Unrecognized key in the memory editor.
4FAD
LD A,L 7D
Load A with L (current position).
4FAE
SUB E 93
SUBtract E (movement offset: 2 for up arrow, 16 for up-line) from A.
4FAF
LD L,A 6F
Store the new position in L.
4FB0
If no borrow (position did not wrap below 00H), JUMP to 4F69H to refresh.
4FB2
LD B,00H 06 00
Set nibble flag to high nibble.
4FB4
LD L,B 68
Set position to 00H (start of page).
4FB5
JUMP to 4F69H to refresh display.
4FB7H - Get Key with Cursor Blink
Waits for a keypress with a timeout counter. The counter in D starts at 00H (set by the caller) and decrements on each call. When D reaches 0, the routine returns with Z flag set (indicating timeout for cursor blink). When a key is pressed, it is converted to uppercase and returned in A with NZ flag.
4FB7
LD D,00H 16 00
Load Register D with 00H - timeout counter (256 iterations before returning Z).
4FB9
PUSH DE D5
[LOOP START] Save DE onto the stack.
4FBA
GOSUB to ROM routine at 002BH to scan the keyboard. Returns the key code in A, or 0 if no key is pressed.
4FBD
POP DE D1
Restore DE from the stack.
4FBE
GOSUB to SYS0 routine at 4548H to convert the character to uppercase.
4FC1
OR A B7
OR A with itself. If A is 0 (no key pressed), the Z FLAG is set.
4FC2
RET NZ C0
If a key was pressed (A is not 0), RETURN with the key code in A and NZ flag.
4FC3
DEC D 15
DECrement the timeout counter D.
4FC4
If D is not zero (timeout has not expired), JUMP back to 4FB9H to scan the keyboard again. [LOOP END]
4FC6
RET C9
RETURN with Z flag set (timeout expired, no key pressed). This signals the caller to toggle the cursor blink state.
4FC7H - Display DEBUG Prompt and Register/Memory Dump
Displays the DEBUG prompt string (with SZ-H-PNC flag indicators) and then either a full register display (42C4H non-zero) or a compact memory dump (42C4H = 0). Clears the screen first via the string display routine at 4467H.
4FC7
LD HL,51D8H 21 D8 51
Point HL to 51D8H - the DEBUG prompt and flag character data string containing "SZ-H-PNC" flag indicators.
4FCA
GOSUB to SYS0 routine at 4467H to display the prompt string and clear the screen.
4FCD
LD HL,3C00H 21 00 3C
Load HL with 3C00H - the start of video RAM (top-left corner).
4FD0
LD A,(42C4H) 3A C4 42
Fetch the display mode flag from 42C4H. 00H = compact dump, non-zero = full register display.
4FD3
OR A B7
OR A with itself to set flags.
4FD4
If the Z FLAG has been set (compact mode), JUMP to 5034H for the compact memory dump display.
4FD6H - Full Register Display Mode
Displays all register values with names and flag bit breakdown. The register name table at 50DBH provides entries for AF, BC, DE, HL (main and alternate), PC, SP, IX, IY. Each is shown as NAME=XXXX. For the AF register, individual flag bits (S, Z, H, P, N, C) are shown as letters when set and dashes when clear. The display is organized in 3 groups of 4 registers.
4FD6
LD DE,404CH 11 4C 40
Load DE with 404CH - the FCB/display pointer address.
4FD9
LD C,03H 0E 03
Load C with 03H - outer loop counter for 3 register groups.
4FDB
PUSH DE D5
[OUTER LOOP START] Save DE.
4FDC
LD DE,50DBH 11 DB 50
Point DE to 50DBH - the register name table.
4FDF
EX (SP),HL E3
Swap HL (video pointer) with the stack value (FCB pointer).
4FE0
PUSH DE D5
Save DE (register table pointer).
4FE1
LD E,(HL) 5E
Fetch low byte of display address from FCB pointer.
4FE2
INC HL 23
INCrement HL.
4FE3
LD D,(HL) 56
Fetch high byte. DE = display address.
4FE4
INC HL 23
INCrement HL past the pointer.
4FE5
POP AF F1
Pop register table pointer into AF (stack manipulation trick).
4FE6
EX (SP),HL E3
Restore video RAM pointer to HL, save updated FCB pointer on stack.
4FE7
PUSH AF F5
Push register table pointer back.
4FE8
LD A,04H 3E 04
Load A with 04H - 4 rows of register data per section.
4FEA
GOSUB to 503BH to display the address (DE) in hex at the start of each row.
4FED
POP DE D1
Pop register table pointer into DE.
4FEE
LD B,04H 06 04
Load B with 04H - 4 registers per row.
4FF0
XOR A AF
Clear A (clear AF' flag indicator).
4FF1
LD A,(DE) 1A
[REGISTER LOOP] Fetch first character of register name.
4FF2
EX AF,AF' 08
Save name character in AF'.
4FF3
EX DE,HL EB
Swap: HL = table pointer, DE = video pointer.
4FF5
LD BC,0003H 01 03 00
Load BC with 3 - number of bytes to copy (2 name chars + offset).
4FF8
LDIR ED B0
Block copy 3 bytes from register table to video RAM (name + formatting).
4FFA
LD A,(HL) 7E
Fetch the register offset/type byte from the table.
4FFB
PUSH HL E5
Save table pointer.
4FFC
GOSUB to 50C9H to calculate the storage address for this register's saved value.
4FFF
LD A,(HL) 7E
Fetch low byte of the register value.
5000
INC HL 23
INCrement HL.
5001
LD H,(HL) 66
Fetch high byte into H.
5002
LD L,A 6F
Move low byte into L. HL = register value.
5003
EX DE,HL EB
DE = register value, HL = video pointer.
5004
INC HL 23
Advance video position.
5005
LD (HL),3DH 36 3D
Write = (3DH) to video RAM.
5008
INC HL 23
Advance (spacing).
5009
GOSUB to 44D2H to display DE (register value) as 4 hex digits.
500C
INC L 2C
Advance video position.
500D
EX AF,AF' 08
Restore saved register name character.
500E
If NZ (valid name character), JUMP to 5027H to advance to next entry.
Special AF register flag bit display. Shows each flag as its letter when set, or '-' when clear.
5010
CP 41H FE 41
Compare A against 41H (A). Tests if this is the AF register.
5012
LD A,E 7B
Load A with E (flags byte from the AF register value).
5013
LD B,08H 06 08
Load B with 8 - number of flag bits.
5015
LD DE,51DBH 11 DB 51
Point DE to 51DBH - flag name characters "SZ-H-PNC".
5018
[FLAG BIT LOOP] If not AF register, skip flag display.
501A
LD (HL),2DH 36 2D
Write - (dash) as default for "flag not set".
501C
RLCA 07
Rotate flags byte left. Top bit goes into Carry.
501D
If NO CARRY (flag bit is 0), keep the dash.
501F
EX AF,AF' 08
Preserve rotated flags.
5020
LD A,(DE) 1A
Fetch flag name character (S, Z, H, P, N, or C).
5021
LD (HL),A 77
Write flag letter to video RAM (flag IS set).
5022
EX AF,AF' 08
Restore rotated flags.
5023
INC HL 23
Advance video position.
5024
INC DE 13
Advance flag name pointer.
5025
DECrement B and loop for all 8 flag bits. [FLAG BIT LOOP END]
5027
INC L 2C
Advance video position (spacing).
5029
INC HL 23
Advance. Add inter-register spacing.
502A
POP DE D1
Restore register table pointer.
502B
POP BC C1
Restore BC (B = registers remaining).
502C
INC DE 13
Advance to next table entry.
502D
DECrement B, loop for next register. [REGISTER LOOP END]
502F
DEC C 0D
DECrement C (group counter).
5030
If more groups, loop back. [OUTER LOOP END]
5032
POP AF F1
Clean up stack.
5033
RET C9
RETURN. Full register display complete.
5034H - Compact Memory Dump Display
Displays a compact 16-row memory dump. Each row shows: a 4-digit hex address, 16 hex byte values (in 8 groups of 2), and the ASCII representation (non-printable bytes shown as periods). Starts at the address stored at (404CH).
5034
LD DE,(404CH) ED 5B 4C 40
Load DE with the display start address from 404CH.
5038
LD E,L 5D
Set E to L (00H from HL=3C00H), aligning to a page boundary.
5039
LD A,10H 3E 10
Load A with 10H (16) - number of rows to display.
503B
PUSH BC C5
[ROW LOOP START] Save BC.
503C
EX AF,AF' 08
Save row counter in AF'.
503D
INC L 2C
Advance video column.
503E
INC L 2C
Advance video column.
503F
GOSUB to 44D2H to display DE (memory address) as 4 hex digits.
5042
LD C,08H 0E 08
Load C with 08H - 8 groups of 2 bytes per row.
5044
INC L 2C
Spacing between address and hex data.
5045
INC L 2C
More spacing.
5046
PUSH HL E5
[GROUP LOOP START] Save hex display position.
5047
LD A,L 7D
Get current video column.
5048
ADD 28H C6 28
ADD 40 columns to get ASCII area position.
504A
LD L,A 6F
Set L to ASCII area column.
504B
EX (SP),HL E3
Swap: HL = hex position, stack = ASCII position.
504C
LD B,02H 06 02
Load B with 2 - bytes per group.
504E
LD A,(DE) 1A
[BYTE LOOP] Fetch memory byte from data address (DE).
504F
GOSUB to 44D7H to display byte as 2 hex digits.
5052
LD A,(428CH) 3A 8C 42
Fetch system flags for printable range check.
5055
AND 10H E6 10
Isolate bit 4 (extended printable range flag).
5057
RLCA 07
Shift to bit 5 position (00H or 20H).
5059
ADD 3FH C6 3F
Calculate upper printable boundary (3FH or 5FH).
505B
LD C,A 4F
Save boundary in C.
505C
LD A,(DE) 1A
Re-fetch the memory byte.
505D
SUB 21H D6 21
SUBtract 21H (start of printable range).
505F
CP C B9
Compare against upper boundary. Carry set if printable.
5061
LD A,(DE) 1A
Re-fetch original byte.
5062
INC DE 13
Advance data pointer.
5063
If printable, JUMP to 5067H to display actual character.
5065
LD A,2EH 3E 2E
Load A with 2EH (period) for non-printable bytes.
5067
EX (SP),HL E3
Swap to ASCII area position.
5068
LD (HL),A 77
Write ASCII character to video RAM.
5069
INC HL 23
Advance ASCII position.
506A
EX (SP),HL E3
Swap back to hex position.
506B
Loop for second byte in group. [BYTE LOOP END]
506D
INC HL 23
Spacing between groups.
506E
DEC C 0D
DECrement group counter.
506F
If more groups, loop back. [GROUP LOOP END]
5071
POP HL E1
Discard ASCII position from stack.
5072
EX AF,AF' 08
Restore row counter.
5073
DEC A 3D
DECrement row counter.
5074
If more rows, loop back. [ROW LOOP END]
5077
RET C9
RETURN. Compact memory dump display complete.
5078H - Parse Hex Number (Skip First Character)
Entry point that skips one character in the input buffer (the command letter or delimiter), then falls through to the hex number parsing routine at 5079H. Returns the parsed 16-bit value in DE.
5078
INC HL 23
INCrement HL to skip one character in the input buffer (typically the command letter or comma delimiter).
5079
LD A,10H 3E 10
Load Register A with 10H (16 decimal) - the default numeric base for hexadecimal parsing.
507B
PUSH BC C5
Save BC onto the stack.
507C
LD C,A 4F
Store the numeric base (10H for hex, or 0AH for decimal from alternate entry at 4E9BH) in Register C.
507D
LD DE,0000H 11 00 00
Clear DE to 0000H - the accumulator for the parsed number.
5080
GOSUB to 509CH to fetch the current character from the input buffer and validate it as a hex digit. Returns the digit value in A and Carry set if valid.
5083
If the NO CARRY FLAG has been set (first character is not a valid digit), JUMP to 50B9H - the ERROR handler. A number must start with a digit.
[ACCUMULATE LOOP] - For each valid digit: multiply the current accumulated value by the base (C), then add the new digit. Check for overflow.
5085
PUSH HL E5
Save HL (input buffer pointer).
5086
EX DE,HL EB
Move accumulated value from DE to HL for multiplication.
5087
LD E,A 5F
Store the new digit value in E.
5088
LD D,00H 16 00
Clear D. DE = the digit value (0-15).
508A
LD A,C 79
Load A with C (the numeric base, 10H or 0AH).
508B
GOSUB to SYS0 routine at 4C39H to multiply HL by A (accumulated value × base). Returns the result in HL (low 16 bits) with overflow possible.
508E
ADD HL,DE 19
ADD DE (the new digit) to HL (the multiplied accumulator). HL = (old_value × base) + new_digit.
508F
EX DE,HL EB
Move the updated accumulated value back to DE.
5090
ADC A,A 8F
ADD with Carry A to A. If the ADD HL,DE caused a carry, this detects 16-bit overflow. If the result was > FFFFH, the NZ flag will be set.
5091
If the NZ FLAG has been set (overflow occurred - number is too large for 16 bits), JUMP to 50B9H - the ERROR handler.
5093
POP HL E1
Restore HL (input buffer pointer).
5094
GOSUB to 509BH to advance HL and check if the next character is a valid hex digit.
5097
If the CARRY FLAG has been set (next character is a valid digit), JUMP back to 5085H to accumulate it. [ACCUMULATE LOOP END]
5099
POP BC C1
Restore BC from the stack.
509A
RET C9
RETURN with the parsed 16-bit value in DE, and HL pointing to the first non-digit character in the input.
509BH - Get Next Hex Digit
Advances HL by one position in the input buffer, then checks if the character at (HL) is a valid hexadecimal digit (0-9 or A-F). Returns the digit value (0-15) in A with Carry set if valid. Returns with No Carry if the character is not a hex digit.
509B
INC HL 23
INCrement HL to advance to the next character in the input buffer.
509C
LD A,(HL) 7E
Fetch the character at the current input buffer position into Register A.
509D
SUB 30H D6 30
SUBtract 30H (ASCII 0) from Register A. If the character was '0'-'9', A now holds 0-9.
509F
CP 0AH FE 0A
Compare Register A against 0AH (10 decimal). If A < 0AH (digit was 0-9), the CARRY FLAG is set.
50A1
RET C D8
If the CARRY FLAG has been set (character was a decimal digit 0-9), RETURN with the digit value in A (0-9) and Carry set.
50A2
SUB 11H D6 11
SUBtract 11H from A. After the initial SUB 30H, letters A-F become 11H-16H. Subtracting 11H converts them to 0-5.
50A4
CP 06H FE 06
Compare against 06H. If A < 06H (original character was A-F), No Carry... but we need Carry set for valid. This is checked inversely.
50A6
RET NC D0
If the NO CARRY FLAG has been set (A >= 06H, meaning the character was NOT A-F), RETURN with No Carry indicating "not a valid hex digit".
50A7
ADD 0AH C6 0A
ADD 0AH to A. Converts 0-5 back to 10-15 (the hex values for A-F).
50A9
SCF 37
Set the Carry Flag to indicate "valid hex digit found".
50AA
RET C9
RETURN with the hex digit value (10-15) in A and Carry set.
50ABH - Parse Hex, Expect Comma Delimiter
Calls 5078H to skip one character and parse a hex number, then checks that the next character is a comma (2CH). If not a comma, jumps to the ERROR handler.
50AB
GOSUB to 5078H to skip one character and parse a hex number. Returns value in DE.
50AE
LD A,2CH 3E 2C
Load A with 2CH (ASCII comma) - the expected delimiter.
50B0
JUMP to 50B7H to compare the current input character against the expected delimiter.
50B2H - Parse Hex, Expect End of Line
Calls 5078H to skip one character and parse a hex number, then checks that the next character is ENTER (0DH). If not ENTER, jumps to the ERROR handler.
50B2
GOSUB to 5078H to skip one character and parse a hex number. Returns value in DE.
50B5
LD A,0DH 3E 0D
Load A with 0DH (ENTER/carriage return) - the expected line terminator.
50B7
CP (HL) BE
Compare A (expected delimiter) against the current character at (HL). If they match, Z flag is set.
50B8
RET Z C8
If the Z FLAG has been set (delimiter matches), RETURN. The parse was successful and properly terminated.
50B9H - ERROR Display and Command Loop Restart
Displays the "ERROR" message, waits for the user to press ENTER, then restarts the command loop at 4D43H. This is the common error exit for all command handlers when parsing fails or an invalid operation is attempted.
50B9
LD HL,51D2H 21 D2 51
Point HL to 51D2H - the "ERROR" ASCII string (45H 52H 52H 4FH 52H 03H = "ERROR" + ETX).
50BC
GOSUB to SYS0 routine at 4467H to display the "ERROR" string.
50BF
[WAIT LOOP] GOSUB to ROM routine at 0049H to scan the keyboard. Returns the key code in A, or 0 if no key pressed.
50C2
CP 0DH FE 0D
Compare A against 0DH (ENTER). If A equals 0DH, the Z FLAG is set.
50C4
If the NZ FLAG has been set (key was not ENTER), JUMP back to 50BFH to wait for ENTER. [WAIT LOOP END]
50C6
JUMP to 4D43H - the command loop restart point. This resets the stack and redisplays the prompt.
50C9H - Register Storage Address Calculator
Given a register offset value in A, calculates the memory address where that register's saved value is stored on the DEBUG stack. The offset is added to the saved SP (at 4D44H) to find the specific register. Special cases: offset 14H maps to the saved PC at 4DC7H, and offset > 14H maps to the return address pointer at 4DC3H.
50C9
LD HL,(4D44H) 2A 44 4D
Load HL with the saved Stack Pointer from 4D44H. This is the base address for all register values on the stack.
50CC
LD C,A 4F
Save the register offset in C.
50CD
LD B,00H 06 00
Clear B. BC = the offset value (0-20).
50CF
ADD HL,BC 09
ADD the offset (BC) to the saved SP (HL). HL now points to the register's storage location on the stack.
50D0
CP 14H FE 14
Compare the original offset (A) against 14H. Offset 14H corresponds to the Program Counter. If A < 14H, Carry is set (normal register on stack).
50D2
RET C D8
If the CARRY FLAG has been set (offset < 14H, this is a normal register stored on the stack), RETURN with HL pointing to the storage location.
50D3
LD HL,4DC7H 21 C7 4D
Load HL with 4DC7H - the address where the saved PC is stored (not on the stack, but in the self-modifying code area).
50D6
RET Z C8
If the Z FLAG has been set (offset was exactly 14H = the PC), RETURN with HL pointing to the saved PC at 4DC7H.
50D7
LD HL,4DC3H 21 C3 4D
Load HL with 4DC3H - the address of the return address pointer. This handles the SP register (offset > 14H), whose value is stored in the self-modifying LD SP instruction.
50DA
RET C9
RETURN with HL pointing to 4DC3H (the saved stack pointer location).
50DBH - Register Name/Offset Lookup Table
This data table provides the register name lookup for the R (Register) command and the full register display. Each entry consists of: 2 bytes for the register name (ASCII characters), 1 byte for formatting/spacing, and 1 byte for the stack offset where the register value is stored. Entries are organized in groups separated by 00H bytes. The table covers all Z80 registers: AF, BC, DE, HL (main), AF', BC', DE', HL' (alternate), PC, SP, IX, IY.
The register name table is organized as groups of entries. Each group has 4 entries and ends with a delimiter. The disassembler shows this data as Z80 instructions because the raw bytes happen to correspond to valid opcodes, but this is pure data, not executable code.
50DB-50EA
DEFB 41 46 20 12 42 43 20 0E 44 45 20 0C 48 4C 20 10
Group 1 - Main Registers:
41H 46H 20H 12H = "AF" + space + offset 12H (AF at SP+18 on stack)
42H 43H 20H 0EH = "BC" + space + offset 0EH (BC at SP+14)
44H 45H 20H 0CH = "DE" + space + offset 0CH (DE at SP+12)
48H 4CH 20H 10H = "HL" + space + offset 10H (HL at SP+16)
50EB-50FA
DEFB 41 46 27 0A 42 43 27 08 44 45 27 06 48 4C 27 04
Group 2 - Alternate Registers:
41H 46H 27H 0AH = "AF'" + offset 0AH (AF' at SP+10)
42H 43H 27H 08H = "BC'" + offset 08H (BC' at SP+8)
44H 45H 27H 06H = "DE'" + offset 06H (DE' at SP+6)
48H 4CH 27H 04H = "HL'" + offset 04H (HL' at SP+4)
50FB-510B
DEFB 50 43 20 14 53 50 20 16 49 58 20 02 49 59 20 00 00
Group 3 - Special Registers + Terminator:
50H 43H 20H 14H = "PC" + space + offset 14H (PC, handled specially at 50C9H)
53H 50H 20H 16H = "SP" + space + offset 16H (SP, handled specially at 50C9H)
49H 58H 20H 02H = "IX" + space + offset 02H (IX at SP+2)
49H 59H 20H 00H = "IY" + space + offset 00H (IY at SP+0)
00H = End of table marker
510CH - Opcode Classification Table
This data table is used by the instruction decoder (at 5125H) to classify Z80 opcodes by their length and addressing mode. The table contains pairs of bytes: [opcode_pattern, handler_address_low]. The instruction decoder uses this table to look up how many bytes follow each opcode, which is essential for single-stepping (the next-instruction trap must be placed at exactly the right address). The data is not executable code.
510C-5124
DEFB 10 81 18 80 C3 96 C9 C8 CB AB CD B8 D3 AB DB AB DD 25 E9 8E ED 9E FD 29 00
Opcode Classification Table (25 bytes). Each pair maps an opcode pattern to a handler offset in the instruction decoder. Key entries:
10H → 81H: DJNZ - 2-byte relative jump
18H → 80H: JR - 2-byte relative jump
C3H → 96H: JP nn - 3-byte absolute jump
C9H → C8H: RET - special handler (return from stack)
CBH → ABH: CB prefix - 2-byte CB instructions
CDH → B8H: CALL nn - 3-byte call
D3H → ABH: OUT (n),A - 2-byte I/O
DBH → ABH: IN A,(n) - 2-byte I/O
DDH → 25H: DD prefix (IX) - variable length
E9H → 8EH: JP (HL) - special handler
EDH → 9EH: ED prefix - variable length
FDH → 29H: FD prefix (IY) - variable length
00H = End of table
5125H - Z80 Instruction Length Decoder
This routine determines the length of the Z80 instruction at the current PC address, which is essential for single-stepping. Given the opcode in C and HL pointing past the opcode, the decoder classifies the instruction and calculates where the next instruction starts. It handles all Z80 opcode prefixes (CBH, DDH, EDH, FDH) and all instruction lengths (1-4 bytes). The result is used to place the next-instruction trap for single-stepping.
Entry: C = opcode byte, HL = address after opcode, B = command flag (0=I, 1=C), E = initial offset (02H for prefixed, 00H for normal).
Exit: HL = address of next instruction (where the trap should be placed).
5125
LD E,02H 1E 02
Load E with 02H - initial instruction length offset for prefixed instructions (DD/FD prefix adds 1 byte).
5127
JUMP to 512BH to begin instruction decoding.
5129
LD E,00H 1E 00
Load E with 00H - normal (non-prefixed) instruction length offset.
512B
LD C,(HL) 4E
Fetch the opcode byte from the instruction address into C.
512C
LD A,C 79
Copy the opcode to A for analysis.
512D
CP E9H FE E9
Compare against E9H (JP (HL) or JP (IX)/JP (IY) with prefix). If match, this is an indirect jump.
512F
INC HL 23
INCrement HL to point past the opcode.
5130
If JP (HL/IX/IY), JUMP to 5190H to handle the indirect jump (reads target from register).
5132
CP CBH FE CB
Compare against CBH (CB prefix for bit/rotate instructions).
5134
If CB prefix, JUMP to 51AAH - all CB instructions are 2 bytes (skip 1 more byte).
5136
SUB 34H D6 34
SUBtract 34H. This transforms opcodes 34H-35H (INC/DEC (HL)) to 0-1.
5138
CP 02H FE 02
Compare against 02H.
513A
If match (opcodes 34H-35H which are INC/DEC (HL) or (IX+d)/(IY+d) with prefix), skip 1 byte for the displacement.
513C
CP 8CH FE 8C
Compare against 8CH.
513E
If less (opcodes in the 34H-BFH range after subtraction), JUMP to 51ABH - these are 2-byte instructions (skip 2 more).
5140
LD A,C 79
Reload the original opcode into A.
5141
CP C0H FE C0
Compare against C0H. Opcodes below C0H are 1-byte instructions.
5143
If below C0H, JUMP to 5168H to handle 1-byte and 2-byte instructions in the 00-BFH range.
Opcodes C0H and above. These include CALL, JP, RET, RST, and various 2/3-byte instructions. Extract the low 3 bits to sub-classify.
5145
AND 07H E6 07
Mask to keep only bits 0-2 (the "column" in the opcode table).
5147
If bits 0-2 = 000 (opcodes C0H, C8H, D0H, D8H, E0H, E8H, F0H, F8H = conditional RETs), JUMP to 51C8H - the RET handler.
5149
CP 02H FE 02
Compare against 02H.
514B
If bits 0-2 = 010 (JP cc,nn - conditional absolute jumps), JUMP to 5196H to read the target address from the instruction.
514D
CP 04H FE 04
Compare against 04H.
514F
If bits 0-2 = 100 (CALL cc,nn - conditional calls), JUMP to 51B8H to handle call instructions.
5152
CP 06H FE 06
Compare against 06H.
5154
If bits 0-2 = 110 (ALU immediate - ADD n, SUB n, etc.), skip 2 bytes.
For other opcodes in the C0-FF range, look up in the classification table at 510CH.
5156
LD DE,510CH 11 0C 51
Point DE to the opcode classification table at 510CH.
5159
LD A,(DE) 1A
[TABLE LOOKUP LOOP] Fetch the opcode pattern from the table.
515A
OR A B7
Test if A is 00H (end of table).
515B
INC DE 13
Advance to the handler offset byte.
515C
If end of table (no match found), JUMP to 51ACH - treat as a 1-byte instruction.
515E
CP C B9
Compare the table opcode against C (the actual opcode).
515F
LD A,(DE) 1A
Fetch the handler offset byte from the table.
5160
INC DE 13
Advance past the handler byte.
5161
If no match, loop to try the next table entry. [TABLE LOOKUP LOOP END]
Match found. The handler offset in A is actually a low byte of an address in the 51xxH page. Build the full address and jump to it.
5163
LD E,A 5F
Store the handler offset in E.
5164
LD D,51H 16 51
Load D with 51H - the high byte of the handler address.
5166
PUSH DE D5
Push the handler address onto the stack.
5167
RET C9
RETURN (effectively jumps to the handler address via the pushed value).
Handle opcodes in the 00H-BFH range (single-byte and 2-byte instructions).
5168
CP 40H FE 40
Compare A against 40H. Opcodes 40H-7FH are all 1-byte LD instructions.
516A
If >= 40H, JUMP to 51ACH - 1-byte instruction (no additional bytes to skip).
516C
AND 0FH E6 0F
Mask to low nibble for 00H-3FH range analysis.
516E
CP 01H FE 01
Compare against 01H.
5170
If low nibble = 01H (LD rr,nn - 3-byte instructions), skip 2 bytes.
5172
AND 07H E6 07
Mask to bits 0-2.
5174
BIT 5,C CB 69
Test bit 5 of the original opcode C. This further classifies the instruction.
5176
If bit 5 is 0, JUMP to 5152H to continue classification.
5178
CP 02H FE 02
Compare against 02H.
517A
If bits 0-2 = 010, skip 2 bytes (LD (nn),A type).
517C
OR A B7
Test if bits 0-2 = 000.
517D
If not 000, JUMP back to 5152H for further classification.
Handle relative branch instructions (JR cc,d).
517F
DEC C 0D
DECrement C (test for sign-extension handling).
5180
INC C 0C
INCrement C back (restores original value, but flags reflect the DEC).
5181
LD A,(HL) 7E
Fetch the relative displacement byte from the instruction.
5182
LD E,A 5F
Store displacement in E.
5183
LD D,00H 16 00
Clear D for positive displacement.
5185
INC HL 23
INCrement HL past the displacement byte.
5186
RLCA 07
Rotate the displacement byte left. If bit 7 was set (negative displacement), Carry is set.
5187
If positive displacement, skip the sign extension.
5189
DEC D 15
DECrement D from 00H to FFH, sign-extending the negative displacement.
518A
EX DE,HL EB
Swap: DE = address after displacement, HL = signed displacement.
518B
ADD HL,DE 19
ADD the displacement to the address. HL = target of the relative branch.
518C
JUMP to 519BH to finalize the branch target.
Handle JP (HL) / JP (IX) / JP (IY) - reads the target from the saved register value.
518E
LD E,10H 1E 10
Load E with 10H - the stack offset for the HL register (for JP (HL)).
5190
LD D,00H 16 00
Clear D.
5192
LD HL,(4D44H) 2A 44 4D
Load HL with the saved SP from 4D44H (base of register storage).
5195
ADD HL,DE 19
ADD the register offset to SP. HL points to the saved register value.
5196
LD E,(HL) 5E
Fetch low byte of the register/target value.
5197
INC HL 23
INCrement HL.
5198
LD D,(HL) 56
Fetch high byte. DE = target address.
5199
INC HL 23
INCrement HL past the value.
519A
EX DE,HL EB
Swap: HL = target address, DE = pointer past value.
519B
LD B,C 41
Copy the original opcode to B.
519C
JUMP to 51BCH to check if the target is within the overlay area.
Handle ED-prefixed instructions - check the secondary opcode for instruction length.
519E
LD A,(HL) 7E
Fetch the second byte of the ED-prefixed instruction.
519F
AND 07H E6 07
Mask bits 0-2.
51A1
CP 05H FE 05
Compare against 05H.
51A3
INC HL 23
Advance past the second byte.
51A4
If bits 0-2 = 101 (RETI/RETN), JUMP to 51C8H - the RET handler.
51A6
CP 03H FE 03
Compare against 03H.
51A8
If not 03H, JUMP to 51ACH (2-byte total for ED+opcode).
51AA
INC HL 23
INCrement HL - skip one additional byte (for 3-byte instructions).
51AB
INC HL 23
INCrement HL - skip one more byte.
51AC
LD D,00H 16 00
Clear D (no branch target, this is a sequential instruction).
51AE
LD A,H 7C
Load A with H (high byte of next instruction address).
51AF
CP 52H FE 52
Compare against 52H. Addresses below 5200H are within the overlay area.
51B1
If address is below the overlay (Carry set), JUMP to 51C5H for ERROR.
51B3
PUSH HL E5
Push HL (next instruction address) as a trap target.
51B4
PUSH DE D5
Push DE (branch target or 0000H) as a second trap target.
51B5
JUMP to 4DA1H to set the traps and exit DEBUG (resume execution).
Handle CALL cc,nn and absolute JP instructions - read the 2-byte target address.
51B8
LD E,(HL) 5E
Fetch the low byte of the call/jump target address.
51B9
INC HL 23
INCrement HL.
51BA
LD D,(HL) 56
Fetch the high byte. DE = target address.
51BB
INC HL 23
INCrement HL past the target address.
51BC
BIT 0,B CB 40
Test bit 0 of B (command flag: 0=I step, 1=C step with call tracing). If bit 0 is set, the C command is active.
51BE
If the C command (bit 0 set), do NOT follow the call/jump - treat it as sequential. JUMP to 51ACH to place trap at the next instruction instead.
51C0
LD A,D 7A
Load A with D (high byte of the target address).
51C1
CP 52H FE 52
Compare against 52H. Check if the target is within the overlay area.
51C3
If target is at or above 5200H (outside overlay), JUMP to 51AEH to set up normal traps.
51C5
JUMP to 50B9H - the ERROR handler. The target address is within the overlay area, which would corrupt DEBUG itself.
51C8H - RET Instruction Handler
When the current instruction is a RET (or conditional RET, RETI, RETN), the next instruction address is not in the code stream - it is on the stack. This handler looks up the return address from the saved stack pointer to determine where execution will go after the RET.
51C8
EX DE,HL EB
Swap DE and HL. Save the current instruction pointer in DE.
51C9
LD HL,(4DC3H) 2A C3 4D
Load HL with the return address pointer from 4DC3H. This points to the saved stack frame above the PC, where the return address that a RET would pop is stored.
51CC
LD A,(HL) 7E
Fetch the low byte of the return address.
51CD
INC HL 23
INCrement HL.
51CE
LD H,(HL) 66
Fetch the high byte into H.
51CF
LD L,A 6F
Move the low byte into L. HL = the return address (where a RET would jump to).
51D0
JUMP to 519BH to use this return address as the branch target for trap placement.
51D2H - Data: "ERROR" String and Prompt Data
Data area containing the "ERROR" message string, the DEBUG prompt/flag character data, and the search pattern buffer. This is not executable code.
51D2-51D7
DEFM 45 52 52 4F 52 03
"ERROR" + 03H (ETX terminator). This string is displayed by the ERROR handler at 50B9H. Bytes: 45H='E', 52H='R', 52H='R', 4FH='O', 52H='R', 03H=ETX.
51D8-51DA
DEFB 1C 1F 03
Control bytes for the DEBUG prompt display: 1CH = cursor home, 1FH = clear to end of screen, 03H = ETX terminator. These are sent via the string display routine to position and clear the screen before the prompt.
51DB-51E2
DEFM 53 5A 31 48 31 50 4E 43
"SZ1H1PNC" - the flag bit name characters used in the full register display. Each character corresponds to one bit of the Flags register (bit 7 = S, bit 6 = Z, bit 5 = '1'/unused, bit 4 = H, bit 3 = '1'/unused, bit 2 = P/V, bit 1 = N, bit 0 = C). The '1' characters for bits 5 and 3 represent the fixed/unused flag positions.
51E3-51E7
DEFB 00 00 00 00 00
Padding bytes (00H). Reserved space.
51E8-51FF
DEFB (24 bytes) ...
Search Pattern Buffer for the F (Find) command. Stores up to 24 bytes of the byte pattern to search for in memory. The input buffer for command entry (at 51ECH) also overlaps this area.
END OF SYS5/SYS (DEBUG) DISASSEMBLY
The DEBUG overlay occupies addresses 4D00H through 51FFH (approximately 1.25 KB). It provides interactive debugging capabilities including: memory examination and modification with a hex/ASCII display, complete register viewing and editing (all Z80 registers including alternates and index registers), two settable breakpoint traps using RST 30H (F7H) patching, single-stepping with instruction length decoding for all Z80 opcodes and prefixes, byte pattern searching across all memory, and direct disk sector read/write capability.