Model I TRSDOS v2.3 SYS5/SYS Explained

This is a disassembly of TRSDOS v2.3’s SYS5/SYS file. SYS5/SYS handles DEBUG.

After a DEBUG ON command has been issued and processed by SYS1/SYS, the DEBUG flag is set. Following that, DEBUG will start when one of 3 things happens: [1] A break is pressed, [2] a CMD file is loaded, and [3] a TRAP instruction (RST 30) is reached.

The first thing DEBUG does is copy the two trap addresses, the display address, all the registers, stack pointer, and program counter as they were, so that they can be restored (since Debug will use them). The memory locations are:

  • 405D-406E = First Trap Address
  • 405F = Original Contents of the Trap Address
  • 4060-4061 = Second Trap Address
  • 4062 = Original Contents of the Second Address
  • 4063-4064 = Display Address
  • 4065-4066 = AF
  • 4067-4068 = BC
  • 4069-406A = DE
  • 406B-406C = HL
  • 406D-406E = AF’
  • 406F-4070 = BC’
  • 4071-4072 = DE’
  • 4073-4074 = HL’
  • 4075-4076 = IX
  • 4077-4078 = IY
  • 4079-407A = SP
  • 407B-407C = PC

4E00 – Entry into SYS5/SYS

First we need to do a lot of pushing registers onto the stack. Why? Because we are running a program within a program, and the program within the program (DEBUG) still needs to be able to display and track the registers from the program that it is running upon!

4E00
POP AF
Restore the entry at the top of the stack into Register Pair AF
4E01
POP AF
Do an extra POP to create a vacancy in the stack which will be filled in later.
4E02
PUSH AF
Save the contents of Register Pair AF to the stack
4E03
PUSH IY
Save the contents of Register IY to the stack
4E05
PUSH IX
Save the contents of Register IX to the stack

Next, we have to save all the alternate registers to the stack as well

4E07
EX AF,AF’
Since EXX doesn’t swap AF and AF’ we have to do it manually.
4E08
EXX
Swap all registers other than AF for their alternate counterparts.
4E09
PUSH HL
Save the contents of (alternate, since we did an EXX) Register Pair HL to the stack
4E0A
PUSH DE
Save the contents of (alternate, since we did an EXX) Register Pair DE to the stack
4E0B
PUSH BC
Save the contents of (alternate, since we did an EXX) Register Pair BC to the stack
4E0C
PUSH AF
Save the contents of (alternate, since we did an EXX) Register Pair AF to the stack
4E0D
EX AF,AF’
Since EXX doesn’t swap AF and AF’ we have to do it manually.
4E0E
EXX
Swap all registers other than AF back their regular counterparts.
4E0F
PUSH HL
Save the contents of (regular) Register Pair HL to the stack
4E10
PUSH DE
Save the contents of (regular) Register Pair DE to the stack
4E11
PUSH BC
Save the contents of (regular) Register Pair BC to the stack
4E12
PUSH AF
Save the contents of (regular) Register Pair AF to the stack

With all registered put into the stack, now we get down to business.

4E13
LD HL,0000H
First, clear HL
4E16
ADD HL,SP
Then add the stack pointer (SP) to HL (which was zero), leaving the SP in HL.
4E17
LD DE,4065H
Store the Debug Register Storage Area address into Register Pair DE
4E1A
LD BC,0018H
Set up Register B to 18H in preparation for a LDIR
4E1D
LDIR
Move BC number of bytes (in this case, 24 bytes) from the memory location held in HL (in this case, the stack where we just pushed all those registers) into the memory location held in DE (in this case, the DEBUG storage area)
4E1F
LD (4079H),HL
Store the value of the stack pointer into RAM location 4079H
4E22
LD SP,HL
Restore the stack pointer to where it was at the time DEBUG was entered into
4E23
LD HL,(407BH)
407BH is the memory location for the PC register + 1. Save that value into HL.
4E26
DEC HL
Decrement HL by 1 so that HL now points to the address which triggered DEBUG so that DEBUG knows how to get the underlying program to continue running
4E27
LD A,(HL)
Put the character pointed to by HL into Register A. Since HL points to the instruction that triggered DEBUG, put that instruction into Register A
4E28
CP 0F7H
Check to see if that instruction was a F7H, which is a RST 30. RST 30 is an express call to DEBUG and we need to figure out WHY we are in DEBUG so this is as good a place to start as any.
4E2A
If the NZ flag is set, then it was NOT a RST 30 so we are in DEBUG for some other reason, and we JUMP to 4E2FH to continue investigating.
4E2C
LD (407BH),HL
If we are here then it was a RST 30 call, so first update the PC register in the Debug Register Storage Area
4E2F
LD HL,405DH
Point HL to the DEBUG TRAP ADDRESS table

We are about to enter into a loop to restore the contents of the locations that had a trap

4E32
LD B,02H
Put a 2 into Register B to signify that there are 2 entries in the table
4E34
XOR A
Zero Register A and all Flags
4E35
LD C,02H
Put a 2 into Register C (for no apparent reason and no apparent usage!)
4E37
LD E,(HL)
Fetch the LSB of the possible trap address from the memory address pointed to by HL and put it into Register E
4E38
LD (HL),A
Zero out that LSB of the possible trap address
4E39
INC HL
Bump HL to point to the MSB of the possible trap address
4E3A
LD D,(HL)
Fetch the MSB of the possible trap address from the memory address pointed to by HL and put it into Register D
4E3B
LD (HL),A
Zero out that MSB of the possible trap address
4E3C
INC HL
Bump HL to point to the original value of the possible trap address
4E3D
4E3E
LD A,E
OR D
Since the Z-80 cannot test a Register Pair against 0, a common trick is to load one of the register pair into A and then OR the other register of the register pair. Only if both are 0 will A will be 0.
4E3F
If the Z Flag is SET then there was no entry, so JUMP down a few instructions to 4E48H
4E41
LD A,(DE)
If we are here, then there was an entry, so we need to check to see if it is valid; so we fetch the contents of the possible trap address (pointed to by DE) into Register A for testing.
4E42
CP 0F7H
Check to see if that instruction was a F7H, which is a RST 30. RST 30 is an express call to DEBUG.
4E44
If NZ is set, then it was NOT a RST 30H, so JUMP forward a few instructions to check the next entry.
4E46
LD A,(HL)
If we are here, then it was a RST 30H, so put the original instruction (pointed to by HL) into Register A
4E47
LD (DE),A
Put that original instruction into the location that held the trap instruction
4E48
INC HL
Bump HL to the next entry in the list. Note: This is where JUMPs above all jumped to.
4E49
DJNZ 4E34H
LOOP back to 4E34H until B is zero

4E4B – Command entry and parsing. This is the return point for almost all command subroutines

