4D00H - DEBUG Entry Point and Register Save
The DEBUG module is entered via CALL or when a breakpoint (F7H opcode triggering RST 18H) is encountered. At entry, the return address is on the stack. The first task is to save ALL CPU registers so they can be displayed and restored when the user exits. The EX (SP),HL trick swaps HL with the return address, saving the original HL while capturing where we came from.
4D00
EX (SP),HL E3
Exchange Register HL with the value on top of stack. This swaps the caller's return address into HL while simultaneously saving the original HL onto the stack. Now HL holds the return address (where we came from).
4D01
PUSH BC C5
Save Register BC onto the stack for later restoration.
4D02
PUSH DE D5
Save Register DE onto the stack for later restoration.
4D03
EX AF,AF' 08
Exchange AF with the alternate register AF'. This switches to the alternate accumulator/flags pair so we can save the primary AF.
4D04
EXX D9
Exchange BC, DE, HL with their alternate registers BC', DE', HL'. After this, the alternate registers are now the active set.
4D05
PUSH AF F5
Save the alternate AF' onto the stack.
4D06
PUSH BC C5
Save the alternate BC' onto the stack.
4D07
PUSH DE D5
Save the alternate DE' onto the stack.
4D08
PUSH HL E5
Save the alternate HL' 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.
Now all registers have been pushed. The stack pointer value needs to be saved so we can access the saved registers later. This is stored via self-modifying code into the LD SP instruction at 4D43H.
4D0D
LD (4D44H),SP ED 73 44 4D
Store the current Stack Pointer value into memory at 4D44H. This is the operand of the LD SP,nnnn instruction at 4D43H. This saved SP value points to our register save area.
4D11
LD HL,0014H 21 14 00
Load Register HL with 0014H (20 decimal). This is the offset from the current SP to where the return address was stored on the original caller's stack.
4D14
ADD HL,SP 39
ADD the Stack Pointer to HL. HL now points to the location on the stack where the return address is stored (past all the pushed registers).
4D15
LD E,(HL) 5E
Load Register E with the low byte of the return address from the stack.
4D16
INC HL 23
INCrement HL to point to the high byte of the return address.
4D17
LD D,(HL) 56
Load Register D with the high byte of the return address. DE now contains the full return address.
4D18
LD (4DC7H),DE ED 53 C7 4D
Store the return address (in DE) into the current execution pointer at 4DC7H. This is the address where execution will resume when the user types "G" to go.
4D1C
INC HL 23
INCrement HL to point past the return address to the caller's original stack frame.
4D1D
DEC DE 1B
DECrement DE. If we came from a breakpoint (RST 18H with F7H), we need to back up one byte to re-execute the replaced instruction. This makes DE point to the actual breakpoint location.
4D1E
PUSH DE D5
Save the adjusted return address (breakpoint location) onto the stack for later use.
4D1F
LD (4DC3H),HL 22 C3 4D
Store HL (pointer to caller's stack frame) into memory at 4DC3H. This allows us to access any additional parameters the caller may have passed.
Now call the delay routine to ensure any disk motors have time to spin down and the system stabilizes before entering interactive mode.
4D22
LD B,80H 06 80
Load Register B with 80H (128 decimal). This is the delay count for the timing loop.
4D24
GOSUB to the SYS0 delay routine at 4CEDH. This provides a short delay allowing disk drives to settle.
Check if there are existing breakpoints that need to be restored. The breakpoint system works by replacing the opcode at the breakpoint address with F7H (which triggers RST 18H). The original opcodes are stored in a table at 404BH. We need to check if any breakpoints are currently active and restore the original bytes.
4D27
LD HL,404BH 21 4B 40
Point Register HL to 404BH, the breakpoint table in the DOS system area. This table holds up to 2 breakpoint entries, each consisting of: address (2 bytes) + original opcode (1 byte).
4D2A
LD B,02H 06 02
Load Register B with 02H. We can have up to 2 breakpoints, so loop twice.
[LOOP START] - Check each breakpoint entry. If a breakpoint is active (the byte at the breakpoint address is F7H), restore the original opcode.
4D2C
LD E,(HL) 5E
Load Register E with the low byte of the breakpoint address from the table.
4D2D
INC HL 23
INCrement HL to point to the high byte of the address.
4D2E
LD D,(HL) 56
Load Register D with the high byte of the breakpoint address. DE now holds the breakpoint address.
4D2F
INC HL 23
INCrement HL to point to the saved original opcode byte.
4D30
LD A,(DE) 1A
Load Register A with the byte currently at the breakpoint address (DE).
4D31
CP F7H FE F7
Compare Register A against F7H (the RST 30H opcode used as breakpoint marker). If the Z FLAG is set, a breakpoint is active here.
4D33
If the NZ FLAG is set (byte is not F7H, meaning no active breakpoint), JUMP forward to 4D40H to skip restoration and move to next entry.
4D35
LD A,(HL) 7E
Load Register A with the saved original opcode from the breakpoint table.
4D36
LD (DE),A 12
Restore the original opcode to the breakpoint address. The F7H is replaced with what was originally there.
4D37
EX (SP),HL E3
Exchange HL with the top of stack. HL now contains the adjusted return address (breakpoint location) that was pushed at 4D1EH.
4D38
RST 18H DF
Call RST 18H to compare DE (breakpoint address) with HL (return address). RST 18H in NEWDOS/80 performs a CP HL,DE comparison, setting Z if they match.
4D39
EX (SP),HL E3
Exchange HL back with the stack, restoring HL to the breakpoint table pointer.
4D3A
If the NZ FLAG is set (this breakpoint is not where we stopped), JUMP to 4D40H to continue checking.
This breakpoint matches where we stopped! Update the execution pointer to this address so the display shows the correct location.
4D3C
LD (4DC7H),DE ED 53 C7 4D
Store the breakpoint address (DE) as the current execution pointer at 4DC7H. This is where we'll resume from.
4D40
INC HL 23
INCrement HL to point to the next breakpoint entry in the table (past the saved opcode byte).
4D41
DECrement B and Jump if Not Zero. [LOOP] Repeat for the second breakpoint entry.
Breakpoints have been cleared. Now set up the stack for the main debug loop. The self-modifying code at 4D43H will be modified to contain our saved SP, and we push the address of 4D43H as a return address so any RET will restart the debug command loop.
4D43
LD SP,0000H 31 00 00
Load Stack Pointer with 0000H. SELF-MODIFYING: The operand at 4D44H was set at 4D0DH to the saved SP value pointing to our register save area. This restores access to the saved registers.
4D46
LD HL,4D43H 21 43 4D
Load Register HL with 4D43H, the address of the LD SP instruction above.
4D49
PUSH HL E5
PUSH 4D43H onto the stack. This becomes the return address for any RET instruction, creating a loop back to restart the debug command prompt.
4D4A
GOSUB to 4FC7H to display the register contents and current state to the user.
4D4DH - Command Input and Parsing Setup
After displaying registers, set up the command input. The cursor position is set to column 64 of the screen (bottom visible area), and user input is read. The input line is then parsed to determine which debug command to execute.
4D4D
LD HL,3FC0H 21 C0 3F
Load Register HL with 3FC0H. This is a video RAM address at the start of line 15 (row 15 × 64 = 960 = 3C0H offset from 3C00H), used for command input display.
4D50
LD (4020H),HL 22 20 40
Store the cursor position (3FC0H) into the DOS cursor position variable at 4020H.
4D53
LD HL,51ECH 21 EC 51
Load Register HL with 51ECH, pointing to the command input buffer where user input will be stored.
4D56
LD B,12H 06 12
Load Register B with 12H (18 decimal). This is the maximum number of characters allowed for command input.
4D58
GOSUB to ROM routine at 0040H to read a line of keyboard input. HL points to the buffer, B is max length. On return, HL points to the start of the input.
Now parse the input. First check if the command starts with a digit (0-3), which selects a display format. The display format pointer at 4EBDH determines how memory is shown.
4D5B
LD DE,405DH 11 5D 40
Load Register DE with 405DH. This is the base address for the display pointer table. The table has entries for different display formats.
4D5E
LD A,(HL) 7E
Load Register A with the first character of the user's input from the buffer.
4D5F
SUB 32H D6 32
SUBtract 32H (ASCII 2) from Register A. This converts '2' to 0, '3' to 1.
4D61
CP 02H FE 02
Compare Register A against 02H. If A < 2, the CARRY FLAG is set (input was '2' or '3').
4D63
If the NO CARRY FLAG is set (input was not '2' or '3'), JUMP to 4D6AH to skip format selection.
4D65
INC A 3C
INCrement A. Now A = 1 for '2', A = 2 for '3'.
4D66
ADD A,A 87
ADD A to itself (multiply by 2). Each table entry is 2 bytes.
4D67
ADD A,E 83
ADD E to A. Calculate the offset into the display pointer table.
4D68
LD E,A 5F
Load Register E with A. DE now points to the selected entry in the display format table.
4D69
INC HL 23
INCrement HL to skip past the format digit in the input buffer.
4D6A
LD (4EBDH),DE ED 53 BD 4E
Store DE into 4EBDH. This sets the display format pointer used when showing memory contents.
Now convert the command line to uppercase. This loop processes each character in the input buffer through the uppercase conversion routine.
4D6E
PUSH HL E5
Save HL (pointer to command) onto the stack.
4D6F
INC B 04
INCrement B. B was zero or contained a residual value; now it becomes the loop counter for uppercase conversion.
[LOOP START] - Convert each character to uppercase.
4D70
LD A,(HL) 7E
Load Register A with the current character from the input buffer.
4D71
GOSUB to SYS0 routine at 45B5H to convert the character in A to uppercase.
4D74
LD (HL),A 77
Store the uppercase character back into the input buffer.
4D75
INC HL 23
INCrement HL to point to the next character.
4D76
DECrement B and Jump if Not Zero. [LOOP] Continue converting until all characters processed.
4D78
POP HL E1
Restore HL (pointer to start of command) from the stack.
Now dispatch based on the first character of the command. Check for 'G' (Go command) first.
4D79
LD A,(HL) 7E
Load Register A with the first character of the command.
4D7A
CP 47H FE 47
Compare Register A against 47H (ASCII G). This tests for the "Go" command.
4D7C
If the NZ FLAG is set (not 'G'), JUMP to 4DCDH to check for other commands.
4D7EH - 'G' (Go) Command Processing
The Go command executes code from a specified address or the current PC. Syntax: G [address][,breakpoint1][,breakpoint2]. First check if there's an address parameter.
4D7E
GOSUB to 509BH to check if the next character is a hex digit. If so, CARRY is set and A contains the digit value.
4D81
If the NO CARRY FLAG is set (no hex digit, so no address given), JUMP to 4D8AH to use the current execution pointer.
4D83
GOSUB to 5079H to parse a 16-bit hex address from the command line into DE.
4D86
LD (4DC7H),DE ED 53 C7 4D
Store the parsed address (DE) as the new execution pointer at 4DC7H. This is where 'G' will jump to.
Now parse up to 2 breakpoint addresses. Each breakpoint is separated by a comma.
4D8A
LD B,02H 06 02
Load Register B with 02H. We can set up to 2 breakpoints.
4D8C
LD D,00H 16 00
Load Register D with 00H. Initialize DE high byte to zero (in case no breakpoint address is given, we'll use 00xxH).
[LOOP START] - Parse each breakpoint address.
4D8E
LD A,(HL) 7E
Load Register A with the current character from the command line.
4D8F
CP 2CH FE 2C
Compare Register A against 2CH (ASCII comma ,). A comma separates the address from breakpoints.
4D91
If the NZ FLAG is set (no comma), JUMP to 4D9BH to push a zero breakpoint address.
4D93
GOSUB to 5078H to skip the comma and parse a hex address into DE.
4D96
LD A,D 7A
Load Register A with D (high byte of the breakpoint address).
4D97
CP 52H FE 52
Compare Register A against 52H. Addresses above 5200H are in the DEBUG module itself and cannot have breakpoints set.
4D99
If the CARRY FLAG is set (address < 5200H), JUMP to 4DE9H to report an error - breakpoint address is invalid (within DEBUG itself).
4D9B
PUSH DE D5
PUSH the breakpoint address (or 0000H if none) onto the stack.
4D9C
DECrement B and Jump if Not Zero. [LOOP] Parse the second breakpoint if present.
Both breakpoints have been parsed and pushed. Now verify the command line ends properly.
4D9E
GOSUB to 50B5H to verify the command line ends with a carriage return (0DH). If not, error.
Set up the breakpoints. The breakpoint table at 404BH stores address (2 bytes) + original opcode (1 byte) for each breakpoint. We install breakpoints by saving the original byte and replacing it with F7H (RST 30H).
4DA1
LD HL,404BH 21 4B 40
Point Register HL to the breakpoint table at 404BH.
4DA4
LD B,02H 06 02
Load Register B with 02H for the two breakpoint entries.
[LOOP START] - Install each breakpoint.
4DA6
POP DE D1
POP the breakpoint address from the stack into DE.
4DA7
LD (HL),E 73
Store the low byte of the breakpoint address into the table.
4DA8
INC HL 23
INCrement HL to the next table byte.
4DA9
LD (HL),D 72
Store the high byte of the breakpoint address into the table.
4DAA
INC HL 23
INCrement HL to point to the saved opcode byte in the table.
4DAB
LD A,(DE) 1A
Load Register A with the byte currently at the breakpoint address. This is the original opcode we need to save.
4DAC
LD (HL),A 77
Store the original opcode into the breakpoint table for later restoration.
4DAD
INC HL 23
INCrement HL to the next table entry.
4DAE
LD A,F7H 3E F7
Load Register A with F7H. This is the RST 30H opcode used as the breakpoint trigger.
4DB0
LD (DE),A 12
Store F7H at the breakpoint address, replacing the original opcode. When execution reaches here, RST 30H will trigger and re-enter DEBUG.
4DB1
DECrement B and Jump if Not Zero. [LOOP] Install the second breakpoint.
4DB3H - Register Restore and Exit
All breakpoints are installed. Now restore all the saved registers and return to execution at the target address. The registers were pushed in order: AF', BC', DE', HL', IX, IY (from the alternate set), then the stack was manipulated. Pop them in reverse order.
4DB3
POP AF F1
Restore the alternate AF' from the stack. (Note: this pops a value that will be discarded or is a placeholder)
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 alternate HL' from the stack.
4DB9
POP DE D1
Restore alternate DE' from the stack.
4DBA
POP BC C1
Restore alternate BC' from the stack.
4DBB
POP AF F1
Restore alternate AF' from the stack.
4DBC
EX AF,AF' 08
Exchange AF with AF', switching back to the primary accumulator set.
4DBD
EXX D9
Exchange BC, DE, HL with their alternates, switching back to the primary register set.
4DBE
POP DE D1
Restore primary DE from the stack.
4DBF
POP BC C1
Restore primary BC from the stack.
4DC0
POP HL E1
Restore primary HL from the stack (this was the original HL that was swapped at entry).
4DC1
POP AF F1
Restore primary AF from the stack.
Now set up the stack pointer and jump to the execution address. The self-modifying code stores the original SP and the target address.
4DC2
LD SP,0000H 31 00 00
Load Stack Pointer with 0000H. SELF-MODIFYING: The operand here (at 4DC3H) should be set to the caller's original stack pointer value.
4DC5
PUSH HL E5
PUSH HL onto the stack. This saves HL so we can use it for the jump address.
4DC6
LD HL,0000H 21 00 00
Load Register HL with 0000H. SELF-MODIFYING: The operand here (at 4DC7H) is the execution pointer - the address where we'll jump to resume execution.
4DC9
EX (SP),HL E3
Exchange HL with the top of stack. This puts the execution address on the stack (as a return address) and restores the original HL value.
4DCA
JUMP to 4C20H in SYS0. This routine performs a RET instruction, effectively jumping to the address we placed on the stack (the execution pointer). The user's program resumes.
4DCDH - 'R' (Register Modify) Command Handler
Check if the command is 'R' for register display/modify. The R command allows viewing and changing CPU register values. Syntax: R [register-name value] where register names are: AF, BC, DE, HL, AF', BC', DE', HL', IX, IY, PC, SP.
4DCD
CP 52H FE 52
Compare Register A against 52H (ASCII R). Test for the Register command.
4DCF
If the NZ FLAG is set (not 'R'), JUMP to 4E03H to check for other commands.
It's the R command. Parse the register name by matching against a table of known names at 50DBH. The table format is: 2-byte name, 1-byte offset code. A space in position 2 means single-char register name.
4DD1
LD DE,50DBH 11 DB 50
Point Register DE to 50DBH, the register name table. Each entry is 3 bytes: 2-char name + offset code.
4DD4
LD B,03H 06 03
Load Register B with 03H. Compare 3 bytes (2 name chars + check for match).
4DD6
PUSH HL E5
Save HL (command line pointer) onto the stack.
[LOOP START] - Compare user input against table entry.
4DD7
INC HL 23
INCrement HL to point to the next character in the user's input (skip the 'R').
4DD8
LD A,(DE) 1A
Load Register A with the current byte from the register name table.
4DD9
CP (HL) BE
Compare the table byte against the user's input character.
4DDA
INC DE 13
INCrement DE to the next table byte.
4DDB
If the Z FLAG is set (characters match), JUMP to 4DECH to continue matching or finish.
4DDD
CP 20H FE 20
Compare the table byte against 20H (ASCII space). A space means "any character matches here" (for single-char names like 'A').
4DDF
If the Z FLAG is set (table has space = wildcard), JUMP to 4DF0H to check for comma delimiter.
No match on this entry. Skip to the next table entry.
4DE1
INC DE 13
INCrement DE to skip past the rest of this table entry.
4DE2
DECrement B and Jump if Not Zero. [LOOP] Skip remaining bytes of this entry.
4DE4
POP HL E1
Restore HL (original command pointer) from the stack.
4DE5
LD A,(DE) 1A
Load Register A with the next byte from the table (start of next entry or terminator).
4DE6
OR A B7
OR A with itself to test if it's zero (end of table marker).
4DE7
If the NZ FLAG is set (not end of table), JUMP back to 4DD4H to try the next entry.
End of table reached with no match. This is an error.
4DE9
JUMP to 50B9H to display "ERROR" message and return to command prompt.
Found a match so far. Continue checking or finish if all chars matched.
4DEC
DECrement B and Jump if Not Zero. [LOOP] Continue matching more characters.
4DEE
INC HL 23
INCrement HL past the matched register name.
4DEF
INC B 04
INCrement B (it was zero after DJNZ; now B=1).
Check that the register name is followed by a comma before the value.
4DF0
LD A,(HL) 7E
Load Register A with the character after the register name.
4DF1
CP 2CH FE 2C
Compare Register A against 2CH (ASCII comma ,). The new value follows the comma.
4DF3
If the NZ FLAG is set (no comma), JUMP back to 4DE1H - might be partial match, try next entry.
Valid register name found with comma. Parse the new value and store it.
4DF5
POP AF F1
POP the saved HL (original command pointer) but discard it into AF - we don't need it anymore.
4DF6
LD A,(DE) 1A
Load Register A with the offset code from the register table. This indicates which register and where to store the value.
4DF7
PUSH AF F5
Save the offset code onto the stack.
4DF8
GOSUB to 50B2H to parse a hex value from the command line into DE and verify it ends with CR.
4DFB
POP AF F1
Restore the offset code from the stack into A.
4DFC
GOSUB to 50C9H to calculate the address in the register save area where this register value is stored. Returns HL pointing to the storage location.
4DFF
LD (HL),E 73
Store the low byte of the new value (E) into the register save area.
4E00
INC HL 23
INCrement HL to point to the high byte location.
4E01
LD (HL),D 72
Store the high byte of the new value (D) into the register save area.
4E02
RET C9
RETurn to the main debug loop (via the return address pushed at 4D49H which points to 4D43H).
4E03H - 'F' (Find) Command Handler
Check for 'F' command - Find bytes in memory. Syntax: F [byte1,byte2,...] searches all of memory for the specified pattern.
4E03
CP 46H FE 46
Compare Register A against 46H (ASCII F). Test for the Find command.
4E05
If the NZ FLAG is set (not 'F'), JUMP to 4E59H to check for other commands.
It's the Find command. Initialize search parameters. If no new pattern is given, use the previous one stored at 51E8H.
4E07
LD DE,0000H 11 00 00
Load Register DE with 0000H. SELF-MODIFYING: The operand at 4E08H stores the last search result address. On first call this is 0000H; subsequent F commands continue from here.
4E0A
INC DE 13
INCrement DE to start searching from the next address after the last match.
4E0B
LD B,00H 06 00
Load Register B with 00H. SELF-MODIFYING: The operand at 4E0CH stores the pattern length. This is set when parsing a new pattern.
4E0D
INC HL 23
INCrement HL to skip past the 'F' command character.
4E0E
LD A,(HL) 7E
Load Register A with the next character from the command line.
4E0F
CP 0DH FE 0D
Compare Register A against 0DH (carriage return). If just "F" was typed, search using the existing pattern.
4E11
If the Z FLAG is set (CR = no new pattern), JUMP to 4E32H to search using the existing pattern.
New pattern specified. Parse hex bytes separated by commas and store them at 51E8H.
4E13
GOSUB to 5079H to parse the first hex byte into E (D will be 0 for single bytes).
4E16
PUSH DE D5
Save DE (parsed start address for search) onto the stack.
4E17
LD B,00H 06 00
Load Register B with 00H. Initialize byte counter for the pattern.
4E19
LD DE,51E8H 11 E8 51
Point Register DE to 51E8H, the search pattern buffer.
[LOOP START] - Parse each pattern byte.
4E1C
PUSH DE D5
Save DE (pattern buffer pointer) onto the stack.
4E1D
GOSUB to 50AEH to check for comma delimiter and continue parsing.
4E20
GOSUB to 5078H to parse the next hex byte into DE.
4E23
LD A,E 7B
Load Register A with E (the parsed byte value).
4E24
POP DE D1
Restore DE (pattern buffer pointer) from the stack.
4E25
INC B 04
INCrement B (pattern length counter).
4E26
LD (DE),A 12
Store the parsed byte into the pattern buffer.
4E27
INC DE 13
INCrement DE to the next position in the pattern buffer.
4E28
LD A,(HL) 7E
Load Register A with the current character from the command line.
4E29
CP 0DH FE 0D
Compare Register A against 0DH (carriage return). Check if end of input.
4E2B
If the NZ FLAG is set (more bytes to parse), JUMP back to 4E1CH. [LOOP]
4E2D
POP DE D1
Restore DE (starting search address) from the stack.
4E2E
LD A,B 78
Load Register A with B (the pattern length).
4E2F
LD (4E0CH),A 32 0C 4E
Store the pattern length into the self-modifying code at 4E0CH for future searches.
Now perform the search. Compare memory starting at DE against the pattern at 51E8H.
4E32
LD HL,51E8H 21 E8 51
Point Register HL to the search pattern buffer at 51E8H.
4E35
EX DE,HL EB
Exchange DE and HL. Now DE=pattern buffer, HL=search address.
[OUTER LOOP] - Try matching at each memory 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 search address) onto the stack.
[INNER LOOP] - Compare pattern bytes against memory.
4E39
LD A,(DE) 1A
Load Register A with the current byte from the pattern buffer.
4E3A
CP (HL) BE
Compare the pattern byte against the byte in memory.
4E3B
INC DE 13
INCrement DE to the next pattern byte.
4E3C
INC HL 23
INCrement HL to the next memory address.
4E3D
If the NZ FLAG is set (bytes don't match), JUMP to 4E41H to try next address.
4E3F
DECrement B and Jump if Not Zero. [INNER LOOP] Continue comparing pattern bytes.
4E41
POP HL E1
Restore HL (search address for this attempt) 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 is set (all bytes matched = pattern found!), JUMP to 4E4BH to report the match.
4E46
INC HL 23
INCrement HL to try matching at the next memory address.
4E47
LD A,H 7C
Load Register A with H (high byte of search address).
4E48
OR L B5
OR H with L. Test if HL has wrapped around to 0000H (searched all memory).
4E49
If the NZ FLAG is set (haven't wrapped around), JUMP back to 4E36H to try next address. [OUTER LOOP]
Pattern found at address HL, or wrapped around (HL=0000H means not found). Store the result and update display pointer.
4E4B
LD (4E08H),HL 22 08 4E
Store the match address (or 0000H if not found) into the self-modifying code at 4E08H for next search.
4E4E
LD DE,FFE0H 11 E0 FF
Load Register DE with FFE0H (-32 in two's complement). This offsets the display to show context before the match.
4E51
ADD HL,DE 19
ADD DE to HL. Back up 32 bytes so the match appears in context on the display.
4E52
LD (405DH),HL 22 5D 40
Store the adjusted address into the display pointer at 405DH. The memory display will start from here.
4E55
LD A,58H 3E 58
Load Register A with 58H (ASCII X). This is a flag/command code indicating display update.
4E57
JUMP to 4ECFH to process the display update command.
4E59H - 'L' (Load Sector) Command Handler
Check for 'L' command - Load a disk sector directly into memory. Syntax: L drive,track,sector,address
4E59
CP 4CH FE 4C
Compare Register A against 4CH (ASCII L). Test for the Load command.
4E5B
If the NZ FLAG is set (not 'L'), JUMP to 4E6BH to check for other commands.
4E5D
GOSUB to 4E87H to parse the disk parameters (drive, track, sector, address) from the command line.
4E60
XOR A AF
XOR A with itself. Set A = 0 and set the Z FLAG.
4E61
If the Z FLAG is set (always true here), GOSUB to SYS0 routine at 4630H to read the disk sector into the buffer.
4E64
RET Z C8
If the Z FLAG is set (read successful), RETurn to the main debug loop.
4E65
CP 06H FE 06
Compare Register A against 06H. Error code 06H means "drive not ready".
4E67
RET Z C8
If the Z FLAG is set (drive not ready), RETurn silently - this is often just the drive being empty.
4E68
JUMP to 50B9H to display "ERROR" message for other disk errors.
4E6BH - 'W' (Write Sector) Command Handler
Check for 'W' command - Write memory to a disk sector. Syntax: WR drive,track,sector,address (the R is required to confirm write).
4E6B
CP 57H FE 57
Compare Register A against 57H (ASCII W). Test for the Write command.
4E6D
If the NZ FLAG is set (not 'W'), JUMP to 4EB5H to check for other commands.
4E6F
INC HL 23
INCrement HL to point to the character after 'W'.
4E70
LD A,(HL) 7E
Load Register A with the next character.
4E71
CP 52H FE 52
Compare Register A against 52H (ASCII R). The 'R' is required as confirmation to prevent accidental writes.
4E73
If the NZ FLAG is set (no 'R' confirmation), JUMP to 4E68H to display "ERROR".
4E75
GOSUB to 4E87H to parse the disk parameters (drive, track, sector, address).
4E78
GOSUB to SYS0 routine at 4634H to perform disk read with retry (this reads the sector to verify the disk is accessible).
4E7B
If the Z FLAG is set (read successful), GOSUB to 4640H to write the sector to disk.
4E7E
If the Z FLAG is set (write successful), JUMP to 4E85H to verify.
4E80
CP 06H FE 06
Compare Register A against 06H (drive not ready error).
4E82
If the Z FLAG is set (drive not ready), try calling 463CH for a write sector operation as a retry.
4E85
JUMP back to 4E61H to read-verify the sector was written correctly.
4E87H - Parse Disk Parameters Subroutine
This subroutine parses disk parameters from the command line for the L and W commands. Format: drive,track,sector,address. It validates the drive number and sets up the DOS disk I/O parameters.
4E87
LD A,(436CH) 3A 6C 43
Load Register A with the DOS flags from 436CH. Bit 7 indicates if disk I/O is allowed.
4E8A
RLCA 07
Rotate Left Circular through Accumulator. Move bit 7 into the Carry flag.
4E8B
If the CARRY FLAG is set (disk I/O disabled), JUMP to 4E68H to display "ERROR".
4E8D
GOSUB to 50ABH to parse the next hex value (drive number) into DE and check for comma.
4E90
LD A,D 7A
Load Register A with D (high byte of parsed value).
4E91
OR A B7
OR A with itself. Test if high byte is zero (drive number should be 0-3).
4E92
LD A,E 7B
Load Register A with E (the drive number).
4E93
If the Z FLAG is set (D was zero), GOSUB to SYS0 routine at 4776H to select the drive and validate the drive number.
4E96
If the NZ FLAG is set (drive select failed), JUMP to 4E68H to display "ERROR".
4E98
INC HL 23
INCrement HL past the comma.
4E99
LD A,0AH 3E 0A
Load Register A with 0AH (10 decimal). This is used as a multiplier base.
4E9B
GOSUB to 507BH to parse track and sector numbers into the DOS parameter area.
4E9E
GOSUB to 50B5H to verify the command line ends with carriage return.
4EA1
XOR A AF
XOR A with itself. Set A = 0.
4EA2
LD (43A4H),A 32 A4 43
Store 0 into 43A4H, clearing the flag that controls special memory display mode.
4EA5
LD HL,4200H 21 00 42
Load Register HL with 4200H. This is the default disk buffer address in the DOS area.
4EA8
LD (405DH),HL 22 5D 40
Store the buffer address into the display pointer at 405DH.
4EAB
RET C9
RETurn to caller.
4EACH - 'Q' (Quit/Exit) Command Handler
Check for 'Q' command - Quit DEBUG and return to DOS. (Note: This address is jumped to from other error paths)
4EAC
CP 51H FE 51
Compare Register A against 51H (ASCII Q). Test for the Quit command.
4EAE
If the NZ FLAG is set (not 'Q'), JUMP to 4E68H to display "ERROR" (unrecognized command).
4EB0
LD A,E3H 3E E3
Load Register A with E3H. This is the SVC function code for returning to DOS.
4EB2
LD C,0CH 0E 0C
Load Register C with 0CH. This is a parameter for the SVC call.
4EB4
RST 28H EF
Execute RST 28H (DOS Supervisor Call) to exit DEBUG and return to the DOS Ready prompt.
4EB5H - 'D' (Deposit) Command Handler
Check for 'D' command - Deposit a value at address 0000H. This is useful for setting the system reset vector. Syntax: D value
4EB5
CP 44H FE 44
Compare Register A against 44H (ASCII D). Test for the Deposit command.
4EB7
If the NZ FLAG is set (not 'D'), JUMP to 4EC3H to check for other commands.
4EB9
GOSUB to 50B2H to parse a hex value into DE and verify CR terminator.
4EBC
LD HL,0000H 21 00 00
Load Register HL with 0000H. This is the target address for the deposit.
4EBF
LD (HL),E 73
Store the low byte of the value (E) at address 0000H.
4EC0
INC HL 23
INCrement HL to address 0001H.
4EC1
LD (HL),D 72
Store the high byte of the value (D) at address 0001H.
4EC2
RET C9
RETurn to the main debug loop.
4EC3H - 'M' (Memory Edit) Command Handler
Check for 'M' command - Interactive memory edit mode. Syntax: M address enters interactive mode where you can type hex values to store and use cursor keys to navigate.
4EC3
CP 4DH FE 4D
Compare Register A against 4DH (ASCII M). Test for the Memory edit command.
4EC5
If the Z FLAG is set (is 'M'), JUMP to 4F0AH for full memory edit mode.
Not 'M'. Process other single-letter commands. These set or adjust the display pointer.
4EC7
INC HL 23
INCrement HL past the command character.
4EC8
LD C,A 4F
Save the command character into Register C for later use.
4EC9
GOSUB to 50B5H to verify the command line ends with carriage return.
4ECC
LD A,C 79
Load Register A with C (the command character saved earlier).
4ECD
LD B,00H 06 00
Load Register B with 00H. Initialize flag to indicate no special processing.
4ECF
LD HL,(4DC7H) 2A C7 4D
Load Register HL with the current execution pointer from 4DC7H.
4ED2
LD C,(HL) 4E
Load Register C with the byte at the current execution address. This is the next instruction opcode.
4ED3
INC HL 23
INCrement HL to point past the opcode.
4ED4
CP 49H FE 49
Compare Register A against 49H (ASCII I). Test for the Instruction step command.
4ED6
If the Z FLAG is set (is 'I'), JUMP to 5140H for instruction step mode.
4ED9
INC B 04
INCrement B. B is now 1, indicating we're processing a display command.
4EDA
CP 43H FE 43
Compare Register A against 43H (ASCII C). Test for the Continue command.
4EDC
If the Z FLAG is set (is 'C'), JUMP back to 4ED6H to also go to instruction step mode (C and I are similar).
Handle other display adjustment commands (X, S, ;, -).
4EDE
LD HL,(4EBDH) 2A BD 4E
Load Register HL with the display format pointer from 4EBDH.
4EE1
LD E,(HL) 5E
Load Register E with the low byte of the display address from the format table.
4EE2
INC HL 23
INCrement HL to the high byte.
4EE3
LD D,(HL) 56
Load Register D with the high byte. DE now contains the current display base address.
4EE4
LD HL,43A4H 21 A4 43
Point Register HL to the display mode flag at 43A4H.
4EE7
LD B,(HL) 46
Load Register B with the current display mode flag.
4EE8
LD (HL),01H 36 01
Set the display mode flag to 01H (enable special display mode).
4EEA
CP 58H FE 58
Compare Register A against 58H (ASCII X). Test for eXit/refresh display command.
4EEC
RET Z C8
If the Z FLAG is set (is 'X'), RETurn - just refresh the display with current settings.
4EED
DEC (HL) 35
DECrement the display mode flag back to 00H.
4EEE
CP 53H FE 53
Compare Register A against 53H (ASCII S). Test for Status/Show command.
4EF0
RET Z C8
If the Z FLAG is set (is 'S'), RETurn - display current state.
4EF1
LD (HL),B 70
Restore the original display mode flag.
4EF2
LD HL,0040H 21 40 00
Load Register HL with 0040H (64 decimal). This is the increment for the ';' command (move forward 64 bytes).
4EF5
CP 3BH FE 3B
Compare Register A against 3BH (ASCII ;). Test for forward scroll command.
4EF7
If the Z FLAG is set (is ';'), JUMP to 4F00H to add the offset.
4EF9
LD HL,FFC0H 21 C0 FF
Load Register HL with FFC0H (-64 in two's complement). This is the decrement for the '-' command.
4EFC
CP 2DH FE 2D
Compare Register A against 2DH (ASCII -). Test for backward scroll command.
4EFE
If the NZ FLAG is set (not '-'), JUMP to 4EACH - fall through to 'Q' check or error.
4F00
LD A,B 78
Load Register A with B (the display mode flag).
4F01
OR A B7
OR A with itself to test if display mode is active.
4F02
If the NZ FLAG is set (display mode active), JUMP to 4F06H to use single increment.
4F04
ADD HL,HL 29
Double HL (multiply by 2).
4F05
ADD HL,HL 29
Double HL again (now multiplied by 4). When not in special mode, scroll by 256 bytes instead of 64.
4F06
ADD HL,DE 19
ADD DE (current display address) to HL (offset). Calculate new display address.
4F07
EX DE,HL EB
Exchange DE and HL. DE now contains the new display address.
4F08
JUMP back to 4EBCH to store the new display address and return.
4F0AH - 'M' Command: Memory Edit Mode Setup
Full memory edit mode. Parse the starting address and enter interactive editing where the user can type hex digits and use cursor keys.
4F0A
GOSUB to 50B2H to parse the starting address into DE and verify CR terminator.
4F0D
EX DE,HL EB
Exchange DE and HL. HL now contains the starting memory address for editing.
4F0EH - Memory Edit Mode: Interactive Loop
The memory edit mode allows interactive viewing and modification of memory. The user sees the current address and value, and can type hex digits to change bytes, or use cursor keys to navigate. This is a sophisticated hex editor built into DEBUG.
4F0E
LD B,00H 06 00
Load Register B with 00H. B tracks which nibble (0=low, 1=high) we're editing within the current byte.
[MAIN EDIT LOOP] - Update display and wait for keypress.
4F10
LD (405DH),HL 22 5D 40
Store the current edit address (HL) into the display pointer at 405DH.
4F13
PUSH HL E5
Save the current edit address onto the stack.
4F14
LD C,L 4D
Save the low byte of the address into C for screen position calculation.
4F15
XOR A AF
XOR A with itself. Clear A and set Z flag.
4F16
LD (43A4H),A 32 A4 43
Store 0 into the display mode flag at 43A4H.
4F19
GOSUB to 4FC7H to update the register and memory display on screen.
Calculate the screen position for the cursor based on the memory address. The display shows memory in rows of 8 bytes.
4F1C
LD H,00H 26 00
Load Register H with 00H. Clear high byte for calculations.
4F1E
LD D,H 54
Load Register D with H (0). Initialize D for calculation.
4F1F
LD E,H 5C
Load Register E with H (0). Initialize E for calculation.
4F20
LD A,C 79
Load Register A with C (low byte of edit address).
4F21
RRA 1F
Rotate Right through Accumulator. Divide by 2, bit 0 goes to Carry.
4F22
RL E CB 13
Rotate Left through E. Carry goes into bit 0 of E. This extracts the odd/even byte position.
4F24
AND 07HAND 00000111 E6 07
AND A with 07H. Keep only bits 0-2 (position within group of 8 bytes).
4F26
LD L,A 6F
Load Register L with A. L = byte position mod 8.
4F27
ADD A,A 87
Double A (multiply by 2).
4F28
ADD A,E 83
ADD E to A.
4F29
ADD A,A 87
Double A again.
4F2A
ADD A,L 85
ADD L to A.
4F2B
ADD A,B 80
ADD B (nibble position: 0 or 1) to A.
4F2C
LD E,A 5F
Load Register E with A. E = column offset for cursor.
4F2D
LD A,C 79
Load Register A with C (original low byte of address).
4F2E
AND 0F0HAND 11110000 E6 F0
AND A with F0H. Keep only the high nibble (row indicator).
4F30
LD L,A 6F
Load Register L with A.
4F31
ADD HL,HL 29
Double HL.
4F32
ADD HL,HL 29
Double HL again. HL = row × 64 (bytes per screen row).
4F33
ADD HL,DE 19
ADD DE (column offset) to HL.
4F34
LD DE,3C08H 11 08 3C
Load Register DE with 3C08H. This is the video RAM base plus offset for the memory display area.
4F37
ADD HL,DE 19
ADD DE to HL. HL now points to the cursor position in video RAM.
Display a blinking cursor at the current position by alternating between the character and a cursor block (BFH).
4F38
LD C,(HL) 4E
Load Register C with the character currently at the cursor position.
4F39
LD (HL),BFH 36 BF
Store BFH (solid block cursor character) at the cursor position.
4F3B
GOSUB to 4FB7H to check for a keypress with a delay.
4F3E
LD (HL),C 71
Restore the original character at the cursor position.
4F3F
If the Z FLAG is set (no key pressed yet), GOSUB to 4FB7H again to wait more.
4F42
If the Z FLAG is set (still no key), JUMP back to 4F39H to continue blinking. [CURSOR BLINK LOOP]
A key was pressed. Process it.
4F44
POP HL E1
Restore the edit address from the stack into HL.
4F45
CP 0DH FE 0D
Compare Register A (the key pressed) against 0DH (ENTER key).
4F47
LD C,A 4F
Save the key code into C.
4F48
RET Z C8
If the Z FLAG is set (ENTER pressed), RETurn - exit memory edit mode.
Check if it's a hex digit (0-9 or A-F) to modify the current byte.
4F49
GOSUB to 509DH to check if A is a valid hex digit. If so, Carry is set and A contains 0-15.
4F4C
If the NO CARRY FLAG is set (not a hex digit), JUMP to 4F6BH to check for cursor keys.
It's a hex digit. Modify the current nibble of the byte at HL.
4F4E
LD E,F0H 1E F0
Load Register E with F0H. This is the mask for keeping the high nibble.
4F50
BIT 0,B CB 40
Test bit 0 of B. If B=0, we're editing the high nibble; if B=1, the low nibble.
4F52
If the NZ FLAG is set (B=1, editing low nibble), JUMP to 4F5AH.
4F54
LD E,0FH 1E 0F
Load Register E with 0FH. Mask for keeping the low nibble.
4F56
RLCA 07
Rotate A left (shift digit to high nibble position).
4F57
RLCA 07
Rotate A left again.
4F58
RLCA 07
Rotate A left again.
4F59
RLCA 07
Rotate A left again. A now has the digit in the high nibble.
4F5A
LD C,A 4F
Save the nibble value into C.
4F5B
LD A,(HL) 7E
Load Register A with the current byte at the edit address.
4F5C
AND E A3
AND A with E (mask). Keep the nibble we're NOT changing.
4F5D
OR C B1
OR A with C (new nibble value). Combine old and new nibbles.
4F5E
LD (HL),A 77
Store the modified byte back to memory.
4F5F
BIT 0,B CB 40
Test bit 0 of B again to see which nibble we just edited.
4F61
If the Z FLAG is set (was high nibble), JUMP to 4F65H to toggle to low nibble.
4F63
INC L 2C
INCrement L. Move to the next byte (after editing low nibble).
4F64
RET Z C8
If the Z FLAG is set (L wrapped to 00H, meaning we crossed a page), RETurn.
4F65
LD A,B 78
Load Register A with B (nibble indicator).
4F66
XOR 01H EE 01
XOR A with 01H. Toggle between 0 and 1 (switch nibble position).
4F68
LD B,A 47
Load Register B with A. Update nibble indicator.
4F69
JUMP back to 4F10H to update display and continue editing. [MAIN EDIT LOOP]
Not a hex digit. Check for cursor/control keys.
4F6B
LD A,C 79
Load Register A with C (the key code saved earlier).
4F6C
CP 20H FE 20
Compare Register A against 20H (SPACE key).
4F6E
If the Z FLAG is set (SPACE pressed), JUMP to 4F74H to move to next byte.
4F70
CP 09H FE 09
Compare Register A against 09H (TAB key or RIGHT arrow).
4F72
If the NZ FLAG is set (not TAB/RIGHT), JUMP to 4F7DH to check other keys.
SPACE or RIGHT arrow: Move to next byte.
4F74
BIT 0,B CB 40
Test bit 0 of B (nibble position).
4F76
If the Z FLAG is set (on high nibble), JUMP to 4F65H to toggle to low nibble first.
4F78
INC L 2C
INCrement L (move to next byte address).
4F79
If the NZ FLAG is set (didn't wrap), JUMP to 4F65H to toggle nibble and continue.
4F7B
JUMP to 4F97H to handle page wrap (set B=1, L=FF).
Check for BACKSPACE (move backward).
4F7D
CP 08H FE 08
Compare Register A against 08H (BACKSPACE or LEFT arrow).
4F7F
If the NZ FLAG is set (not BACKSPACE), JUMP to 4F8CH to check other keys.
4F81
BIT 0,B CB 40
Test bit 0 of B (nibble position).
4F83
If the NZ FLAG is set (on low nibble), JUMP to 4F65H to toggle to high nibble.
4F85
INC L 2C
INCrement L (temporarily).
4F86
DEC L 2D
DECrement L. These two instructions test if L was FFH (would wrap to 00H then back).
4F87
If the Z FLAG is set (was at first byte of page), JUMP to 4F69H without moving.
4F89
DEC L 2D
DECrement L to actually move back one byte.
4F8A
JUMP to 4F65H to toggle nibble and continue.
Check for DOWN arrow (move down one row = +2 bytes in this display).
4F8C
LD E,02H 1E 02
Load Register E with 02H. Down moves 2 bytes (next row in display).
4F8E
CP 19H FE 19
Compare Register A against 19H (DOWN arrow key code).
4F90
If the NZ FLAG is set (not DOWN), JUMP to 4F9DH to check other keys.
4F92
LD A,L 7D
Load Register A with L.
4F93
ADD A,E 83
ADD E (2) to A.
4F94
LD L,A 6F
Load Register L with A. Move address down 2 bytes.
4F95
If the NO CARRY FLAG is set (didn't wrap past FFH), JUMP to 4F69H to continue.
Wrapped past end of page. Set position to end.
4F97
LD B,01H 06 01
Load Register B with 01H. Set to low nibble.
4F99
LD L,FFH 2E FF
Load Register L with FFH. Set to last byte of page.
4F9B
JUMP to 4F69H to continue editing at the last position.
Check for UP arrow (move up one row = -2 bytes).
4F9D
CP 18H FE 18
Compare Register A against 18H (UP arrow key code).
4F9F
If the Z FLAG is set (UP pressed), JUMP to 4FADH to move up.
4FA1
LD E,10H 1E 10
Load Register E with 10H (16). This is the movement for newline (next 16-byte row).
4FA3
CP 0AH FE 0A
Compare Register A against 0AH (LINE FEED / move down a row of 16).
4FA5
If the Z FLAG is set (LF pressed), JUMP to 4F92H to add 16 to address.
4FA7
LD C,L 4D
Save L into C.
4FA8
CP 5BH FE 5B
Compare Register A against 5BH (ESC or special exit key).
4FAA
If the NZ FLAG is set (unrecognized key), JUMP to 50B9H to display "ERROR".
UP arrow: Subtract E from L to move up.
4FAD
LD A,L 7D
Load Register A with L.
4FAE
SUB E 93
SUBtract E from A.
4FAF
LD L,A 6F
Load Register L with A.
4FB0
If the NO CARRY FLAG is set (didn't wrap past 00H), JUMP to 4F69H.
4FB2
LD B,00H 06 00
Load Register B with 00H. Set to high nibble.
4FB4
LD L,B 68
Load Register L with B (0). Set to first byte of page.
4FB5
JUMP to 4F69H to continue editing at the first position.
4FB7H - Key Wait with Delay Subroutine
This subroutine waits for a keypress while providing a delay for cursor blinking. It decrements a counter and checks for keyboard input. Returns with Z flag clear if a key was pressed, Z set if no key.
4FB7
LD D,00H 16 00
Load Register D with 00H. Initialize the inner delay counter.
[DELAY LOOP]
4FB9
PUSH DE D5
Save DE (counter) onto the stack.
4FBA
GOSUB to ROM routine at 002BH to scan the keyboard. Returns A=key code or 0 if no key.
4FBD
POP DE D1
Restore DE (counter) from the stack.
4FBE
GOSUB to 45B5H to convert the key to uppercase.
4FC1
OR A B7
OR A with itself. Set Z flag if no key pressed (A=0).
4FC2
RET NZ C0
If the NZ FLAG is set (key pressed), RETurn with the key code in A.
4FC3
DEC D 15
DECrement D (inner delay counter).
4FC4
If the NZ FLAG is set (counter not zero), JUMP back to 4FB9H to continue waiting. [DELAY LOOP]
4FC6
RET C9
RETurn with Z flag set (no key pressed after delay).
4FC7H - Display Register and Memory Contents
This routine displays the CPU registers and memory contents on screen. It first displays the flags header, then either a full register display or a memory dump depending on the 43A4H flag. The display format is optimized for debugging.
4FC7
LD HL,51D8H 21 D8 51
Point Register HL to 51D8H, the flags header string "SZ1H1PNC" which labels the flag bits.
4FCA
GOSUB to SYS0 routine at 4467H to display the string pointed to by HL on the screen.
4FCD
LD HL,3C00H 21 00 3C
Load Register HL with 3C00H. This is the start of video RAM (top-left of screen).
4FD0
LD A,(43A4H) 3A A4 43
Load Register A with the display mode flag from 43A4H.
4FD3
OR A B7
OR A with itself to test if display mode is 0 or non-zero.
4FD4
If the Z FLAG is set (mode=0), JUMP to 5034H for simple memory display.
Full register display mode (mode ≠ 0). Display all registers with their values.
4FD6
LD DE,405DH 11 5D 40
Point Register DE to 405DH, the base of the display format table.
4FD9
LD C,03H 0E 03
Load Register C with 03H. There are 3 register groups to display.
[OUTER LOOP] - Display each register group.
4FDB
PUSH DE D5
Save DE (format table pointer) onto the stack.
4FDC
LD DE,50DBH 11 DB 50
Point Register DE to 50DBH, the register name table.
4FDF
EX (SP),HL E3
Exchange HL with top of stack. HL now has format table pointer, stack has video position.
4FE0
PUSH DE D5
Save DE (register name table pointer) onto the stack.
4FE1
LD E,(HL) 5E
Load Register E with the low byte of the display address from the format table.
4FE2
INC HL 23
INCrement HL to the high byte.
4FE3
LD D,(HL) 56
Load Register D with the high byte. DE now has the memory address to display.
4FE4
INC HL 23
INCrement HL to the next entry.
4FE5
POP AF F1
POP the register name pointer into AF (we only need A for temporary storage).
4FE6
EX (SP),HL E3
Exchange HL with stack. HL now has video position, stack has format table pointer.
4FE7
PUSH AF F5
Save the register name pointer (in AF) back onto the stack.
4FE8
LD A,04H 3E 04
Load Register A with 04H. Display 4 register pairs in this group.
4FEA
GOSUB to 503BH to display register group header and values.
4FED
POP DE D1
Restore register name pointer into DE.
4FEE
LD B,04H 06 04
Load Register B with 04H. 4 register pairs to display.
4FF0
XOR A AF
XOR A with itself. Clear A (will be used as AF' flag indicator).
[INNER LOOP] - Display each register pair's name and value.
4FF1
LD A,(DE) 1A
Load Register A with the current byte from the register name table.
4FF2
EX AF,AF' 08
Exchange AF with AF'. Save the byte in AF' for later processing.
4FF3
EX DE,HL EB
Exchange DE and HL.
4FF4
PUSH BC C5
Save BC (loop counter) onto the stack.
4FF5
LD BC,0003H 01 03 00
Load BC with 0003H. Copy 3 bytes (register name).
4FF8
LDIR ED B0
Block copy BC bytes from (HL) to (DE). Copy the register name to video RAM.
4FFA
LD A,(HL) 7E
Load Register A with the offset code byte following the register name.
4FFB
PUSH HL E5
Save HL (name table pointer) onto the stack.
4FFC
GOSUB to 50C9H to get the address of this register's saved value based on the offset code in A.
4FFF
LD A,(HL) 7E
Load Register A with the low byte of the saved register value.
5000
INC HL 23
INCrement HL to the high byte.
5001
LD H,(HL) 66
Load Register H with the high byte of the saved register value.
5002
LD L,A 6F
Load Register L with A (low byte). HL now contains the register value.
5003
EX DE,HL EB
Exchange DE and HL. DE=register value, HL=video position.
5004
INC HL 23
INCrement HL to skip a space in the display.
5005
LD (HL),3DH 36 3D
Store 3DH (ASCII =) at the current video position.
5007
INC HL 23
INCrement HL past the equals sign.
5008
INC HL 23
INCrement HL again for spacing.
5009
GOSUB to SYS0 routine at 4063H to display DE as 4 hex digits at video position HL.
500C
INC L 2C
INCrement L to add spacing after the hex value.
500D
EX AF,AF' 08
Exchange AF with AF'. Retrieve the register name byte saved earlier.
500E
If the NZ FLAG is set (not processing AF register), JUMP to 5027H to skip flags display.
This is the AF register - display the individual flag bits.
5010
CP 41H FE 41
Compare Register A against 41H (ASCII A). Check if this is the primary AF (starts with 'A') vs AF'.
5012
LD A,E 7B
Load Register A with E (low byte = flags byte F).
5013
LD B,08H 06 08
Load Register B with 08H. 8 flag bits to display.
5015
LD DE,51DBH 11 DB 51
Point Register DE to 51DBH, a reserved area (likely a fallback for flag display).
5018
If the NZ FLAG is set (this is AF' not AF), JUMP to 5023H to skip enhanced display.
501A
LD (HL),2DH 36 2D
Store 2DH (ASCII -) to indicate flags section.
501C
RLCA 07
Rotate A left. Move bit 7 (Sign flag) into the Carry.
501D
If the NO CARRY FLAG is set (flag is 0), JUMP to 5023H to continue.
Flag bit is 1 - show the flag character.
501F
EX AF,AF' 08
Exchange AF with AF'.
5020
LD A,(DE) 1A
Load Register A with the flag character from the header string.
5021
LD (HL),A 77
Store the flag character at the video position.
5022
EX AF,AF' 08
Exchange AF with AF' to restore the flags byte.
5023
INC HL 23
INCrement HL to the next video position.
5024
INC DE 13
INCrement DE to the next flag character in the header.
5025
DECrement B and Jump if Not Zero. [FLAG BIT LOOP] Display all 8 flag bits.
5027
INC L 2C
INCrement L for spacing.
5028
INC HL 23
INCrement HL for more spacing.
5029
INC HL 23
INCrement HL again.
502A
POP DE D1
Restore DE (register name table pointer) from the stack.
502B
POP BC C1
Restore BC (loop counter) from the stack.
502C
INC DE 13
INCrement DE to the next register entry in the name table.
502D
DECrement B and Jump if Not Zero. [INNER LOOP] Display next register pair.
502F
DEC C 0D
DECrement C (group counter).
5030
If the NZ FLAG is set (more groups), JUMP back to 4FDFH. [OUTER LOOP]
5032
POP AF F1
POP and discard the saved format table pointer.
5033
RET C9
RETurn to caller.
5034H - Simple Memory Display Mode
This routine displays a simple memory dump starting at the address in (405DH). It shows memory contents in a grid format with addresses and hex values.
5034
LD DE,(405DH) ED 5B 5D 40
Load Register DE with the display base address from 405DH.
5038
LD E,L 5D
Load Register E with L. Align E to the low byte of video position for consistent display.
5039
LD A,10H 3E 10
Load Register A with 10H (16). Display 16 rows of memory.
503B
PUSH BC C5
Save BC onto the stack.
503C
EX AF,AF' 08
Exchange AF with AF'. Save the row counter in AF'.
[ROW LOOP] - Display each row of memory.
503D
INC L 2C
INCrement L to advance video position.
503E
INC L 2C
INCrement L again.
503F
GOSUB to 4063H to display the address (DE) as 4 hex digits.
5042
LD C,08H 0E 08
Load Register C with 08H. 8 byte pairs (16 bytes total) per row.
[BYTE PAIR LOOP] - Display pairs of bytes within each row.
5044
INC L 2C
INCrement L for spacing.
5045
INC L 2C
INCrement L again.
5046
PUSH HL E5
Save HL (video position) onto the stack.
5047
LD A,L 7D
Load Register A with L (video column).
5048
ADD 28H C6 28
ADD 28H (40) to A. Calculate position for ASCII character display.
504A
LD L,A 6F
Load Register L with A. HL now points to ASCII display column.
504B
EX (SP),HL E3
Exchange HL with stack. HL back to hex display position, stack has ASCII position.
504C
LD B,02H 06 02
Load Register B with 02H. Display 2 bytes in this group.
[SINGLE BYTE LOOP]
504E
LD A,(DE) 1A
Load Register A with the memory byte at address DE.
504F
GOSUB to 4068H to display byte A as 2 hex digits at video position HL.
Check if the byte is a printable ASCII character for the ASCII column.
5052
LD A,(436CH) 3A 6C 43
Load Register A with DOS flags from 436CH.
5055
AND 10H E6 10
AND A with 10H. Check bit 4 for display mode.
5057
RLCA 07
Rotate Left. Move bit to position 1.
5058
PUSH BC C5
Save BC onto the stack.
5059
ADD 3FH C6 3F
ADD 3FH (63) to A. Calculate threshold for printable characters.
505B
LD C,A 4F
Save threshold in C.
505C
LD A,(DE) 1A
Load Register A with the memory byte again.
505D
SUB 21H D6 21
SUBtract 21H from A. Convert to range for printability check.
505F
CP C B9
Compare A against C (threshold). Check if printable.
5060
POP BC C1
Restore BC from the stack.
5061
LD A,(DE) 1A
Load the memory byte one more time.
5062
INC DE 13
INCrement DE to the next memory address.
5063
If the CARRY FLAG is set (character is printable), JUMP to 5067H.
5065
LD A,2EH 3E 2E
Load Register A with 2EH (ASCII .). Use period for non-printable characters.
5067
EX (SP),HL E3
Exchange HL with stack. HL now points to ASCII column position.
5068
LD (HL),A 77
Store the character (printable or '.') at the ASCII column.
5069
INC HL 23
INCrement HL for next ASCII position.
506A
EX (SP),HL E3
Exchange HL back with stack.
506B
DECrement B and Jump if Not Zero. [SINGLE BYTE LOOP]
506D
INC HL 23
INCrement HL past the byte pair.
506E
DEC C 0D
DECrement C (byte pair counter).
506F
If the NZ FLAG is set (more pairs), JUMP back to 504CH. [BYTE PAIR LOOP]
5071
POP HL E1
Restore HL (video position for next row) from the stack.
5072
EX AF,AF' 08
Exchange AF with AF'. Get the row counter.
5073
DEC A 3D
DECrement A (row counter).
5074
If the NZ FLAG is set (more rows), JUMP back to 503CH. [ROW LOOP]
5076
POP BC C1
Restore BC from the stack.
5077
RET C9
RETurn to caller.
5078H - Parse Hexadecimal Number from Input
This routine parses a hexadecimal number from the command line input. It converts ASCII hex digits (0-9, A-F) into a 16-bit binary value in DE. The routine is called extensively throughout DEBUG for address and data input. Entry at 5078H skips the first character (used when a delimiter has been checked); entry at 5079H processes from the current position.
5078
INC HL 23
Advance HL to point to the next character in the input buffer, skipping the current character (typically a delimiter that was just checked).
5079
LD A,10H 3E 10
Load Register A with 10H (16 decimal) - this is the maximum number of hex digits to parse (4 digits = 16 bits, but we allow leading zeros so 16 is generous).
507B
PUSH BC C5
Save Register Pair BC onto the stack to preserve it during parsing.
507C
LD C,A 4F
Copy the digit counter from Register A into Register C. Register C will serve as the loop counter for maximum digits.
507D
LD DE,0000H 11 00 00
Initialize Register Pair DE to 0000H - this will accumulate the parsed hex value.
5080
GOSUB to 509CH to fetch and convert the next hex digit. Returns with CARRY set if valid hex digit found, digit value in A.
5083
If the NO CARRY FLAG is set (no valid hex digit found), JUMP to 50B9H to display an error message. This means the input was invalid.
At this point we have a valid hex digit (0-F) in Register A. Now we need to shift the accumulated value left 4 bits and add this new digit.
5085
PUSH HL E5
Save the input buffer pointer HL onto the stack.
5086
EX DE,HL EB
Exchange DE and HL. Now HL holds the accumulated hex value, DE is free.
5087
LD E,A 5F
Load Register E with the new hex digit value (0-15).
5088
LD D,00H 16 00
Clear Register D so DE now contains just the new digit as a 16-bit value.
508A
LD A,C 79
Load Register A with the digit counter from Register C.
508B
GOSUB to 4C94H (SYS0 math routine) to shift HL left by 4 bits (multiply by 16). This makes room for the new hex digit.
508E
ADD HL,DE 19
Add the new hex digit (in DE) to the shifted accumulated value (in HL).
508F
ADC A,A 8F
Add Register A to itself with carry. This checks for overflow - if the value overflowed 16 bits, the carry will propagate here.
5090
If the NZ FLAG is set (overflow occurred - value too large), JUMP to 50B9H to display an error. Maximum valid hex input is FFFFH.
5092
EX DE,HL EB
Exchange DE and HL. The accumulated value goes back into DE.
5093
POP HL E1
Restore the input buffer pointer from the stack back into HL.
5094
GOSUB to 509BH to check if there are more hex digits. This advances HL and checks the next character.
5097
If the CARRY FLAG is set (another valid hex digit found), [LOOP] back to 5085H to process it.
5099
POP BC C1
Restore Register Pair BC from the stack.
509A
RET C9
RETURN to caller. DE contains the parsed 16-bit hex value, HL points to the first non-hex character.
509BH - Get Next Character and Check for Hex Digit
This small routine advances to the next input character and checks if it's a valid hexadecimal digit. Entry at 509BH advances HL first; entry at 509CH processes the current character. Returns CARRY set if valid hex digit found (value in A), CARRY clear if not.
509B
INC HL 23
Advance HL to point to the next character in the input buffer.
509C
LD A,(HL) 7E
Load Register A with the character at the current input buffer position.
509D
SUB 30H D6 30
Subtract 30H (ASCII 0) from Register A. This converts ASCII digits '0'-'9' to values 0-9.
509F
CP 0AH FE 0A
Compare Register A against 0AH (10). If A < 10, it was a valid decimal digit.
50A1
RET C D8
If CARRY is set (A was 0-9), RETURN immediately. The hex digit value is in A, CARRY indicates success.
If we reach here, the character was not '0'-'9'. Check if it's 'A'-'F'.
50A2
SUB 11H D6 11
Subtract 11H (17) from Register A. After the previous SUB 30H, this effectively subtracts 41H total from the original ASCII. This converts 'A' (41H) to 0, 'B' to 1, etc.
50A4
CP 06H FE 06
Compare Register A against 06H (6). If A < 6, the original character was 'A'-'F'.
50A6
RET NC D0
If NO CARRY (character was not 'A'-'F'), RETURN with CARRY clear to indicate "not a hex digit".
50A7
ADD A,0AH C6 0A
Add 0AH (10) to Register A. This adjusts the value so 'A'=10, 'B'=11, ... 'F'=15.
50A9
SCF 37
Set the CARRY FLAG to indicate a valid hex digit was found.
50AA
RET C9
RETURN to caller with hex digit value (0-15) in A and CARRY set.
50ABH - Parse Hex Number and Expect Comma
Wrapper routine that parses a hex number and verifies a comma follows it. Used when parsing multiple parameters separated by commas.
50AB
GOSUB to 5078H to parse a hex number (skipping current character first). Result in DE.
50AE
LD A,2CH 3E 2C
Load Register A with 2CH (ASCII comma ,) - this is the expected delimiter.
50B0
JUMP to 50B7H to compare the current character against the expected comma.
50B2H - Parse Hex Number and Expect End of Line
Wrapper routine that parses a hex number and verifies it's followed by a carriage return (end of command). Used when parsing the final or only parameter.
50B2
GOSUB to 5078H to parse a hex number (skipping current character first). Result in DE.
50B5
LD A,0DH 3E 0D
Load Register A with 0DH (ASCII carriage return) - this is the expected end-of-line marker.
50B7
CP (HL) BE
Compare the expected delimiter (in A) against the current input character at (HL).
50B8
RET Z C8
If the Z FLAG is set (delimiter matches), RETURN successfully to the caller.
If the expected delimiter was not found, fall through to the error handler below.
50B9H - Display "ERROR" and Wait for ENTER
This routine displays the "ERROR" message and waits for the user to press ENTER before returning to the main DEBUG loop. It's the common error exit point for all parsing and command errors.
50B9
LD HL,51D2H 21 D2 51
Point Register Pair HL to 51D2H, the address of the "ERROR" message string.
50BC
GOSUB to 4467H (SYS0 routine) to display the null-terminated string pointed to by HL. This prints "ERROR".
50BF
[LOOP START] GOSUB to ROM routine at 0049H to scan the keyboard and return any pressed key in Register A (0 if none).
50C2
CP 0DH FE 0D
Compare Register A against 0DH (ASCII carriage return / ENTER key).
50C4
If the NZ FLAG is set (ENTER not pressed), [LOOP] back to 50BFH to keep waiting for ENTER.
50C6
JUMP to 4D43H to restart the main DEBUG command loop. This discards the current command and prompts for a new one.
50C9H - Calculate Register Storage Address
This routine calculates the memory address where a specific CPU register value is stored within DEBUG's saved register block. The register is identified by an offset code in A. The saved registers are on the stack at (4D44H), with specific offsets for each register pair.
50C9
LD HL,(4D44H) 2A 44 4D
Load Register Pair HL with the saved stack pointer from 4D44H. This points to the base of the saved register block.
50CC
LD C,A 4F
Copy the register offset code from Register A into Register C.
50CD
LD B,00H 06 00
Clear Register B so BC contains just the offset.
50CF
ADD HL,BC 09
Add the offset (in BC) to the base address (in HL). HL now points to the register storage location.
50D0
CP 14H FE 14
Compare the offset against 14H (20). Offsets 00H-13H are in the main saved block, 14H and above are special.
50D2
RET C D8
If CARRY is set (offset < 14H), RETURN with HL pointing to the register in the saved stack block.
For offsets 14H and above, we need to return pointers to special storage locations.
50D3
LD HL,4DC7H 21 C7 4D
Point HL to 4DC7H - the storage location for the Program Counter (PC).
50D6
RET Z C8
If the Z FLAG is set (offset was exactly 14H = PC register), RETURN with HL pointing to PC storage.
50D7
LD HL,4DC3H 21 C3 4D
Point HL to 4DC3H - the storage location for the Stack Pointer (SP).
50DA
RET C9
RETURN with HL pointing to SP storage (offset was > 14H).
50DBH - Register Name and Offset Table
This is a data table containing register pair names (2 ASCII characters each) followed by their offset codes for the R (Register display/modify) command. The table is searched to match user input like "AF", "BC", etc. Each entry is: 2-char name, 1-byte offset, 1-byte display offset. The table ends with a 00H byte.
50DB
DEFB 41H,46H 41 46
ASCII characters AF - Register pair AF (Accumulator and Flags).
50DD
DEFB 20H,12H 20 12
Space (match terminator) and offset 12H - AF is stored at saved_SP + 12H.
50DF
DEFB 42H,43H 42 43
ASCII characters BC - Register pair BC.
50E1
DEFB 20H,0EH 20 0E
Space (match terminator) and offset 0EH - BC is stored at saved_SP + 0EH.
50E3
DEFB 44H,45H 44 45
ASCII characters DE - Register pair DE.
50E5
DEFB 20H,0CH 20 0C
Space (match terminator) and offset 0CH - DE is stored at saved_SP + 0CH.
50E7
DEFB 48H,4CH 48 4C
ASCII characters HL - Register pair HL.
50E9
DEFB 20H,10H 20 10
Space (match terminator) and offset 10H - HL is stored at saved_SP + 10H.
The following entries are for the alternate register set (AF', BC', DE', HL') accessed via EX AF,AF' and EXX instructions.
50EB
DEFB 41H,46H 41 46
ASCII characters AF - Start of AF' entry.
50ED
DEFB 27H,0AH 27 0A
ASCII ' (apostrophe) and offset 0AH - AF' is stored at saved_SP + 0AH.
50EF
DEFB 42H,43H 42 43
ASCII characters BC - Start of BC' entry.
50F1
DEFB 27H,08H 27 08
ASCII ' and offset 08H - BC' is stored at saved_SP + 08H.
50F3
DEFB 44H,45H 44 45
ASCII characters DE - Start of DE' entry.
50F5
DEFB 27H,06H 27 06
ASCII ' and offset 06H - DE' is stored at saved_SP + 06H.
50F7
DEFB 48H,4CH 48 4C
ASCII characters HL - Start of HL' entry.
50F9
DEFB 27H,04H 27 04
ASCII ' and offset 04H - HL' is stored at saved_SP + 04H.
Index registers and special registers follow.
50FB
DEFB 50H,43H 50 43
ASCII characters PC - Program Counter.
50FD
DEFB 20H,14H 20 14
Space and offset 14H - PC uses special handling at offset 14H (points to 4DC7H).
50FF
DEFB 53H,50H 53 50
ASCII characters SP - Stack Pointer.
5101
DEFB 20H,16H 20 16
Space and offset 16H - SP uses special handling at offset 16H (points to 4DC3H).
5103
DEFB 49H,58H 49 58
ASCII characters IX - Index Register IX.
5105
DEFB 20H,02H 20 02
Space and offset 02H - IX is stored at saved_SP + 02H.
5107
DEFB 49H,59H 49 59
ASCII characters IY - Index Register IY.
5109
DEFB 20H,00H 20 00
Space and offset 00H - IY is stored at saved_SP + 00H (bottom of saved block).
510B
DEFB 00H 00
End of table marker (00H).
510CH - Opcode Classification Table
This is a lookup table used by the instruction length decoder at 5125H. Each pair of bytes contains: an opcode byte to match, and a jump offset within the decoder. This allows the decoder to handle special cases like prefixed instructions (CBH, DDH, EDH, FDH) and multi-byte instructions. The table is scanned to find matching opcodes.
510C
DEFB 10H,81H 10 81
Opcode 10H (DJNZ) - offset 81H points to relative jump handler.
510E
DEFB 18H,80H 18 80
Opcode 18H (JR) - offset 80H points to relative jump handler.
5110
DEFB C3H,96H C3 96
Opcode C3H (JP nn) - offset 96H points to absolute jump handler.
5112
DEFB C9H,C8H C9 C8
Opcode C9H (RET) - offset C8H points to return instruction handler.
5114
DEFB CBH,ABH CB AB
Opcode CBH (CB prefix) - offset ABH points to CB prefix handler (2-byte instruction).
5116
DEFB D3H,B8H D3 B8
Opcode D3H (OUT (n),A) - offset B8H points to 2-byte I/O handler.
5118
DEFB ABH,DBH AB DB
Opcode DBH (IN A,(n)) - offset ABH (note: bytes swapped in memory = DB AB).
511A
DEFB ABH,DDH AB DD
Opcode DDH (IX prefix) - offset ABH. Actually stored as DD prefix indicator.
511C
DEFB 25H,E9H 25 E9
Opcode E9H (JP (HL)) - offset 25H. This is an indirect jump.
511E
DEFB 8EH,EDH 8E ED
Opcode EDH (ED prefix) - offset 8EH points to ED prefix handler.
5120
DEFB 9EH,FDH 9E FD
Opcode FDH (IY prefix) - offset 9EH points to FD prefix handler.
5122
DEFB 29H,00H 29 00
End marker with offset 29H. The 00H terminates the table scan.
5124
DEFB 00H 00
Table terminator byte.
5125H - Instruction Length Decoder
This routine determines the length of a Z80 instruction and calculates the address of the next instruction to execute. It's essential for the single-step (S) and trace (T) commands. The decoder handles all Z80 instruction formats including prefixed instructions (CB, DD, ED, FD), relative jumps, and variable-length instructions. Entry at 5125H sets up for IX-prefixed; 5129H for unprefixed.
5125
LD E,02H 1E 02
Load Register E with 02H - this indicates we're processing a DD/FD prefix (adds 2 to base length).
5127
JUMP to 512BH to continue with prefix handling.
5129
LD E,00H 1E 00
Load Register E with 00H - no prefix, base instruction length.
512B
LD C,(HL) 4E
Load Register C with the opcode byte at the current instruction address (HL).
512C
LD A,C 79
Copy the opcode into Register A for analysis.
512D
CP E9H FE E9
Compare against E9H (JP (HL) / JP (IX) / JP (IY) opcode).
512F
INC HL 23
Advance HL to point past this opcode byte.
5130
If the Z FLAG is set (opcode was E9H = indirect jump), JUMP to 5190H to handle JP (HL/IX/IY).
5132
CP CBH FE CB
Compare against CBH (bit manipulation prefix).
5134
If the Z FLAG is set (CB prefix), JUMP to 51AAH to add 1 byte for the CB instruction.
5136
SUB 34H D6 34
Subtract 34H from A. This tests if opcode is INC (HL) or DEC (HL) which are 34H and 35H.
5138
CP 02H FE 02
Compare result against 02H. If A < 2, original opcode was 34H or 35H.
513A
If Z (opcode was INC/DEC (IX/IY+d)), JUMP to 51AAH to add displacement byte.
513C
CP 8CH FE 8C
Compare against 8CH. Testing for opcodes in the 34H-BFH range.
513E
If CARRY (opcode < C0H after adjustment), JUMP to 51ABH - standard instruction length.
Opcode is C0H or higher. These include RET conditions, CALLs, RSTs, and other control flow.
5140
LD A,C 79
Reload the original opcode from C into A.
5141
CP C0H FE C0
Compare against C0H. Opcodes C0H and above are special.
5143
If CARRY (opcode < C0H), JUMP to 5168H for further classification.
5145
AND 07HAND 00000111 E6 07
Mask to keep only the low 3 bits of the opcode. This identifies the instruction type within the C0-FF range.
5147
If Z (low bits = 000), JUMP to 51C8H - conditional RET instructions (C0, C8, D0, D8, E0, E8, F0, F8).
5149
CP 02H FE 02
Compare against 02H. Low bits = 010 means conditional JP nn.
514B
If Z (conditional JP), JUMP to 5196H to read the 16-bit target address.
514D
CP 04H FE 04
Compare against 04H. Low bits = 100 means conditional CALL nn.
514F
If Z (conditional CALL), JUMP to 51B8H to read the 16-bit target and add 3 bytes.
5152
CP 06H FE 06
Compare against 06H. Low bits = 110 means immediate operation (ADD A,n etc.).
5154
If Z (immediate op), JUMP to 51ABH - 2-byte instruction.
Remaining opcodes (low bits 001, 011, 101, 111) - check against the special opcode table.
5156
LD DE,510CH 11 0C 51
Point DE to 510CH, the opcode classification table.
5159
LD A,(DE) 1A
[LOOP START] Load Register A with the opcode byte from the table.
515A
OR A B7
Test if we've reached the end of the table (00H marker).
515B
INC DE 13
Advance DE to the offset byte in the table entry.
515C
If Z (end of table), JUMP to 51ACH - no special handling needed.
515E
CP C B9
Compare the table opcode against our instruction's opcode (in C).
515F
LD A,(DE) 1A
Load the jump offset from the table into A.
5160
INC DE 13
Advance DE to the next table entry.
5161
If NZ (no match), [LOOP] back to 5159H to check the next table entry.
Found a matching opcode in the table. Use the offset to jump to the appropriate handler.
5163
LD E,A 5F
Load the jump offset into Register E.
5164
LD D,51H 16 51
Load 51H into Register D. DE now contains the full address 51xxH.
5166
PUSH DE D5
Push the handler address onto the stack.
5167
RET C9
RET to the handler address (effectively a computed JUMP).
5168H - Instruction Decoder: Opcodes 40H-BFH Range
This section handles opcodes in the 40H-BFH range, which includes LD register-to-register instructions, arithmetic/logic operations, and some special cases. These are mostly 1-byte instructions except when using (IX+d) or (IY+d) addressing.
5168
CP 40H FE 40
Compare the adjusted opcode against 40H.
516A
If NO CARRY (opcode >= 40H after previous adjustment), JUMP to 51ACH - standard 1-byte instruction.
516C
AND 0FHAND 00001111 E6 0F
Mask to keep only the low 4 bits of the adjusted opcode.
516E
CP 01H FE 01
Compare against 01H. Testing for LD rr,nn instructions (16-bit immediate loads).
5170
If Z (LD rr,nn), JUMP to 51AAH - needs 2 more bytes for the 16-bit immediate.
5172
AND 07HAND 00000111 E6 07
Mask to keep only the low 3 bits.
5174
BIT 5,C CB 69
Test bit 5 of the original opcode (in C). This distinguishes 00-1F from 20-3F ranges.
5176
If Z (bit 5 clear, opcode 00-1F), JUMP back to 5152H for further processing.
Bit 5 is set, so opcode is in the 20-3F range (conditional JR, LD (nn),A, etc.).
5178
CP 02H FE 02
Compare low bits against 02H. Testing for LD (nn),HL type instructions.
517A
If Z (LD (nn),HL etc.), JUMP to 51AAH - 3-byte instruction.
517C
OR A B7
Test if the low bits are zero (opcode ends in 0 or 8).
517D
If NZ (not zero), JUMP back to 5152H for standard handling.
Low bits are zero - this is a JR cc,e instruction (conditional relative jump). Need to handle the signed displacement.
517F
DEC C 0D
Decrement C (adjust for the DEC/INC pair optimization trick).
5180
INC C 0C
Increment C back. This clears flags without changing C's value.
5181
LD A,(HL) 7E
Load Register A with the relative displacement byte following the opcode.
5182
LD E,A 5F
Copy the displacement into Register E.
5183
LD D,00H 16 00
Clear Register D. DE now holds the unsigned displacement.
5185
INC HL 23
Advance HL past the displacement byte to the next instruction.
5186
RLCA 07
Rotate A left. This moves the sign bit (bit 7) into the CARRY flag.
5187
If NO CARRY (displacement was positive), JUMP to 518AH.
5189
DEC D 15
Decrement D to FFH. This sign-extends a negative displacement so DE = FFxxH.
518A
EX DE,HL EB
Exchange DE and HL. Now HL = displacement, DE = address after instruction.
518B
ADD HL,DE 19
Add DE (address after instruction) to HL (signed displacement). Result is the branch target.
518C
JUMP to 519BH to store the result and return.
518EH - Instruction Decoder: JP (HL) / JP (IX) / JP (IY) Handler
This handler processes indirect jumps through HL, IX, or IY. The next instruction address is the current value of the register pair, which we need to retrieve from the saved register block.
518E
LD E,10H 1E 10
Load Register E with 10H - the offset for saved HL in the register block.
5190
LD D,00H 16 00
Clear Register D. DE = 0010H (offset to saved HL).
5192
LD HL,(4D44H) 2A 44 4D
Load HL with the saved stack pointer base address from 4D44H.
5195
ADD HL,DE 19
Add the offset to get the address of saved HL (or IX/IY if prefixed).
5196
LD E,(HL) 5E
Load Register E with the low byte of the saved register value.
5197
INC HL 23
Advance HL to the high byte.
5198
LD D,(HL) 56
Load Register D with the high byte. DE now contains the indirect jump target.
5199
INC HL 23
Advance HL (not used, but maintains consistency).
519A
EX DE,HL EB
Exchange DE and HL. HL now contains the jump target address.
519B
LD B,C 41
Copy the original opcode from C to B (preserves it for the caller).
519C
JUMP to 51BCH to check bounds and return the result.
519EH - Instruction Decoder: ED Prefix Handler
This handles ED-prefixed instructions. After ED, the second byte determines the instruction. Most ED instructions are 2 bytes total, but some like LD (nn),rr are 4 bytes.
519E
LD A,(HL) 7E
Load Register A with the byte following the ED prefix.
519F
AND 07HAND 00000111 E6 07
Mask to keep only the low 3 bits of the second opcode byte.
51A1
CP 05H FE 05
Compare against 05H. Testing for RETN (45H) type instructions.
51A3
INC HL 23
Advance HL past the second byte of the ED instruction.
51A4
If Z (RETN/RETI type), JUMP to 51C8H to handle as a return instruction.
51A6
CP 03H FE 03
Compare against 03H. Testing for LD (nn),rr and LD rr,(nn) instructions.
51A8
If NZ (not a 4-byte instruction), JUMP to 51ACH - standard 2-byte ED instruction.
51AA
INC HL 23
Advance HL by one more byte (for 3 or 4 byte instructions).
51AB
INC HL 23
Advance HL by another byte.
51AC
LD D,00H 16 00
Clear Register D for the bounds check comparison.
51AE
LD A,H 7C
Load Register A with the high byte of the next instruction address.
51AF
CP 52H FE 52
Compare against 52H. Check if address is at or above 5200H (end of DEBUG overlay).
51B1
If CARRY (address < 5200H, within valid range), JUMP to 51C5H to return normally.
Address is >= 5200H, which would be outside the DEBUG overlay. Need to set breakpoints for the step.
51B3
PUSH HL E5
Save the calculated next instruction address onto the stack.
51B4
PUSH DE D5
Save DE (contains flags/status) onto the stack.
51B5
JUMP to 4DA1H to set up breakpoints for stepping through code outside DEBUG.
51B8H - Instruction Decoder: CALL nn Handler
This handles CALL instructions which are 3 bytes (opcode + 16-bit address). The target address is read from the instruction stream.
51B8
LD E,(HL) 5E
Load Register E with the low byte of the CALL target address.
51B9
INC HL 23
Advance HL to the high byte of the target address.
51BA
LD D,(HL) 56
Load Register D with the high byte. DE now contains the CALL target.
51BB
INC HL 23
Advance HL past the CALL instruction (now points to instruction after CALL).
51BC
BIT 0,B CB 40
Test bit 0 of Register B. B contains flags about how to handle this instruction.
51BE
If NZ (bit 0 set), JUMP to 51ACH - return the sequential next address, not the target.
51C0
LD A,D 7A
Load Register A with the high byte of the target address.
51C1
CP 52H FE 52
Compare against 52H. Check if target is within DEBUG overlay (< 5200H).
51C3
If NO CARRY (target >= 5200H), JUMP to 51AEH to use sequential address instead.
51C5
JUMP to 50B9H to display error (shouldn't reach here normally - this is a fallback).
51C8H - Instruction Decoder: RET Handler
This handles RET instructions. The next instruction address is obtained by reading the return address from the saved stack pointer location.
51C8
EX DE,HL EB
Exchange DE and HL. Save the current instruction pointer in DE.
51C9
LD HL,(4DC3H) 2A C3 4D
Load HL with the saved Stack Pointer value from 4DC3H.
51CC
LD A,(HL) 7E
Load Register A with the low byte of the return address (from the stack).
51CD
INC HL 23
Advance HL to the high byte of the return address.
51CE
LD H,(HL) 66
Load H with the high byte of the return address.
51CF
LD L,A 6F
Load L with the low byte. HL now contains the return address (next instruction after RET).
51D0
JUMP to 519BH to store the result and return.
51D2H - "ERROR" Message String
This is the null-terminated "ERROR" message displayed when the user enters an invalid command or parameter.
51D2
DEFB 45H,52H,52H,4FH,52H 45 52 52 4F 52
ASCII string "ERROR" (45H='E', 52H='R', 52H='R', 4FH='O', 52H='R').
51D7
DEFB 03H 03
End-of-string marker (03H = ETX, End of Text).
51D8H - DEBUG Prompt and Flag Characters
This area contains the DEBUG prompt characters and the flag character lookup table for displaying CPU flags in the register display.
51D8
DEFB 1CH,1FH,03H 1C 1F 03
Control codes: 1CH (cursor home), 1FH (clear to end of screen), 03H (ETX/end marker). Used to clear the screen before displaying registers.
51DB
DEFB 53H,5AH,31H 53 5A 31
ASCII SZ1 - First 3 flag indicator characters: Sign, Zero, and bit 5 (always 1 in documentation but unused).
51DE
DEFB 48H,31H,50H 48 31 50
ASCII H1P - Next 3 flag indicators: Half-carry, bit 3 (always 1), Parity/Overflow.
51E1
DEFB 4EH,43H 4E 43
ASCII NC - Final 2 flag indicators: Subtract (N), Carry.
51E3
DEFB 00H,00H,00H,00H,00H 00 00 00 00 00
Padding bytes (00H) - reserved space or alignment.
51E8H - Search Pattern Buffer
This is a buffer area used by the F (Find) command to store the byte pattern being searched for in memory. The buffer can hold up to 32 bytes of search pattern.
51E8-51FFH
DEFB (24 bytes) ...
Search pattern buffer for the Find command. Stores up to 24 bytes of the pattern to search for in memory. Initialized to zeros at startup.