TRS-80 DOS - TRSDOS v1.3 - SYS05/SYS Disassembled

Overview

General

SYS5 implements the TRSDOS 1.3 DEBUG monitor. It is loaded as an overlay by the DOS loader when the user enters the DEBUG command, or when a running program triggers a breakpoint (RST 30H, OPCODE 0F7H) while the debugger is enabled. The overlay occupies 4E00H through 5562H in RAM, providing the following functions:

KeyRoutineDescription
J / GGO (4FF7H)Both keys run GO: the ADDRESS? = prompt takes an optional new PC and up to two breakpoint addresses (separated by a space or comma); GO then puts back the registers and runs the program.
SPAGE (4EB3H)Switch to full-page (16-row) memory display mode.
XOVER (4EB2H)Switch back to half-page (8-row) memory display mode.
;NXTMEM (4EE3H)Advance the memory display by 16 bytes (half-page mode) or 256 bytes (full-page mode).
-BCKMEM (4F0AH)Back up the memory display by 16 bytes (half-page mode) or 256 bytes (full-page mode).
C / ISINGLE (50DBH)Single-step. C steps over CALL instructions (executes the subroutine in one step); I steps into them.
DDOIT (4EC1H)Prompt for a new memory-display (dump) address.
MMEMORY (504DH)Modify user RAM: prompt for an address, then allow byte-by-byte editing with cursor keys and hex digits.
RREGIST (508AH)Modify a user register: prompt for register name (AF, BC, AF', etc.), then prompt for a new value.
UUPDATE (4EB7H)Continuously redisplay memory until a key is pressed (live view).
FTRA (52BDH)Enter the Disk Utility: prompt for a filespec, open the file via OPEN SVC, and allow browsing/modifying its records.
QQUIT (5286H)Clear the disk-side flag (CSIDE) and return to DOS via SYS1IN.

Memory Map

RangeContents
4E00H–52B8HMain DEBUG monitor code: entry/register save, command dispatch loop, display routines, single-step engine, hex input parser, and shared I/O helpers.
52B9H–52BCHENTRY, the transfer address the loader jumps to: POP AF takes back the program's AF (pushed by DEBUG at 440DH before it loaded SYS5), then JP START.
52BDH–5525HDisk Utility code: filespec prompt, file open, record browsing loop, record-modify engine, error handler, and disk write-back.
5526H–554EHStatic message strings: TITLE (5526H, "Debug Disk Utility Ver 1.3") and BPROMT (5543H, "Filespec: ").
554FH–5562HDisk Utility workspace: WHERE, CURSA, MOVFLG, SLRL and the first 14 bytes of the DCB BDCB (with DRV, NRN and ERN inside it).
5600HENDBUG: the lowest address the D and M commands accept, and the lowest display address ; and - can reach (4ED8H, 4EFEH, 5067H). TRSDOS, its buffers and SYS5 itself lie below it.
4100H–411FHSYS5 register-save area (MEM through MEM+31). Used only while DEBUG is active; physically shares RAM with BASIC's workspace.

Register Save Area (MEM+0 through MEM+31)

START pushes all the registers and copies the 24 bytes (12 register pairs) from the STACK to MEM+8 (4108H-411FH). MEM+0 through MEM+5 hold the two breakpoints, MEM+6 and MEM+7 the display address.

OffsetAddressPurpose
MEM+04100H-4102HBreakpoint 2 (set second; SINGLE puts the jump target here): address LSB, MSB, then the byte that the F7H (RST 30H) replaced. On every entry START2 puts the byte back and clears the address.
MEM+14101HAlso the display mode flag: 00H = half page (8 lines), not zero = full page (16 lines, set by S). START2 clears it, so the display is half page after each entry.
MEM+34103H-4105HBreakpoint 1 (set first; SINGLE puts the next instruction here): address LSB, MSB, then the replaced byte.
MEM+34103H-4104HAlso the address of the M command, rounded down to nn00H; the M display shows the 256 bytes from there.
MEM+64106H-4107HThe memory display address (D, ;, -), a multiple of 10H.
MEM+84108HThe program's AF
MEM+10410AHThe program's BC
MEM+12410CHThe program's DE
MEM+14410EHThe program's HL (also where JP (HL) goes when single stepping)
MEM+164110HThe program's AF'
MEM+184112HThe program's BC'
MEM+204114HThe program's DE'
MEM+224116HThe program's HL'
MEM+244118HThe program's IX
MEM+26411AHThe program's IY
MEM+28411CHThe program's SP (the address above the PC that RST 30H pushed). START5 also loads it into SP, so DEBUG's own STACK lies below it.
MEM+30411EHThe program's PC, where execution goes on. When the byte before it is F7H (a breakpoint), START backs it up by 1.

Self-Modifying Code Locations

SYS5 uses four self-modifying code locations within its overlay space. Each source label marks an operand byte within an instruction whose runtime value is written by other code in SYS5. They hold their values only while SYS5 is in memory.

AddressLabelDescription
4F61HCURSAVOperand byte of LD HL,0 inside DISPLY. Set to the current cursor position by the register-display routine, and loaded back when the display shifts down to draw the PC byte line.
5054HSAVCUROperand byte of LD HL,0 inside MEMOR0. Used by both DOIT (dump-address prompt) and MEMORY (modify-memory prompt) to save and restore the cursor position across re-prompts.
545FHNODISKOperand byte of LD A,0 in the BACK1 keyboard-wait loop. Set to 00H = Disk Utility mode (so ENTER writes back to disk), or non-zero = Memory-modify mode (so ENTER returns to DEBUG without a disk write).
5366HCHGBMPInitially a NOP at the top of the LOP1 display loop. Once a file is opened, BREADX (5312H-5314H) stores 23H (INC HL) there, so the record number shown counts from 1. It stays INC HL until SYS5 is loaded again.

Disk Utility Workspace (554FH–5562H)

AddressLabelDescription
554FHWHERECurrent buffer/position pointer (defaults to BUFF1 = 4300H). Tracks which byte the user is editing within the file record.
5551HCURSAScreen address of the byte being edited (CHECK stores it when it draws the block); GETKEY copies it into CURSOR (4020H) and DIGIT shows the typed digits there. 3C00H in the file.
5553HMOVFLGDisplay-block flag: 00H = show data normally, non-zero = also show the block cursor at WHERE.
5554HSLRLThe source's comment is USERS LRL SAVED HERE. No instruction in SYS5 reads or writes it; 52EEH sets the LRL in the DCB to 00H (256) without saving the old value.
5555HBDCBThe DCB of the file the Disk Utility works on. KEYN (0040H) first reads the filespec (up to 31 characters) into it; OPEN (4424H) turns it into the open DCB. The file holds its first 14 bytes (5555H-5562H); the rest lies above 5562H.
555BHDRVDCB offset 06H: the drive the file is on; CONT2 shows it as the first digit of each line.
555FHNRNDCB offset 0AH-0BH: the next record number, the record shown (READ and BACKSP leave it there). The M command stores the MSB of its address here.
5561HERNDCB offset 0CH-0DH: the ending record number set by OPEN; 52FCH-5300H add 1 when the EOF byte (offset 08H) is not 00H.

DOS Entry Points Used

AddressLabelPurpose
002BHKBDPoll keyboard; returns 00H in A if no key is pressed, else the ASCII code
0033HDSPDisplay the character in A at the current cursor position
0040HKEYNRead a full line from the keyboard (up to B chars, terminated by ENTER); BREAK sets carry
0049HKEYWait for a single keyboard character (blocking)
021BHPRINTDisplay the string at (HL) until a 03H terminator is encountered
01C9HCLSClear the screen (ROM routine)
402DHSYS1INNormal return-to-DOS entry point (used by QUIT)
4409HERRORSYS0 error vector: PUSH AF / LD A,84H / RST 28H loads SYS4, which shows error A. BERR1 sets bits 6 and 7: the full text, then return.
4424HOPENSYS0 OPEN vector (SYS2 entry 1): open an existing file; DE = the DCB holding the filespec, HL = the buffer, B = the LRL (00H = 256)
4436HREADSYS0 READ SVC: read one record from the file whose DCB is at DE, into the buffer at HL
4439HWRITESYS0 WRITE SVC: write the current record to the file whose DCB is at DE
443FHREWINDSYS0 REWIND SVC: rewind the file at DE to its first record
4445HBACKSPSYS0 BACKSP SVC: back up one record in the file at DE
4448HPOSEOFSYS0 POSEOF SVC: position the file at DE to its end-of-file record

External RAM Variables Referenced

AddressLabelUsage by SYS5
4020HCURSORSYS0's cursor-position variable. SYS5 reads and writes it during display operations.
4023HCURSCRSYS0's cursor-character variable. SYS5 writes 0B0H (block cursor) at several points to set the display cursor style.
442BHOVLFLGSYS0's overlay-loaded flag. On entry, SYS5 clears bit 4 to indicate SYS6 (Library Commands) is no longer in memory (since SYS5 just displaced it).
4463HCSIDESYS0's current-disk-side variable. QUIT clears it to 0 before returning to DOS, forcing side 0 for the next disk operation.

Single-Step Opcode Tables

The single-step engine (SINGLE, 50DBH) uses three data tables to decode the next instruction and determine where to place a breakpoint:

AddressLabelPurpose
5160HTABLE1"Normal" Z80 opcode table: matches opcode bytes against masks to classify as simple step, relative jump, absolute jump, call, return, or JP (HL)
518EHTABLE2"ED" prefix opcode table: LD (nn),rr and LD rr,(nn) (4 bytes), RETN and RETI; every other ED instruction is taken as 2 bytes
5195HTABLE3"DD" and "FD" prefix opcode table: for IX/IY indexed instructions including JP (IX) and JP (IY)

Each table entry is a 3-byte record containing a mask byte, a match byte, and an options byte. The options byte encodes both the instruction length (low nibble) and the branching type (high nibble).

A table ends with one byte below 05H, which is the options byte for every opcode the table does not list. SINGLE puts the first breakpoint after the instruction (PC plus the length); bits 7-4 tell where the second breakpoint goes:

Bits 7-4Instruction and second breakpoint
0No jump: only the breakpoint after the instruction.
1JP (HL): the program's HL (MEM+14, 410EH).
2JP (IX) / JP (IY): IX (MEM+24) or IY (MEM+26), chosen by bit 5 of Register C. C holds E9H there, so the IY value is always taken.
3JR / DJNZ: PC + 2 + the displacement.
4JP nn: the address at PC+1.
5RET, RETI, RETN: the address at the program's SP (MEM+28, 411CH).
6CALL: the address at PC+1 for I; none for C, so the subroutine runs at full speed.

Cross-References and Analysis Notes

  • 545FH label note: This self-modifying operand is labeled NODISK in the SYS5 source (via NODISK EQU $+1). The page consistently uses the source label NODISK for this address.
  • LEFT/RIGHT source-label quirk: In the Disk Utility keyboard dispatch, the source labels LEFT and RIGHT are swapped relative to their behavior. The key-code dispatch compensates (key 09H = right arrow jumps to LEFT, which does INC L; key 08H = left arrow jumps to RIGHT, which does DEC L). Net behavior is correct; source labels are kept verbatim here for traceability.
  • MEM at 4100H: The 32-byte breakpoint and register save area at 4100H-411FH is valid only while DEBUG is in use; it shares RAM with BASIC's workspace.
  • ENDBUG = 5600H: This is an assemble-time constant (not a RAM variable), baked into the binary at 4ED8H, 4EFEH, and 5067H as LD DE,5600H. Its purpose is to refuse DUMP and MODIFY commands that would reach into SYS5's own code or SYS0's resident data.
  • ENTRY vs START: The loader enters SYS5 at ENTRY (52B9H), the END address of the source. DEBUG at 440DH (reached from RST 30H through 400FH) pushed the program's AF before LD A,85H / RST 28H; ENTRY's POP AF takes it back, and START (4E00H) then saves all the registers.

Disassembly

4E00H - START - Entry Point

 
ORG 4E00HORG START

Since DEBUG is going to need to use all registers for itself, but yet leave them undisturbed for the program being debugged, it is necessary to preserve all registers, so the next bunch of steps do just that.

4E00START
PUSH AF F5
Save Register AF to the top of the STACK.
Original Source Code Comment: SAVE ALL REGISTERS
4E01
PUSH IY FD E5
Save Register IY to the top of the STACK.
4E03
PUSH IX DD E5
Save Register IX to the top of the STACK.
4E05
EX AF,AF' 08
EXchange the value stored in Register Pair AF' with the value stored in Register Pair AF.
4E06
EXX D9
EXchange all Register Pairs for their Alternate
4E07
PUSH HL E5
Save Register HL to the top of the STACK.
4E08
PUSH DE D5
Save Register DE to the top of the STACK.
4E09
PUSH BC C5
Save Register BC to the top of the STACK.
4E0A
PUSH AF F5
Save Register AF to the top of the STACK.
4E0B
EX AF,AF' 08
EXchange the value stored in Register Pair AF' with the value stored in Register Pair AF.
4E0C
EXX D9
EXchange all Register Pairs for their Alternate
4E0D
PUSH HL E5
Save Register HL to the top of the STACK.
4E0E
PUSH DE D5
Save Register DE to the top of the STACK.
4E0F
PUSH BC C5
Save Register BC to the top of the STACK.
4E10
PUSH AF F5
Save Register AF to the top of the STACK.

With all the registers now preserved in the STACK, we next copy the STACK to 4108H and on to save them.

4E11
LD HL,0000H 21 00 00
We want to copy the STACK Pointer into HL, but there is no easy way to do that, so we will need to ADD SP to HL. Naturally, we need to first set Register Pair HL = 0000H as a base for math.
Original Source Code Comment: GET THE STACK POINTER
4E14
ADD HL,SP 39
ADD the value held in Register Pair SP to Register Pair HL, so that HL now points to the bottom of the area where the registers are saved. This is setting up to do a LDIR to REALLY save all those registers into an area of RAM.
Original Source Code Comment: INTO HL
4E15
LD DE,4108HLD DE,MEM+8 11 08 41
LET Register Pair DE = 4108H, which is the bottom of the storage area where those registers are going to get preserved.
Original Source Code Comment: MOVE THE REGISTER SAVES TO
4E18
LD BC,0018H 01 18 00
LET Register Pair BC = 0018H (24): the 24 bytes on the STACK to copy, 12 register pairs (AF, BC, DE, HL, AF', BC', DE', HL', IX, IY, the AF pushed first, and the program's PC).
Original Source Code Comment: OUR OWN AREA
4E1B
LDIR ED B0
Move all those registers into 4108H+ via a LDIR which transfers a byte of data from the memory location pointed to by HL to the memory location pointed to by DE. Then HL and DE are incremented and BC is decremented. If BC is not zero, this operation is repeated. Interrupts can trigger while this instruction is processing.
4E1D
LD (411CH),HLLD (MEM+28),HL 22 1C 41
Store the value held in Register HL (i.e., the old STACK pointer) into the memory location 411CH for safekeeping.
Original Source Code Comment: SAVE THE POINTER TO THE REGISTERS
4E20
LD A,(442BH)LD A,(OVLFLG) 3A 2B 44
Fetch the value stored at memory location 442BH and put it into Register A.
NOTE: 442BH is the storage location for the OVERLAY FLAG flag.
Original Source Code Comment: GET THE OVERLAY FLAG
4E23
RES 4,A CB A7
RESet (i.e., set as 0) BIT 4 of Register A to designate that OVERLAY 6 is not in RAM.
Original Source Code Comment: SHOW SYS6 NOT IN MEMORY
4E25
LD (442BH),ALD (OVLFLG),A 32 2B 44
Store the value held in Register A into the memory location 442BH.
NOTE: 442BH is the storage location for the OVERLAY FLAG flag.
Original Source Code Comment: SAVE THE FLAG

Check to see what the OP CODE was when DEBUG was invoked, and also see if it was from a RST 30H call or not.

4E28
LD SP,HL F9
LET Register Pair SP = Register Pair HL (i.e., the ORIGINAL STACK pointer); to reset the STACK now that the running program's registers have all been preserved.
Original Source Code Comment: SET TOP OF REGISTERS AS STACK
4E29
LD HL,(411EH)LD HL,(MEM+30) 2A 1E 41
Fetch the value stored at memory location 411EH (i.e., the Program Counter for the running program) and put it into Register HL.
Original Source Code Comment: GET THE USERS PC
4E2C
DEC HL 2B
Back up 1 instruction by DECrementing the value stored in Register Pair HL.
Original Source Code Comment: BACK UP ONE INSTRUCTION
4E2D
LD A,(HL) 7E
Fetch the value stored at memory location pointed to by Register Pair HL (i.e., the command which was just run) and put it into Register A.
Original Source Code Comment: GET IT
4E2E
CP 0F7H FE F7
Compare the value held in Register A against 0F7H (i.e.,. the OPCODE for RST 30H) to see if DEBUG was initiated by a RST 30H call. Results: If Register A equals RST 30H, the Z FLAG is set; otherwise the NZ FLAG is set.
Original Source Code Comment: WAS THIS OUR BREAKPOINT?
4E30
If the NZ FLAG (Not Zero) is set then the OPCODE was not RST 30H, meaning that this wasn't a breakpoint, so JUMP to "START2" (i.e., 4E35H).
Original Source Code Comment: NO, JUST DISPLAY
4E32
LD (411EH),HLLD (MEM+30),HL 22 1E 41
Store the value held in Register HL (i.e., the Program Counter for the running program MINUS 1) into the memory location 411EH.
Original Source Code Comment: YES, SAVE AT USERS PC

If this was a RST 30H call, we need to see if DEBUG was involked by a breakpoint.

4E35START2
LD HL,4100HLD HL,MEM 21 00 41
LET Register Pair HL = 4100H (i.e., a RAM area where the BREAKPOINTS are stored).
4E38
LD B,02H 06 02
LET Register B = 02H to indicate that there are TWO possible BREAKPOINTS.

4E3AH - "START1" - Top of loop checking breakpoints

Top of a loop of TWO iterations to check the two possible breakpoint locations for valid data.

4E3ASTART1
XOR A AF
Set Register A to ZERO and clear all Flags.
4E3B
LD C,02H 0E 02
LET Register C = 02H. Register C is not used by this loop.
4E3D
LD E,(HL) 5E
Fetch the value stored at memory location pointed to by Register Pair HL (i.e., the BREAKPOINT storage area) and put it into Register E.
4E3E
LD (HL),A 77
Store the value held in Register A (i.e., a ZERO) into the memory location pointed to by Register Pair HL; thus clearing that breakpoint.
4E3F
INC HL 23
Bump the value stored in Register Pair HL by 1 to point to the second of the two possible breakpoints.
4E40
LD D,(HL) 56
Fetch the value stored at memory location pointed to by Register Pair HL (i.e., the BREAKPOINT storage area) and put it into Register D.
4E41
LD (HL),A 77
Store the value held in Register A (i.e., a ZERO) into the memory location pointed to by Register Pair HL; thus clearing that breakpoint.
4E42
INC HL 23
Bump the value stored in Register Pair HL (i.e., the BREAKPOINT storage area) by 1.
4E43
LD A,E 7B
LET Register A = Register E (the LSB of the breakpoint address).
4E44
OR D B2
OR Register D (the MSB) into A: the Z FLAG is set only when the address in DE is 0000H (no breakpoint).
4E45
If the Z FLAG (Zero) is set, meaning that the breakpoint address was ZERO, JUMP to 4E4EH to move to the next breakpoint.
4E47
LD A,(DE) 1A
Since the breakpoint was NOT zero, fetch the value stored at memory location pointed to by Register Pair DE (i.e., the value which was at the breakpoint memory location) and put it into Register A.
4E48
CP 0F7H FE F7
Compare the value held in Register A against 0F7H (i.e.,. the OPCODE for RST 30H) to see if DEBUG was initiated by a RST 30H call. Results: If Register A equals RST 30H, the Z FLAG is set; otherwise the NZ FLAG is set.
4E4A
If the NZ FLAG (Not Zero) is set then the OPCODE was not RST 30H, so JUMP to 4E4EH to move to the next breakpoint.
4E4C
LD A,(HL) 7E
Fetch the value stored at memory location pointed to by Register Pair HL (i.e., the original OPCODE at the location) and put it into Register A.
4E4D
LD (DE),A 12
Store the value held in Register A (i.e., the original OPCODE at the location) into the memory location pointed to by Register Pair DE (i.e., the call to DEBUG).
4E4ESTART4
INC HL 23
Bump the value stored in Register Pair HL by 1 to move to the next breakpoint in the breakpoint storage area.
4E4F
LOOP back to 4E3AH until Register B is ZERO.

4E51H - START5 - Command loop

Set up STACK, turn on cursor, display the screen, and process the DEBUG commands.

4E51START5
LD SP,(411CH)LD SP,(MEM+28) ED 7B 1C 41
Fetch the value stored at memory location 411CH (i.e., the old STACK pointer) and put it into Register SP. This sets up the SP to be fresh for each command.
Original Source Code Comment: RESET THE STACK POINTER
4E55
LD A,0B0H 3E B0
LET Register A = 0B0H (ASCII: BLOCK cursor).
4E57
LD (4023H),ALD (CURSCR),A 32 23 40
Store the value held in Register A into the memory location 4023H.
NOTE: 4023H is the storage location for the CURSOR CHARACTER.
Original Source Code Comment: SET THE CURSOR
4E5A
LD A,0EH 3E 0E
LET Register A = 0EH, which is ENABLE cursor.
Original Source Code Comment: INSURE CURSOR ON
4E5C
GOSUB to 0033H.
NOTE: 0033H is the character print routine, to put the character held in Register A at the current cursor position.
Original Source Code Comment: OUTPUT IT
4E5F
EI FB
Enable Interrupts.
Original Source Code Comment: INTERRUPTS ON
4E60
GOSUB to 4F0FH to display the DEBUG screen and all the registers.
Original Source Code Comment: DISPLAY ALL THE REGISTERS

4E63H - "START6" - Main command processing

4E63START6
LD HL,3FC0H 21 C0 3F
LET Register Pair HL = 3FC0H, which would be the first character on the 15th line of the display.
Original Source Code Comment: RESET THE CURSOR TO MIDDLE LINE
4E66
LD (4020H),HLLD (CURSOR),HL 22 20 40
Store the value held in Register HL into the memory location 4020H.
NOTE: 4020H is the storage location for the CURSOR POSITION ON SCREEN.
Original Source Code Comment: SET CURSOR
4E69
EI FB
Enable Interrupts.
Original Source Code Comment: INTERRUPTS ON
4E6A
GOSUB to 51F1H to get character from the keyboard and process accordingly.
Original Source Code Comment: GET A COMMAND
4E6D
CP 4AH FE 4A
Compare the value held in Register A against 4AH (ASCII: J). Results: If Register A equals J, the Z FLAG is set; otherwise the NZ FLAG is set.
Original Source Code Comment: JUMP?
4E6F
If the Z FLAG (Zero) is set, meaning that a J key was pressed, JUMP to 4FF7H.
4E72
CP 47H FE 47
Compare the value held in Register A against 47H (ASCII: G). Results: If Register A equals G, the Z FLAG is set; otherwise the NZ FLAG is set.
Original Source Code Comment: GO?
4E74
If the Z FLAG (Zero) is set, meaning that a G key was pressed, JUMP to 4FF7H, which is the same jump as above!

All the remaining commands do something that requires returning to the DEBUG screen and entering a new command, so we need to specify that when they exit, they come back to this COMMAND LOOP.

4E77
LD HL,4E51HLD HL,START5 21 51 4E
LET Register Pair HL = 4E51H (i.e., this command loop) as the return address
Original Source Code Comment: PUT A 'RET' ADDRESS ON THE STACK
4E7A
PUSH HL E5
Save Register HL (i.e., the return address) to the top of the STACK so that the top of the STACK contains the address we want to RETurn to.
4E7B
CP 53H FE 53
Compare the value held in Register A against 53H (ASCII: S). Results: If Register A equals S, the Z FLAG is set; otherwise the NZ FLAG is set.
Original Source Code Comment: FULL SCREEN?
4E7D
If the Z FLAG (Zero) is set, meaning that a S key was pressed, JUMP to 4EB3H.
4E7F
CP 3BH FE 3B
Compare the value held in Register A against 3BH (ASCII: ;). Results: If Register A equals ;, the Z FLAG is set; otherwise the NZ FLAG is set.
Original Source Code Comment: NEXT BLOCK OF MEMORY?
4E81
If the Z FLAG (Zero) is set, meaning that a ;). Re key was pressed, JUMP to 4EE3H.
4E83
CP 2DH FE 2D
Compare the value held in Register A against 2DH (ASCII: -). Results: If Register A equals -, the Z FLAG is set; otherwise the NZ FLAG is set.
Original Source Code Comment: BACK UP ONE BLOCK?
4E85
If the Z FLAG is set (the - key), JUMP to 4F0AH (BCKMEM) to move the display back.
4E88
CP 43H FE 43
Compare the value held in Register A against 43H (ASCII: C). Results: If Register A equals C, the Z FLAG is set; otherwise the NZ FLAG is set.
Original Source Code Comment: SINGLE STEP (AROUND CALLS)?
4E8A
If the Z FLAG (Zero) is set, meaning that a C key was pressed for a single-step-around-calls function, JUMP to 4E92H.
4E8C
CP 44H FE 44
Compare the value held in Register A against 44H (ASCII: D). Results: If Register A equals D, the Z FLAG is set; otherwise the NZ FLAG is set.
Original Source Code Comment: DISPLAY RAM LOCATIONS?
4E8E
If the Z FLAG (Zero) is set, meaning that a D key was pressed, JUMP to 4EC1H.
4E90
CP 49H FE 49
Compare the value held in Register A against 49H (ASCII: I). Results: If Register A equals I, the Z FLAG is set; otherwise the NZ FLAG is set.
Original Source Code Comment: SINGLE STEP?
4E92HERE1
If the Z FLAG (Zero) is set, meaning that a I key was pressed, JUMP to 50DBH.
4E95
CP 4DH FE 4D
Compare the value held in Register A against 4DH (ASCII: M). Results: If Register A equals M, the Z FLAG is set; otherwise the NZ FLAG is set.
Original Source Code Comment: ALTER MEMORY LOCATIONS?
4E97
If the Z FLAG (Zero) is set, meaning that a M key was pressed, JUMP to 504DH.
4E9A
CP 52H FE 52
Compare the value held in Register A against 52H (ASCII: R). Results: If Register A equals R, the Z FLAG is set; otherwise the NZ FLAG is set.
Original Source Code Comment: CHANGE REGISTER?
4E9C
If the Z FLAG (Zero) is set, meaning that a R key was pressed, JUMP to 508AH.
4E9F
CP 55H FE 55
Compare the value held in Register A against 55H (ASCII: U). Results: If Register A equals U, the Z FLAG is set; otherwise the NZ FLAG is set.
Original Source Code Comment: UPDATE DISPLAY?
4EA1
If the Z FLAG (Zero) is set, meaning that a U key was pressed, JUMP to 4EB7H.
4EA3
CP 58H FE 58
Compare the value held in Register A against 58H (ASCII: X). Results: If Register A equals X, the Z FLAG is set; otherwise the NZ FLAG is set.
Original Source Code Comment: BACK TO NORMAL MODE?
4EA5
If the Z FLAG (Zero) is set, meaning that a X key was pressed, JUMP to 4EB2H.
4EA7
CP 46H FE 46
Compare the value held in Register A against 46H (ASCII: F). Results: If Register A equals F, the Z FLAG is set; otherwise the NZ FLAG is set.
Original Source Code Comment: DISK OPERATION?
4EA9
If the Z FLAG (Zero) is set, meaning that a F key was pressed, JUMP to 52BDH.
4EAC
CP 51H FE 51
Compare the value held in Register A against 51H (ASCII: Q). Results: If Register A equals Q, the Z FLAG is set; otherwise the NZ FLAG is set.
Original Source Code Comment: QUIT DEBUG AND RETURN TO DOS?
4EAE
If the Z FLAG (Zero) is set, meaning that a Q key was pressed, JUMP to 5286H.
4EB1
RET C9
RETurn to the caller.
Original Source Code Comment: NOTHING SUPPORTED. EXIT AND TRY AGAIN

4EB2H - OVER - X Command - Half Page Display

4EB2OVER
XOR A AF
Set Register A to ZERO and clear all Flags.
Original Source Code Comment: ENTRY POINT FOR 'X'

4EB3H - PAGE - S Command - Full Page Display

4EB3PAGE
LD (4101H),ALD (MEM+1),A 32 01 41
Store the value held in Register A (i.e., a S, or really just any non-zero value) into the memory location 4101H.
Original Source Code Comment: ENTRY POINT FOR 'S'
4EB6
RET C9
RETurn to the caller.

4EB7H - UPDATE - U Command - Continuous Redisplay of Memory

Continuous redisplay of memory until a key is pressed

4EB7UPDATE
GOSUB to 002BH (i.e., the ROM Keyboard scanning routine; Register A exits with the ASCII value for the key that was pressed or ZERO if no key was pressed.
Original Source Code Comment: TRY FOR A KEYBOARD CHAR
4EBA
OR A B7
Set FLAGS based on the contents of Register A.
Original Source Code Comment: ANY THERE?
4EBB
RET NZ C0
If the NZ FLAG (Not Zero) is set, meaning a key was pressed, RETurn to the caller.
Original Source Code Comment: YES, EXIT
4EBC
GOSUB to 4F0FH to display memory.
Original Source Code Comment: NO, DISPLAY MEMORY
4EBF
LOOP BACK to the top of this routine at 4EB7H.
Original Source Code Comment: AND CONTINUE LOOKING FOR KEYBOARD

4EC1H - DOIT - D Command - Dump Memory

4EC1DOIT
LD HL,(4020H)LD HL,(CURSOR) 2A 20 40
Fetch the value stored at memory location 4020H and put it into Register HL.
NOTE: 4020H is the storage location for the CURSOR POSITION ON SCREEN.
Original Source Code Comment: GET THE CURSOR POSITION
4EC4
LD (5054H),HLLD (SAVCUR),HL 22 54 50
Store the value held in Register HL (i.e., the CURSOR POSITION ON SCREEN) into the memory location 5054H which is in the middle of a LD HL,nnnnH OPCODE.
Original Source Code Comment: SAVE IT
4EC7DOIT0
LD HL,(5054H)LD HL,(SAVCUR) 2A 54 50
Fetch the value stored at memory location 5054H (i.e., the CURSOR POSITION ON SCREEN) and put it into Register HL.
Original Source Code Comment: GET THE CURSOR
4ECA
LD (4020H),HLLD (CURSOR),HL 22 20 40
Store HL (the cursor position saved at SAVCUR) into 4020H-4021H (CURSOR, the ROM's cursor address in video RAM).
Original Source Code Comment: RESET IT
4ECD
LD HL,4FE7HLD HL,ADDR 21 E7 4F
LET Register Pair HL = 4FE7H (ADDR), the prompt 1EH (erase to the end of the line), ' ADDRESS? = ', 1EH, 0EH (cursor on), 03H.
Original Source Code Comment: HL => 'ADDRESS' MSB
4ED0
GOSUB to 021BH.
NOTE: 021BH will display the character at (HL) until a 03H is found.
Original Source Code Comment: DISPLAY IT
4ED3
GOSUB to 521FH to to get input from the user and store it in Register Pair HL (i.e., to get the DUMP address from the User).
Original Source Code Comment: GET THE ADDRESS
4ED6
RET Z C8
If the Z FLAG (Zero) is set then that CALL returned an error, so RETurn to the caller.
Original Source Code Comment: EXIT IF SILLY ANSWER
4ED7
PUSH HL E5
Save Register HL (i.e., the user entered address) to the top of the STACK.
Original Source Code Comment: SAVE ADDR POINTER
4ED8
LD DE,5600HLD DE,ENDBUG 11 00 56
LET Register Pair DE = 5600H, as the lowest memory address which a DUMP is permitted.
Original Source Code Comment: DE => LOWEST LEGAL ADDRESS
4EDB
OR A B7
Set FLAGS based on the contents of Register A.
Original Source Code Comment: CLEAR CARRY
4EDC
SBC HL,DE ED 52
Subtract the value stored in Register Pair DE (i.e., the lowest DUMPable memory location) and the carry flag from the value stored in Register Pair HL (i.e., the requested DUMP location) to see if we are within the limits of the DUMP command.
Original Source Code Comment: SEE IF LEGAL ADDR
4EDE
POP HL E1
Restore Register Pair HL (i.e., the response from the CALL) from the top of the STACK.
Original Source Code Comment: GET ADDR BACK
4EDF
If the C FLAG (Carry) is set then we are below the limits, so LOOP back to 4EC7H to try again.
Original Source Code Comment: NO, TRY IT AGAIN
4EE1
JUMP to 4EF7H to store the answer and continue the DUMP command.
Original Source Code Comment: ELSE STORE THE ANSWER

4EE3H - NXTMEM - ; Command - Advance display to the next line

4EE3NXTMEM
LD BC,0010H 01 10 00
LET Register Pair BC = 0010H (Decimal 16) to move 16 bytes forward.
Original Source Code Comment: SET FOR + 16 BYTES
4EE6NXTME0
LD HL,(4106H)LD HL,(MEM+6) 2A 06 41
Fetch the value stored at memory location 4106H (i.e., the current DUMP address) and put it into Register HL.
Original Source Code Comment: GET THE CURRENT DISPLAY ADDRESS
4EE9
LD A,(4101H)LD A,(MEM+1) 3A 01 41
Fetch the value stored at memory location 4101H (i.e., the display mode; ZERO for HALF PAGE and NON-ZERO for FULL PAGE) and put it into Register A.
Original Source Code Comment: ARE WE IN FULL PAGE MODE?
4EEC
OR A B7
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A.
4EED
If the Z FLAG (Zero) is set then we are at HALF PAGE display so JUMP to 4EF6H to bump the display by 16.
Original Source Code Comment: NO, BUMP DISPLAY BY 16

We need to process a full screen.

4EEF
LD C,00H 0E 00
LET Register C = 00H (wiping out the 16 which was put there in 4EE3) to set up for a 256 byte multiple
Original Source Code Comment: YES, DISTROY THE '16'
4EF1
LD A,B 78
LET Register A = Register B.
Original Source Code Comment: IS THE AMOUNT 256
4EF2
OR A B7
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A.
4EF3
If the NZ FLAG (Not Zero) is set, skip the next instruction and JUMP to 4EF6H.
Original Source Code Comment: YES, UPDATE ADDRESS
4EF5
INC B 04
Bump the value stored in Register B by 1 to increase the MSB.
Original Source Code Comment: NO, MAKE IT 256
4EF6OUT1
ADD HL,BC 09
ADD the value held in Register Pair BC to Register Pair HL, so that HL has the new DUMP address.
Original Source Code Comment: ADD THE OFFSET TO OLD ADDRESS
4EF7OUT2
LD A,L 7D
LET Register A = Register L to prepare to make sure we have a smooth HL value.
Original Source Code Comment: GET THE LSB OF THE ADDRESS
4EF8
AND 0F0H E6 F0
MASK the value of Register A against 0F0H (1111 0000) to make a round number.
Original Source Code Comment: FORCE IT TO 0 BOUNDARY
4EFA
LD L,A 6F
LET Register L = the masked/smoothed Register A.
Original Source Code Comment: NEW LSB
4EFBOUT4
LD (4106H),HLLD (MEM+6),HL 22 06 41
Store the value held in Register HL into the memory location 4106H (i.e., the current DUMP address).
Original Source Code Comment: SAVE THE NEW DISPLAY ADDRESS
4EFE
LD DE,5600HLD DE,ENDBUG 11 00 56
LET Register Pair DE = 5600H, as the lowest memory address which a DUMP is permitted.
Original Source Code Comment: LOWEST USER RAM ALLOWED
4F01
OR A B7
Set FLAGS based on the contents of Register A.
4F02
SBC HL,DE ED 52
Subtracts the value stored in Register Pair DE (i.e., the lowest DUMPable memory location) and the carry flag from the value stored in Register Pair HL (i.e., the requested DUMP location) to see if we are within the limits of the DUMP command.
Original Source Code Comment: WITHIN RANGE?
4F04
RET NC D0
If the NC FLAG (No Carry) is set then we are still good on the dump range so, RETurn to the caller.
Original Source Code Comment: YES, EXIT
4F05
LD (4106H),DELD (MEM+6),DE ED 53 06 41
OTHERWISE, we need to set a new dump address, so set it to the floor (held in Register Pair DE) and put that into memory location 4106H (i.e., the current DUMP address).
Original Source Code Comment: NO, SET DEFAULT MEMORY
4F09
RET C9
RETurn to the caller.
Original Source Code Comment: DONE

4F0AH - BCKMEM - - Command - Backspace next line

4F0ABCKMEM
LD BC,0FFF0H 01 F0 FF
LET Register Pair BC = 0FFF0H (Decimal: -16).
Original Source Code Comment: SET FOR -16
4F0D
JUMP to 4EE6H of the prior location to do everything the advance line routine does, but with a negative number.
Original Source Code Comment: AND CONTINUE

4F0FH - DISPLY - SUBroutine to display the DEBUG screen

4F0FDISPLY
DI F3
Disable Interrupts.
Original Source Code Comment: INTERRUPTS OFF
4F10
LD A,(4101H)LD A,(MEM+1) 3A 01 41
Fetch the value stored at memory location 4101H (i.e., the display mode; ZERO for HALF PAGE and NON-ZERO for FULL PAGE) and put it into Register A.
Original Source Code Comment: WE IN FULL PAGE MODE?
4F13
OR A B7
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A.
4F14
If the NZ FLAG is set (MEM+1 is not 00H: full page mode), JUMP to 4F93H (CURS1) to display 16 lines of memory.
Original Source Code Comment: YES, DISPLAY FULL PAGE

We need to process a FULL SCREEN debug screen.

4F17
LD A,1CH 3E 1C
LET Register A = 1CH (home the cursor).
Original Source Code Comment: HOME CURSOR
4F19
GOSUB to 0033H.
NOTE: 0033H is the character print routine, to put the character held in Register A at the current cursor position.
Original Source Code Comment: OUT TO THE DISPLAY
4F1C
LD HL,3C00H 21 00 3C
LET Register Pair HL = 3C00H (i.e., the first screen location).
Original Source Code Comment: TOP OF THE SCREEN
4F1F
LD (4020H),HLLD (CURSOR),HL 22 20 40
Set the cursor position by storing the value held in Register HL into the memory location 4020H.
NOTE: 4020H is the storage location for the CURSOR POSITION ON SCREEN.
Original Source Code Comment: SET THE CURSOR POSITION
4F22
GOSUB to 4F80H to display the memory.
Original Source Code Comment: DISPLAY THE MEMORY
4F25
GOSUB to 5273H to display a carriage return.
Original Source Code Comment: OUTPUT A CR
4F28
LD HL,(4020H)LD HL,(CURSOR) 2A 20 40
Fetch the value stored at memory location 4020H (i.e., the cursor location on screen) and put it into Register HL.
Original Source Code Comment: GET THE PRESENT CURSOR LOCATION
4F2B
LD (4F61H),HLLD (CURSAV),HL 22 61 4F
Store the value held in Register HL (i.e., the cursor location on screen) into the memory location 4F61H.
Original Source Code Comment: AND SAVE IT FOR LATER
4F2E
LD BC,00C0H 01 C0 00
LET Register Pair BC = 00C0H (Decimal: 192) as an offset to HL to move the cursor down 3 lines.
Original Source Code Comment: MOVE THE CURSOR DOWN 3 LINES
4F31
ADD HL,BC 09
ADD the value held in Register Pair BC (the 3 line offset) to Register Pair HL (the current screen position). The results are held in Register Pair HL.
Original Source Code Comment: HL = NEW CURSOR POSITION
4F32
LD (4020H),HLLD (CURSOR),HL 22 20 40
Store the value held in Register HL into the memory location 4020H.
NOTE: 4020H is the storage location for the CURSOR POSITION ON SCREEN.
Original Source Code Comment: SET IT
4F35
LD HL,4FA2HLD HL,DISPL7 21 A2 4F
LET Register Pair HL = 4FA2H so as to point to the message storage area for "SP PC AF ..".
Original Source Code Comment: HL => 'SP PC AF ETC' MSG
4F38
GOSUB to 021BH to display that message.
NOTE: 021BH will display the character at (HL) until a 03H is found.
Original Source Code Comment: DISPLAY IT
4F3B
GOSUB to 5273H to display a carriage return.
Original Source Code Comment: AND A CR
4F3E
LD HL,4108HLD HL,MEM+8 21 08 41
LET Register Pair HL = 4108H to point to the bottom of the REGISTER SAVE area.
4F41
PUSH HL E5
Save Register HL (i.e., the pointer to the REGISTER SAVE area) to the top of the STACK. In a few instructions we will have a EXchange command to swap this value.
4F42
LD HL,4FA2HLD HL,DISPL7 21 A2 4F
LET Register Pair HL = 4FA2H (i.e., the storage location for the message " AF BC DE HL AF").
4F45
LD B,0CH 06 0C
LET Register B = 0CH (Decimal: 12) since there are 12 register pairs.
Original Source Code Comment: SET FOR 12 REGISTER PAIRS
4F47DISPL0 / DISPL1
EX (SP),HL E3
EXchange the value stored in Register Pair HL (i.e., the storage location for the message " AF BC DE HL AF") with the value stored at the top of the STACK (i.e., the pointer to the REGISTER SAVE area).
4F48
LD E,(HL) 5E
Fetch the value stored at memory location pointed to by Register Pair HL (i.e., the LSB of one of the registers) and put it into Register E.
4F49
INC HL 23
Bump the value stored in Register Pair HL by 1.
4F4A
LD D,(HL) 56
Fetch the MSB of the saved register pair into Register D. DE now holds the saved value (4F48H-4F4AH is the source's LD DE,(HL)).
4F4B
INC HL 23
Bump the value stored in Register Pair HL by 1 to point to the LSB of the next register pair in the REGISTER SAVE area.
4F4C
PUSH HL E5
Save Register HL (i.e., the pointer to the next register pair in the REGISTER SAVE area) to the top of the STACK.
4F4D
EX DE,HL EB
EXchange the value stored in Register Pair HL (i.e., the pointer to the next register pair in the REGISTER SAVE area) with the value stored in Register Pair DE (i.e., the value of a saved register pair from the REGISTER SAVE area).
4F4E
LD A,H 7C
LET Register A = Register H so that we can display the MSB of the value held for that Register Pair.
4F4F
GOSUB 5258H (OUTBYT) to display Register A (the MSB) as two hex digits.
4F52
LD A,L 7D
LET Register A = Register L (the LSB of the value).
4F53
GOSUB to 526CH to display a byte held in Register A (i.e., that LSB) as a two byte ascii value followed by a space.
4F56
LD A,B 78
LET Register A = Register B (i.e., the counter for the 12 register pairs to dump).
4F57
AND 0BH E6 0B
AND 0BH on the count in A. No instruction tests the flags this sets: DISPL5 follows either way.

The AND 0BH and CP 08H set flags that no instruction tests: the source has no jump between them and DISPL5.

4F59
CP 08H FE 08
Compare A with 08H. No instruction tests the result: DISPL5 follows either way.
4F5BDISPL5
POP HL E1
Restore Register Pair HL (i.e., the pointer to the next register pair in the REGISTER SAVE area) the from the top of the STACK.
4F5C
EX (SP),HL E3
EXchange the value stored in Register Pair HL (i.e., the pointer to the next register pair in the REGISTER SAVE area) with the value stored at the top of the STACK (i.e., the storage location for the message " AF BC DE HL AF").
4F5D
LOOP back to 4F47H until Register B is ZERO.
4F5F
POP HL E1
Clear the STACK.
4F60
LD HL,0000HLD HL,0 21 00 00
LET Register Pair HL = the cursor address stored at 4F61H-4F62H (CURSAV, the operand of this instruction) by 4F2BH: the line under the memory display.
Original Source Code Comment: CURSOR SAVED HERE
4F63
LD BC,0040HLD BC,64 01 40 00
LET Register Pair BC = 0040H (64), one screen line.
Original Source Code Comment: BUMP DOWN ONE LINE
4F66
ADD HL,BC 09
ADD the value held in Register Pair BC (i.e., one screen line offset) to Register Pair HL (i.e., the saved cursor location). The results are held in Register Pair HL.
Original Source Code Comment: HL = NEW CURSOR
4F67
LD (4020H),HLLD (CURSOR),HL 22 20 40
Store the value held in Register HL (i.e., the advanced by one line cursor location) into the memory location 4020H.
NOTE: 4020H is the storage location for the CURSOR POSITION ON SCREEN.
Original Source Code Comment: SET IT
4F6A
LD HL,4FD7HLD HL,PC 21 D7 4F
LET Register Pair HL = 4FD7H, which points to the message PC.
Original Source Code Comment: HL => 'PC' MSG
4F6D
GOSUB to 021BH to display that message.
NOTE: 021BH will display the character at (HL) until a 03H is found.
Original Source Code Comment: DISPLAY IT
4F70
GOSUB to 526FH to display a space.
Original Source Code Comment: AND A SPACE
4F73
LD HL,(411EH)LD HL,(MEM+30) 2A 1E 41
Fetch 411EH-411FH (MEM+30, the program's PC) into Register Pair HL.
Original Source Code Comment: HL => USERS PC AREA
4F76
LD B,10H 06 10
LET Register B = 10H (Decimal: 16) to set up for a loop of 16.
Original Source Code Comment: SET FOR 16 BYTES
4F78CURSA1
LD A,(HL) 7E
Fetch the value stored at memory location pointed to by Register Pair HL and put it into Register A.
Original Source Code Comment: GET A BYTE
4F79
GOSUB to 526CH to print a byte held in Register A as a two byte ascii value followed by a space.
Original Source Code Comment: OUTPUT IT AS TWO BYTE ASCII AND SPACE
4F7C
INC HL 23
Bump Register Pair HL to point to the next byte.
Original Source Code Comment: BUMP TO NEXT BYTE
4F7D
LOOP back to 4F78H until Register B is ZERO.
Original Source Code Comment: LOOP FOR COUNT
4F7F
RET C9
RETurn to the caller.
Original Source Code Comment: DONE WITH DISPLAY

4F80H - ONELNE - SUBroutine to display RAM locations

4F80ONELNE
LD HL,(4106H)LD HL,(MEM+6) 2A 06 41
Fetch the value stored at memory location 4106H (i.e., the current DUMP ADDRESS) and put it into Register HL.
Original Source Code Comment: GET THE MEMORY POINTER
4F83
LD B,08H 06 08
LET Register B = 08H to set up for a DJNZ loop of 8 iterations for 8 rows.
Original Source Code Comment: SET FOR 8 ROWS
4F85LOOP1
GOSUB to 5253H to display the address in hexadecimal.
Original Source Code Comment: OUTPUT THE ADDRESS ON SCREEN
4F88
GOSUB to 526FH to display a space.
Original Source Code Comment: AND A SPACE
4F8B
GOSUB to 51B1H to display a data line.
Original Source Code Comment: DISPLAY ONE LINE
4F8E
LOOP back to 4F85H until Register B is ZERO (i.e., 8 iterations).
Original Source Code Comment: LOOP FOR COUNT
4F90
JUMP to 5277H to clear the rest of the screen and exit.
Original Source Code Comment: AND CLEAR THE REST OF THE SCREEN

4F93H - CURS1 - Continuation of the SUBroutine to display the DEBUG screen, jumped to for a full page display

4F93CURS1
LD HL,3C00H 21 00 3C
LET Register Pair HL = 3C00H, which is the top of the screen.
Original Source Code Comment: HL = TOP OF SCREEN ADDRESS
4F96
LD (4020H),HLLD (CURSOR),HL 22 20 40
Store the value held in Register HL into the memory location 4020H.
NOTE: 4020H is the storage location for the CURSOR POSITION ON SCREEN.
Original Source Code Comment: SET IT AS CURSOR POSITION
4F99
LD HL,(4106H)LD HL,(MEM+6) 2A 06 41
Fetch the value stored at memory location 4106H (i.e., the address to display) and put it into Register HL.
Original Source Code Comment: HL => ADDRESS TO DISPLAY
4F9C
LD L,00H 2E 00
LET Register L = 00H to have a smooth address / even page in HL.
Original Source Code Comment: INSURE EVEN BOUNDARY
4F9E
LD B,10H 06 10
LET Register B = 10H (Decimal: 16) for a loop of 16 rows to display.
Original Source Code Comment: SET FOR 16 ROWS
4FA0
JUMP to 4F85H (LOOP1) to display the 16 lines.
Original Source Code Comment: AND DISPLAY IT

4FA2H - DISPL7 - Message Storage Area

4FA2-4FD6DISPL7
DEFM " AF BC DE HL AF' BC' DE' HL' IX IY SP" 20 41 46 20 20 20 42 43 20 20 20 44 45 20 20 20 48 4C 20 20 20 41 46 27 20 20 42 43 27 20 20 44 45 27 20 20 48 4C 27 20 20 49 58 20 20 20 49 59 20 20 20 53 50
DISPL7: the names of the 12 register pairs, one per 5 columns, shown above the values (DISPLY at 4F35H); REGIST (50A2H) searches them. The source writes each ' as DEFB 27H.
4FD7-4FDDPC
DEFM " PC " 20 20 20 50 43 20 20
PC: the label of the line of 16 bytes at the program's PC (LD HL,4FD7H at 4F6AH).
4FDE
DEFB 03H 03
03H ends the text for PRINT (021BH).
4FDF-4FE6FLAGS
DEFM "SZ1H1POC" 53 5A 31 48 31 50 4F 43
FLAGS: one letter per bit of the F register, bit 7 first. No instruction in SYS5 uses it.
4FE7ADDR
DEFB 1EH 1E
ADDR: the prompt of the D, M and G/J commands. 1EH erases to the end of the line.
4FE8-4FF3
DEFM " ADDRESS? = " 20 41 44 44 52 45 53 53 3F 20 3D 20
4FF4-4FF6
DEFB 1EH,0EH,03H 1E 0E 03
1EH erases to the end of the line, 0EH turns the cursor on, 03H ends the text for PRINT (021BH).

4FF7H - GO - Routine to process "G" and "J" by JUMPing to a specified address

4FF7GO
LD HL,4FE7HLD HL,ADDR 21 E7 4F
LET Register Pair HL = 4FE7H, which is the pointer to the message "ADDRESS? = ".
4FFA
GOSUB to 021BH.
NOTE: 021BH will display the character at (HL) until a 03H is found.
4FFD
LD B,02H 06 02
LET Register B = 02H, as there are two breakpoint locations.
4FFF
LD DE,4105HLD DE,MEM+5 11 05 41
LET Register Pair DE = 4105H to point to the breakpoint storage area.
5002
GOSUB to 521FH to to get input from the user and store it in Register Pair HL (i.e., the JUMP address).
5005
If the Z FLAG (Zero) is set, meaning that no address was given, we will default to the PROGRAM COUNTER, so JUMP to 500AH.
5007
LD (411EH),HLLD (MEM+30),HL 22 1E 41
A new address was typed: store it into 411EH-411FH (MEM+30, the program's PC), where the program goes on.
500AGO1
GO1: If the CARRY FLAG is set (the last entry ended with ENTER or an arrow), no breakpoint follows: JUMP to 5016H (GO2).
500C
GOSUB to 521FH to get input from the user and store it in Register Pair HL (i.e., the breakpoint).
500F
PUSH AF F5
Save Register AF to the top of the STACK.
5010
If the NZ FLAG (Not Zero) is set then we need to save the breakpoint into a table, so GOSUB to 503CH.
5013
POP AF F1
Restore Register Pair AF from the top of the STACK.
5014
LOOP back to 500AH until Register B is ZERO (i.e., both breakpoints have been processed).
5016GO2 / MISS1
LD HL,411DHLD HL,MEM+29 21 1D 41
GO2 / MISS1: LET Register Pair HL = 411DH (MEM+29), the MSB of the saved SP.
5019
LD B,0BH 06 0B
LET Register B = 0BH (Decimal: 11) for a loop of 11 Register Pairs.
501BGO3
LD D,(HL) 56
GO3: Fetch the MSB of a saved register pair into Register D. The loop pushes the 11 pairs from MEM+28 (SP) down to MEM+8 (AF).
501C
DEC HL 2B
DECrement the value stored in Register Pair HL by 1 so as to point to the LSB of that register pair.
501D
LD E,(HL) 5E
Fetch the value stored at memory location pointed to by Register Pair HL (i.e., the LSB byte of any of the 12 register pairs) and put it into Register E.
501E
DEC HL 2B
DECrement the value stored in Register Pair HL by 1 so as to point to the MSB of the next register pair.
501F
PUSH DE D5
Save Register DE to the top of the STACK.
5020
LOOP back to 501BH until the 11 pairs are on the STACK.

Restore all the registers

5022
POP AF F1
Restore Register Pair AF from the top of the STACK.
5023
POP BC C1
Restore Register Pair BC from the top of the STACK.
5024
POP DE D1
Restore Register Pair DE from the top of the STACK.
5025
POP HL E1
Restore Register Pair HL from the top of the STACK.
5026
EX AF,AF' 08
EXchange AF with AF': the program's AF goes into AF', and the next POP AF fills AF with the program's AF'.
5027
EXX D9
EXchange BC, DE and HL with BC', DE' and HL': the program's BC, DE and HL go into the alternate set, and the next POPs fill BC, DE and HL with the program's BC', DE' and HL'.
5028
POP AF F1
Restore Register Pair AF from the top of the STACK.
5029
POP BC C1
Restore Register Pair BC from the top of the STACK.
502A
POP DE D1
Restore Register Pair DE from the top of the STACK.
502B
POP HL E1
Restore Register Pair HL from the top of the STACK.
502C
EX AF,AF' 08
EXchange AF with AF' again: AF holds the program's AF and AF' the program's AF'.
502D
EXX D9
EXchange BC, DE, HL with BC', DE', HL' again: every register except IX, IY, HL and SP now holds the program's value.
502E
POP IX DD E1
Restore Register Pair IX from the top of the STACK.
5030
POP IY FD E1
Restore Register Pair IY from the top of the STACK.
5032
POP HL E1
Restore Register Pair HL from the top of the STACK.
5033
LD SP,HL F9
LET Register Pair SP = Register Pair HL.
5034
LD HL,(411EH)LD HL,(MEM+30) 2A 1E 41
Fetch 411EH-411FH (MEM+30, the program's PC) into Register Pair HL.
5037
PUSH HL E5
Push the program's PC; the RET at 503BH jumps to it.
5038
LD HL,(410EH)LD HL,(MEM+14) 2A 0E 41
Fetch the value stored at memory location 410EH (i.e., the saved value for Register Pair HL) and put it into Register HL.
503B
RET C9
Run the calling program.

503CH - SET - SUBroutine to Save the Breakpoint into a Table (done backwards)

503CSET
LD A,(HL) 7E
Fetch the value stored at memory location pointed to by Register Pair HL (i.e., which would be an OPCODE) and put it into Register A.
503D
LD (DE),A 12
Store the value held in Register A (i.e., the OPCODE) into the memory location pointed to by Register Pair DE (i.e., the BREAKPOINT STORAGE TABLE).
503E
DEC DE 1B
DECrement the value stored in Register Pair DE by 1 to back up one byte in the table
503F
LD A,0F7H 3E F7
LET Register A = 0F7H (OPCODE: RST 30H).
5041
LD (HL),A 77
Store the value held in Register A (i.e., RST 30H) into the memory location pointed to by Register Pair HL (i.e., to overwrite the existing OPCODE).
5042
CP (HL) BE
Compare the value held in Register A against the value held in the memory location (HL) to verify it was written correctly. Results: If Register A equals (HL), the Z FLAG is set; otherwise the NZ FLAG is set.
5043
If the NZ FLAG (Not Zero) is set then the byte was not written to RAM correctly, so JUMP to 4E35H.
5046
LD A,H 7C
LET Register A = Register H (i.e., the MSB of the breakpoint address).
5047
LD (DE),A 12
Store the value held in Register A (i.e., the MSB of the breakpoint address) into the memory location pointed to by Register Pair DE.
5048
DEC DE 1B
DECrement the value stored in Register Pair DE by 1 to back up one byte in the table.
5049
LD A,L 7D
LET Register A = Register L (i.e., the LSB of the breakpoint address).
504A
LD (DE),A 12
Store the value held in Register A (i.e., the LSB of the breakpoint address) into the memory location pointed to by Register Pair DE.
504B
DEC DE 1B
DECrement the value stored in Register Pair DE by 1 to back up one byte in the table.
504C
RET C9
RETurn to the caller.

504DH - MEMORY - Routine to MODIFY AND DISPLAY RAM - the "M" option

504DMEMORY
LD HL,(4020H)LD HL,(CURSOR) 2A 20 40
Fetch the cursor position (i.e., stored at memory location 4020H) and put it into Register HL.
NOTE: 4020H is the storage location for the CURSOR POSITION ON SCREEN.
5050
LD (5054H),HLLD (SAVCUR),HL 22 54 50
Store the value held in Register HL (i.e., the cursor position on screen) into the memory location 5054H.
5053MEMOR0
LD HL,0000HLD HL,0 21 00 00
MEMOR0: LET Register Pair HL = the cursor address stored at 5054H-5055H (SAVCUR, the operand of this instruction) by 5050H (MEMORY) or 4EC4H (DOIT).
Original Source Code Comment: CURSOR SAVED HERE
5056
LD (5054H),HLLD (SAVCUR),HL 22 54 50
Store the value held in Register HL (i.e., the cursor position on screen) into the memory location 5054H.
5059
LD HL,4FE7HLD HL,ADDR 21 E7 4F
LET Register Pair HL = 4FE7H so as to point to the "ADDRESS" message.
505C
GOSUB to 021BH.
NOTE: 021BH will display the character at (HL) until a 03H is found.
505F
LD HL,(4103H)LD HL,(MEM+3) 2A 03 41
Fetch the value stored at memory location 4103H (i.e., the old dump address) and put it into Register HL just in case we get a NULL answer.
5062
GOSUB to 521FH to get input from the user and store it in Register Pair HL (i.e., the new address).
5065
RET C D8
If the C FLAG (Carry) is set then we got a value which is invalid so, RETurn to the caller.
5066
PUSH HL E5
Save Register HL (i.e., the address we got from the user) to the top of the STACK.
5067
LD DE,5600HLD DE,ENDBUG 11 00 56
LET Register Pair DE = 5600H, as the lowest memory address which a DUMP is permitted.
506A
OR A B7
Set FLAGS based on the contents of Register A.
506B
SBC HL,DE ED 52
Subtract the value stored in Register Pair DE (i.e., the lowest DUMPable memory location) and the carry flag from the value stored in Register Pair HL (i.e., the requested DUMP location) to see if we are within the limits of the DUMP command.
506D
POP HL E1
Restore Register Pair HL (i.e., the response from the user) from the top of the STACK.
506E
If the C FLAG (Carry) is set then we are below the limits, so LOOP back to 5053H to try again.
5070
LD (554FH),HLLD (WHERE),HL 22 4F 55
Store the value held in Register HL (i.e., the response from the user) into the memory location 554FH.
5073
LD L,00H 2E 00
LET Register L = 00H so that Register Pair HL is smooth (i.e., nn00H)
5075
LD (4103H),HLLD (MEM+3),HL 22 03 41
Store the value held in Register HL (i.e., the smoothed response from the user) into the memory location 4103H (i.e., the new default).
5078
LD A,H 7C
LET Register A = Register H (i.e., the MSB of the smoothed response from the user).
5079
LD (555FH),ALD (NRN),A 32 5F 55
Store the value held in Register A into the memory location 555FH.

We need to set some flags to indicate that this is a MEMORY routine and not a DISK routine.

507C
XOR A AF
Set Register A to ZERO and clear all Flags.
507D
LD (5560H),ALD (NRN+1),A 32 60 55
Store the value held in Register A (i.e., a ZERO) into the memory location 5560H.
5080
DEC A 3D
DECrement the value stored in Register A by 1, thus tripping the NZ Flag and setting Register A to FFH.
5081
LD (545FH),ALD (NODISK),A 32 5F 54
Store FFH into 545FH (NODISK, the operand of LD A at 545EH): FFH = the M command is editing memory, 00H = the disk utility is editing a record.
Original Source Code Comment: SHOW IT'S MEMORY CALLING, NOT DISK
5084
LD (5553H),ALD (MOVFLG),A 32 53 55
Store the value held in Register A (i.e., FFH) into the memory location 5553H to indicate that we need to display the cursor.
5087
JUMP to 544FH to display and get the changes.

508AH - REGIST - Command "R" - Modify the User Registers

508AREGIST
GOSUB to 51F1H to get character from the keyboard and process accordingly.
508D
RET Z C8
If the Z FLAG is set (ENTER, an arrow, a space or a comma), RETurn: no register name was typed.
Original Source Code Comment: EXIT IF SILLY
508E
LD C,A 4F
LET Register C = Register A (i.e., the first character of the desired register name).
508F
GOSUB to 51F1H to get character from the keyboard and process accordingly..
5092
RET Z C8
If the Z FLAG is set (ENTER, an arrow, a space or a comma), RETurn without a change.
5093
LD D,A 57
LET Register D = Register A (i.e., the second character of the user desired register name).
5094
LD E,20H 1E 20
LET Register E = 20H (ASCII: SPACE) so that the default for the third character will be a SPACE.
5096
GOSUB to 51F1H to get character from the keyboard and process accordingly..
5099
RET C D8
If the CARRY FLAG is set (ENTER, or an arrow other than the right arrow), RETurn without a change.
509A
If the Z FLAG is set (a space, a comma or the right arrow), the name has two letters: JUMP to 50A2H (REG1) with E = 20H (space).
509C
LD E,A 5F
LET Register E = the third character typed (the ' of AF', BC', DE', HL').
509D
GOSUB to 51F1H to get character from the keyboard and process accordingly..
50A0
RET NZ C0
If the NZ FLAG is set (a fourth character that is not a space or comma), RETurn without a change.
50A1
RET C D8
If the CARRY FLAG is set (ENTER or an arrow), RETurn without a change.
50A2REG1
LD HL,4FA3HLD HL,DISPL7+1 21 A3 4F
REG1: LET Register Pair HL = 4FA3H (DISPL7+1), the register names ' AF BC DE ...' past the first space.
50A5
LD B,0CH 06 0C
LET Register B = 0CH (Decimal: 12) since there are 12 register pairs.
50A7REG2
LD A,(HL) 7E
REG2: Fetch a character of the DISPL7 name text into Register A.
50A8
CP C B9
Compare it with Register C (the first letter typed).
50A9
If they match, JUMP to 50B6H (REG5) to check the next characters.

While there is one INC HL which is definitely used, the following two INC HL's are jump points; this is all to advance HL to the next name in the DISPL7 name text (4FA2H), which may be 3, 2, or 1 character away.

50AB
INC HL 23
Bump HL past the first letter of this name.
50ACREG3
INC HL 23
REG3: Bump HL past the second letter.
50ADREG4
INC HL 23
REG4: Bump HL.
50AE
LD A,(HL) 7E
Fetch the character at HL into Register A.
50AF
CP 20H FE 20
Compare the value held in Register A against 20H (i.e., an ASCII SPACE. Results: If Register A equals SPACE, the Z FLAG is set; otherwise the NZ FLAG is set.
50B1
If it is a space, JUMP back to 50ADH (REG4): skip the spaces up to the next name.
50B3
LOOP back to 50A7H for the next of the 12 names; Register B counts them (12 = AF ... 1 = PC).
50B5
RET C9
No name matched: RETurn without a change.

50B6H - REG5 - Continuation of the "R" Command. Jumped here when the first character typed matches the first letter of a name in DISPL7

50B6REG5
INC HL 23
REG5: Bump HL to the second letter of the name.
50B7
LD A,(HL) 7E
Fetch it into Register A.
50B8
CP D BA
Compare it with Register D (the second letter typed).
50B9
If they differ, JUMP to 50ACH (REG3) to skip to the next name.
50BB
INC HL 23
Bump HL to the third character of the name (a ' or a space).
50BC
LD A,(HL) 7E
Fetch it into Register A.
50BD
CP E BB
Compare it with Register E (the third character typed, or a space).
50BE
If they differ, JUMP to 50ADH (REG4) to skip to the next name.

If we are here then all 3 of the characters entered by the user for the desired register to modify have been found. With this, we need to do some math to find the location of the matched register pair with the stored value for that register pair. Register B holds the counter where we stopped parsing register pairs.

50C0
LD A,18H 3E 18
LET Register A = 18H (Decimal: 24).
50C2
SUB B 90
SUBtract the value held in Register B (i.e., the stopping point of the backwards countdown searching for register name matches in the REGISTER STORAGE TABLE) from Register A.
50C3
SUB B 90
SUBtract the value held in Register B (i.e., the stopping point of the backwards countdown searching for register name matches in the REGISTER STORAGE TABLE) from Register A.
50C4
LD C,A 4F
LET Register C = Register A (i.e., 24 - B*2).
50C5
LD B,00H 06 00
LET Register B = 00H so that Register Pair BC = Register C.
50C7
LD HL,4108HLD HL,MEM+8 21 08 41
LET Register Pair HL = 4108H to point to the bottom of the REGISTER SAVE area.
50CA
ADD HL,BC 09
ADD the value held in Register Pair BC (i.e., 24 - 2 x the stopping point of the register name search) to Register Pair HL (i.e., the bottom of the REGISTER SAVE are). The results are held in Register Pair HL.
50CB
PUSH HL E5
Save Register HL (i.e., the location of the VALUE of the register sought) to the top of the STACK.
50CC
LD A,1EH 3E 1E
LET Register A = 1EH (ASCII: to erase to end of line)
50CE
GOSUB to 0033H.
NOTE: 0033H is the character print routine, to put the character held in Register A at the current cursor position.
50D1
POP DE D1
Restore the top of the STACK (i.e., the location of the VALUE of the register sought) into Register Pair DE.
50D2
GOSUB to 521FH to get input from the user and store it in Register Pair HL (i.e., the new value for the register pair).
50D5
RET Z C8
If the Z FLAG (Zero) is set, meaning we didn't get anything from the user, RETurn to the caller.
50D6
EX DE,HL EB
EXchange the value stored in Register Pair HL (i.e., the user supplied new value for the register pair) with the value stored in Register Pair DE (i.e., the location of the VALUE of the register sought).
50D7
LD (HL),E 73
Store the value held in Register E (i.e., the LSB of the user supplied new value for the register pair) into the memory location pointed to by Register Pair HL (i.e., the location of the VALUE of the register sought).
50D8
INC HL 23
Bump the value stored in Register Pair HL by 1.
50D9
LD (HL),D 72
Store the value held in Register D (i.e., the MSB of the user supplied new value for the register pair) into the memory location pointed to by Register Pair HL (i.e., the location of the VALUE of the register sought).
50DA
RET C9
RETurn to the caller.

50DBH - SINGLE - "I" and "C" Commands - Instruction Step / Call Step Single Step Routines

50DBSINGLE
PUSH AF F5
SINGLE: Save AF; Register A = the command key, 'C' (43H, step over a CALL) or 'I' (49H, step into it). The POP AF at 512DH takes it back.
50DC
LD DE,(411EH)LD DE,(MEM+30) ED 5B 1E 41
Fetch 411EH-411FH (MEM+30, the program's PC) into Register Pair DE.
50E0
LD A,(DE) 1A
Fetch the opcode at the PC into Register A.
50E1
LD HL,5195HLD HL,TABLE3 21 95 51
LET Register Pair HL = 5195H (TABLE3, the table for the byte after a DDH or FDH prefix).
50E4
CP 0DDH FE DD
Compare the opcode with DDH (the IX prefix).
50E6
If DDH, JUMP to 50F6H (SINGL1) to fetch the byte after the prefix.
50E8
CP 0FDH FE FD
Compare the opcode with FDH (the IY prefix).
50EA
If FDH, JUMP to 50F6H (SINGL1).
50EC
LD HL,5160HLD HL,TABLE1 21 60 51
LET Register Pair HL = 5160H (TABLE1, the table for opcodes without a prefix).
50EF
CP 0EDH FE ED
Compare the opcode with EDH (the ED prefix).
50F1
If it is not EDH, JUMP to 50F9H (SINGL2) with the opcode in Register A.
50F3
LD HL,518EHLD HL,TABLE2 21 8E 51
LET Register Pair HL = 518EH (TABLE2, the table for the byte after an EDH prefix).
50F6SINGL1
INC DE 13
SINGL1: Bump DE to the byte after the prefix.
50F7
LD A,(DE) 1A
Fetch that byte into Register A.
50F8
DEC DE 1B
DECrement DE back to the PC.
50F9SINGL2
LD C,A 4F
SINGL2: LET Register C = the byte to look up (the opcode, or the byte after a DDH, EDH or FDH prefix).
50FASINGL3
LD A,(HL) 7E
SINGL3: Fetch the mask byte of a table entry into Register A.
50FB
AND C A1
AND it with Register C (the byte being looked up).
50FC
INC HL 23
Bump HL to the value byte of the entry.
50FD
CP (HL) BE
Compare the masked byte with the value byte.
50FE
INC HL 23
Bump HL to the type byte of the entry.
50FF
If they match, JUMP to 5107H (SINGL4) with HL at the type byte.
5101
INC HL 23
Bump HL to the next entry.
5102
LD A,(HL) 7E
Fetch its first byte into Register A.
5103
CP 05H FE 05
Compare it with 05H. Every mask is 05H or more; a byte below 05H ends the table and is the type byte for every opcode the table does not list.
5105
If it is 05H or more (a mask), LOOP back to 50FAH (SINGL3); otherwise go on to SINGL4 with HL at the end byte.
5107SINGL4
LD A,(HL) 7E
SINGL4: Fetch the type byte into Register A: bits 3-0 = the length of the instruction, bits 7-4 = the kind of jump.
5108
LD B,A 47
Keep the type byte in Register B.
5109
AND 0FH E6 0F
AND 0FH keeps the length.
510B
LD L,A 6F
LET Register L = the length (510BH-510CH is the source's LD HL,A).
510C
LD H,00H 26 00
LET Register H = 00H: HL = the length.
510E
ADD HL,DE 19
ADD the PC (DE): HL = the address of the next instruction.
510F
PUSH DE D5
Save the PC on the STACK.
5110
LD DE,4105HLD DE,MEM+5 11 05 41
LET Register Pair DE = 4105H (MEM+5), the last byte of the first breakpoint entry (MEM+3 to MEM+5).
5113
GOSUB 503CH (SET) to put the first breakpoint (F7H, RST 30H) on the next instruction. SET leaves DE = 4102H (MEM+2), the last byte of the second entry.
5116
POP HL E1
Restore the PC into Register Pair HL.
5117
LD A,B 78
LET Register A = the type byte.
5118
AND 0F0H E6 F0
AND F0H keeps bits 7-4, the kind of jump.
511A
If 00H (no jump), JUMP to 5132H (SINGL5): run the instruction with the one breakpoint.
511C
INC HL 23
Bump HL to PC+1, the operand of the jump.
511D
CP 20H FE 20
Compare the kind with 20H.
511F
If 10H (JP (HL)), JUMP to 5158H (SINGLA).
5121
If 20H (JP (IX) or JP (IY)), JUMP to 514CH (SINGL9).
5123
CP 40H FE 40
Compare the kind with 40H.
5125
If 30H (JR or DJNZ), JUMP to 5140H (SING70).
5127
If 40H (JP nn), JUMP to 5138H (SINGL7) to fetch the address at PC+1.
5129
CP 60H FE 60
Compare the kind with 60H.
512B
If 50H (RET, RETI, RETN), JUMP to 5135H (SINGL6).
512D
POP AF F1
60H, a CALL: restore AF; Register A = the command key.
512E
CP 49H FE 49
Compare it with 49H ('I').
5130
If 'I', JUMP to 5138H (SINGL7) to put the second breakpoint on the address the CALL goes to. For 'C' only the breakpoint after the CALL is set, so the subroutine runs at full speed.
5132SINGL5
SINGL5: JUMP to 5016H (MISS1) to put back the registers and run the program.

5135H - SINGL6 - Continuation of the "I"/"C" routine - Set a BREAKPOINT for either RET or JP

If the next opcode was a RET ...

5135SINGL6
LD HL,(411CH)LD HL,(MEM+28) 2A 1C 41
SINGL6: Fetch 411CH-411DH (MEM+28, the program's SP) into Register Pair HL: the return address is at the top of the program's STACK.

If the next opcode was a JP or CALL.

5138SINGL7
PUSH AF F5
SINGL7: Save AF (5138H-513DH is the source's LD HL,(HL)).
5139
LD A,(HL) 7E
Fetch the LSB of the address at HL into Register A.
513A
INC HL 23
Bump HL.
513B
LD H,(HL) 66
Fetch the MSB into Register H.
513C
LD L,A 6F
LET Register L = the LSB: HL = the address the jump goes to.
513D
POP AF F1
Restore AF.
513E
JUMP to 515BH (SINGLB) to set the second breakpoint.

5140H - SING70 - Continuation of the "I"/"C" routine - Set a BREAKPOINT for JR or DJNZ

5140SING70
LD C,(HL) 4E
SING70: Fetch the displacement byte of the JR or DJNZ into Register C.
5141
XOR A AF
LET Register A = 00H, the MSB for a forward jump.
5142
BIT 7,C CB 79
Test bit 7 of the displacement.
5144
If bit 7 is clear (a forward jump), JUMP to 5147H (SINGL8).
5146
CPL 2F
CPL: Register A = FFH, the MSB for a backward jump.
5147SINGL8
LD B,A 47
SINGL8: LET Register B = the MSB, so BC = the displacement as a signed 16 bit value.
5148
INC HL 23
Bump HL to PC+2, the next instruction.
5149
ADD HL,BC 09
ADD the displacement: HL = the address the jump goes to.
514A
JUMP to 515BH (SINGLB).

514CH - SINGL9 - Continuation of the "I"/"C" routine - Set a BREAKPOINT for either JP (IX) or JP (IY)

514CSINGL9
LD HL,(4118H)LD HL,(MEM+24) 2A 18 41
SINGL9: Fetch 4118H-4119H (MEM+24, the program's IX) into Register Pair HL.
514F
BIT 5,C CB 69
Test bit 5 of Register C, meant to tell DDH (bit 5 clear, IX) from FDH (bit 5 set, IY). Register C holds the byte after the prefix, E9H, whose bit 5 is set, so the IY value is always taken: JP (IX) is stepped to the address in IY.
5151
If bit 5 is clear, JUMP to 515BH (SINGLB) with the IX value. With C = E9H this jump is never taken.
5153
LD HL,(411AH)LD HL,(MEM+26) 2A 1A 41
Fetch 411AH-411BH (MEM+26, the program's IY) into Register Pair HL.
5156
JUMP to 515BH (SINGLB).

5158H - SINGLA - Continuation of the "I"/"C" routine - Set a BREAKPOINT for either JP (HL)

5158SINGLA
LD HL,(410EH)LD HL,(MEM+14) 2A 0E 41
SINGLA: Fetch 410EH-410FH (MEM+14, the program's HL) into Register Pair HL: where JP (HL) goes.
515BSINGLB
SINGLB: GOSUB 503CH (SET) to put the second breakpoint (F7H, RST 30H) on the jump target; DE = 4102H (MEM+2), so this entry is MEM+0 to MEM+2.
515E
JUMP to 5132H (SINGL5), which goes on to 5016H (MISS1) to run the program.

5160H - TABLE1 - OPCODE TABLE - "NORMAL" OPCODES

5160-5162TABLE1
DEFB C7H,C0H,51H C7 C0 51
Mask C7H, value C0H: RET cc (C0H, C8H ... F8H). Type 51H: 1 byte, return.
5163-5165
DEFB FFH,C9H,51H FF C9 51
Mask FFH, value C9H: RET (C9H). Type 51H: 1 byte, return.
5166-5168
DEFB FFH,E9H,11H FF E9 11
Mask FFH, value E9H: JP (HL) (E9H). Type 11H: 1 byte, JP (HL).
5169-516B
DEFB CFH,01H,03H CF 01 03
Mask CFH, value 01H: LD BC/DE/HL/SP,nn (01H, 11H, 21H, 31H). Type 03H: 3 bytes, no jump.
516C-516E
DEFB E7H,22H,03H E7 22 03
Mask E7H, value 22H: LD (nn),HL, LD HL,(nn), LD (nn),A, LD A,(nn) (22H, 2AH, 32H, 3AH). Type 03H: 3 bytes, no jump.
516F-5171
DEFB C7H,C2H,43H C7 C2 43
Mask C7H, value C2H: JP cc,nn (C2H ... FAH). Type 43H: 3 bytes, JP nn.
5172-5174
DEFB FFH,C3H,43H FF C3 43
Mask FFH, value C3H: JP nn (C3H). Type 43H: 3 bytes, JP nn.
5175-5177
DEFB C7H,C4H,63H C7 C4 63
Mask C7H, value C4H: CALL cc,nn (C4H ... FCH). Type 63H: 3 bytes, CALL.
5178-517A
DEFB FFH,CDH,63H FF CD 63
Mask FFH, value CDH: CALL nn (CDH). Type 63H: 3 bytes, CALL.
517B-517D
DEFB C7H,06H,02H C7 06 02
Mask C7H, value 06H: LD r,n (06H ... 3EH). Type 02H: 2 bytes, no jump.
517E-5180
DEFB F7H,D3H,02H F7 D3 02
Mask F7H, value D3H: OUT (n),A and IN A,(n) (D3H, DBH). Type 02H: 2 bytes, no jump.
5181-5183
DEFB C7H,C6H,02H C7 C6 02
Mask C7H, value C6H: ADD ... CP n (C6H ... FEH). Type 02H: 2 bytes, no jump.
5184-5186
DEFB FFH,CBH,02H FF CB 02
Mask FFH, value CBH: the CB prefix. Type 02H: 2 bytes, no jump.
5187-5189
DEFB F7H,10H,32H F7 10 32
Mask F7H, value 10H: DJNZ and JR (10H, 18H). Type 32H: 2 bytes, relative jump.
518A-518C
DEFB E7H,20H,32H E7 20 32
Mask E7H, value 20H: JR NZ, JR Z, JR NC, JR C (20H, 28H, 30H, 38H). Type 32H: 2 bytes, relative jump.
518D
DEFB 01H 01
End of TABLE1 (below 05H): every other opcode is 1 byte with no jump.

518EH - TABLE2 - OPCODE TABLE - "ED" OPCODES

518E-5190TABLE2
DEFB C7H,43H,04H C7 43 04
Mask C7H, value 43H: LD (nn),rr and LD rr,(nn) (ED 43H, 4BH ... 7BH). Type 04H: 4 bytes, no jump.
5191-5193
DEFB F7H,45H,52H F7 45 52
Mask F7H, value 45H: RETN and RETI (ED 45H, 4DH). Type 52H: 2 bytes, return.
5194
DEFB 02H 02
End of TABLE2: every other ED instruction is 2 bytes with no jump.

5195H - TABLE3 - OPCODE TABLE - "DD" and "FD" OPCODES

5195-5197TABLE3
DEFB FEH,34H,03H FE 34 03
Mask FEH, value 34H: INC (IX+d), DEC (IX+d) (34H, 35H). Type 03H: 3 bytes, no jump.
5198-519A
DEFB C0H,40H,03H C0 40 03
Mask C0H, value 40H: LD r,(IX+d) and LD (IX+d),r (40H-7FH). Type 03H: 3 bytes, no jump.
519B-519D
DEFB C0H,80H,03H C0 80 03
Mask C0H, value 80H: ADD A,(IX+d) ... CP (IX+d) (80H-BFH). Type 03H: 3 bytes, no jump.
519E-51A0
DEFB FFH,21H,04H FF 21 04
Mask FFH, value 21H: LD IX,nn (21H). Type 04H: 4 bytes, no jump.
51A1-51A3
DEFB FFH,22H,04H FF 22 04
Mask FFH, value 22H: LD (nn),IX (22H). Type 04H: 4 bytes, no jump.
51A4-51A6
DEFB FFH,2AH,04H FF 2A 04
Mask FFH, value 2AH: LD IX,(nn) (2AH). Type 04H: 4 bytes, no jump.
51A7-51A9
DEFB FFH,36H,04H FF 36 04
Mask FFH, value 36H: LD (IX+d),n (36H). Type 04H: 4 bytes, no jump.
51AA-51AC
DEFB FFH,CBH,04H FF CB 04
Mask FFH, value CBH: the DD CB / FD CB bit instructions. Type 04H: 4 bytes, no jump.
51AD-51AF
DEFB FFH,E9H,22H FF E9 22
Mask FFH, value E9H: JP (IX), JP (IY) (E9H). Type 22H: 2 bytes, JP (IX)/(IY).
51B0
DEFB 02H 02
End of TABLE3: every other DD or FD instruction is 2 bytes with no jump.

51B1H - OUTLNE - Display One Line of Memory

51B1OUTLNE
PUSH BC C5
Save Register Pair BC (i.e., the counter) to the top of the STACK.
51B2
PUSH HL E5
Save Register Pair HL (i.e., the RAM DATA pointer) to the top of the STACK.
51B3
LD B,08H 06 08
LET Register B = 08H for an 8 byte DJNZ loop
51B5OUTLN1
GOSUB to 526FH to display a SPACE.
51B8
GOSUB to 524FH to display the MSB of the address.
51BB
GOSUB to 524FH to display the LSB of the address.
51BE
LD A,B 78
LET Register A = Register B (i.e., the counter).
51BF
CP 05H FE 05
Compare the value held in Register A against 05H to see if we are in the middle of the screen. Results: If Register A equals 05H, the Z FLAG is set; otherwise the NZ FLAG is set.
51C1
If the Z FLAG (Zero) is set then we are at the middle of the screen so display one extra SPACE by GOSUB to 526FH.
51C4
LOOP back to 51B5H until Register B is ZERO.
51C6
POP HL E1
Restore Register Pair HL (i.e., the RAM DATA pointer) from the top of the STACK.
51C7
GOSUB to 526FH to display a SPACE.
51CA
LD B,10H 06 10
LET Register B = 10H (Decimal: 16) to prepare for a loop of 16 characters.
51CCOUTLN2
LD A,(HL) 7E
Fetch the value stored at memory location pointed to by Register Pair HL and put it into Register A.
51CD
CP 20H FE 20
Compare the value held in Register A against 20H (ASCII: SPACE). Results:
  • If Register A equals a SPACE, the Z FLAG is set.
  • If A < 20H, the CARRY FLAG will be set.
  • if A >= 20H, the NO CARRY FLAG will be set.
51CF
If the C FLAG (Carry) is set then we have a CONTROL CHARACTER we need to alter it by JUMPing to 51D5H.
51D1
CP 7BH FE 7B
Compare the value held in Register A against 7BH (ASCII: The first graphic character). Results:
  • If Register A equals 7BH, the Z FLAG is set.
  • If A < 7BH, the CARRY FLAG will be set.
  • if A >= 7BH, the NO CARRY FLAG will be set.
51D3
If the C FLAG (Carry) is set then we do NOT have a graphic character, so skip 1 instruction and JUMP to 51D7H to display it.
51D5PERIOD
LD A,2EH 3E 2E
LET Register A = 2EH (ASCII: .).
51D7OUTLN3
GOSUB to 0033H to display the character.
NOTE: 0033H is the character print routine, to put the character held in Register A at the current cursor position.
51DA
INC HL 23
Bump HL so that it points to the next character in the RAM DATA area.
51DB
LOOP BACK to 51CCH for 16 iterations (i.e., until Register B is ZERO).
51DD
PUSH HL E5
Save Register HL (i.e., the RAM DATA POINTER) to the top of the STACK.
51DE
LD HL,(4020H)LD HL,(CURSOR) 2A 20 40
Fetch the value stored at memory location 4020H and put it into Register HL.
NOTE: 4020H is the storage location for the CURSOR POSITION ON SCREEN.
51E1
LD BC,3FE0H 01 E0 3F
LET Register Pair BC = 3FE0H, which is the last row on the screen
51E4
OR A B7
Set FLAGS based on the contents of Register A.
51E5
SBC HL,BC ED 42
Subtracts the value stored in Register Pair BC (i.e., the last row on the screen) and the carry flag from the value stored in Register Pair HL (i.e., the cursor position).
51E7
POP HL E1
Restore Register Pair HL (i.e., the RAM DATA POINTER) from the top of the STACK.
51E8
If the NC FLAG (No Carry) is set, then BC-HL didn't result in a CARRY, meaning that we on the last row of the screen, so JUMP to 51EFH to skip displaying a carriage return.
51EA
LD A,0DH 3E 0D
LET Register A = 0DH (ASCII: CARRIAGE RETURN).
51EC
GOSUB to 0033H.
NOTE: 0033H is the character print routine, to put the character held in Register A at the current cursor position.
51EFOUTLN4
POP BC C1
Restore Register Pair BC (i.e., the counter) from the top of the STACK.
51F0
RET C9
RETurn to the caller.

51F1H - KEYLIN - SUBROUTINE to get a character from the keyboard and process accordingly

51F1KEYLIN
PUSH DE D5
Save Register DE to the top of the STACK.
51F2KEYLN0
GOSUB to 0049H in the ROM to get a character from the keyboard.
51F5
CP 0DH FE 0D
Compare the value held in Register A against 0DH (ASCII: CARRIAGE RETURN). Results: If Register A equals CARRIAGE RETURN, the Z FLAG is set; otherwise the NZ FLAG is set.
51F7
If the Z FLAG (Zero) is set then we have a CARRIAGE RETURN, so JUMP to 5217H.
51F9
CP 08H FE 08
Compare the value held in Register A against 08H (ASCII: ←). Results: If Register A equals LEFT ARROW, the Z FLAG is set; otherwise the NZ FLAG is set.
51FB
If the Z FLAG (Zero) is set then we have a LEFT ARROW, so JUMP to 5217H.
51FD
CP 0AH FE 0A
Compare the value held in Register A against 0AH (ASCII: ↓). Results: If Register A equals DOWN ARROW, the Z FLAG is set; otherwise the NZ FLAG is set.
51FF
If the Z FLAG (Zero) is set then we have a DOWN ARROW, so JUMP to 5217H.
5201
CP 09H FE 09
Compare the value held in Register A against 09H (ASCII: →). Results: If Register A equals RIGHT ARROW, the Z FLAG is set; otherwise the NZ FLAG is set.
5203
If the Z FLAG (Zero) is set then we have a RIGHT ARROW, so JUMP to 521AH.
5205
CP 5BH FE 5B
Compare the value held in Register A against 5BH (ASCII: ↑). Results: If Register A equals UP ARROW, the Z FLAG is set; otherwise the NZ FLAG is set.
5207
If the Z FLAG (Zero) is set then we have a UP ARROW, so JUMP to 5217H.
5209
CP 20H FE 20
Compare the value held in Register A against 20H (ASCII: SPACE. Results:
  • If Register A equals 20H, the Z FLAG is set.
  • If A < 20H, the CARRY FLAG will be set.
  • if A >= 20H, the NO CARRY FLAG will be set.
520B
If the C FLAG (Carry) is set, then we are below 20H meaning we have a control characters, so JUMP to 51F2H to ignore it.
520D
GOSUB to 0033H.
NOTE: 0033H is the character print routine, to put the character held in Register A at the current cursor position.
5210
POP DE D1
Restore Register Pair DE from the top of the STACK.
5211
CP 2CH FE 2C
Compare the value held in Register A against 2CH (ASCII: ,). Results:
  • If Register A equals ,, then we have a breakpoint specifier and the Z FLAG is set.
  • If A < 2CH, the CARRY FLAG will be set.
  • if A >= 2CH, the NO CARRY FLAG will be set.
5213
RET Z C8
If the Z FLAG (Zero) is set then we have a breakpoint specifier so, RETurn to the caller with Z FLAG set.
5214KEYOUT
CP 20H FE 20
Compare the value held in Register A against 20H (ASCII: SPACE). Results:
  • If Register A equals 20H, the Z FLAG is set.
  • If A < 20H, the CARRY FLAG will be set.
  • if A >= 20H, the NO CARRY FLAG will be set.
5216
RET C9
RETurn to the caller with Z FLAG set only if a SPACE was present, otherwise NZ is set.

5217H - KEYLN1 - Continuation of the routine to get a character from the user, jumped if the key was a CARRIAGE RETURN, ←, ↓, or ↑

5217KEYLN1
POP DE D1
Restore Register Pair DE from the top of the STACK.
5218
SCF 37
We need to show that a control character was set (and we are at the end of our input), so we SET the CARRY FLAG.
5219
RET C9
RETurn to the caller.

521AH - KEYLN3 - Continuation of the routine to get a character from the user, jumped if the key was a →

521AKEYLN3
LD A,20H 3E 20
Let Register A = 20H (ASCII: SPACE).
521C
POP DE D1
Restore Register Pair DE from the top of the STACK.
521D
JUMP to 5214H to return with the Z FLAG set.

521FH - ADJUST - Get hexadecimal input from the user and store it in Register Pair HL

521FADJUST
ADJUST: GOSUB 51F1H (KEYLIN) for the first character. ADJUST returns Z when nothing was typed; NZ with the hex value in HL; and the CARRY FLAG set when the entry ended with ENTER or an arrow, clear when it ended with a space or comma.
Original Source Code Comment: INPUT THE CHARACTER
5222
RET Z C8
If the Z FLAG is set (ENTER, an arrow, a space or a comma: nothing typed), RETurn with Z; the CARRY FLAG tells which (set = ENTER or an arrow).
Original Source Code Comment: EXIT IF CR OR ARROW
5223
CP 08H FE 08
Compare the value held in Register A against 08H (ASCII: BACK ARROW). Results:
  • If Register A equals BACK ARROW, the Z FLAG is set.
  • If A < 08H, the CARRY FLAG will be set.
  • if A >= 08H, the NO CARRY FLAG will be set.
5225
RET Z C8
If the Z FLAG is set, RETurn. KEYLIN returns the left arrow with Z at 5222H and any other key here is 20H or more, so this RET is never taken.
Original Source Code Comment: YES, EXIT
5226ADJ0
LD HL,0000H 21 00 00
LET Register Pair HL = 0000H to prepare for some math.
5229ADJ0
GOSUB to 523EH to get a hex digit's value.
522C
If the C FLAG (Carry) is set then we got an unusable response from the user, so JUMP to 4E51H to re-enter the DEBUG COMMAND LOOP.

The next instructions turn the typed hex digits into a value in HL: move the value so far left 4 bits, then put the new digit into bits 3-0.

522F
ADD HL,HL 29
ADD HL,HL (1 of 4): HL x 16 makes room for the new digit in bits 3-0.
Original Source Code Comment: BUMP THE NUMBER BY 16
5230
ADD HL,HL 29
ADD HL,HL (2 of 4).
5231
ADD HL,HL 29
ADD HL,HL (3 of 4).
5232
ADD HL,HL 29
ADD HL,HL (4 of 4).
5233
OR L B5
OR Register L against Register A. The results are stored in Register A.
5234
LD L,A 6F
LET Register L = Register A.
5235
GOSUB to 51F1H to get character from the keyboard and process accordingly.
5238
If the NZ FLAG (Not Zero) is set, JUMP to 5229H.
523A
RRA 1F
RRA: bit 7 of Register A = the CARRY FLAG from KEYLIN (set for ENTER or an arrow).
523B
ADC A,81H CE 81
ADC A,81H: Register A becomes not zero (NZ: a value was typed) and the CARRY FLAG again shows how the entry ended: set = ENTER or an arrow, clear = a space or comma.
523D
RET C9
RETurn to the caller.

523EH - ADJ1 - SUBroutine called from the prior routine to get a hex digit's value

523EADJ1
SUB 30H D6 30
ADJ1: SUBtract 30H ('0'). ADJ1 returns NC with A = 0-15 for a hex digit 0-9 or A-F, and the CARRY FLAG set for any other character.
Original Source Code Comment: IS IT A NUMBER?
5240
RET C D8
If the CARRY FLAG is set, the character is below '0': RETurn with C.
5241
ADD A,0E9H C6 E9
ADD 0E9H: the CARRY FLAG is set when A was 17H or more (a character above 'F').
5243
RET C D8
If the CARRY FLAG is set, RETurn with C: not a hex digit.
5244
ADD A,06H C6 06
ADD 06H: the CARRY FLAG is set when A was 11H-16H ('A' to 'F').
5246
If the CARRY FLAG is set ('A' to 'F'), JUMP to 524BH (ADJ2).
5248
ADD A,07H C6 07
ADD 07H: the CARRY FLAG is set when A was 0AH-10H (':' to '@').
524A
RET C D8
If the CARRY FLAG is set, RETurn with C: not a hex digit.
524BADJ2
ADD A,0AH C6 0A
ADJ2: ADD 0AH: Register A = the value of the digit, 0-15.
524D
OR A B7
OR A clears the CARRY FLAG: a hex digit.
524E
RET C9
RETurn with NC and Register A = 0-15.

524FH - OUTLOC - SUBroutine to Display Bytes Held in (HL) In Hexadecimal

524FOUTLOC
LD A,(HL) 7E
Fetch the value stored at memory location (i.e., the byte to display in hex) pointed to by Register Pair HL and put it into Register A.
5250
INC HL 23
Bump the value stored in Register Pair HL by 1 to point to the next byte.
5251
JUMP to 5258H to convert the byte held in Register A to ASCII and display.

5253H - OUTWRD - SUBROUTINE inside the DISPLAY DEBUG ROUTINE to display the address pointed to by Register Pair HL in hexadecimal

5253OUTWRD
LD A,H 7C
LET Register A = Register H (i.e., the MSB of a 2 byte address held in the memory location pointed to by Register Pair HL).
5254
GOSUB to 5258H to convert the byte held in Register A to ASCII and display.
5257
LD A,L 7D
LET Register A = Register L (i.e., the LSB of a 2 byte address held in the memory location pointed to by Register Pair HL).

This is the commonly jumped to OUTBYT, which converts Register A to ASCII and displays it.

5258OUTBYT
PUSH AF F5
Save Register AF (i.e., the byte to be displayed) to the top of the STACK.
5259
RRA 1F
RRA (1 of 4): shift the high nibble of A down into bits 3-0; HEX1 masks off the other bits.
Original Source Code Comment: SHIFT IT TO THE LSB
525A
RRA 1F
RRA (2 of 4).
525B
RRA 1F
RRA (3 of 4).
525C
RRA 1F
RRA (4 of 4).
525D
GOSUB 5261H (HEX1) to display bits 3-0 of A as a hex digit.
Original Source Code Comment: CONVERT TO ASCII AND DISPLAY IT
5260
POP AF F1
Restore Register Pair AF (i.e., the byte to be displayed) from the top of the STACK.
5261HEX1
AND 0FH E6 0F
MASK the value of Register A against 0FH (0000 1111). This has the effect of turning off bits 7, 6, 5, 4, leaving only bits 3, 2, 1, 0 active, since are dealing in lower-4-bit patterns here.

What is next is a clever way to manipulate a 4 bit byte into ASCII. Point to remember is that 0-F are contained in 4 bits, so that's the range.

5263
ADD A,90H C6 90
ADD the value 90H to Register A (Results held in Register A), so that 00H-00FH are now 1001 + nnnn (what they were).
5265
DAA 27
Adjust Register A for BCD addition and subtraction operations. DAA is way too complicated to go into here, but if the low 4 bits are greater than 9, the H FLAG is set and 06H is addded to Register A and if the high 4 bits are greater than 9, the C FLAG is set and 60H is added to Register A.
5266
ADC A,40H CE 40
Add 40H and the carry to register A.
5268
DAA 27
Adjust Register A for BCD addition and subtraction operations. Once this has run, Register A will contain 30H-39H for 0-9, and 41H-46H for A-F.
5269VIDEO
JUMP to 0033H.
NOTE: 0033H is the character print routine, to put the character held in Register A at the current cursor position.

526CH - OUTBSP - SUBROUTINE to display a byte held in Register A as a two-byte ascii value followed by a space

526COUTBSP
GOSUB to 5258H to convert the byte held in Register A to ASCII and display.
526FOUTSPC
LD A,20H 3E 20
LET Register A = 20H (ASCII: SPACE.
5271
JUMP to 5269H to display the character held in Register A (i.e., a SPACE).

5273H - OUTCR - Display a CARRIAGE RETURN and continue at 5269H

5273OUTCR
LD A,0DH 3E 0D
LET Register A = 0DH (ASCII: CARRIAGE RETURN.
5275
JUMP to 5269H to display the character held in Register A (i.e., a CARRIAGE RETURN).

5277H - OUTCLR - Clear to the End of Screen via a ROM CALL and RETURN

5277OUTCLR
LD A,1FH 3E 1F
LET Register A = 1FH (ASCII: CLEAR TO END OF SCREEN.
5279
JUMP to 0033H.
NOTE: 0033H is the character print routine, to put the character held in Register A (i.e., the ASCII code for CLEAR TO END OF SCREEN) at the current cursor position.

527CH - OUT3 - Display the 3 characters pointed to by (HL), (HL+1), and (HL+2), and then RETurn

527COUT3
GOSUB to 5282H to put the character pointed to by Register Pair HL into Register A, Bump HL to point to the next character, displays the character on screen, and RETurns.
527F
GOSUB to 5282H to put the character pointed to by Register Pair HL into Register A, Bump HL to point to the next character, displays the character on screen, and RETurns.
5282DSPR
LD A,(HL) 7E
Fetch the value stored at memory location pointed to by Register Pair HL and put it into Register A.
5283
INC HL 23
Bump the value stored in Register Pair HL by 1.
5284
JUMP to 5269H which JUMPs to 0033H in the ROM to display the character held in Register A on the screen and RETurn.

5286H - QUIT - "Q" Option - Quit the Utility

5286QUIT
XOR A AF
Set Register A to ZERO and clear all Flags.
Original Source Code Comment: SET FOR SIDE 1
5287
LD (4463H),ALD (CSIDE),A 32 63 44
Store 00H into 4463H (CSIDE, the current disk side): side 0 for the next disk access.
528A
JUMP to "DOS READY" via 402DH.
Original Source Code Comment: AND EXIT TO DOS

528DH - CHKNUM - Validate a Decimal Digit and Convert to Binary

528DCHKNUM
SUB 30H D6 30
SUBtract the value 30H from Register A, thus converting an ASCII number to Binary.
Original Source Code Comment: MASK OFF ASCII
528F
RET C D8
If the C FLAG (Carry) is set then the value was lower than a "0", which is not permitted, so RETurn to the caller.
Original Source Code Comment: WASN'T NUMBER
5290
CP 0AH FE 0A
Compare the value held in Register A against 0AH (Decimal: 10). Results:
  • If Register A equals 0AH, the Z FLAG is set.
  • If A < 0AH, the CARRY FLAG will be set.
  • if A >= 0AH, the NO CARRY FLAG will be set.

Original Source Code Comment: GREATER THAN NUMBER?
5292
CCF 3F
Invert the state of the CARRY FLAG so that GREATER than 10 has CARRY FLAG set, to indicate an error.
5293
RET C9
RETurn to the caller.

5294H - GETHEX - Convert the Hexadecimal Text at HL into a Value in HL

5294GETHEX
PUSH HL E5
GETHEX: Push HL; with the POP IX that follows this is the source's LD IX,HL.
Original Source Code Comment: MOVE THE POINTER TO IX
5295
POP IX DD E1
POP IX: Register Pair IX = the pointer to the hex text.
5297
LD HL,0000H 21 00 00
LET Register Pair HL = 0000H to prepare for some math.
Original Source Code Comment: CLEAR A 16 BIT ACCUMULATOR
529AGETHE1
LD A,(IX+00H) DD 7E 00
Fetch the value stored at the memory location pointed to by IX+00H (i.e., the first character to be checked) and put it into Register A.
Original Source Code Comment: GET A DIGIT
529D
INC IX DD 23
Bump the value stored in Register Pair IX by 1 to point to the next character to be checked.
Original Source Code Comment: BUMP TO NEXT CHARACTER
529F
SUB 30H D6 30
SUBtract the value 30H from Register A, thus converting an ASCII number to Binary.
Original Source Code Comment: MASK OFF ASCII
52A1
If the C FLAG (Carry) is set then the value was lower than a "0", which is not permitted, so JUMP to 52B7H to put the LSB into Register A and return (with the CARRY FLAG set).
Original Source Code Comment: EXIT IF END OF NUMBER
52A3
CP 0AH FE 0A
Compare A with 0AH (10): below 10 is a digit 0-9.
Original Source Code Comment: ALPHA?
52A5
If the CARRY FLAG is set (0-9), JUMP to 52A9H (GETHE2).
Original Source Code Comment: NO, IS NUMBER
52A7
SUB 07H D6 07
Convert "A"-"F" to 10-15 by SUBtracting the value 07H from Register A.
Original Source Code Comment: CORRECT FOR ALPHAS
52A9GETHE2
CP 10H FE 10
Compare the value held in Register A against 10H (which would be a value which is too large to be good). Results:
  • If Register A equals 10H, the Z FLAG is set.
  • If A < 10H, the CARRY FLAG will be set.
  • if A >= 10H, the NO CARRY FLAG will be set.

Original Source Code Comment: DUMB ANSWER
52AB
If the NC FLAG (No Carry) is set then the value is too large, so JUMP to 52B7H.
Original Source Code Comment: YES, EXIT
52AD
ADD HL,HL 29
ADD HL,HL (1 of 4): HL x 16 makes room for the new digit.
Original Source Code Comment: OLD DIGIT TIMES 16
52AE
ADD HL,HL 29
ADD HL,HL (2 of 4).
52AF
ADD HL,HL 29
ADD HL,HL (3 of 4).
52B0
ADD HL,HL 29
ADD HL,HL (4 of 4).
52B1
LD E,A 5F
LET Register E = Register A (i.e., the value of the digit).
Original Source Code Comment: NEW DIGIT INTO DE
52B2
LD D,00H 16 00
LET Register D = 00H so that Register Pair DE holds the value of the digit.
52B4
ADD HL,DE 19
ADD the value held in Register Pair DE to Register Pair HL. The results are held in Register Pair HL.
Original Source Code Comment: ADD IT IN
52B5
LOOP to 529AH for the next hex value.
Original Source Code Comment: GO GET ANOTHER DIGIT

52B7H - GETHE3 - Jump point from the prior routine if the value received is less than 0

52B7GETHE3
LD A,L 7D
LET Register A = Register L (i.e., the LSB).
Original Source Code Comment: GET THE LSB
52B8
RET C9
RETurn to the caller.

52B9H - ENTRY - DEBUG routine entry from DOS Loader

52B9ENTRY
POP AF F1
ENTRY (the transfer address the loader jumps to): POP AF takes back the program's AF, which DEBUG (440DH) pushed before LD A,85H / RST 28H loaded SYS5.
Original Source Code Comment: GET SYSTEM VECTOR OFF STACK
52BA
JUMP to 4E00H (i.e., the start of this overlay).

52BDH - TRA - Disk File Display/Modify Routine

52BDTRA
LD A,0B0H 3E B0
LET Register A = 0B0H (ASCII: Block Cursor).
Original Source Code Comment: SET THE CURSOR BACK TO DEFAULT
52BF
LD (4023H),ALD (CURSCR),A 32 23 40
Store the value held in Register A into the memory location 4023H.
NOTE: 4023H is the storage location for the CURSOR CHARACTER.
52C2
LD HL,5526HLD HL,TITLE 21 26 55
LET Register Pair HL = 5526H, to point to the message storage area for 1CH + 1FH + "Debug Disk Utility Ver 1.3" + 0DH + 0AH.
Original Source Code Comment: HL => 'DISK UTILITY' MSG
52C5
GOSUB to 021BH.
NOTE: 021BH will display the character at (HL) until a 03H or 0AH is found.
Original Source Code Comment: DISPLAY IT
52C8CONT1
LD HL,5543HLD HL,BPROMT 21 43 55
LET Register Pair HL = 5543H, to point to the message storage area for 0AH + "Filespec: " + 03H
Original Source Code Comment: HL => 'PROMPT'
52CB
GOSUB to 021BH.
NOTE: 021BH will display the character at (HL) until a 03H or 0AH is found.
Original Source Code Comment: DISPLAY IT
52CE
LD B,1FH 06 1F
LET Register B = 1FH (Decimal: 31), so as to prepare to read up to 31 characters from the keyboard (as a filespec).
Original Source Code Comment: SET FOR 31 CHARACTERS
52D0
LD HL,5555HLD HL,BDCB 21 55 55
LET Register Pair HL = 5555H to point to a memory buffer for the input.
Original Source Code Comment: PLACE TO STORE ANSWER
52D3
GOSUB to 0040H in the ROM to read a full line from the KEYBOARD until ENTER or BREAK. If a BREAK is hit, the CARRY FLAG is set.
Original Source Code Comment: CALL KEYBOARD LINE
52D6
If the C FLAG (Carry) is set, then the BREAK was just so JUMP to 5286H.
Original Source Code Comment: IF 'BREAK', EXIT TO DOS
52D8
LD HL,4300HLD HL,BUFF1 21 00 43
LET Register Pair HL = 4300H, which is DOS Buffer 1.
Original Source Code Comment: HL => BUFFER
52DB
LD DE,5555HLD DE,BDCB 11 55 55
LET Register Pair DE = 5555H, which is the Buffer holding the filename just entered.
Original Source Code Comment: DE => DCB
52DE
LD B,00H 06 00
LET Register B = 00H (0000 0000).
Original Source Code Comment: LRL OF 256
52E0
GOSUB to 4424H from OVERLAY 00 (which opens a disk file for use) by setting an OVERLAY CALL of 92H (Routine 1 of Overlay 2) and then calling RST 28H.
Original Source Code Comment: OPEN THE FILE
52E3
If the NZ FLAG (Not Zero) is set, then that CALL returned an error, so JUMP to 5405H to handle the diskette-related error.
Original Source Code Comment: EXIT IF ERROR

If we have an open file, we now need to adjust the DCB for the file.

52E6
LD IX,5555HLD IX,BDCB DD 21 55 55
LET Register Pair IX = 5555H to point to a memory buffer for the filename we just got from the user.
Original Source Code Comment: IX => DCB
52EA
RES 7,(IX+01H) DD CB 01 BE
RESet (i.e., set as 0) BIT 7 of Register (IX+01H) to set the DCB for "SECTOR I/O".
Original Source Code Comment: SET FOR LRL OF 256
52EE
LD (IX+09H),00H DD 36 09 00
Store a 00H in IX+09H (i.e., the LRL of the DCB) to signify a 256 byte file.
Original Source Code Comment: SET LRL FOR 256
52F2
LD A,(IX+08H) DD 7E 08
Fetch the value stored at the memory location pointed to by IX+08H (i.e., the position in the DCB for the EOF byte) and put it into Register A.
Original Source Code Comment: GET THE EOF
52F5
LD (IX+08H),00H DD 36 08 00
Store 00H into DCB offset 08H (the EOF byte): every record is shown as a full 256 bytes.
Original Source Code Comment: CLEAR ANY EOF
52F9
OR A B7
Set FLAGS based on the contents of Register A to see if it actually was zero (i.e., an even boundary).
Original Source Code Comment: EOF ON EVEN BOUNDARY?
52FA
If the Z FLAG (Zero) is set then we can skip ahead and we JUMP to 5303H.
Original Source Code Comment: YES, CONTINUE
52FC
LD HL,(5561H)LD HL,(ERN) 2A 61 55
Fetch 5561H-5562H (ERN, DCB offset 0CH, the ending record number) into Register Pair HL.
Original Source Code Comment: GET THE ERN
52FF
INC HL 23
Bump the value stored in Register Pair HL (i.e., the EOF Sector) by 1.
Original Source Code Comment: CORRECT FOR THE EOF
5300
LD (5561H),HLLD (ERN),HL 22 61 55
Store the value held in Register HL (i.e., the EOF Sector) into the memory location 5561H.
Original Source Code Comment: SAVE NEW VALUE
5303BREADX
LD DE,5555HLD DE,BDCB 11 55 55
LET Register Pair DE = 5555H to point to a memory buffer for the filename we just got from the user.
Original Source Code Comment: DE => DCB
5306
LD HL,4300HLD HL,BUFF1 21 00 43
LET Register Pair HL = 4300H, which is DOS Buffer 1.
Original Source Code Comment: HL => INTERNAL BUFFER
5309
GOSUB to 4448H which is the POSEOF Vector stored in Overlay 0. This will position to the last record.
Original Source Code Comment: INIT THE POINTERS
530C
GOSUB to 4436H which is the READ Vector stored in Overlay 0. This will read that last record.
Original Source Code Comment: READ IN THE LAST SECTOR
530F
GOSUB to 443FH which is the REWIND Vector stored in Overlay 0. This will rewind the file.
Original Source Code Comment: NOW TO THE FRONT
5312
LD A,23H 3E 23
LET Register A = 23H, the opcode of INC HL.
Original Source Code Comment: 'INC HL' INSTRUCTION
5314
LD (5366H),ALD (CHGBMP),A 32 66 53
Store the value held in Register A (i.e., a INC HL OPCODE) into the memory location 5366H, which is currently a NOP.

The next few instructions clear Buffer # 1

5317BREAD
LD HL,4300HLD HL,BUFF1 21 00 43
LET Register Pair HL = 4300H, which is DOS Buffer 1.
Original Source Code Comment: PLACE WHERE DATA WILL BE STORED
531A
LD DE,4301HLD DE,BUFF1+1 11 01 43
LET Register Pair DE = 4301H (BUFF1+1).
531D
LD BC,00FFH 01 FF 00
LET Register Pair BC = 00FFH (255), the bytes after the first to clear.
5320
LD (HL),00H 36 00
Get the ball rolling by putting a 00H into the memory location pointed to by Register Pair HL.
Original Source Code Comment: CLEAR IT OUT
5322
LDIR ED B0
Cascade that 00H all the way down via a LDIR, which transfers a byte of data from the memory location pointed to by HL to the memory location pointed to by DE. Then HL and DE are incremented and BC is decremented. If BC is not zero, this operation is repeated. Interrupts can trigger while this instruction is processing.
5324
LD DE,5555HLD DE,BDCB 11 55 55
LET Register Pair DE = 5555H, to point to the specified file.
Original Source Code Comment: DE => DCB
5327
GOSUB 4436H (READ, the SYS0 vector) to read the record at NRN (DCB offset 0AH) into 4300H (BUFF1).
Original Source Code Comment: READ A RECORD
532A
If the NZ FLAG (Not Zero) is set then that CALL resulted in an ERROR, so JUMP to JUMP to 5405H to handle the diskette-related error.
Original Source Code Comment: EXIT IF ERROR
532D
GOSUB 4445H (BACKSP, the SYS0 vector) to step NRN back to the record just read.
Original Source Code Comment: BACK UP TO THE RECORD
5330CONT0
XOR A AF
Set Register A to ZERO and clear all Flags.
5331
LD (5553H),ALD (MOVFLG),A 32 53 55
Store the value held in Register A into the memory location 5553H to indicate that we are reading data from diskette.
5334
LD (545FH),ALD (NODISK),A 32 5F 54
Store the value held in Register A into the memory location 545FH to clear the modify mode. 545FH is in the middle of a LD A,(nn)" OPCODE, with FF=Memory and anything else =Disk
5337
GOSUB to 533CH to display the page for modification.
533A
JUMP to the command loop at 53AEH.

533CH - CONT2 - Display the Page for Modification

533CCONT2
LD A,0B0H 3E B0
LET Register A = 0B0H (ASCII: BLOCK cursor).
Original Source Code Comment: SET DEFAULT CURSOR
533E
LD (4023H),ALD (CURSCR),A 32 23 40
Store the value held in Register A into the memory location 4023H.
NOTE: 4023H is the storage location for the CURSOR CHARACTER.
5341
LD A,0FH 3E 0F
LET Register A = 0FH (cursor off).
Original Source Code Comment: INSURE CURSOR OFF
5343
GOSUB to 0033H.
NOTE: 0033H is the character print routine, to put the character held in Register A at the current cursor position.
5346
LD A,(545FH)LD A,(NODISK) 3A 5F 54
Fetch the value stored at memory location 545FH to see if we are dumping a memory file or a disk file, and put it into Register A. 545FH is in the middle of a LD A,(nn)" OPCODE, with FF=Memory and anything else =Disk
Original Source Code Comment: IS THIS DISK CALLING?
5349
OR A B7
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A.
534A
If the Z FLAG (Zero) is set, then we are working on a DISK file, so JUMP to 5351H.
Original Source Code Comment: YES, GET BUFFER ADDRESS
534C
LD HL,(4103H)LD HL,(MEM+3) 2A 03 41
If we are here, then we are dealing with MEMORY, so fetch the value stored at memory location 4103H (i.e., the old dump address) and put it into Register HL.
Original Source Code Comment: NO, IS MEMORY. GET MEMORY ADDRESS
534F
JUMP to 5354H to continue.
Original Source Code Comment: AND DISPLAY RAM LOCATIONS

5351H - GETBUF - Display Data

5351GETBUF
LD HL,4300HLD HL,BUFF1 21 00 43
LET Register Pair HL = 4300H, which is DOS Buffer 1.
Original Source Code Comment: GET THE DISK BUFFER
5354CNT00
LD DE,3C00H 11 00 3C
LET Register Pair DE = 3C00H, which is the top of the screen.
5357LOP1
LD B,08H 06 08
LET Register B = 08H to signify 16 bytes to display.
5359
PUSH HL E5
Save Register HL (i.e., the data address) to the top of the STACK.
535A
LD A,(555BH)LD A,(DRV) 3A 5B 55
Fetch the value stored at memory location 555BH (i.e., the disk drive number) and put it into Register A.
535D
ADD A,30H C6 30
ADD the value 30H to Register A (Results held in Register A) to turn the hex drive number into its ASCII equivalent.
535F
GOSUB to 5402H to display a character.
5362
PUSH HL E5
Save Register HL (i.e., the data address) to the top of the STACK.
Original Source Code Comment: SAVE THE POINTER
5363
LD HL,(555FH)LD HL,(NRN) 2A 5F 55
Fetch the value stored at memory location 555FH (i..e, the sector number) and put it into Register HL.
Original Source Code Comment: GET THE NRN
5366CHGBMP
NOP 00
No Operation (Do Nothing) -or- INC HL, depending on what OPCODE was put into this address.
Original Source Code Comment: CORRECT FOR 1'S OFFSET
5367
LD A,H 7C
LET Register A = Register H (i.e., the MSB of HL).
Original Source Code Comment: GET THE MSB
5368
ADD A,30H C6 30
ADD 30H to the MSB of the record number to make it an ASCII digit.
536A
GOSUB to 5402H to display a character.
536D
LD A,L 7D
LET Register A = Register L (i.e., the LSB of HL).
Original Source Code Comment: GET THE LSB
536E
GOSUB to 53EDH to display the low byte in ASCII (2 characters).
Original Source Code Comment: OUTPUT AS HEX VALUE
5371
POP HL E1
Restore Register Pair HL (i.e., the buffer pointer) from the top of the STACK.
Original Source Code Comment: GET THE BUFFER POINTER BACK
5372
LD A,L 7D
LET Register A = Register L (i.e., the line start address).
5373
GOSUB to 53EDH to display the low byte in ASCII (2 characters).
5376
LD A,3AH 3E 3A
LET Register A = 3AH (ASCII: :).
5378
GOSUB to 5402H to display a character.
537BLOOP2
LD A,20H 3E 20
LET Register A = 20H (ASCII: SPACE).
537D
GOSUB to 5402H to display a character.
5380
GOSUB to 5423H to see if we are at the cursor position.
5383
If the C FLAG (Carry) is set then we are at the proper cursor position, so JUMP to 5389H.
5385LOP2
LD A,(HL) 7E
Fetch the value stored at memory location pointed to by Register Pair HL and put it into Register A.
5386
GOSUB to 53EDH to display the low byte in ASCII (2 characters).
5389LOP3
INC L 2C
Bump the value stored in Register L by 1.
538A
GOSUB to 5423H to see if we are at the cursor position.
538D
If the C FLAG (Carry) is set, JUMP to 5393H.
538F
LD A,(HL) 7E
Fetch the value stored at memory location pointed to by Register Pair HL and put it into Register A.
5390
GOSUB to 53EDH to display the low byte in ASCII (2 characters).
5393LOP4
INC L 2C
Bump the value stored in Register L by 1.
5394
LOOP back to 537BH until Register B is ZERO.
5396
LD A,20H 3E 20
LET Register A = 20H (ASCII: SPACE).
Original Source Code Comment: OUTPUT A SPACE
5398
GOSUB to 5402H to display a character.
Original Source Code Comment: TO THE SCREEN
539B
POP HL E1
Restore Register Pair HL (i.e., the data address) from the top of the STACK.
Original Source Code Comment: GET BUFFER POINTER BACK
539C
LD B,10H 06 10
LET Register B = 10H (Decimal: 16) to prepare for a loop of 16.
Original Source Code Comment: SET FOR 16 CHARACTERS
539ELOOP3
LD A,(HL) 7E
Fetch the value stored at memory location pointed to by Register Pair HL (i.e., the data to display) and put it into Register A.
Original Source Code Comment: GET A BYTE
539F
CP 20H FE 20
Compare the value held in Register A against 20H to see if we have a control character. Results:
  • If Register A equals 20H, the Z FLAG is set.
  • If A < 20H, the CARRY FLAG will be set.
  • if A >= 20H, the NO CARRY FLAG will be set.
53A1
If the NO CARRY FLAG is set (20H or more), JUMP to 53A5H (CONT4) to show the byte as it is.
53A3DOT
LD A,2EH 3E 2E
DOT: LET Register A = 2EH ('.') in place of a control code.
53A5CONT4
GOSUB to 5402H to display a character.
53A8
INC L 2C
Bump the value stored in Register L by 1 to point to the next byte to display.
Original Source Code Comment: BUMP TO NEXT LOCATION
53A9
RET Z C8
If the Z FLAG (Zero) is set then we are at the end of the page, so RETurn to the caller.
Original Source Code Comment: EXIT IF ALL OF BUFFER
53AA
LOOP back to 539EH until Register B is ZERO.
Original Source Code Comment: ELSE, LOOP FOR COUNT
53AC
JUMP to 5357H to go to the next line.
Original Source Code Comment: AND DO ANOTHER ROW

53AEH - SCAN - Scan the Keyboard for Display Mode Commands

53AESCAN
DI F3
Disable Interrupts.
Original Source Code Comment: INTERRUPTS OFF
53AF
GOSUB to 0049H to wait for a key to be pressed.
Original Source Code Comment: GET A KEYBOARD CHAR
53B2
CP 01H FE 01
Compare the value held in Register A against 01H (i.e., BREAK). Results: If Register A equals BREAK, the Z FLAG is set; otherwise the NZ FLAG is set.
53B4
If the Z FLAG (Zero) is set then the BREAK was set, so JUMP to 52BDH to restart the routine.
53B7
CP 3BH FE 3B
Compare the value held in Register A against 3BH (i.e., ;). Results: If Register A equals ;, the Z FLAG is set; otherwise the NZ FLAG is set.
53B9
If the Z FLAG (Zero) is set then we got a ;, so JUMP to 53CEH to go to the next page.
53BB
CP 2BH FE 2B
Compare the value held in Register A against 2BH (i.e., +). Results: If Register A equals +, the Z FLAG is set; otherwise the NZ FLAG is set.
53BD
If the Z FLAG (Zero) is set then we got a +, so JUMP to 53CEH to go to the next page.
53BF
CP 2DH FE 2D
Compare the value held in Register A against 2DH (i.e., -). Results: If Register A equals -, the Z FLAG is set; otherwise the NZ FLAG is set.
53C1
If the Z FLAG (Zero) is set then we got a -, so JUMP to 53E2H to go to the previous page.
53C3
CP 3DH FE 3D
Compare the value held in Register A against 3DH (i.e., =). Results: If Register A equals =, the Z FLAG is set; otherwise the NZ FLAG is set.
53C5
If the Z FLAG (Zero) is set then we got a =, so JUMP to 53E2H to go to the previous page.
53C7
CP 4DH FE 4D
Compare the value held in Register A against 4DH (i.e., M). Results: If Register A equals M, the Z FLAG is set; otherwise the NZ FLAG is set.
53C9
If the Z FLAG (Zero) is set then we got a M, so JUMP to 5445H to go to modify mode.
53CC
JUMP to the command loop for DISPLAY MODE commands at 53AEH.

53CEH - UP - Advance to the Next Page of the Display

53CEUP
LD BC,(555FH)LD BC,(NRN) ED 4B 5F 55
Fetch the value stored at memory location 555FH (i.e., the page or sector number) and put it into Register BC.
53D2
INC BC 03
Bump the value stored in Register Pair BC by 1 to point to the next page or sector.
Original Source Code Comment: BUMP FOR THE NEXT RECORD
53D3
LD HL,(5561H)LD HL,(ERN) 2A 61 55
Fetch the value stored at memory location 5561H (i.e., the EOF Sector or Last Page of Memory) and put it into Register HL.
53D6
XOR A AF
Set Register A to ZERO and clear all Flags.
53D7
SBC HL,BC ED 42
Subtracts the value stored in Register Pair BC and the carry flag from the value stored in Register Pair HL.
53D9
If NRN+1 equals ERN (past the last record), JUMP back to 53AEH (SCAN): no move.
Original Source Code Comment: IF EQUAL ALSO
53DBPOS
LD (555FH),BCLD (NRN),BC ED 43 5F 55
Store the value held in Register BC (i.e., the page or sector number) into the memory location 555FH (i.e., the storage for the sector number).
Original Source Code Comment: SAVE THE NRN
53DF
JUMP to 5317H to get the new page.
Original Source Code Comment: GO DO THE READ

53E2H - DN - Back up to the Previous Page of the Display

53E2DN
LD BC,(555FH)LD BC,(NRN) ED 4B 5F 55
Fetch the value stored at memory location 555FH (i.e., the page or sector number) and put it into Register BC.
53E6
LD A,B 78
LET Register A = Register B (the MSB of NRN).
53E7
OR C B1
OR Register C (the LSB) into A: the Z FLAG is set only when NRN is 0000H.
Original Source Code Comment: WE ON 1ST ONE
53E8
If the Z FLAG is set (already at record 0), JUMP back to 53AEH (SCAN): no move.
53EA
DEC BC 0B
DECrement the value stored in Register Pair BC by 1 so as to move to the previous page or sector number.
Original Source Code Comment: BACK UP ONE RECORD
53EB
JUMP to 53DBH to save the new page or sector number and continue.

53EDH - HEX - Display a Byte in Two Digit Hexadecimal

53EDHEX
LD C,A 4F
LET Register C (i.e., the LSB) = Register A.
53EE
SRL A CB 3F
SRL A (1 of 4): shift the high nibble of A down into bits 3-0, with 0 into bits 7-4.
53F0
SRL A CB 3F
SRL A (2 of 4).
53F2
SRL A CB 3F
SRL A (3 of 4).
53F4
SRL A CB 3F
SRL A (4 of 4).
53F6
GOSUB to 53FAH to convert the byte to ASCII and display it.
53F9
LD A,C 79
LET Register A = Register C (i.e., the original, unmodified LSB).
53FATEST
AND 0FH E6 0F
MASK the value of Register A against 0FH (0000 1111). This has the effect of turning off bits 7, 6, 5, 4, leaving only bits 3, 2, 1, 0 active, thus isolating the low nybble.

What is next is a clever way to manipulate a 4 bit byte into ASCII. Point to remember is that 0-F are contained in 4 bits, so that's the range.

53FC
ADD A,90H C6 90
ADD the value 90H to Register A (Results held in Register A), so that 00H-00FH are now 1001 + nnnn (what they were).
53FE
DAA 27
Adjust Register A for BCD addition and subtraction operations. DAA is way too complicated to go into here, but if the low 4 bits are greater than 9, the H FLAG is set and 06H is addded to Register A and if the high 4 bits are greater than 9, the C FLAG is set and 60H is added to Register A.
53FF
ADC A,40H CE 40
Add 40H and the carry to register A.
5401
DAA 27
Adjust Register A for BCD addition and subtraction operations. Once this has run, Register A will contain 30H-39H for 0-9, and 41H-46H for A-F.
5402DISP
LD (DE),A 12
DISP: Store Register A into the video RAM at DE (the screen address).
5403
INC DE 13
Bump the value stored in Register Pair DE by 1 to point to the next byte.
5404
RET C9
RETurn to the caller.

5405H - BERR - This routine is JUMPed to if OPEN, READ or WRITE returned an error

5405BERR
LD B,A 47
LET Register B = Register A (i.e., the error code returned).
Original Source Code Comment: ERROR INTO B
5406
AND 0FEH E6 FE
MASK the value of Register A against 0FEH (1111 1110). This has the effect of turning off bit 0.
Original Source Code Comment: MASK ROR TO EOF
5408
CP 1CH FE 1C
Compare the value held in Register A against 1CH (i.e., an END OF FILE error). Results: If Register A equals 1CH, the Z FLAG is set; otherwise the NZ FLAG is set.
Original Source Code Comment: END OF FILE?
540A
If the NZ FLAG (Not Zero) is set, then we do not have an END OF FILE error, so JUMP to 5415H to deal with other errors.
Original Source Code Comment: NO, ANOTHER ERROR
540C
LD HL,(5561H)LD HL,(ERN) 2A 61 55
Fetch the value stored at memory location 5561H (i.e., the EOF Sector or Last Page of Memory) and put it into Register HL.
Original Source Code Comment: GET THE ERN
540F
LD (555FH),HLLD (NRN),HL 22 5F 55
Store the value held in Register HL into the memory location 555FH (i.e., the storage for the sector number).
Original Source Code Comment: SET AS NRN
5412
JUMP to 5330H to continue.
Original Source Code Comment: AND CONTINUE

5415H - BERR1 - This routine is JUMPed to if OPEN, READ or WRITE returned an error other than an end of file error

5415BERR1
LD A,B 78
LET Register A = Register B (i.e., the error code returned).
Original Source Code Comment: GET THE ERROR CODE BACK
5416
PUSH AF F5
Save Register AF (i.e., the error code returned) to the top of the STACK.
Original Source Code Comment: SAVE IT
5417
GOSUB to 01C9H in the ROM to clear the screen.
Original Source Code Comment: CLEAR THE SCREEN
541A
POP AF F1
Restore Register Pair AF (i.e., the error code returned) from the top of the STACK.
Original Source Code Comment: GET THE ERROR CODE BACK
541B
OR 0C0H F6 C0
OR Register A against 0C0H, so as to enable the LONG ERROR MESSAGE bits.
541D
GOSUB 4409H (ERROR, the SYS0 vector: PUSH AF / LD A,84H / RST 28H loads SYS4 to show the error). Bits 6 and 7 of A are set: the full text, then return here.
5420
JUMP to 52C8H to get a new filespec from the user and continue.

5423H - CHECK - Subroutine to check to see if we are at the cursor position

5423CHECK
LD A,(5553H)LD A,(MOVFLG) 3A 53 55
Fetch the value stored at memory location 5553H (i.e., the memory locaiton signifying if the cursor is active) and put it into Register A.
5426
OR A B7
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A.
5427
RET Z C8
If the Z FLAG (Zero) is set, then the cursor is NOT active, so RETurn to the caller.
5428
PUSH DE D5
Save Register DE to the top of the STACK.
5429
PUSH HL E5
Save Register HL to the top of the STACK.
542A
LD DE,(554FH)LD DE,(WHERE) ED 5B 4F 55
Fetch the value stored at memory location 554FH (i.e., the location where we store the cursor location) and put it into Register DE.
542E
OR A B7
Set FLAGS based on the contents of Register A.
542F
SBC HL,DE ED 52
Subtracts the value stored in Register Pair DE and the carry flag from the value stored in Register Pair HL to see if we are at the cursor location.
5431
POP HL E1
Restore Register Pair HL from the top of the STACK.
5432
POP DE D1
Restore Register Pair DE from the top of the STACK.
5433
If the Z FLAG (Zero) is set then we are actually where we want to be, so JUMP to 5437H.
5435
OR A B7
Set FLAGS based on the contents of Register A.
5436
RET C9
RETurn to the caller.

5437H - CHECK1 - Continuation of the above routine if the cursor is properly positioned

5437CHECK1
LD (5551H),DELD (CURSA),DE ED 53 51 55
Store the value held in Register DE into the memory location 5551H (i.e., the cursor position).
543B
LD A,8FH 3E 8F
LET Register A = 8FH, a graphics character; it is shown twice in place of the two hex digits of the byte at WHERE.
Original Source Code Comment: GRAPHICS BLOCK
543D
GOSUB to 5402H to display a character.
Original Source Code Comment: DISPLAY IT
5440
GOSUB to 5402H to display a character.
5443
SCF 37
Set the CARRY FLAG
5444
RET C9
RETurn to the caller.

5445H - MOVE - Enter Modify Mode

5445MOVE
LD HL,4300HLD HL,BUFF1 21 00 43
LET Register Pair HL = 4300H, which is DOS Buffer 1.
5448
LD (554FH),HLLD (WHERE),HL 22 4F 55
Store the value held in Register HL (i.e., DOS Buffer 1) into the memory location 554FH.
544B
LD A,H 7C
LET Register A = Register H (i.e., 43H).
544C
LD (5553H),ALD (MOVFLG),A 32 53 55
Store the value held in Register A into the memory location 5553H to signify that the cursor is active.

544FH - BACK - Display Data for the MODIFY COMMAND

544FBACK
LD HL,(554FH)LD HL,(WHERE) 2A 4F 55
Fetch the value stored at memory location 554FH (i.e., the applicable data) and put it into Register HL.
5452
PUSH HL E5
Save Register HL (i.e, the address) to the top of the STACK.
5453
GOSUB to 533CH to display a page of data.
5456
POP HL E1
Restore Register Pair HL (i.e, the address) from the top of the STACK.

5457H - BACK1 - Command Loop for the MODIFY COMMAND

5457BACK1
GOSUB to 54FEH to get the command.
545A
CP 0DH FE 0D
Compare the value held in Register A against 0DH (ASCII: ENTER). Results: If Register A equals ENTER, the Z FLAG is set; otherwise the NZ FLAG is set.
Original Source Code Comment: CR
545C
If the NZ FLAG (Not Zero) is set, then we did not get an ENTER, so JUMP to 5467H.
Original Source Code Comment: NO
545E
LD A,00HLD A,0 3E 00
LET Register A = the byte at 545FH (NODISK, the operand of this instruction): 00H when the disk utility called (CONT0 stores 00H), FFH when the M command called (MEMORY stores FFH).
5460
OR A B7
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A.
Original Source Code Comment: DISK CALLING?
5461
If the Z FLAG (Zero) is set, the we are doing DISK I/O, so JUMP to 550FH.
Original Source Code Comment: YES, DO THE WRITE
5464
JUMP to 4E51H to re-enter the DEBUG COMMAND LOOP.
Original Source Code Comment: NO, EXIT

5467H - BACK2 - Continuation of the Command Loop for the MODIFY COMMAND (to handle a BREAK key)

5467BACK2
CP 01H FE 01
Compare the value held in Register A against 01H so as to test for a BREAK. Results: If Register A equals 01H, the Z FLAG is set; otherwise the NZ FLAG is set.
5469
If the NZ FLAG (Not Zero) is set, then we did NOT get a BREAK, so JUMP to 5475H.
Original Source Code Comment: NO
546B
LD A,(545FH)LD A,(NODISK) 3A 5F 54
Fetch the value stored at memory location 545FH and put it into Register A so as to test if the data was from disk or RAM. 545FH is in the middle of a LD A,(nn)" OPCODE, with FF=Memory and anything else =Disk
Original Source Code Comment: DISK CALLING?
546E
OR A B7
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A.
546F
If the Z FLAG (Zero) is set, then we were doing DISK I/O, so JUMP to 5330H to get a new file.
Original Source Code Comment: YES, DO IT
5472
JUMP to 4E51H to re-enter the DEBUG COMMAND LOOP.
Original Source Code Comment: NO, EXIT

5475H - BACK3 - Continuation of the Command Loop for the MODIFY COMMAND

5475BACK3
CP 0AH FE 0A
Compare the value held in Register A against 0AH (ASCII: LINE FEED). Results: If Register A equals 0AH, the Z FLAG is set; otherwise the NZ FLAG is set.
5477
If the Z FLAG (Zero) is set, then we got a LINE FEED, so JUMP to 54ACH.
5479
CP 5BH FE 5B
Compare the value held in Register A against 5BH (ASCII: UP ARROW). Results: If Register A equals 5BH, the Z FLAG is set; otherwise the NZ FLAG is set.
547B
If the Z FLAG (Zero) is set then we got a UP ARROW so JUMP to 54A3H to move up.
547D
CP 09H FE 09
Compare the value held in Register A against 09H (ASCII: RIGHT ARROW). Results: If Register A equals 09H, the Z FLAG is set; otherwise the NZ FLAG is set.
547F
If 09H (the right arrow), JUMP to 549DH, which the source names LEFT: it does INC L, one byte to the right.
5481
CP 08H FE 08
Compare the value held in Register A against 08H (ASCII: BACKSPACE). Results: If Register A equals 08H, the Z FLAG is set; otherwise the NZ FLAG is set.
5483
If 08H (the left arrow), JUMP to 5497H, which the source names RIGHT: it does DEC L, one byte to the left.
5485
CP 30H FE 30
Compare the value held in Register A against 30H (ASCII: 0). Results:
  • If Register A equals 30H, the Z FLAG is set.
  • If A < 30H, the CARRY FLAG will be set.
  • if A >= 30H, the NO CARRY FLAG will be set.
5487
If the C FLAG (Carry) is set then A < 0, which would be invalid, so LOOP BACK to to the top of the command loop for the Modify Command at 5457H.
5489
CP 3AH FE 3A
Compare the value held in Register A against 3AH (ASCII: 1 more than 9). Results:
  • If Register A equals 1 more than 9, the Z FLAG is set.
  • If A < 1 more than 9, the CARRY FLAG will be set.
  • if A >= 1 more than 9, the NO CARRY FLAG will be set.
548B
If A < 1 more than 9 the C FLAG (Carry) will be is set, so JUMP to 54B8H.
548D
CP 41H FE 41
Compare the value held in Register A against 41H (ASCII: A). Results:
  • If Register A equals A, the Z FLAG is set.
  • If A < A, the CARRY FLAG will be set.
  • if A >= A, the NO CARRY FLAG will be set.
548F
If A < A, then the the C FLAG (Carry) will be set, so LOOP BACK to to the top of the command loop for the Modify Command at 5457H.
5491
CP 47H FE 47
Compare the value held in Register A against 47H (ASCII: 1 more than F). Results:
  • If Register A equals 1 more than F, the Z FLAG is set.
  • If A < 1 more than F, the CARRY FLAG will be set.
  • if A >= 1 more than F, the NO CARRY FLAG will be set.
5493
If A < 1 more than F then the C FLAG (Carry) will be set, so JUMP to 54B8H.
5495
LOOP BACK to to the top of the command loop for the Modify Command at 5457H.

5497H - RIGHT - Continuation of the Command Loop for the MODIFY COMMAND - Process a BACKSPACE

5497RIGHT
LD HL,(554FH)LD HL,(WHERE) 2A 4F 55
RIGHT (reached with the left arrow): Fetch 554FH-5550H (WHERE, the address of the byte being edited) into Register Pair HL.
549A
DEC L 2D
DECrement the value stored in Register L (i.e., the CURSOR POSITION) by 1.
549B
JUMP to 54B3H to save the new cursor position and continue.

549DH - LEFT - Continuation of the Command Loop for the MODIFY COMMAND - Process a RIGHT ARROW

549DLEFT
LD HL,(554FH)LD HL,(WHERE) 2A 4F 55
LEFT (reached with the right arrow): Fetch 554FH-5550H (WHERE, the address of the byte being edited) into Register Pair HL.
54A0
INC L 2C
Bump the value stored in Register L (i.e., the CURSOR POSITION) by 1.
54A1
JUMP to 54B3H to save the new cursor position and continue.

54A3H - DWN1 - Continuation of the Command Loop for the MODIFY COMMAND - Process a UP ARROW

54A3DWN1
LD HL,(554FH)LD HL,(WHERE) 2A 4F 55
Fetch the value stored at memory location 554FH (i.e., the CURSOR POSITION) and put it into Register HL.
54A6
LD A,L 7D
LET Register A = Register L (i.e., the CURSOR POSITION).
54A7
SUB 10H D6 10
SUBtract the value 10H (Decimal: 16) from Register A (i.e., the CURSOR POSITION) to move 1 row up.
54A9
LD L,A 6F
LET Register L = Register A (i.e., the CURSOR POSITION - 16).
54AA
JUMP to 54B3H to save the new cursor position and continue.

54ACH - UP1 - Continuation of the Command Loop for the MODIFY COMMAND - Process a LINE FEED

54ACUP1
LD HL,(554FH)LD HL,(WHERE) 2A 4F 55
Fetch the value stored at memory location 554FH (i.e., the CURSOR POSITION) and put it into Register HL.
54AF
LD A,L 7D
LET Register A = Register L (i.e., the CURSOR POSITION).
54B0
ADD A,10H C6 10
ADD the value 10H (Decimal: 16) to Register A (i.e., the CURSOR POSITION) to move 1 row down.
54B2
LD L,A 6F
LET Register L = Register A (i.e., the CURSOR POSITION + 16).
54B3DONE
LD (554FH),HLLD (WHERE),HL 22 4F 55
Store the value held in Register HL into the memory location 554FH (i.e., the CURSOR POSITION).
54B6
JUMP to 544FH (BACK) to show the change and wait for the next key.

54B8H - DIGIT - Modify RAM

54B8DIGIT
LD DE,(5551H)LD DE,(CURSA) ED 5B 51 55
Fetch the value stored at memory location 5551H (i.e., the cursor position) and put it into Register DE.
54BC
GOSUB to 5402H to display a character.
54BF
LD (5551H),DELD (CURSA),DE ED 53 51 55
Store the value held in Register DE into the memory location 5551H (i.e., the cursor position).
54C3
GOSUB 551EH (MAKHEX) to turn the ASCII hex digit into its value 0-15.
54C6
SLA A CB 27
SLA A (1 of 4): move the value into bits 7-4, the high nibble of the byte.
54C8
SLA A CB 27
SLA A (2 of 4).
54CA
SLA A CB 27
SLA A (3 of 4).
54CC
SLA A CB 27
SLA A (4 of 4).
54CE
LD B,A 47
LET Register B = Register A (i.e., the nybble rotated decimal value).
54CF
PUSH BC C5
Save Register BC, which includes the nybble rotated decimal value, to the top of the STACK.
54D0DIGIT1
GOSUB to 54FEH to get the next character.
54D3
CP 30H FE 30
Compare the value held in Register A against 30H (ASCII: 0). Results:
  • If Register A equals 0, the Z FLAG is set.
  • If A < 0, the CARRY FLAG will be set.
  • if A >= 0, the NO CARRY FLAG will be set.
54D5
If the C FLAG (Carry) is set because A < 0, then the character is too low, so JUMP back to 54D0H.
54D7
CP 3AH FE 3A
Compare the value held in Register A against 3AH (ASCII: 1 more than 9). Results:
  • If Register A equals 1 more than 9, the Z FLAG is set.
  • If A < 1 more than 9, the CARRY FLAG will be set.
  • if A >= 1 more than 9, the NO CARRY FLAG will be set.
54D9
If the C FLAG (Carry) is set because A < 1 more than 9, then we have a digit, so JUMP to 54E3H.
54DB
CP 41H FE 41
Compare the value held in Register A against 41H (ASCII: A). Results:
  • If Register A equals A, the Z FLAG is set.
  • If A < A, the CARRY FLAG will be set.
  • if A >= A, the NO CARRY FLAG will be set.
54DD
If the C FLAG (Carry) is set because A < A, then the character is too low (because we already know its not a digit, and everything else down there is invalid), so JUMP back to 54D0H.
54DF
CP 47H FE 47
Compare the value held in Register A against 47H (ASCII: 1 more than F). Results:
  • If Register A equals 1 more than F, the Z FLAG is set.
  • If A < 1 more than F, the CARRY FLAG will be set.
  • if A >= 1 more than F, the NO CARRY FLAG will be set.
54E1
If the NC FLAG (No Carry) is set because A >= 1 more than F, then the character is too high, so JUMP back to 54D0H.

If we are here, the key typed is 0-9 or A-F.

54E3DIGIT2
LD DE,(5551H)LD DE,(CURSA) ED 5B 51 55
Fetch the value stored at memory location 5551H (i.e., the cursor position) and put it into Register DE.
54E7
GOSUB to 5402H to display the entered character.
54EA
LD (5551H),DELD (CURSA),DE ED 53 51 55
Store the value held in Register DE into the memory location 5551H (i.e., the cursor position).
54EE
GOSUB 551EH (MAKHEX) to turn the ASCII hex digit into its value 0-15.
54F1
POP BC C1
Restore Register Pair BC (i.e., the nybble rotated decimal value) the from the top of the STACK.
54F2
ADD A,B 80
ADD the value held in Register B to Register A (Results held in Register A) to reconstitute the byte.
54F3
LD HL,(554FH)LD HL,(WHERE) 2A 4F 55
Fetch the value stored at memory location 554FH (i.e., the data address to modify) and put it into Register HL.
54F6
LD (HL),A 77
Store the value held in Register A (i.e., the reconstituted byte received from the user) into the memory location pointed (i.e., the data address to modify) to by Register Pair HL.
54F7
INC L 2C
Bump the value stored in Register L by 1 to point to the next byte.
54F8
LD (554FH),HLLD (WHERE),HL 22 4F 55
Store the value held in Register HL into the memory location 554FH (i.e., the next data address).
54FB
JUMP to 544FH to display and get the changes.

54FEH - GETKEY - Get a Character from the User

54FEGETKEY
PUSH HL E5
Save Register HL to the top of the STACK.
Original Source Code Comment: SAVE POINTER
54FF
LD HL,(5551H)LD HL,(CURSA) 2A 51 55
Fetch the value stored at memory location 5551H (i.e., the cursor position) and put it into Register HL.
Original Source Code Comment: GET THE SAVED CURSOR POSITION
5502
LD (4020H),HLLD (CURSOR),HL 22 20 40
Store the value held in Register HL into the memory location 4020H.
NOTE: 4020H is the storage location for the CURSOR POSITION ON SCREEN.
Original Source Code Comment: MAKE IT THE TRUE CURSOR POSITION
5505
POP HL E1
Restore Register Pair HL from the top of the STACK.
Original Source Code Comment: GET THE POINTER BACK
5506
LD A,0FH 3E 0F
LET Register A = 0FH (cursor off).
Original Source Code Comment: INSURE CURSOR OFF
5508
GOSUB 0033H (DSP) to send it to the display.
550B
EI FB
Enable Interrupts.
Original Source Code Comment: INSURE INTERRUPTS ON
550C
JUMP to 0049H in the ROM to wait for a keyboard response and RETURN.
Original Source Code Comment: GET A KEYBOARD CHAR

550FH - BWRITE - Write a Diskette File Page to Diskette

550FBWRITE
LD DE,5555HLD DE,BDCB 11 55 55
LET Register Pair DE = 5555H (i.e., the FCB).
5512
GOSUB 4439H (WRITE, the SYS0 vector) to write 4300H (BUFF1) as the record at NRN.
5515
If the NZ FLAG (Not Zero) is set, then the WRITE VECTOR call produced an error, so JUMP to 5405H to handle the diskette-related error.
5518
GOSUB 4445H (BACKSP, the SYS0 vector) to step NRN back to the record just written.
Original Source Code Comment: BACK UP TO SAME RECORD
551B
JUMP to 5330H to re-display the current page and continue.

551EH - MAKHEX - Convert the ASCII Hexadecimal Digit in A into its Value 0-15 in A

551EMAKHEX
SUB 30H D6 30
MAKHEX: SUBtract 30H. MAKHEX turns an ASCII hex digit ('0'-'9', 'A'-'F') into 0-15.
5520
CP 0AH FE 0A
Compare the value held in Register A against 0AH (Decimal: 10). Results:
  • If Register A equals 10, the Z FLAG is set.
  • If A < 10, the CARRY FLAG will be set.
  • if A >= 0AH, the NO CARRY FLAG will be set.
5522
RET C D8
If A < 10 then the C FLAG (Carry) will be set and we need to RETurn to the caller.
5523
SUB 07H D6 07
Convert "A"-"F" to 10-15 by SUBtracting the value 07H from Register A.
5525
RET C9
RETurn to the caller.

5526H - TITLE - Message Storage Area

5526-5527TITLE
DEFB 1CH,1FH 1C 1F
TITLE: 1CH homes the cursor, 1FH clears to the end of the screen.
5528-5541
DEFM "Debug Disk Utility Ver 1.3" 44 65 62 75 67 20 44 69 73 6B 20 55 74 69 6C 69 74 79 20 56 65 72 20 31 2E 33
5542
DEFB 0DH 0D
0DH ends the line and the text for PRINT (021BH).
5543BPROMT
DEFB 0AH 0A
BPROMT: 0AH starts a new line.
5544-554D
DEFM "Filespec: " 46 69 6C 65 73 70 65 63 3A 20
554E
DEFB 03H 03
03H ends the text for PRINT (021BH).
554F-5550WHERE
DEFW 4300H 00 43
WHERE: the address of the byte being edited (BUFF1, 4300H, in the file); the M command stores its address here.
5551-5552CURSA
DEFW 3C00H 00 3C
CURSA: the screen address of the byte being edited (CHECK stores it); GETKEY copies it into CURSOR (4020H).
5553MOVFLG
DEFB 00H 00
MOVFLG: 00H = no edit block; not zero = CHECK draws the block at WHERE (M in the disk utility, and the M command).
5554SLRL
DEFB 00H 00
SLRL: the source's comment is USERS LRL SAVED HERE; no instruction in SYS5 uses it.
5555-555ABDCB
DEFW 0000H,0000H,0000H 00 x 6
BDCB: the DCB of the file the disk utility works on (DCB offsets 00H-05H). KEYN first reads the filespec, up to 31 characters, into it; the rest of the DCB lies above 5562H.
555B-555EDRV
DEFW 0000H,0000H 00 00 00 00
DRV: DCB offset 06H, the drive of the file, shown at the start of each line (offsets 07H-09H follow).
555F-5560NRN
DEFW 0000H 00 00
NRN: DCB offsets 0AH-0BH, the next record number (the record shown).
5561-5562ERN
DEFW 0000H 00 00
ERN: DCB offsets 0CH-0DH, the ending record number.
 
END 4E00HEND START