4E4B
LD SP,(4079H)
The value of the STACK POINTER was stored into (4079H) in 4E1FH. Put it back.
4E4F
GOSUB to 4ECFH which will display the register values.
4E52
LD HL,3FC0H
Point HL to 3FC0H which is the last line on the display.
4E55
LD (4020H),HL
Save that screen address into (4020H).
4E58
GOSUB to 518AH to get a character from the keyboard
4E5B
CP 47H
Test the character against a “G” (for GO)
4E5D
If the Z Flag is SET then the key was a “G” (Go), so JUMP to 4F80H to deal with that.
4E60
LD HL,4E4BH
Every other possible DEBUG command, other than GO, ultimately needs to return to this input routine, so set HL to point to 4E4BH (which is this input routine)
4E63
PUSH HL
Save the return point (held in Register Pair HL) to the stack
4E64
CP 53H
Test the character against a “S”(Set the video format to MEMORY VIEW)
4E66
If the Z Flag is SET then the key was a “S”, so JUMP to 4E9AH to deal with that.
4E68
CP 3BH
Test the character against a “;” (Increment Memory Display by 1 Page)
4E6A
If the Z Flag is SET then the key was a “l”, so JUMP to 4EAEH to deal with that.
4E6C
CP 2DH
Test the character against a “-” (Decrement Memory Display by 1 Page)
4E6E
If the Z Flag is SET then the key was a “-“, so JUMP to 4EC6H to deal with that.
4E70
CP 41H
Test the character against a “A” (ASCII Display)
4E72
If the Z Flag is SET then the key was a “A”, so JUMP to 4ECBH to deal with that.
4E74
CP 43H
Test the character against a “C” (Single Step with Calls)
4E76
If the Z Flag is SET then the key was a “C”, so JUMP to 4E82H to deal with that. Note: 4E82H is the processor for the “I” command, so this jumps RELATIVE to “I” processor instead of just outright jumping to the actual routine, saving 2 bytes.
4E78
CP 44H
Test the character against a “D (Display Memory)”
4E7A
If the Z Flag is SET then the key was a “D”, so JUMP to 4EA8H to deal with that.
4E7C
CP 48H
Test the character against a “H” (Hexadecimal Display)
4E7E
If the Z Flag is SET then the key was a “H”, so JUMP to 4ECBH to deal with that.
4E80
CP 49H
Test the character against a “I” (Single Step Next Instruction)
4E82
If the Z Flag is SET then the key was a “I”, so JUMP to 505DH to deal with that.
4E85
CP 4DH
Test the character against a “M” (Memory modification mode)
4E87
If the Z Flag is SET then the key was a “M”, so JUMP to 4FDBH to deal with that.
4E8A
CP 52H
Test the character against a “R” (Register modifier)
4E8C
If the Z Flag is SET then the key was a “R”, so JUMP to 5011H to deal with that.
4E8F
CP 55H
Test the character against a “U” (Dynamic Display)
4E91
If the Z Flag is SET then the key was a “U”, so JUMP to 4E9EH to deal with that.
4E93
CP 58H
Test the character against a “X” (Set the video format to REGISTER VIEW)
4E95
If the Z Flag is SET then the key was a “X”, so JUMP to 4E99H to deal with that.
4E97
RST 28H
Perform a RST 28H which is an overlay call
4E98
RET
RETURN (to 4E4BH since that was the address pushed onto the top of the stack at 4E63H)

4E99 – Process the “X” Command.

The “X” command is “Register Display Mode”. A 128-byte block of memory will be displayed, starting with the next lower address which is an even multiple of 16. The next line on the display starting with PC is a list of the 16 bytes to be found beginning at the address specified by the PC register. The bottom two lines of the display are the Z-80 registers and their contents.

4E99
XOR A
Clear Register A. This is because the memory location where the flag will be stored will checked for 0 or something else.

4E9A – Process the “S” Command.

The “S” command is “Memory Display Mode”. Only memory is displayed; no registers. In this mode, the Dxxxx starting address is actually rounded up to the nearest 256-byte page.

This routine is also fallen into by the “X” routine. If “S” was directly called, then Register A actually is stil holding an “S”, so the memory location will either be 0 or”S”.

4E9A
LD (405EH),A
Put the contents of Register A (either a 0 or “S”) into memory location 405EH to signify what display we want
4E9D
RET
RETURN (to 4E4BH since that was the address pushed onto the top of the stack at 4E63H)

4E9E – Process the “U” Command.

The “U” command is “Update”. Pressing U will cause the display to be updated continuously. This function will be of use if you have interrupt driven devices attached to your TRS-80, or for looking at the Model III real time clock, address 4040H. Press any key to exit this mode.

4E9E
GOSUB to 002BH in the ROM to scan the keyboard and put the results into Register A
4EA1
OR A
Set the flags on Register A
4EA2
RET NZ
If the NZ flag is set then a key was pressed, so RETURN (to 4E4BH since that was the address pushed onto the top of the stack at 4E63H)
4EA3
GOSUB to 4ECFH to update the display
4EA6
LOOP back to the top of this “U” routine until any key is pressed

4EA8 – Process the “D” Command.

The “D” command is “Display Memory Contents” which will display a block of memory. If the user presses “D” then DEBUG will prompt with “ADDRESS = “. The user would enter the hexadecimal address of the beginning byte of the block of memory the user wishes to see followed by the Space Bar. If a mistake is made, the user should just type in the correct address as DEBUG will look only at the last four characters typed. The display will be either half- or full -screen , depending on the format currently specified by “X” or “S”

4EA8
GOSUB to 51A3H to get the beginning address from the keyboard
4EAB
RET Z
If the Z flag is set then that routine returned an error, so RETURN (to 4E4BH since that was the address pushed onto the top of the stack at 4E63H)
4EAC
If we are here, then there was no error and we have a starting display address, so JUMP to 4EC2H to save that address

4EAE – Process the “;” command.

The “;” command increments the display address. The display address is modified by 16 in half-screen mode and 256 in full-screen mode.

4EAE
LD BC,0040H
Load Register C with 40H (64 decimal), representing the amount to advance the display by 1 page
4EB1
LD HL,(4063H)
Fetch the current beginning of display address from (4063H) and put it into Register pair HL
4EB4
LD A,(405EH)
Fetch the display mode flag from (405EH) and put it into Register A. Commands “X” and “S” set this byte.
4EB7
OR A
Since a LD operation doesn’t set flags, OR A against itself to set the flags based on Register A. The way “X” and “S” are handled, is that the jump point for X erases A and then falls to the “S” routine. The “S” routine puts whatever is held in A into (405EH). At that point, if “S” was chosen, Register A actually holds an “S”. So the test is really for Zero or “something else.”
4EB8
If the Z Flag is SET then we are in “Half” display mode, so skip the next few instuctions and jump to 4EC1H
4EBA
LD C,00H
If we are here then we are in “Full” display mode, so clear the 40H from Register C (the LSB of the adjustment address) that was put there at the beginning of this routine.
4EBC
LD A,B
Put the MSB of the adjustment address into Register A
4EBD
OR A
Since a LD operation doesn’t set flags, OR A against itself to set the flags based on Register A
4EBE
If NZ is set, then we have a NEGATIVE adjustment, so skip the next instruction
4EC0
INC B
BUMP Register B by 1 (which bumps BC by 100)
4EC1
ADD HL,BC
Calculate the new display address by taking the current beginning display address (held in HL from 4063H) and adding the offset held in BC
4EC2
LD (4063H),HL
Put this new display address into 4063H
4EC5
RET
RETURN (to 4E4BH since that was the address pushed onto the top of the stack at 4E63H)

4EC6 – Process the “-” Command.

The “-” command decrements the display address. The display address is modified by 16 in half-screen mode and 256 in full-screen mode.

4EC6
LD BC,0FFC0H
Load Register Pair BC with -64
4EC9
Jump to 4EB1H in the the “;” routine to handle the rest

4ECB – Process the “A” and “H” Command.

“A” and “H” affect the display mode. A will display in ASCII, H in Hex.

4ECB
LD (405DH),A
Fetch the display mode value from 405DH and put it into Register A
4ECE
RET
RETURN (to 4E4BH since that was the address pushed onto the top of the stack at 4E63H)

4ECF – SUBROUTINE to display the register values.

4ECF
LD A,(405EH)
Fetch the display mode flag from (405EH) and put it into Register A. Commands “X” and “S” set this byte.
4ED2
OR A
Since a LD operation doesn’t set flags, OR A against itself to set the flags based on Register A
4ED3
If NZ is set then the registers are not set to display, so JUMP to 4F45H to handle the long display
4ED5
LD A,1CH
Put the ASCII value for HOME CURSOR into Register A
4ED7
GOSUB to 0033H in the ROM to send the character held in Register A to the current device
4EDA
LD HL,4065H
Store the Debug Register Storage Area address into Register Pair HL
4EDD
PUSH HL
Save the contents of Register Pair HL to the stack
4EDE
LD HL,4F54H
Store the address of the register name text message into Register Pair HL
4EE1
LD B,0CH
Set the number of register values to display to 12
4EE3
JUMP to 4EEAH to display the register context

4EE5 – Display the register values plus the contents of the addresses they contain.

4EE5
LD A,0DH
Put a CARRIAGE RETURN into Register A
4EE7
GOSUB to 0033H in the ROM to send the character held in Register A to the current device
4EEA
GOSUB to 51F6H to display the register name pointed to by HL.
4EED
EX (SP),HL
Put the next register name into the stack and the Debug Register Storage Area address for that register into HL
4EEE
LD E,(HL)
Fetch the LSB of the register value from the Debug Register Storage Area into Register E
4EEF
INC HL
Bump HL to point to the MSB of the register value from the Debug Register Storage Area
4EF0
LD D,(HL)
Fetch the MSB of the register value from the Debug Register Storage Area into Register E
4EF1
INC HL
Bump HL to point to the address of the next register set
4EF2
PUSH HL
Save the address of the next register set (held in HL) to the stack
4EF3
EX DE,HL
SWAP Register Pair DE with Register Pair HL so that DE holds address of the next register set and HL holds the register value from the Debug Register Storage Area
4EF4
LD A,3DH
Put the ASCII character “= into Register A
4EF6
GOSUB to 0033H in the ROM to send the character held in Register A to the current device
4EF9
GOSUB to 51F2 to display a blank space after the “=”
4EFC
LD A,H
Put Register H (the MSB of the Debug Register Storage Area) into Register A
4EFD
GOSUB to 51EFH to convert Register A to ASCII HEX and then display it
4F00
LD A,L
Put Register L (the LSB of the Debug Register Storage Area) into Register A
4F01
GOSUB to 51EFH to convert Register A to ASCII HEX and then display it
4F04
LD A,B
Put Register B (the remaining number of register values to be displayed) into Register A for processing/testing
4F05
AND 0BH
AND that value against 0000 1011 to enable a specific test to see if the value is 8 (which is 1000)
4F07
CP 08H
Compare the result of the masked number of remaining register values to display against 8
4F09
If NZ is set, then it was NOT 8, meaning that it is not currently displaying Register Pair AF, so JUMP to 4F27H
4F0B
LD C,L
If we are here, then it was 8 and is displaying Register Pair AF, so save the status flags (held in Register L) to Register C
4F0C
PUSH BC
Save the contents of Register Pair BC (the number of registers left to display AND the status flags) to the stack
4F0D
LD HL,4F78H
Point HL to the address of the ASCII characters for the status bits
4F10
LD B,08H
Set Register B to 8, meaning the number of status bits to examine
4F12
SLA C
Shift a status bit into the CARRY FLAG. The SLA C opcode shift the contents of Register C left one bit position, with the contents of bit 7 copied to the carry flag and a zero put into bit 0.
4F14
LD A,(HL)
Fetch the letter for the status condition contained in the memory location pointed to by HL into A
4F15
If the SLA C opcode set the CARRY FLAG, then JUMP to 4F19H to display the letter
4F17
LD A,2DH
If we are here then the CARRY FLAG was zero, meaning there is nothing to display, so load up Register A with a “ character.
4F19
GOSUB to 0033H in the ROM to send the character held in Register A to the current device
4F1C
INC HL
Bump HL to point to the next letter in the status list
4F1D
DJNZ 4F12H
LOOP back to 4F1D until B is zero (i.e., all status bits have been handled)
4F1F
POP BC
Restore the number of registers left to display into Register B and restore the status flags into Register C
4F20
LD A,0ECH
Load Register A with the ASCII compression code for 44 spaces
4F22
GOSUB to 0033H in the ROM to send the character held in Register A to the current device
4F25
Skip the next instruction
4F27
GOSUB to 5131H to display => and then the contents of the address in the register
4F2A
POP HL
Restore the address of the next register set to process from the top of the stack into Register Pair HL
4F2B
EX (SP),HL
Put that next register set address into the stack pointer
4F2C
DJNZ 4EE5H
LOOP back to 4EE5 until B is zero (meaning that all registeres have been handled)
4F2E
POP HL
Clear the stack
4F2F
LD HL,(4063H)
Fetch the current beginning of display address from (4063H) and put it into Register pair HL
4F32
LD B,04H
Set Register B to 04 to represent the number of lines to display
4F34
LD A,0C7H
Set Register A to the ASCII compression code for 7 spaces
4F36
GOSUB to 0033H in the ROM to send the character held in Register A to the current device
4F39
GOSUB to 51D4H to display the hex for the value held in the HL register
4F3C
GOSUB to 51F2H to display a blank space
4F3F
GOSUB to 5131H to display 16 bytes
4F42
DJNZ 4F34H
LOOP back to 4F34H until B is zero (meaning all 4 lines to display have been displayed)
4F44
RET
RETURN

4F45 – This is the routine for a long display.

4F45
LD HL,3BFFH
Load HL with the address of the video display area -1
4F48
LD (4020H),HL
Save that screen address into (4020H).
4F4B
LD HL,(4063H)
Fetch the display address held in (4063H)
4F4E
LD L,00H
Set Register L to 00
4F50
LD B,10H
Set Register B to 16, which is the number of lines to display
4F52
Jump back to 4F34H to display 16 lines

4F54 – Message Storage Area

4F54
DEFM ‘AF ‘
4F57
DEFM ‘BC ‘
4F5A
DEFM ‘DE ‘
4F5D
DEFM ‘HL ‘
4F60
DEFM ‘AF’ ‘
4F63
DEFM ‘BC’ ‘
4F66
DEFM ‘DE’ ‘
4F69
DEFM ‘HL’ ‘
4F6C
DEFM ‘IX ‘
4F6F
DEFM ‘IY ‘
4F72
DEFM ‘SP ‘
4F75
DEFM ‘PC ‘
4F78
DEFM ‘SZ1H1PNC’

4F80 – This routine processes a user instruction of “G” (GO)

The “G” command resumes running the program, either at a user specified address or wherever the PC was left off. Up to 2 trap addresses can also be specified; and those are put into a table. This neccesitates putting all the registers back.

4F80
LD B,02H
Set Register B to 2, which is the maximum number of trap addresses to input
4F82
LD DE,4062H
Point DE to 4062H which is the address of the trap table
4F85
GOSUB to 51A3H to get the 1st address from the keyboard
4F88
If the Z Flag is SET then that routine returned an error so skip the next instruction
4F8A
LD (407BH),HL
Put the contents of Register Pair HL into (407BH) which is the PC (Program Counter) in the Debug Register Storage Area
4F8D
If C is set then there was no comma after the first address, meaning we don’t need to process a second address, so JUMP to 4F99 to skip all that
4F8F
GOSUB to 51A3H to get the 2nd address from the keyboard
4F92
PUSH AF
Save the contents of Register Pair AF to the stack
4F93
If the NZ Flag is SET then we have a valid input, so GOSUB to 4FCAH to update the trap table address accordingly
4F96
POP AF
Restore the entry at the top of the stack into Register Pair AF
4F97
DJNZ 4F8DH
LOOP back to 4F8DH until B is zero (meaning all 2 trap addresses have been input)

At this point, we have gotten all the addresses we are going to get (either 1 with no comma, or 2)

4F99
LD HL,400FH
Point HL to the vector address to load DEBUG (i.e., 400FH)
4F9C
LD (4316H),HL
Put the DEBUG LOAD vector address into memory location (4316H)
4F9F
LD A,0C3H
Set Register A to be the OPCODE for JP
4FA1
LD (4315H),A
Put the JUMP instruction before the DEBUG LOAD vector address
4FA4
LD HL,407AH
Point HL to the SP Register in the Debug Register Storage Area
4FA7
LD B,0BH
Set Register B to 11, to signify the number of registers to be transferred

At this point, we have gotten all the addresses we are going to get (either 1 with no comma, or 2), so next we must transfer the register calues from the Debug Register Storage Area to the stack.

4FA9
LD D,(HL)
Fetch the MSB of the saved value in the Debug Register Storage Area and put it into Register D
4FAA
DEC HL
Decrement HL by 1 to point to the LSB of the saved value in the Debug Register Storage Area
4FAB
LD E,(HL)
Fetch the LSB of the saved value in the Debug Register Storage Area and put it into Register E
4FAC
DEC HL
Decrement HL by 1 to point to the next register value in the Debug Register Storage Area
4FAD
PUSH DE
Save the contents of Register Pair DE to the stack
4FAE
DJNZ 4FA9H
LOOP back to 4FA9H until B is zero (meaning, all 11 registers have been transferred to the stack)

The registers from the Debug Register Storage Area have all been put into the stack, so now we need to restore the values to the actual registers

4FB0
POP AF
Restore the entry at the top of the stack into Register Pair AF
4FB1
POP BC
Restore the entry at the top of the stack into Register Pair BC
4FB2
POP DE
Restore the entry at the top of the stack into Register Pair DE
4FB3
POP HL
Restore the entry at the top of the stack into Register Pair HL
4FB4
EX AF,AF’
Swap Register Pair AF with the alternate Register Pair AF’
4FB5
EXX
Swap ALL registers from normal to alternate
4FB6
POP AF
Restore the entry at the top of the stack into Register Pair AF
4FB7
POP BC
Restore the entry at the top of the stack into Register Pair BC
4FB8
POP DE
Restore the entry at the top of the stack into Register Pair DE
4FB9
POP HL
Restore the entry at the top of the stack into Register Pair HL
4FBA
EX AF,AF’
Swap Register Pair AF with the alternate Register Pair AF’
4FBB
EXX
Swap ALL registers from alternate to normal
4FBC
POP IX
Restore the entry at the top of the stack into Register Pair IX
4FBE
POP IY
Restore the entry at the top of the stack into Register Pair IY
4FC0
POP HL
Restore the entry at the top of the stack, which was the stack pointer at the time of the DEBUG trap, into Register Pair HL
4FC1
LD SP,HL
Put the stack pointer at the time of the DEBUG trap, held in HL, into the actual Stack Pointer
4FC2
LD HL,(407BH)
Fetch the resumption address from 407BH (which is the PC register) and put that address into Register Pair HL
4FC5
PUSH HL
Save the contents of Register Pair HL (the resumption address) to the stack
4FC6
LD HL,(406BH)
Restore HL from the Debug Register Storage Area
4FC9
RET
RETURN to the instruction where the trap occurred

4FCA – This SUBROUTINE is called because we have a valid address input to update the trap table address

4FCA
LD A,(HL)
Put the original contents of the trap location (the memory address pointed to by HL) into Register A
4FCB
LD (DE),A
Put that into the trap table list pointed to by DE
4FCC
DEC DE
Decrement DE by 1 to point to the next entry in the trap list
4FCD
LD A,0F7H
Set Register A to the OPCODE for RST 30H which is the trap instruction
4FCF
LD (HL),A
Put the RST 30H opcode into the memory location pointed to by HL
4FD0
CP (HL)
Compare Register A against the memory location pointed to by HL to double check that it was properly stored
4FD1
If NZ is set then it was NOT properly stored so JUMP away to 4E2FH
4FD4
LD A,H
If we are here, then it was properly stored, so put the MSB of the trap address (held in Register H) into Register A since there is no LD (DE),H opcode
4FD5
LD (DE),A
Put the MSB of the trap address (held in Register A) into the memory location pointed to by DE (i.e., the trap table)
4FD6
DEC DE
Decrement DE by 1 to point to the LSB of the trap address
4FD7
LD A,L
Put the LSB of the trap address (held in Register H) into Register A since there is no LD (DE),L opcode
4FD8
LD (DE),A
Put the LSB of the trap address (held in Register A) into the memory location pointed to by DE (i.e., the trap table)
4FD9
DEC DE
Decrement DE by 1 to point to the next entry in the trap list
4FDA
RET
RETURN

4FDB – Process the “M” Command.

The “M” command modifies a memory location. Left and Right graphic bars are placed around the memory location being modified.

4FDB
LD HL,(4060H)
Fetch the contents of memory location 4060H (which is the CURRENT modify address) and put that value into Register Pair HL
4FDE
GOSUB to 51A3H to get the NEXT modify address from the keyboard
4FE1
LD (4060H),HL
Put the NEXT modify address, if one was entered, into the memory location 4060H
4FE4
RET C
If the user input was a CARRIAGE RETURN, then RETURN as there is nothing more to do here
4FE5
PUSH HL
Save the address to be modified to the stack
4FE6
GOSUB to 4ECFH to update the display
4FE9
LD HL,3F40H
Point HL to the screen memory location for current memory contents
4FEC
LD (4020H),HL
Save that screen address into (4020H).
4FEF
LD HL,(4060H)
Fetch the contents of memory location 4060H (which is the modify address) and put that value into Register Pair HL
4FF2
GOSUB to 51D4H to display the hex for the value held in the HL register
4FF5
PUSH HL
Save the modify address to the stack
4FF6
LD HL,3F80H
Point HL to the address on the display for the modified memory
4FF9
LD (4020H),HL
Save that screen address into (4020H).
4FFC
POP HL
Restore the modify address from the stack into Register Pair HL
4FFD
GOSUB to 51D0H to display the contents of the location to be modified, followed by a “=
5000
LD A,2DH
Put the ASCII value for a “” into Register A
5002
GOSUB to 0033H in the ROM to send the character held in Register A to the current device
5005
POP DE
Restore the modify address from the stack into Register Pair DE
5006
GOSUB to 51A3H to get the new value for this memory location from the keyboard
5009
EX DE,HL
SWAP Register Pair DE with Register Pair HL so that DE holds the new value for the memory location and HL holds the memory location to modify. Note: No flags are affected by EX
500A
If the Z Flag is SET (from the keyboard entry routine at 51A3H), then skip the next instruction as there is nothing to modify.
500C
LD (HL),E
Put the new value for the memory location (held in E) into the memory location (pointed to by HL)
500D
RET C
If the CARRY FLAG is set (from the keyboard entry routine at 51A3H) that means an ENTER was hit, so RETURN in that case as there are no more addresses to modify
500E
INC HL
Bump HL to point to the next address to be modified
500F
LOOP back to 4FE1H to update the display, and get the next replacement value

5011 – Process the “R” Command.

The “R” command modifies a register. Up to 3 characters are permitted to designate the register.

5011
GOSUB to 518AH to get a character from the keyboard – this will be the first letter of the desired Register Pair
5014
RET Z
If the Z flag is set from 518AH then either a comma, blank, or Carriage Return was hit. In those ERROR cases, just RETURN
5015
LD C,A
Save the first letter of the register pair (which was gotten from the user through the prior call to 518AH) into Register C
5016
GOSUB to 518AH to get a character from the keyboard – this will be the second letter of the desired Register Pair
5019
RET Z
If the Z flag is set from 518AH then either a comma, blank, or Carriage Return was hit. In those ERROR cases, just RETURN
501A
LD D,A
Save the second letter of the register pair (which was gotten from the user through the prior call to 518AH) into Register D
501B
LD E,20H
Save a terminator to Register E
501D
GOSUB to 518AH to get a character from the keyboard
5020
RET C
The keyboard input needs to be either a blank or a comma to be valid, so RETURN if anything else
5021
If we are here, then we either have a blank or a comma, so JUMP to 5029H
5023
LD E,A
Put the actual character retrieved into Register E, to free up Register A for the next keyboard fetch
5024
GOSUB to 518AH to get a character from the keyboard
5027
RET NZ
We need to check for a comma or blank, so we have TWO RET instructions to trap each of them because it is illegal
5028
RET C
5029
LD HL,4F54H
Point HL to 4F54H which is the address of the Register Pair Table
502C
LD B,0CH
Set B to 12, representing the number of register pairs in the Register Pair Table
502E
LD A,(HL)
Fetch the first character of the register pair in the register table pointed to by (HL) into Register A for testing
502F
CP C
Compare the character from the register table against the first letter of the register pair entered from the keyboard call at 5011H
5030
If the Z Flag is SET then we have a match so we need to then JUMP to 5038H to check the 2nd character.
5032
INC HL
If we are here, then there was no match to the current entry in the register table, so we need to jump down 3 to get to the next register entry in the register table
5033
INC HL
Note: If the 2nd character doesn’t match, this is the jump point since then HL only needs to be moved down 2
5034
INC HL
Note: If the 3rd character doesn’t match, this is the jump point since then HL only needs to be moved down 1
5035
DJNZ 502EH
LOOP back to 502EH until all 12 register entries in the Register Pair Table have been checked
5037
RET
RETURN

This is jumped to if we have matched the first character entered by the user against the first character of an entry in the Register Pair Table

5038
INC HL
Bump HL to point to the next character in the Register Pair Table
5039
LD A,(HL)
Put the character pointed to by HL into Register A
503A
CP D
Compare that 2nd character from the table (held in A) against the the second character entered from the keyboard at 5016H, held in Register D
503B
If NZ is set, then the second character did not match, so we need to move to the next entry
503D
INC HL
If we are here then we have a 1st and 2nd character match, so bump HL to point to the third character in the Register Pair Table
503E
LD A,(HL)
Put the third character in the Register Pair Table into Register A
503F
CP E
Compare that 2nd character from the table (held in A) against the the third character entered from the keyboard at 5024H, held in Register E
5040
If NZ is set, then the third character did not match, so we need to move to the next entry

If we are here, then all 3 characters entered by the user match a three character entry in the Register Pair Table.

5042
LD A,18H
Set A with 24, which is two times the number of entries in the Register Pair Table
5044
5044
SUB A,B
SUB A,B
Subtract 2 * Register B to give an offset for the matching entry
5046
LD C,A
Put the modified offset Register A into Register C
5047
LD B,00H
Set Register B to 00H so that Register Pair BC now containes the modified offset Register E
5049
LD HL,4065H
Point HL to 4065H which is the Debug Register Storage Area
504C
ADD HL,BC
Add the offset held in Register Pair BC to the base of the Debug Register Storage Area so that HL now points to the offset entry (i.e., the entry to be modified)
504D
PUSH HL
Save the contents of Register Pair HL to the stack
504E
LD A,1EH
Put the ASCII code for ERASE TO END OF LINE into Register A for displaying
5050
GOSUB to 0033H in the ROM to send the character held in Register A to the current device
5053
POP DE
Restore the the entry to be modified from the stack into Register Pair DE
5054
GOSUB to 51A3H to put the value for register pair pointed to by DE
5057
RET Z
If the Z flag is set by the routine at 51A3H then a bad character was entered so RETURN to the caller
5058
EX DE,HL
SWAP Register Pair DE with Register Pair HL so that DE holds the value to use and HL holds the address for the new value
5059
LD (HL),E
Put the LSB of the new register value into the Debug Register Storage Area for the appropriate register (held in HL)
505A
INC HL
Bump HL to point to the next byte of the Debug Register Storage Area (i.e., the MSB of the appropriate register)
505B
LD (HL),D
Put the MSB of the new register value into the Debug Register Storage Area for the appropriate register (held in HL)
505C
RET
RETURN

505D – Process the “I” and “C” Commands.

The “I” and “C” commands single step through the program. “C” will run subroutines without requiring they be stepped through and “I” will step every single instruction. This is accomplished by replacing the next instruction with a trap and then executing “G”, so a lot of storing what is coming up and the putting it back happens.

But knowing how long the instruction to replace is is not very easy, and if the instruction was a jump, then the jump point actually needs to be replaced by the trap instead of the next instruction (since the “next” instruction isn’t the one going to be executed)! To figure all this out, there are 3 tables and 6 types which are pre-set to handle everything that can be thrown at DEBUG.

505D
PUSH AF
Save the comamnd specifications that may be sitting in Register Pair AF to the stack
505E
LD DE,(407BH)
Fetch the resumption address from memory location 407BH (which is the PC register in the Debug Register Storage Area) into Register Pair DE
5062
LD A,(DE)
Fetch the OPCODE which is sitting at the resumption address and put it into Register A
5063
LD HL,5115H
Set HL to 5115H which is the address of the GROUP 3 INSTRUCTION TABLE
5066
CP 0DDH
Check the OPCODE sitting at the resumption address against 0DDH which is the IX Index Instruction Set in the Z-80
5068
If the Z Flag is SET then the OPCODE is the IX Index Instruction Set so then JUMP to 5078H
506A
CP 0FDH
Check the OPCODE sitting at the resumption address against 0DDH which is the IY Index Instruction Set in the Z-80
506C
If the Z Flag is SET then the OPCODE is the IY Index Instruction Set so then JUMP to 5078H
506E
LD HL,50E0H
Set HL to 50E0H which is the address of the GROUP 1 INSTRUCTION TABLE
5071
CP 0EDH
Check the OPCODE sitting at the resumption address against 0EDH which is the Misc Index Instruction Set in the Z-80
5073
If the NZ Flag is SET then the OPCODE is not from the IX Index Instruction Set, IY Index Instruction Set, or Misc Index Instruction Set so then JUMP to 507BH
5075
LD HL,510EH
Set HL to 510EH which is the address of the GROUP 2 INSTRUCTION TABLE
5078
INC DE
Bump DE to point to the next OPCODE at the resumption address
5079
LD A,(DE)
Fetch the OPCODE which is sitting at the resumption address + 1 and put it into Register A
507A
DEC DE
Decrement DE by 1 to point to the first OPCODE at the resumption address
507B
LD C,A
Put the LSB of the OPCODE into Register C since we need to use Register A for other things

We are about to start a loop. HL will have been set along the way to point to one of 3 instruction tables: 5063 would have set it to Group 3 if it was in the IX or IY Instruction Set, 506E would have set it to Group 1 if it was in the Misc Instruction Set, and 5075 would have set it to Group 2 otherwise.

507C
LD A,(HL)
Fetch the OPCODE mask from the designated Instruction Table 1, 2, or 3 and put it into Register A
507D
AND A,C
Apply the mask of Register C against the LSB of the OPCODE held in Register A
507E
INC HL
Bump HL to point to the OPCODE in the designated Instruction Table
507F
CP (HL)
Compare the masked LSB OPCODE against the next byte in the designated Instruction Table
5080
INC HL
Bump HL to point to the next byte in the designated Instruction Table
5081
If the Z Flag is SET then the OPCODEs match so then JUMP to 5089 to stop looking
5083
INC HL
If we are here then we need to keep looking, so bump HL to point to the next three byte entry in the designated Instruction Table
5084
LD A,(HL)
Fetch the mask from the currently pointed to entry in the designated Instruction Table
5085
CP 05H
Compare against 5, which is the list terminator
5087
If the end of list has not yet been reached, JUMP back to 507CH

At this point, we have stopped checking the list, either because we found something or ran out of list to check.

5089
LD A,(HL)
If we are here, HL is pointing to the code/length value of the instruction from the matched entry in the designated Instruction Table. Fetch that into Register A.
508A
LD B,A
… and then put it into Register B, as we will need to use that value in 5099H
508B
AND 0FH
Mask the code/length value from the matched entry in the designated Instruction Table against 00001111 to keep only the lowest 4 bits (i.e., single cycle instructions).
508D
LD L,A
Put the masked code/length value from the matched entry in the designated Instruction Table into Register L
508E
LD H,00H
Set Register H to 00H so that way Register Pair HL has the masked code/length value from the matched entry in the designated Instruction Table
5090
ADD HL,DE
Add the masked code/length value from the matched entry in the designated Instruction Table to the address of the next instruction to execute
5091
PUSH DE
Save the address of the next instruction to the stack
5092
LD DE,4062H
Load DE with 4062H which is the trap address save location in memory
5095
GOSUB to 4FCAH to update the trap table address accordingly
5098
POP HL
Restore the address of the next instruction from the stack into Register Pair HL
5099
LD A,B
Put the code/length value of the instruction from the matched entry in the designated Instruction Table into Register A
509A
AND 0F0H
Mask that value against 0F0H to isolate the OPCODE type to those opcodes in the F0H-FFH range
509C
If the Z Flag is SET then we had a F0, so JUMP to 50B4H to continue at the next address
509E
INC HL
Bump HL to point to the instruction
509F
CP 20H
Compare the masked Register A against 20H, meaning that the OPCODE is a JP instruction
50A1
If the CARRY flag is set, then we must have a JP (HL) instruction
50A3
If the Z Flag is SET, then we must have a JP (IX/IY) instruction
50A5
CP 40H
Compare the masked Register A against 40H, meaning that the OPCODE is a JP XXXX instruction
50A7
If the CARRY flag is set, then we must have a DJNZ instruction
50A9
If the Z flag is set, then we must have a JP XXXX instruction
50AB
CP 60H
Compare the masked Register A against 60H
50AD
If the CARRY flag is set, then we must have a RET instruction
50AF
POP AF
Restore Register Pair AF from the stack to see what command we are workign with – either “C” or “I”
50B0
CP 49H
Compare Register A against an “I”
50B2
If the Z Flag is SET then the instruction was “I”, so JUMP to 50BA to process.
50B4
If we are here, then we had a “C” command, so JUMP to 4FA4H

50B7 – These routines are the various jump points from the above “C”/”I” routine OPCODE tests. In many cases, they build on each other.

If we are here, then the “C”/”I” routine felt that the opcode was a RET instruction. It is going to bleed down into the JP XXXX code, as it is the same, so long as the address is set. So it sets the address and then bleeds down.

50B7
LD HL,(4079H)
Fetch the value of the stack pointer from the Debug Register Storage Area and put it into HL

If we are here, then the “C”/”I” routine felt that the opcode was a RET or a JP XXXX instruction.

50BA
LD A,(HL)
Put the LSB of the return address into Register A
50BB
INC HL
Bump HL to point to the MSB of the return address
50BC
LD H,(HL)
Put the MSB of the return address into Register H
50BD
LD L,A
Put the LSB of the return address into Register L, so now Register Pair HL holds the return address
50BE
Jump down to 50DBH to restore the registers from the Debug Register Storage Area address and resume execution of the program

If we are here, then the “C”/”I” routine felt that the opcode was a DJNZ or JR instruction.

50C0
LD C,(HL)
Fetch offset for the DJNZ or JR opcode (held in the memory location pointed to by HL) and put it into Register C
50C1
XOR A
Clear all status flags
50C2
BIT 7,C
Test the SIGN bit of the offset
50C4
If the Z Flag is SET then the offset is positive, so skip the next instruction.
50C6
CPL
If we are here then the offset was negative, so complement it do convert to an 8 bit negative number
50C7
LD B,A
Zero out Register B
50C8
INC HL
Bump HL to point to the address of the next instruction
50C9
ADD HL,BC
Add the offset to HL to get the address of the next instruction
50CA
Jump down to 50DBH to restore the registers from the Debug Register Storage Area address and resume execution of the program

If we are here, then the “C”/”I” routine felt that the opcode was a JP (IX/IY) instruction.

50CC
LD HL,(4075H)
Let’s start off by assuming it was an IX instruction. With this, load HL with the IX register from the Debug Register Storage Area
50CF
BIT 5,C
Test Bit 5 of Register C
50D1
If the Z Flag is SET then we have a JP (IX) instruction, so jump down to 50DBH to restore the registers from the Debug Register Storage Area address and resume execution of the program
50D3
LD HL,(4077H)
If we are here, then it was IY and not IX so load HL with the IY register from the Debug Register Storage Area
50D6
Jump down to 50DBH to restore the registers from the Debug Register Storage Area address and resume execution of the program

50D8 is the common jump point from all the above. Each routine above loaded HL with a specific address and then us it here.

50D8
LD HL,(406BH)
Restore HL from the Debug Register Storage Area
50DB
GOSUB to 4FCAH to update the trap table address
50DE
Jump RELATIVE to 50B4 which then JUMPS to 4FA4H, which is the “C” command

50E0 – This set, and the two sets which follow, are referred to as INSTRUCTION LISTS. This is Group 1.

Each Instruction List entry consists of 3 bytes: Mask, Opcode, and Type/Length.

The Type is a code from 0-6 indicating where the address of the instruction might be found since that can vary greatly (think JP (HL) vs JP xxxx vs JP C, XXXX, etc).

  • Type 0 – The next instruction follows the current instruction
  • Type 1 – The next instruction address comes from HL. An example would be JP (HL)
  • Type 2 – The next instruction conditionally comes from the operand. An example would be JP C, xxxx
  • Type 3 – The jump is conditional. An example would be DJNZ xxxx
  • Type 4 – The operand is provided. An example would be JP xxxx
  • Type 5 – Conditional and indirect. An example would be RET or RET C
  • Type 6 – Conditional and operand supplied. An example would be CALL NZ, xxxx or CALL xxxx
50E0
DEFB 0C7H,0C0H,51H
50E3
DEFB 0FFH,0C9H,51H
50E6
DEFB 0FFH,0E9H,11H
50E9
DEFB 0CFH,001H,03H
50EC
DEFB 0E7H,022H,03H
50EF
DEFB 0C7H,0C2H,43H
50F1
DEFB 0FFH,0C3H,43H
50F5
DEFB 0C7H,0C4H,63H
50F8
DEFB 0FFH,0CDH,63H
50FB
DEFB 0C7H,006H,02H
50FE
DEFB 0F7H,0D3H,02H
5101
DEFB 0C7H,0C6H,02H
5104
DEFB 0FFH,0CBH,02H
5107
DEFB 0F7H,010H,32H
510A
DEFB 0E7H,020H,32H
510D
DEFB 01H
1 byte default length for any instructions not appearing earlier in this list

510E – This is INSTRUCTION LISTS group 2.

510E
DEFB 0C7H,43H,04H
5111
DEFB 0F7H,45H,52H
5114
DEFB 02H
2 byte default length for any instructions not appearing earlier in this list

5115 – This is INSTRUCTION LISTS group 3.

5115
DEFB 0FEH,34H,03H
5118
DEFB 0C0H,40H,03H
511B
DEFB 0C0H,80H,03H
511E
DEFB 0FFH,21H,04H
5122
DEFB 0FFH,22H,04H
5124
DEFB 0FFH,2AH,04H
5127
DEFB 0FFH,36H,04H
512A
DEFB 0FFH,0CBH,04H
512D
DEFB 0FFH,0E9H,22H
5130
DEFB 02H
2 byte default length for any instructions not appearing earlier in this list

5131 – Display => and then the contents of the address in the register

5131
PUSH BC
Preserve BC into the stack to be put back at the end of the routine
5132
LD A,3DH
Put the ASCII value for “=” into Register A
5134
GOSUB to 0033H in the ROM to send the character held in Register A to the current device
5137
LD A,3EH
Put the ASCII value for “>” into Register A
5139
GOSUB to 0033H in the ROM to send the character held in Register A to the current device
513C
GOSUB to 51F2 to display a blank space after the “>
513F
LD B,10H
Load B with 16, which is the number of values to display, in preparation for a DJNZ operation.
5141
GOSUB to 5165H to put bars around the address being modified
5144
LD A,(405DH)
Fetch the display mode value from 405DH and put it into Register A
5147
CP 41H
Compare the display mode value held in Register A against an “A”
5149
If NZ is set then the value is not alphabetic so JUMP to 515EH
514B
GOSUB to 51F2H to display a blank space
514E
LD A,(HL)
Fetch the character pointed to by HL into Register A
514F
CP 20H
Compare that value to a space.
5151
If the CARRY FLAG is set then the characters is NOT greater than a space (meaning, it is a control code), so skip the next 2 instructions
5153
CP 0C0H
Compare that value against 0C0H
5155
If the CARRY FLAG is set then the characters is NOT greater than 0C0H (meaning, it is not a compression code), so skip the next instruction
5157
LD A,2EH
Put the ASCII value for “.” into Register A
5159
GOSUB to 0033H in the ROM to send the character held in Register A to the current device
515C
INC HL
Bump HL to point to the next character from the list
515D
XOR A
Clear all flags. This skips the next instruction.
515E
If the NZ Flag is SET, then GOSUB to 51D0H to display a hex value
5161
DJNZ 5141H
LOOP back to until B is zero (meaning, all 16 values have been displayed)
5163
POP BC
Restore the caller’s BC from the stack
5164
RET
RETURN

5165 – Display bars around the address being modified. On entry, HL points to the current display address.

5165
LD DE,(4060H)
Fetch the contents of memory location 4060H (which is the 2nd trap address) and put that value into Register Pair DE
5169
INC DE
Bump DE to point to the instruction after the trap instruction
516A
PUSH HL
Save the contents of Register Pair HL (the current display address) to the stack
516B
XOR A
Clear all flags and Zero out Register A
516C
SBC HL,DE
SUBTRACT WITH CARRY the instruction after the trap instruction from the current display address. This effectively compares the display address and the modifty address.
516E
LD A,95H
Put the ASCII value for a graphic left bar into Register A.
5170
If the Z Flag is SET, meaning that the display address and the modify address are the same, JUMP to 5180H to display the left bar (held in Register A) right where we are.
5172
GOSUB to 5184H to add a space if 8 values had been displayed
5175
INC HL
Bump HL to point to the next display address
5176
5177
LD A,L
OR H
Since the Z-80 cannot test a Register Pair against 0, a common trick is to load one of the register pair into A and then OR the other register of the register pair. Only if both are 0 will A will be 0.
5178
POP HL
Restore the current display address from the stack into Register Pair HL
5179
LD A,0AAH
Put the ASCII value for a graphic right bar into Register A.
517B
If the Z Flag is SET (meaning that the display address and the modify address are the same), then JUMP to 0033H in the ROM to send the character held in Register A to the current device
517E
Jump RELATIVE to 5188H which then JUMPS to 51F2H to display a blank space

5180H is called for purposes of displaying the LEFT graphic bracket. The right graphic bracket is a hard jump to ROM.

5180
GOSUB to 0033H in the ROM to send the character held in Register A to the current device
5183
POP HL
Restore the display address from the stack into Register Pair HL
5184
LD A,B
Put Register B (the number of lines still left to display) into Register A for processing/testing
5185
CP 08H
Compare the number of lines still left to display against 8 (meaning a half a line)
5187
RET NZ
If the NZ flag is set then we are not yet at the half way point, so RETURN to the caller
5188
JUMP (not GOSUB!) to 51F2H to display a blank space and return to caller

518A – Get a character from the keyboard.

518A
PUSH DE
Preserve DE into the stack to be put back at the end of the routine
518B
A call to 0049H returns as soon as any key on keyboard is pressed, exactly how the INKEY$ function works in BASIC. ASCII value for character entered is returned in A register.
518E
CP 0DH
Compare the character pressed against a CARRIAGE RETURN
5190
If the Z Flag is SET then we have a CARRIAGE RETURN meaning we are at the end of the line so JUMP to 51A0H
5192
CP 20H
Compare the character pressed against 20H
5194
If the CARRY FLAG is set then the characters is NOT greater than a space (meaning, it is a control code), so loop back and get another keystroke
5196
If we are here then it wasn’t a carriage return and it wasn’t a control code so GOSUB to 0033H in the ROM to send the character held in Register A to the current device
5199
POP DE
Restore the caller’s DE from the stack
519A
CP 2CH
Compare the character pressed against an ASCII “,”
519C
RET Z
If the Z flag is set then the key was a comma so, then RETURN to the caller
519D
CP 20H
Compare the character pressed against a space to set the flags according to that test
519F
RET
RETURN

If we are here then the above routine found a carriage return.

51A0
POP DE
Restore the entry at the top of the stack into Register Pair DE
51A1
SCF
Set the CARRY FLAG which will signal that we received a CARRIAGE RETURN
51A2
RET
RETURN

51A3 – This routine is called when DEBUG wants get an address from the user. Will return Z set if there is an error. Result stored in HL.

51A3
GOSUB to 518AH to get a character from the keyboard
51A6
RET Z
If the Z flag is set then it was either a “,” or a space so RETURN to the caller
51A7
LD HL,0000H
Since we’re about to do math, we need to zero out HL
51AA
GOSUB to 51BFH to get the binary value if we are dealing with a hexadecimal digit
51AD
That routine returns a C if the the value was not a hexadecimal digit (A-F, 0-9), so if that’s the case, JUMP to 4E4BH to get a new command
51B0
51B1
51B2
51B3
ADD HL,HL
ADD HL,HL
ADD HL,HL
ADD HL,HL
Multiply the digit received by 16
51B4
OR A,L
Add in the 2nd of the 2 hex numbers
51B5
LD L,A
Put that result back in Register L
51B6
GOSUB to 518AH to get a character from the keyboard
51B9
LOOP back to 51AA to get the next character
51BB
RRA
Rotate Register A so that the CARRY FLAG is moved to Bit 7
51BC
ADC A,81H
Add with CARRY 81H to Register A, which will set the CARRY FLAG if a carriage return was pressed (which is an exit signal for carriage return)
51BE
RET
RETURN

51BF – This SUBROUTINE is called only from 51AAH to test a character to make sure only A-F and 0-9 are present. CARRY FLAG is set if it is outside that range. Since that is how this routine is going to report an error, all of the value tests are set up so as to trigger or not trigger the CARRY FLAG.

51BF
SUB A,30H
Compare the character stored in Register A against ASCII “0”
51C1
RET C
If the CARRY FLAG is set then the it is a character less then “0” (because when you subtracted 30H from it, it went below zero). This means the character is bad.
51C2
ADD A,0E9H
Register A is now 30H less than what was pressed, so ADD E9H to it. This is the same as testing to see if it is greater than ASCII “F”. How? Well, let’s say the value passed was a “G”, which is 47H. First we subtract 30H giving us 17H as a result of the prior test. Now we add 0E9H to 17H and we get 100H, which is greater than FFH, triggering the CARRY FLAG.
51C4
RET C
If the CARRY FLAG is set then Register A is greater than the test value of “F”, so it is out of range. RETURN (with CARRY FLAG set)
51C5
ADD A,06H
Add 6 to Register A, which is the same as testing to see if it is a letter (A-Z)
51C7
If the CARRY FLAG is set then Register A is a letter, so JUMP to 51CCH
51C9
ADD A,07H
If we are here then it wasn’t a letter, so add another 07H to Register A, which will make Register A be between “0” and “9”.
51CB
RET C
This will never be executed as the CARRY FLAG cannot be set from the above addition
51CC
ADD A,0AH
Add yet another 10 to Register A, which will then result in the binary value
51CE
OR A
Set the flags
51CF
RET
RETURN

51D0 – This SUBROUTINE displays the hex for the value POINTED TO by the HL register

51D0
LD A,(HL)
Fetch the value stored in the memory location pointed to by HL and put it into Register A
51D1
INC HL
Bump HL to point to the next address
51D2
Jump down a few instructions to 51D9H, which is shared by 51D0H and this 51D4H routine

51D4 – This SUBROUTINE displays the hex for the value HELD in the HL register

51D4
LD A,H
Put the MSB of the value to convert/display into Register A
51D5
GOSUB to 51D9H, which is shared by 51D0H and this 51D4H routine. This is cute – it GOSUBs the routine to process H, and then just flows into that routine when it has L
51D8
LD A,L
Put the LSB of the value to convert/display into Register A

51D9H is the common jump point for both 51D0H and 51D4 once A contains the value to be dealt with.

51D9
PUSH AF
Save the value to be converted to the stack
51DA
51DB
51DC
51DD
RRA
RRA
RRA
RRA
RRA rotates contents of Register A right one bit position, so these 4 instructions do it 4 times. With RRA, the contents of bit 0 are copied to the carry flag and the previous contents of the carry flag are copied to bit 7 so this is just a rotation with no data loss.
51DE
Now that the upper 4 bits are the lower 4 bits, GOSUB to 51E2 (2 instructions down) to convert to hex ASCII and display
51E1
POP AF
Restore the value to be converted from the stack, since we destroyed it with 4 RRA’s
51E2
AND 0FH
Mask the value to be converted by 00001111, thus removing the high 4 bits … the opposite of what we just did with the 4 RRA’s.
51E4
ADD A,30H
Convert the number to ASCII by adding 30H to it (30H=ASCII ‘0’, 31H=ASCII ‘1’, …)
51E6
CP 3AH
Compare Register A against a “:”
51E8
If the CARRY FLAG is set after a CP then the character is NOT greater than a “:” (meaning, it “9” or less), so skip the next instruction which processes A-F
51EA
ADD A,07H
Add 07H to Register A which will give an “A”-“F”
51EC
JUMP to 0033H in the ROM to send the character held in Register A to the current device
51EF
GOSUB back to the top of this routine to do a second digit

51F2H, while part of the prior routine, is also a common call to display a blank.

51F2
LD A,20H
Put the ASCII value of a ” ” into Register A
51F4
JUMP RELATIVE to 51ECH which then JUMPS to 0033H in the ROM to send the character held in Register A to the current device
4EEA
GOSUB to 51F6H to display the register name pointed to by HL for the number of registers pointed to by Register B.

51F6 – This SUBROUTINE is called by 4EEAH to display the register name pointed to by HL. It processes 3 characters

51F6
GOSUB two instructions down to get the character in the memory location pointed to by Register HL, display it, and then RETURN to the next OPCODE (i.e., 51F9H)
51F9
GOSUB to the next instruction to get the character in the memory location pointed to by Register HL, display it, and then RETURN to the next OPCODE (i.e., 51FCH)
51FC
LD A,(HL)
Put the character in the memory location pointed to by Register HL into Register A
51FD
INC HL
Bump HL to point to the next character
51FE
Jump to 51ECH to display the character, and RETURN to 51FCH