5200H – Overlay Stub and Return
The first two bytes of SYS18/SYS form a minimal stub routine. When another part of NEWDOS/80 needs to test whether SYS18 is loaded into the overlay area, it performs a CALL to 5200H. If the overlay is present, CP A compares Register A against itself (always producing Z flag set and clearing the CARRY flag), then RET returns to the caller. If the overlay is NOT loaded, the memory at 5200H contains whatever was previously there (or 00H = NOP), and the behavior differs — allowing the caller to detect the overlay's absence.
5200
CP A BF
Compare Register A against itself. This always sets the Z FLAG (since A == A) and clears the CARRY FLAG. This is the "overlay present" signature — callers test the Z flag after CALL 5200H to confirm SYS18 is loaded.
5201
RET C9
Return to the caller with Z flag set, confirming that SYS18/SYS is resident in the overlay area.
5202H – Main Entry Point: Direct Statement Executor
This is the primary entry point for SYS18, called from the ROM BASIC command execution loop when a direct-mode statement needs to be processed. The code first sends a control character to initialize the cursor, then checks the DOS state flags to determine the input method. If the extended input mode is active (bit 5 of 4289H set), it invokes the full line input routine at 05D9H which provides line editing capabilities. Otherwise, it uses the simple keyboard scan at 0049H which returns a single keypress. After obtaining the input character, the code checks the keyboard intercept flag at 63FAH — if set, input is redirected to ROM routine 2831H for special processing. Otherwise, the key value is classified through a series of comparisons to determine which command handler to invoke.
5202
LD A,0EH 3E 0E
Load Register A with 0EH (decimal 14), the Cursor On control character. This enables the blinking cursor on the display so the user can see where input will appear.
5204
GOSUB to ROM routine at 0033H to display the character in Register A (the 0EH cursor-on control code) at the current cursor position.
5207
LD A,(4289H) 3A 89 42
Fetch the DOS state flags byte from memory location 4289H into Register A. Bit 5 of this byte controls whether the extended line input routine is used (bit 5 = 1) or the simple single-key scanner is used (bit 5 = 0).
520A
BIT 5,A CB 6F
Test bit 5 of Register A (the DOS state flags). If bit 5 is clear (0), the Z FLAG is set, indicating the simple keyboard scan should be used. If bit 5 is set (1), the NZ FLAG is set, indicating the full line input routine should be used.
520C
SIMPLE INPUT PATH
If the Z FLAG is set (bit 5 of 4289H is clear, meaning the simple keyboard mode is active), JUMP forward to 521AH to use the single-key scanner at 0049H.
The extended input path follows. This is used when the DOS has configured full line editing mode (e.g., after a SYSTEM command changes the input mode). The code saves BC, loads the line input buffer pointer from 40A7H, sets the maximum buffer length to F0H (240 characters), and calls the ROM line input routine at 05D9H.
520E
PUSH BC C5
Save Register Pair BC onto the stack. BC holds context from the caller that must be preserved across the line input call.
520F
LD HL,(40A7H) 2A A7 40
Point Register Pair HL to the line input buffer by loading the 2-byte pointer stored at 40A7H. This is the DOS-configured buffer where keyboard input will be stored by the line input routine.
5212
LD B,F0H 06 F0
Load Register B with F0H (decimal 240), the maximum number of characters the line input routine is allowed to accept. This is the buffer length limit passed to the ROM input routine.
5214
GOSUB to ROM routine at 05D9H, the line input routine. On entry: HL points to the storage buffer, B holds the maximum input length (F0H = 240). This routine accepts keyboard input with full line editing (cursor movement, delete, insert) until ENTER or BREAK is pressed. On return: the input line is stored at (HL), terminated by 0DH (carriage return), and the CARRY flag is set if BREAK was pressed.
5217
EXTENDED INPUT → KEYWORD PARSE
JUMP to 53C5H, the keyword dispatcher. After the full line input routine returns, the entire input line is in the buffer and needs to be parsed for command keywords (EDIT, LIST, DELETE, DI, DU, AUTO, RENEW, RENUM, REF). The keyword dispatcher handles this parsing.
The simple keyboard input path begins here. This path reads a single keypress (not a full line) and classifies it to determine the action. This is the normal path used during interactive BASIC LIST/EDIT scrolling.
521A
GOSUB to ROM routine at 0049H, the keyboard scan routine. This checks the keyboard and returns immediately with the ASCII value of any key currently pressed in Register A, or 00H if no key is pressed.
521D
PUSH AF F5
Save Register Pair AF (the key value in A and the flags) onto the stack. The key value will be needed after the intercept check.
521E
LD A,(63FAH) 3A FA 63
Fetch the keyboard intercept flag from 63FAH into Register A. This flag is set by the single-step debugger (CMD"F=SS") in BASIC/CMD. When non-zero, keyboard input is redirected to special handling.
5221
OR A B7
OR Register A with itself to test whether the intercept flag is zero or non-zero. If zero, the Z FLAG is set (normal processing). If non-zero, the NZ FLAG is set (intercept active).
5222
INTERCEPT REDIRECT
If the NZ FLAG is set (the keyboard intercept flag at 63FAH is non-zero, meaning the single-step debugger or another intercept handler is active), JUMP to ROM routine at 2831H to redirect input processing to the intercept handler. This is a dead-end exit from SYS18.
5225
POP AF F1
Restore Register Pair AF from the stack. Register A now holds the key value returned by the keyboard scan at 0049H.
Now the key classification begins. The code translates the backtick character (60H) to an at-sign (40H) for consistency, stores the translated value as a self-modifying operand at 5227H, then tests the key against a series of specific values to determine which handler to invoke.
5226
LD L,00H 2E 00
Load Register L with 00H, clearing it. Register L will later be used in the colon-handler path to distinguish a colon at the start of the program (L=00H) from a colon after a line number search (L=40H).
5228
CP 60H FE 60
Compare Register A (the input key value) against 60H (decimal 96), the ASCII backtick character. On the TRS-80, the backtick (60H) and the at-sign (40H) are related through uppercase conversion. If the key is a backtick, it needs to be translated to 40H.
522A
If the NZ FLAG is set (the key is NOT a backtick 60H), JUMP forward to 522EH to skip the translation and proceed with the original key value.
522C
LD A,40H 3E 40
Load Register A with 40H (decimal 64, the ASCII at-sign @). This translates the backtick key (60H) to the at-sign (40H). On the TRS-80 keyboard, the at-sign and backtick share the same physical key position with different shift states.
522E
PUSH AF F5
Save Register Pair AF (the translated key value in A and flags) onto the stack for later use.
522F
LD (5227H),A 32 27 52
Store the translated key value (Register A) to memory location 5227H. [SELF-MODIFYING CODE] This overwrites the low byte of the operand in the CP 60H instruction at 5228H. On re-entry, the comparison will be against the last key pressed instead of 60H. This is used by the colon-handler at 5271H to compare the stored key value.
The key classification cascade begins. Each comparison tests the key value against a specific ASCII code and branches to the corresponding handler if matched.
5232
CP 3AH FE 3A
Compare Register A against 3AH (decimal 58), the ASCII colon character :. A colon in direct mode means "execute the following as a BASIC statement." This allows multi-statement direct mode entry.
5234
COLON → EXECUTE STATEMENT
If the Z FLAG is set (the key is a colon, 3AH), JUMP forward to 5271H to handle direct-mode statement execution.
5236
CP 0AH FE 0A
Compare Register A against 0AH (decimal 10), the ASCII line-feed character. Line-feed is the ↓ (down arrow) key on the TRS-80 Model III keyboard. Pressing down-arrow during a LIST display advances to the next screenful.
5238
DOWN ARROW → CONTINUE LIST
If the Z FLAG is set (the key is line-feed / down-arrow, 0AH), JUMP forward to 527CH to load the current line number from 40ECH and continue the LIST from the current position.
523A
CP 5BH FE 5B
Compare Register A against 5BH (decimal 91), the ASCII left-bracket character [. On the TRS-80, left-bracket is used as an alternate "continue listing" key.
523C
LEFT-BRACKET → CONTINUE LIST
If the Z FLAG is set (the key is left-bracket, 5BH), JUMP forward to 527CH to continue the LIST from the current position.
523E
CP 2EH FE 2E
Compare Register A against 2EH (decimal 46), the ASCII period character .. A period means "re-display the current line" (the last line that was listed, edited, or deleted).
5240
PERIOD → REDISPLAY CURRENT
If the Z FLAG is set (the key is a period, 2EH), JUMP forward to 527CH to load the current line number from 40ECH and re-display from that position.
5242
CP 2CH FE 2C
Compare Register A against 2CH (decimal 44), the ASCII comma character ,. A comma means "continue listing from the current position" (same as down-arrow and left-bracket).
5244
COMMA → CONTINUE LIST
If the Z FLAG is set (the key is a comma, 2CH), JUMP forward to 527CH to continue the LIST from the current position.
The next group of comparisons handles keys that require loading the BASIC program start address first. The BASIC program start is loaded from 40A4H into HL before testing for semicolon (3BH) and cursor-right (1BH).
5246
LD HL,(40A4H) 2A A4 40
Point Register Pair HL to the start of the BASIC program by loading the 2-byte address stored at 40A4H. HL now points to the first byte (the link pointer low byte) of the first line in the BASIC program linked list.
5249
CP 3BH FE 3B
Compare Register A against 3BH (decimal 59), the ASCII semicolon character ;. A semicolon means "LIST from the beginning of the program."
524B
SEMICOLON → LIST FROM START
If the Z FLAG is set (the key is a semicolon, 3BH), JUMP forward to 524FH. Both semicolon and cursor-right (1BH) converge at 524FH to test whether the program is empty.
524D
CP 1BH FE 1B
Compare Register A against 1BH (decimal 27), the cursor-right control character. On the TRS-80 Model III, cursor-right is the → key. Pressing right-arrow also means "LIST from the beginning of the program."
524F
LIST FROM TOP → READY DISPLAY
If the Z FLAG is set (the key is either semicolon 3BH or cursor-right 1BH), JUMP to 537AH to display the READY prompt and enter the BASIC warm restart. When HL already points to the program start (40A4H), this will LIST from the first line.
For keys that did not match any of the above, the code now tests for cursor-up (1AH), slash (2FH), and at-sign (40H). Cursor-up and slash both set DE = FFFFH as a "search for specific line" indicator, while at-sign uses the current line number from 40ECH.
5252
LD DE,FFFFH 11 FF FF
Load Register Pair DE with FFFFH. This value serves as a sentinel meaning "find a specific line" — when the line search routine at 5280H sees DE = FFFFH, it searches for the exact line number rather than a relative offset.
5255
CP 1AH FE 1A
Compare Register A against 1AH (decimal 26), the cursor-up control character. On the TRS-80 Model III, cursor-up is the ↑ key. Pressing up-arrow scrolls the listing backward (toward lower line numbers).
5257
UP ARROW → SCROLL BACKWARD
If the Z FLAG is set (the key is cursor-up, 1AH), JUMP forward to 5280H to enter the line search routine with DE = FFFFH.
5259
CP 2FH FE 2F
Compare Register A against 2FH (decimal 47), the ASCII slash character /. Slash is an alternate key for scrolling backward through the listing (same as up-arrow).
525B
SLASH → SCROLL BACKWARD
If the Z FLAG is set (the key is a slash, 2FH), JUMP forward to 5280H to enter the line search routine with DE = FFFFH.
525D
CP 40H FE 40
Compare Register A against 40H (decimal 64), the ASCII at-sign character @. The at-sign means "re-display the current line for editing" — it acts as an EDIT shortcut.
525F
AT-SIGN → EDIT CURRENT LINE
If the Z FLAG is set (the key is at-sign, 40H), JUMP forward to 527CH to load the current line number from 40ECH and display that line.
If the key did not match any recognized single-character command, the code falls through to the full line input path. The key value is treated as the first character of a command line, so BC is saved and the full line input routine is called with the character already placed at the start of the buffer. This allows typed commands like "EDIT 100" or "DELETE 50-80" to be processed.
5261
POP AF F1
Restore Register Pair AF from the stack. Register A holds the unrecognized key value that will become the first character of the input line.
5262
PUSH BC C5
Save Register Pair BC onto the stack. BC holds caller context that must be preserved across the line input call.
5263
LD HL,53C5H 21 C5 53
Load Register Pair HL with 53C5H, the address of the keyword dispatcher. This address will be pushed onto the stack as a return address, so that when the line input routine finishes and the subsequent code executes a RET (or JP), control transfers to the keyword dispatcher.
5266
PUSH HL E5
Save Register Pair HL (53C5H, the keyword dispatcher address) onto the stack. This sets up a "return to keyword dispatcher" sequence — after the line input routine completes, execution will eventually reach 53C5H.
5267
LD HL,(40A7H) 2A A7 40
Point Register Pair HL to the line input buffer by loading the 2-byte pointer stored at 40A7H. This is the same buffer used by the extended input path at 520FH.
526A
LD B,F0H 06 F0
Load Register B with F0H (decimal 240), the maximum buffer length for the line input routine.
526C
LD C,B 48
Copy Register B into Register C. Register C now also holds F0H. The ROM line input routine at 05E3H uses C as an additional parameter (the initial buffer offset or display column width).
526D
PUSH HL E5
Save Register Pair HL (the line input buffer address from 40A7H) onto the stack. This preserves the buffer pointer for use after the input routine returns.
526E
UNRECOGNIZED KEY → FULL LINE INPUT → KEYWORD PARSE
JUMP to ROM routine at 05E3H. This is an alternate entry point to the line input routine (05D9H is the standard entry; 05E3H is the entry that accepts a pre-loaded first character in Register A). The first character typed by the user is already in A, so the input routine begins with that character already placed in the buffer. When input is complete (ENTER pressed), the routine returns, and since 53C5H was pushed onto the stack, execution continues at the keyword dispatcher.
5271H – Colon Handler: Direct Statement Execution
When the user presses the colon key (3AH) in direct mode, this handler is invoked. A colon at the READY prompt means "execute the text on the current screen line as a BASIC direct statement." The handler examines Register L (which was cleared to 00H at 5226H) to determine the context. If L is 00H (colon pressed at the top level), DE is set to 0000H (line number zero = direct statement). If L is 40H (colon pressed after an at-sign), the code checks whether the stored key was an at-sign and branches accordingly. Otherwise, the current line number is loaded from 40ECH.
5271
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H. DE = 0000H indicates "line number zero," which in BASIC means a direct statement (not a stored program line). This is the default for colon pressed at the READY prompt.
5274
CP L BD
Compare Register A (which holds 3AH, the colon) against Register L. Register L was set to 00H at 5226H. Since 3AH is not equal to 00H, the NZ FLAG is set, and since 3AH > 00H, the NO CARRY FLAG is set.
5275
If the Z FLAG is set (A equals L), JUMP forward to 5280H. This branch is taken when L was set to a value matching the colon (never happens with L=00H from the initial path, but can occur on re-entry when L has been modified).
5277
LD A,L 7D
Load Register A with Register L. Register L holds the context flag (00H from initial entry, or 40H if the at-sign path was taken). This retrieves the context for the next comparison.
5278
CP 40H FE 40
Compare Register A (now holding the value of L) against 40H (decimal 64). If L was 40H (the at-sign/backtick key value), it means the user pressed colon after an at-sign sequence, which is an EDIT-then-execute operation.
527A
If the Z FLAG is set (L was 40H, meaning the at-sign context is active), JUMP forward to 5280H to enter the line search with DE = 0000H (direct statement at the current line).
527C
LD DE,(40ECH) ED 5B EC 40
Load Register Pair DE with the 2-byte value stored at 40ECH, the current BASIC line number. This is the line number of the most recently listed, edited, or deleted line. DE now holds the target line number for the LIST/EDIT operation.
5280H – BASIC Line Search Routine
This routine walks the BASIC program linked list starting at the address stored in 40A4H, searching for a line whose line number matches or exceeds the target value in DE. Each line in the BASIC program consists of a 2-byte link pointer (address of the next line), a 2-byte line number, and the tokenized BASIC text terminated by 00H. The end of the program is indicated by a link pointer of 0000H. The routine counts lines in BC as it walks the list. On exit: HL points to the line that matched or exceeded the target (or the last line if the target was not found), BC holds the count of lines preceding the target, and the flags reflect the comparison result.
5280
LD HL,(40A4H) 2A A4 40
Point Register Pair HL to the start of the BASIC program by loading the 2-byte address stored at 40A4H. HL now points to the link pointer (low byte) of the first line in the program.
5283
LD BC,0000H 01 00 00
Load Register Pair BC with 0000H. BC serves as the line counter — it will be INCremented for each line that has a line number less than the target in DE.
LOOP START
The main line search loop begins here. Each iteration reads the link pointer of the current line, checks for end-of-program, then compares the line number against the target in DE.
5286
LD A,(HL) 7E
Fetch the low byte of the current line's link pointer from (HL) into Register A. The link pointer is the address of the next line in the program.
5287
INC HL 23
INCrement HL by 1 to point to the high byte of the link pointer.
5288
OR (HL) B6
OR Register A (low byte of link pointer) with the byte at (HL) (high byte of link pointer). If both bytes are 00H, the result is 00H and the Z FLAG is set, indicating end-of-program (a link pointer of 0000H marks the last line).
5289
DEC HL 2B
DECrement HL by 1 to restore it back to the start of the current line (pointing to the link pointer low byte again).
528A
END OF PROGRAM — target line not found
If the Z FLAG is set (the link pointer is 0000H, meaning the end of the BASIC program has been reached without finding the target line), JUMP to 537AH to display the READY prompt and return to the BASIC warm restart.
The line exists (link pointer is not 0000H). Now read the line number from offset +2/+3 within the line structure and compare it against the target in DE. The line structure is: [link_low][link_high][linenum_low][linenum_high][tokenized text...][00H].
528E
INC HL 23
INCrement HL by 1. HL now points to the high byte of the link pointer (offset +1).
528F
INC HL 23
INCrement HL by 1. HL now points to the low byte of the line number (offset +2).
5290
INC HL 23
INCrement HL by 1. HL now points to the high byte of the line number (offset +3).
5291
LD A,(HL) 7E
Fetch the high byte of the current line's line number from (HL) into Register A.
5292
CP D BA
Compare Register A (high byte of current line number) against Register D (high byte of target line number in DE). If the current line's high byte is less than D, the CARRY FLAG is set. If equal, the Z FLAG is set and the low bytes must also be compared.
5293
DEC HL 2B
DECrement HL by 1. HL now points back to the low byte of the line number (offset +2).
5295
LD A,(HL) 7E
Fetch the low byte of the current line's line number from (HL) into Register A. This is only meaningful if the high bytes matched (Z flag set from the CP D above).
5296
CP E BB
Compare Register A (low byte of current line number) against Register E (low byte of target line number). This comparison is only reached if the high bytes were equal (JR NZ at 5293H was not taken). Together with the previous CP D, this completes a 16-bit comparison of the current line number against DE.
5297
DEC HL 2B
DECrement HL by 1. HL now points to the high byte of the link pointer (offset +1).
5298
DEC HL 2B
DECrement HL by 1. HL now points back to the start of the current line (offset +0, the link pointer low byte).
5299
TARGET FOUND OR PASSED
If the NO CARRY FLAG is set (the current line number is greater than or equal to the target in DE), JUMP forward to 52ADH. The search has found the target line (or the first line with a number exceeding the target).
The current line number is less than the target. Follow the link pointer to advance to the next line in the program, INCrement the line counter in BC, and continue the search loop.
529B
PUSH HL E5
Save Register Pair HL (pointing to the start of the current line) onto the stack. This preserves the address of the current line in case it is the last line before the target.
529C
LD A,(HL) 7E
Fetch the low byte of the current line's link pointer from (HL) into Register A.
529D
INC HL 23
INCrement HL by 1 to point to the high byte of the link pointer.
529E
LD H,(HL) 66
Load Register H with the high byte of the link pointer from (HL). Register H now holds the high byte of the next line's address.
529F
LD L,A 6F
Load Register L with Register A (the low byte of the link pointer). HL now points to the start of the next line in the program.
52A0
LD A,(HL) 7E
Fetch the low byte of the next line's link pointer from (HL) into Register A. This tests whether the next line is the end-of-program marker.
52A1
INC HL 23
INCrement HL by 1 to point to the high byte of the next line's link pointer.
52A2
OR (HL) B6
OR Register A (low byte) with (HL) (high byte) of the next line's link pointer. If both are 00H, the Z FLAG is set, indicating the end of the program has been reached.
52A3
END OF PROGRAM DURING SEARCH
If the Z FLAG is set (the next line's link pointer is 0000H, meaning the program ends here), JUMP forward to 52A9H. The target line was not found — the search ran off the end of the program.
52A5
INC BC 03
INCrement the line counter in BC by 1. This counts the number of lines that have been skipped (lines whose line numbers are less than the target).
52A6
POP AF F1
Discard the saved HL from the stack (the address of the previous line is no longer needed since we successfully advanced to the next line). POP AF is used instead of POP HL to avoid corrupting HL, which now points to the next line.
52A7
LOOP — next line
JUMP back to 528EH to continue the loop with the next line. HL points to the link pointer high byte of the next line (offset +1), and the INC HL at 528EH will advance to offset +2 (line number low byte).
End-of-program reached during the search loop. The target line number was not found in the program. POP HL restores the address of the last line before the end marker, POP AF discards the saved key value, and the code jumps to 52BFH to handle the "line not found" case.
52A9
POP HL E1
Restore Register Pair HL from the stack. HL now points to the start of the last valid line in the program (the line before the end-of-program marker).
52AA
POP AF F1
Discard the saved key value from the stack (pushed at 522EH). The key value is no longer needed since the search has concluded.
52AB
LINE NOT FOUND → DISPLAY FROM END
JUMP forward to 52BFH, the "at-sign / re-display" handler. When the target line was not found, this path sets DE = 0000H and falls through to the offset calculator.
52ADH – Line Found: Key-Dependent Offset Selection
Execution reaches here when the line search at 5280H found a line whose number is greater than or equal to the target. The saved key value (from the stack, originally pushed at 522EH) is now analyzed to determine the screen offset — how many lines before or after the found line should be displayed. Different keys produce different offsets: down-arrow (0AH) sets DE = 0001H (display starting one line after), left-bracket (5BH) sets DE = FFFFH (display starting at the very beginning of the screen page), at-sign (40H) sets DE = 0000H (display starting at the found line), and colon (3AH) sets DE = FFF3H (display starting 13 lines before, to center the line on screen). Any other key is an error and jumps to 5379H.
52AD
POP DE D1
Restore Register Pair DE from the stack. DE now holds the saved key value (low byte in E, high byte undefined) that was pushed as AF at 522EH. The flags in D reflect the original flag state.
52AE
LD A,D 7A
Load Register A with Register D. Register D holds the saved flags byte (from the POP DE which restored the AF that was pushed at 522EH). The Z flag state from the line number comparison is encoded in this byte.
52AF
If the NZ FLAG is set (the found line's number does NOT exactly equal the target — it is greater than the target), JUMP forward to 52B8H. An inexact match means the requested line does not exist, so the listing offset is set to FFFFH for a "nearest match" display.
The found line exactly matches the target line number. Now determine the display offset based on which key was pressed.
52B1
LD DE,0001H 11 01 00
Load Register Pair DE with 0001H (decimal 1). This offset means "start displaying one line after the found line." This is the default for the down-arrow (0AH) key, which advances the listing by one line.
52B4
CP 0AH FE 0A
Compare Register A (which still holds the saved flags byte from D) against 0AH. This is checking for the line-feed / down-arrow key (0AH).
52B6
DOWN ARROW — offset +1
If the Z FLAG is set (the key was down-arrow, 0AH), JUMP forward to 52CEH with DE = 0001H to begin the offset calculation.
52B8
LD DE,FFFFH 11 FF FF
Load Register Pair DE with FFFFH. This offset is used when the line was not found exactly or when left-bracket (5BH) was pressed. FFFFH is treated as a signed -1, which combined with the line count in BC, causes the display to start from a position that shows the previous screen page.
52BB
CP 5BH FE 5B
Compare Register A against 5BH (decimal 91), the left-bracket key [.
52BD
LEFT-BRACKET — offset -1
If the Z FLAG is set (the key was left-bracket, 5BH), JUMP forward to 52CEH with DE = FFFFH to begin the offset calculation.
52BF
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H. This offset means "start displaying at the found line itself." This is the default for the at-sign (40H) key and for the "line not found" fallthrough from 52ABH.
52C2
CP 40H FE 40
Compare Register A against 40H (decimal 64), the at-sign key @.
52C4
AT-SIGN — offset 0, display from found line
If the Z FLAG is set (the key was at-sign, 40H), JUMP forward to 52CEH with DE = 0000H to begin the offset calculation.
52C6
LD DE,FFF3H 11 F3 FF
Load Register Pair DE with FFF3H (signed value -13 decimal). This offset is used for the colon (3AH) key. Starting 13 lines before the found line positions it roughly in the middle of the 15-line Model III screen, so the target line appears centered.
52C9
CP 3AH FE 3A
Compare Register A against 3AH (decimal 58), the colon key :.
52CB
UNRECOGNIZED KEY — exit to READY
If the NZ FLAG is set (the key does not match any recognized value — not 0AH, 5BH, 40H, or 3AH), JUMP to 5379H to push AF and fall through to the READY prompt at 537AH. This is the "unrecognized key in this context" error exit.
52CEH – Line Offset Calculator and Line Walk
This routine takes the line count (BC = number of lines before the target) and the display offset (DE = signed value from the key handler above), combines them to calculate the absolute line index to start displaying from, then walks the BASIC program linked list from the beginning to reach that line. The calculation is: absolute_index = BC + DE. If the result is negative (underflow), it is clamped to 0 (start of program). The routine then walks forward through the linked list, counting down from the calculated index, to reach the target display line.
52CE
PUSH AF F5
Save Register Pair AF (the key value in A and flags) onto the stack. The key value will be needed later to determine the display mode (colon vs at-sign vs other).
52CF
EX DE,HL EB
Exchange DE and HL. HL now holds the display offset (from DE), and DE now holds the address of the found line (from HL).
52D0
ADD HL,BC 09
ADD the line count (BC) to the display offset (HL). HL = offset + count = the absolute line index in the program. For example, if BC = 10 (10 lines before target) and HL = FFF3H (-13), then HL = 10 + (-13) = -3, which will be clamped to 0.
52D1
LD A,H 7C
Load Register A with Register H (the high byte of the calculated absolute index). If H is FFH, the result is negative (underflow).
52D2
CP FFH FE FF
Compare Register A against FFH. If H is FFH, the calculated index is negative (the offset tried to go before the start of the program).
52D4
INDEX VALID
If the NZ FLAG is set (H is not FFH, meaning the index is non-negative), JUMP forward to 52D9H to proceed with the line walk.
52D6
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H. The negative index is clamped to zero — display will start from the first line of the program.
HL now holds the absolute line index (the Nth line from the start of the program to begin displaying). The code needs to calculate how many lines to skip from the current position. It computes: skip_count = old_line_count (BC from search) - absolute_index (HL). This tells us how many lines to walk forward from the program start.
52D9
PUSH BC C5
Save Register Pair BC (the original line count from the search) onto the stack.
52DA
LD B,H 44
Copy the high byte of the absolute index from H into B.
52DB
LD C,L 4D
Copy the low byte of the absolute index from L into C. BC now holds the absolute line index.
52DC
POP HL E1
Restore the original line count from the stack into HL. HL now holds the line count that was in BC before the PUSH.
52DD
OR A B7
Clear the CARRY flag by ORing A with itself. This prepares for the SBC instruction which subtracts with carry.
52DE
SBC HL,BC ED 42
Subtract BC (absolute index) from HL (original line count) with borrow. HL = original_count - absolute_index = number of lines to skip forward from the start of the program. This is the walk count.
HL now holds the walk count (how many lines from the program start to reach the display start line). The code pushes this on the stack, reloads the program start address, and walks forward through the linked list, following each line's link pointer and decrementing BC until it reaches zero.
52E0
PUSH HL E5
Save Register Pair HL (the walk count) onto the stack. It will be popped into BC after the program start address is loaded.
52E1
LD HL,(40A4H) 2A A4 40
Point Register Pair HL to the start of the BASIC program by loading the address from 40A4H. The line walk will begin from here.
LOOP START
The line walk loop. Each iteration reads the link pointer of the current line into DE, decrements the walk counter in BC, and advances HL to the next line by swapping DE and HL.
52E4
LD E,(HL) 5E
Fetch the low byte of the current line's link pointer from (HL) into Register E.
52E5
INC HL 23
INCrement HL by 1 to point to the high byte of the link pointer.
52E6
LD D,(HL) 56
Fetch the high byte of the current line's link pointer from (HL) into Register D. DE now holds the address of the next line.
52E7
DEC HL 2B
DECrement HL by 1 to restore it to the start of the current line.
52E8
LD A,B 78
Load Register A with Register B (the high byte of the walk counter).
52E9
OR C B1
OR Register A with Register C (the low byte of the walk counter). If BC is 0000H, the result is 00H and the Z FLAG is set, meaning the walk is complete — HL points to the target display line.
52EA
DEC BC 0B
DECrement the walk counter in BC by 1. Note: DEC BC does not affect flags, so the Z flag from the OR test above is still valid.
52EB
EX DE,HL EB
Exchange DE and HL. HL now points to the next line (from DE), and DE holds the address of the line just visited.
52EC
LOOP — walk to next line
If the NZ FLAG is set (the walk counter BC was not zero before the DEC, meaning more lines need to be skipped), JUMP back to 52E4H to advance to the next line.
LOOP END
The walk is complete. HL now points to the BASIC line where the display should begin. The code pops the remaining stack values and prepares for the screen display.
52EE
POP BC C1
Restore Register Pair BC from the stack. BC held the walk count (now consumed), but the POP is needed to clean the stack.
52EF
EX DE,HL EB
Exchange DE and HL. After the loop, HL pointed to the next line and DE pointed to the target line. After this exchange, HL points to the target display line.
52F0
INC BC 03
INCrement BC by 1. BC was decremented one extra time by the loop (the DEC at 52EAH executes before the loop test at 52ECH). This corrects the off-by-one, so BC now holds the correct remaining line count.
52F1
POP AF F1
Restore Register Pair AF from the stack (pushed at 52CEH). Register A holds the key value that determined the display offset.
52F2
CP 3AH FE 3A
Compare Register A (the key value) against 3AH (colon). This determines the display mode — colon means "display with EDIT capability," while other keys mean "LIST only."
52F4
LD B,A 47
Copy the key value from A into B. Register B will carry the key value through the display loop for later use by the READY prompt handler.
52F5
COLON → display with edit context
If the Z FLAG is set (the key was a colon, 3AH), JUMP forward to 52FCH to begin the screen display.
52F7
CP 40H FE 40
Compare Register A (the key value) against 40H (at-sign). The at-sign also triggers the display path.
52F9
UNRECOGNIZED → exit to READY
If the NZ FLAG is set (the key is not colon 3AH and not at-sign 40H — some other unrecognized key in this context), JUMP to 5379H to push AF and exit to the READY prompt.
52FB
LD C,A 4F
Copy the key value (40H, the at-sign) from A into C. Register C carries the key value for the at-sign display mode, distinguishing it from the colon mode (which set B instead).
52FCH – Screen Clear and Line Display Loop
This routine clears the screen by sending control codes 1CH (clear screen) and 1FH (home cursor), then enters the main line display loop. The loop iterates through BASIC program lines starting from HL, calling ROM routine 2B7EH to detoken and display each line, and ROM routine 5D0BH to display the line number. The code tracks screen row usage to stop when the screen is full (15 rows on the Model III) or the end of the program is reached. Register D counts screen rows consumed, Register E counts columns within the current row, and Register C holds the maximum number of lines to display per page.
52FC
POP AF F1
Discard the top-of-stack value. This cleans up the stack from the key classification push sequence, aligning the stack for the display routine.
52FD
LD A,1CH 3E 1C
Load Register A with 1CH (decimal 28), the Clear Screen control character. On the TRS-80 Model III, sending 1CH to the display clears all 1024 bytes of video RAM (3C00H–3FFFH) and homes the cursor to position 3C00H.
52FF
GOSUB to 5D3FH (the display character routine in BASIC/CMD) to send the clear-screen control code (1CH) to the display. The screen is now blank with the cursor at the top-left corner.
5302
LD A,1FH 3E 1F
Load Register A with 1FH (decimal 31), the Home Cursor control character. This positions the cursor at column 0 of the current line (effectively a carriage return without line feed).
5304
GOSUB to 5D3FH to send the home-cursor control code (1FH) to the display. The cursor is now at position 3C00H (top-left corner of the screen).
The screen is cleared. Now set up the line display loop. HL points to the first BASIC line to display. The code pushes HL, initializes DE (the row/column counter), and enters the loop.
5307
PUSH HL E5
Save Register Pair HL (the address of the current line to display) onto the stack. This will be needed after the display to advance to the next line.
5308
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H. Register D is the screen row counter (starts at 0), and Register E is the column counter within the current row (starts at 0). These track how much screen space the displayed lines consume.
LOOP START
The line display loop begins here. For each line: save the counters, skip past the 2-byte link pointer to reach the line number, display the line number, call ROM 2B7EH to detoken and display the line text, then count the screen rows consumed. The loop exits when the screen is full (D + rows >= 0FH = 15) or the program ends.
530B
PUSH HL E5
Save Register Pair HL (address of the current line being displayed) onto the stack.
530C
PUSH DE D5
Save Register Pair DE (the row/column counters) onto the stack.
530D
PUSH BC C5
Save Register Pair BC (B = key value, C = line limit or key value) onto the stack.
530E
INC HL 23
INCrement HL by 1. HL now points to the high byte of the link pointer (offset +1).
530F
INC HL 23
INCrement HL by 1. HL now points to the low byte of the line number (offset +2).
5310
LD E,(HL) 5E
Fetch the low byte of the line number from (HL) into Register E.
5311
INC HL 23
INCrement HL by 1. HL now points to the high byte of the line number (offset +3).
5312
LD D,(HL) 56
Fetch the high byte of the line number from (HL) into Register D. DE now holds the 16-bit line number of the current program line.
5313
PUSH DE D5
Save Register Pair DE (the line number) onto the stack for later display by 5D0BH.
5314
INC HL 23
INCrement HL by 1. HL now points to the first byte of the tokenized BASIC text (offset +4), which is the start of the line body.
5315
GOSUB to ROM routine at 2B7EH, the BASIC line detokenizer and display routine. On entry: HL points to the tokenized BASIC text. This routine expands tokens back to their keyword text and sends each character to the display. On return: HL points past the end of the displayed line.
5318
POP DE D1
Restore Register Pair DE (the line number) from the stack.
5319
PUSH DE D5
Save Register Pair DE (the line number) back onto the stack. It will be needed again after the line number display.
531A
GOSUB to 5D0BH (the integer-to-ASCII display routine in BASIC/CMD). On entry: DE holds the 16-bit line number. This routine converts the number to decimal ASCII and displays it, followed by a space, at the current cursor position. The line number appears at the start of the display line.
The line text and line number have been displayed. Now count the screen rows consumed by this line. The code reads through the line input buffer (40A7H) character by character, counting carriage returns and line feeds to determine how many screen rows the displayed text occupied. Register D counts rows, Register E counts columns (resetting at 64 columns per row or on CR/LF).
531D
XOR A AF
Set Register A to 00H and clear all flags. A = 00H will be used to zero-terminate a string or serve as an initial value.
531E
LD D,01H 16 01
Load Register D with 01H. D is the row counter, starting at 1 (the line being displayed consumes at least one screen row).
5320
INC E 1C
INCrement Register E (the column counter) by 1. This accounts for the line number display that was just output.
5321
LD (BC),A 02
Store 00H (from Register A, cleared by XOR A at 531DH) to the address in BC. This writes a null terminator to the output buffer pointed to by BC, marking the end of the previously displayed text.
5322
LD HL,(40A7H) 2A A7 40
Point Register Pair HL to the line input buffer by loading the 2-byte pointer from 40A7H. The displayed line text is also in this buffer (ROM 2B7EH writes its output here), so the code will scan through it to count screen rows.
5325
ENTER ROW COUNT LOOP
JUMP forward to 5337H to enter the row-counting loop at the fetch point (skip the character classification and go directly to reading the first character).
LOOP START
The row-counting inner loop. Each iteration reads one character from the buffer, checks for CR (0DH) or LF (0AH) which start a new row, otherwise increments the column counter. When the column counter reaches 64 (bit 6 set), a new row is started. The loop exits when a 00H terminator is found.
5327
CP 0DH FE 0D
Compare Register A (the current character from the buffer) against 0DH (decimal 13), the carriage return character. A CR forces a new display row.
5329
CR → new row
If the Z FLAG is set (the character is a carriage return, 0DH), JUMP forward to 5334H to start a new row.
532B
CP 0AH FE 0A
Compare Register A against 0AH (decimal 10), the line feed character. A LF also forces a new display row.
532D
LF → new row
If the Z FLAG is set (the character is a line feed, 0AH), JUMP forward to 5334H to start a new row.
532F
INC E 1C
INCrement Register E (the column counter) by 1. Each displayed character advances the cursor one column to the right.
5330
BIT 6,E CB 73
Test bit 6 of Register E (the column counter). Bit 6 is set when E reaches 40H (decimal 64). The Model III screen is 64 columns wide, so when the column counter reaches 64, the display wraps to the next row.
5332
COLUMN OK — continue
If the Z FLAG is set (bit 6 of E is clear, meaning the column counter has NOT reached 64), JUMP forward to 5337H to continue reading characters without starting a new row.
5334
INC D 14
INCrement Register D (the row counter) by 1. A new screen row has been consumed by either a CR, LF, or column wraparound.
5335
LD E,00H 1E 00
Load Register E with 00H, resetting the column counter to zero for the start of the new row.
5337
LD A,(HL) 7E
Fetch the next character from the buffer at (HL) into Register A.
5338
OR A B7
OR Register A with itself to test for 00H (the null terminator). If A is 00H, the Z FLAG is set, indicating the end of the line text.
5339
INC HL 23
INCrement HL by 1 to advance to the next character in the buffer. This is done before the branch so that HL is always ready for the next iteration.
533A
LOOP — next character
If the NZ FLAG is set (the character is not 00H, meaning more characters remain in the line), JUMP back to 5327H to classify the next character.
LOOP END
The row count for this line is complete. D holds the number of screen rows this line consumed. The code now restores the saved context and adds the row count to the cumulative total to determine if the screen is full.
533C
LD A,D 7A
Load Register A with Register D (the row count for the line just displayed).
533D
POP HL E1
Restore Register Pair HL from the stack. This is the BC that was pushed at 530DH — but note the stack order: the POP sequence is HL←BC, BC←DE, DE←HL from the pushes at 530BH-530DH. HL now holds the saved BC (key value pair).
533E
POP BC C1
Restore Register Pair BC from the stack. BC now holds the saved DE (the cumulative row/column counter from the previous iteration).
533F
POP DE D1
Restore Register Pair DE from the stack. DE now holds the saved HL (the address of the line that was just displayed).
5340
ADD A,D 82
ADD Register D (the cumulative row counter from previous lines) to Register A (the row count for the line just displayed). A now holds the total number of screen rows consumed so far by all displayed lines.
5341
LD D,A 57
Store the updated cumulative row count back into Register D.
5342
CP 0FH FE 0F
Compare Register A (total rows consumed) against 0FH (decimal 15). The Model III screen has 16 rows (0–15), and the last row is reserved for the READY prompt, so 15 rows of program text is the maximum before the screen is full.
5344
SCREEN NOT FULL — continue
If the CARRY FLAG is set (total rows < 15, meaning the screen is NOT yet full), JUMP forward to 5354H to continue displaying more lines.
The screen is full (15 or more rows consumed). The code checks whether the display mode is "at-sign" (edit mode) or "colon/list" mode to determine what to do next.
5346
POP HL E1
Restore Register Pair HL from the stack. HL holds the address of the first line displayed on this page (pushed at 5307H).
5347
LD A,B 78
Load Register A with Register B (the key value saved during the offset calculation at 52F4H).
5348
CP 40H FE 40
Compare Register A against 40H (at-sign). If the display mode is at-sign (EDIT), the code exits to the line editor.
534A
AT-SIGN → EDIT LINE
If the Z FLAG is set (the key was at-sign, 40H), JUMP forward to 5367H to extract the line number of the target line and exit to the READY prompt with that line ready for editing.
The display mode is LIST (colon or other key). The screen is full, so prepare for the next page. Pop the remaining stack frame, DECrement the line limit counter, follow the link pointer to the next line, and loop back to display the next page.
534C
POP HL E1
Restore Register Pair HL from the stack. HL holds the address of the line that was the "first line" pointer saved during an earlier iteration.
534D
DEC C 0D
DECrement Register C by 1. Register C serves as a page counter or line limit — when it reaches zero, no more pages are displayed.
534E
LD A,(HL) 7E
Fetch the low byte of the current line's link pointer from (HL) into Register A. This follows the linked list to advance to the next line.
534F
INC HL 23
INCrement HL by 1 to point to the high byte of the link pointer.
5350
LD H,(HL) 66
Load Register H with the high byte of the link pointer.
5351
LD L,A 6F
Load Register L with Register A (the low byte of the link pointer). HL now points to the start of the next BASIC line.
5352
NEXT PAGE — loop back to display
JUMP back to 5307H to clear the screen and display the next page of lines starting from the new HL.
5354H – Screen Not Full: Continue to Next Line
When the screen is not yet full (fewer than 15 rows consumed), this code stores the current line address for later use, follows the link pointer to the next line, checks for end-of-program, and either loops back to display the next line or exits if the program has ended or the line limit is reached.
5354
LD (5373H),HL 22 73 53
Store Register Pair HL (the address of the current line) to memory location 5373H. [SELF-MODIFYING CODE] This overwrites the operand of the LD HL,0000H instruction at 5372H, so that when the READY prompt handler executes, HL will hold the address of the last displayed line.
5357
POP HL E1
Restore Register Pair HL from the stack. HL holds the address of the first line displayed on this page (pushed at 530BH during the current display iteration).
5358
LD A,(HL) 7E
Fetch the low byte of the link pointer from the current line at (HL) into Register A.
5359
INC HL 23
INCrement HL by 1 to point to the high byte of the link pointer.
535A
LD H,(HL) 66
Load Register H with the high byte of the link pointer.
535B
LD L,A 6F
Load Register L with Register A (the low byte of the link pointer). HL now points to the next BASIC line in the program.
535C
LD A,(HL) 7E
Fetch the low byte of the next line's link pointer from (HL) into Register A.
535D
INC HL 23
INCrement HL by 1 to point to the high byte of the next line's link pointer.
535E
OR (HL) B6
OR Register A (low byte) with (HL) (high byte) of the next line's link pointer. If both are 00H, the end of the BASIC program has been reached.
535F
DEC HL 2B
DECrement HL by 1 to restore it to the start of the next line.
5360
If the Z FLAG is set (the next line's link pointer is 0000H, meaning the end of the program), JUMP forward to 5367H to exit the display loop and show the READY prompt. [END OF PROGRAM]
5362
INC E 1C
INCrement Register E (the display line counter within the current page) by 1.
5363
LD A,E 7B
Load Register A with Register E (the current display line counter).
5364
CP C B9
Compare Register A (display line counter) against Register C (the maximum number of lines to display). If A is less than C, there is room for more lines.
5365
If the CARRY FLAG is set (the display line counter E is less than the maximum C, meaning more lines can be displayed), JUMP back to 530BH to display the next line. [LOOP — display next line]
5367H – End of Listing: Extract Line Number and Prepare READY
This code extracts the line number from the last displayed line and stores it into the self-modifying operand at 5272H (which is the operand of LD DE at 5271H). This allows the colon handler to recall the last displayed line number. It then sets up the stack for the READY prompt display by pushing 0000H as a sentinel and jumping to 53B8H which enters the BASIC warm restart.
5367
POP HL E1
Restore Register Pair HL from the stack. HL holds the address of the first line on the display page (pushed at 5307H).
5368
PUSH HL E5
Save Register Pair HL back onto the stack. The address is preserved for the READY prompt handler.
5369
INC HL 23
INCrement HL by 1. HL now points to the high byte of the link pointer (offset +1).
536A
INC HL 23
INCrement HL by 1. HL now points to the low byte of the line number (offset +2).
536B
LD E,(HL) 5E
Fetch the low byte of the line number from (HL) into Register E.
536C
INC HL 23
INCrement HL by 1. HL now points to the high byte of the line number (offset +3).
536D
LD D,(HL) 56
Fetch the high byte of the line number from (HL) into Register D. DE now holds the 16-bit line number of the first line on the displayed page.
536E
LD (5272H),DE ED 53 72 52
Store Register Pair DE (the line number) to memory locations 5272H–5273H. [SELF-MODIFYING CODE] This overwrites the operand of the LD DE,0000H instruction at 5271H. On the next colon-handler entry, DE will load with this line number instead of 0000H, allowing the colon to reference the last displayed line.
5372
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H. [SELF-MODIFYING CODE TARGET] The operand at 5373H is overwritten by the LD (5373H),HL at 5354H with the address of the last displayed line. On re-entry, HL will hold that saved address instead of 0000H.
5375
EX (SP),HL E3
Exchange (SP) with HL. The top of the stack held the line address (from the PUSH at 5368H); that address goes into HL, and 0000H (or the self-modified value) goes onto the stack in its place.
5376
PUSH HL E5
Save Register Pair HL (the line address retrieved from the stack) onto the stack again. This sets up the stack for the READY prompt handler.
5377
JUMP forward to 53B8H to enter the BASIC warm restart at 2B33H. [EXIT TO BASIC WARM RESTART]
5379H – READY Prompt Display and BASIC Warm Restart
This routine displays the READY prompt on the bottom line of the screen with appropriate cursor positioning. It first sends cursor-home (1DH) to position the cursor. Then it checks whether the current bottom line of the screen already contains the "READY" text — if so, it sends a cursor-right (1BH) to skip past it rather than reprinting. Finally, it sends cursor-down (1EH) and jumps to the BASIC warm restart at 2B33H. The entry at 5379H is the error/fallthrough path that pushes AF first; the entry at 537AH is the direct path from end-of-program detection.
5379
PUSH AF F5
Save Register Pair AF onto the stack. This is the error/fallthrough entry point — the key value is preserved on the stack for the stack cleanup at 537FH.
537A
LD A,1DH 3E 1D
Load Register A with 1DH (decimal 29), the Cursor Home (beginning of line) control character. This positions the cursor at column 0 of the last screen row.
537C
GOSUB to ROM routine at 0033H to send the cursor-home control code (1DH) to the display.
537F
POP AF F1
Discard the top-of-stack value. This cleans up the AF that was pushed at 5379H (or the line address from other entry paths).
5380
POP BC C1
Restore Register Pair BC from the stack. BC holds context from the display loop.
5381
LD B,H 44
Copy Register H into Register B. This saves the high byte of HL (the current line address) into B for later reference.
5382
LD C,L 4D
Copy Register L into Register C. BC now holds the address from HL (the current line in the program).
5383
INC HL 23
INCrement HL by 1. HL now points to the high byte of the link pointer (offset +1).
5384
INC HL 23
INCrement HL by 1. HL now points to the low byte of the line number (offset +2).
5385
LD E,(HL) 5E
Fetch the low byte of the line number from (HL) into Register E.
5386
INC HL 23
INCrement HL by 1. HL now points to the high byte of the line number (offset +3).
5387
LD D,(HL) 56
Fetch the high byte of the line number from (HL) into Register D. DE now holds the line number of the current BASIC line.
5388
CP 2CH FE 2C
Compare Register A against 2CH (decimal 44), the comma character. The comma indicates a "continue listing" command that was entered from the ROM BASIC input loop at 2E65H.
538A
If the Z FLAG is set (the character was a comma, 2CH), JUMP to ROM routine at 2E65H, the BASIC tokenizer/executor entry point. The comma causes the BASIC command interpreter to continue processing the remainder of the input line. [COMMA → continue BASIC execution]
The key was not a comma, so this is a normal LIST termination. Send cursor-off (0FH) to hide the cursor, then check whether the bottom screen line already shows "READY" to avoid redundant output.
538D
PUSH DE D5
Save Register Pair DE (the line number of the current line) onto the stack.
538E
PUSH BC C5
Save Register Pair BC (the address of the current line) onto the stack.
538F
LD A,0FH 3E 0F
Load Register A with 0FH (decimal 15), the Cursor Off control character. This hides the blinking cursor during the screen check.
5391
GOSUB to ROM routine at 0033H to send the cursor-off control code (0FH) to the display.
5394
LD HL,(4020H) 2A 20 40
Load Register Pair HL with the current cursor position from 4020H. The cursor position is an absolute address within video RAM (3C00H–3FFFH).
5397
LD DE,FFC0H 11 C0 FF
Load Register Pair DE with FFC0H (signed value -64 decimal). Subtracting 64 from the cursor position moves back one full screen row (64 columns per row on the Model III).
539A
ADD HL,DE 19
ADD DE (FFC0H = -64) to HL (cursor position). HL now points to the beginning of the screen row immediately above the cursor's current row.
539B
LD A,H 7C
Load Register A with Register H (the high byte of the calculated screen address).
539C
CP 3CH FE 3C
Compare Register A against 3CH. Video RAM starts at 3C00H, so if H is less than 3CH, the calculated address is outside video RAM (above the top of the screen). This means the cursor was on the first row and there is no previous row to check.
539E
If the CARRY FLAG is set (the address is below 3C00H, meaning the cursor was on the top row), JUMP forward to 53B3H to skip the "READY" text check and go directly to the cursor-down output. [TOP ROW — skip READY check]
The cursor is not on the top row, so check the previous row to see if it already contains "READY " (the 10-byte string at 53BBH). If it does, send cursor-right (1BH) to skip past it without reprinting.
53A0
EX DE,HL EB
Exchange DE and HL. DE now holds the address of the start of the previous screen row (calculated above), and HL is free for use as the comparison string pointer.
53A1
LD B,0AH 06 0A
Load Register B with 0AH (decimal 10), the length of the "READY" comparison string (5 characters of "READY" plus 5 trailing spaces). B serves as the loop counter for the byte-by-byte comparison.
53A3
LD HL,53BBH 21 BB 53
Point Register Pair HL to 53BBH, the address of the "READY " text string stored within SYS18. This is the reference string for the comparison.
LOOP START
Compare the screen contents against the "READY" string, one byte at a time.
53A6
LD A,(DE) 1A
Fetch one byte from video RAM at the address in DE (the previous screen row) into Register A.
53A7
INC DE 13
INCrement DE by 1 to advance to the next character in video RAM.
53A8
CP (HL) BE
Compare Register A (the character from video RAM) against (HL) (the corresponding character from the "READY" reference string). If they do not match, the NZ flag is set.
53A9
INC HL 23
INCrement HL by 1 to advance to the next character in the reference string.
53AA
If the NZ FLAG is set (the screen character does not match the reference string), JUMP forward to 53B3H. The screen does not contain "READY" at this position, so no cursor-right is needed. [MISMATCH — skip cursor-right]
53AC
DECrement B and JUMP back to 53A6H if B is not zero. B counts down from 10 (0AH). [LOOP — compare next byte]
LOOP END
All 10 bytes matched — the screen already shows "READY " on the previous row. Send cursor-right (1BH) to advance the cursor past it without reprinting.
53AE
LD A,1BH 3E 1B
Load Register A with 1BH (decimal 27), the Cursor Right control character. This advances the cursor one position to the right.
53B0
GOSUB to ROM routine at 0033H to send the cursor-right control code (1BH) to the display.
53B3
LD A,1EH 3E 1E
Load Register A with 1EH (decimal 30), the Cursor Down control character. This moves the cursor down one row, positioning it for the next command input.
53B5
GOSUB to ROM routine at 0033H to send the cursor-down control code (1EH) to the display.
53B8
JUMP to ROM routine at 2B33H, the BASIC warm restart entry point. This returns control to the BASIC command loop, which displays the "READY" prompt and waits for the next user input. [EXIT — BASIC warm restart]
53BBH – "READY" Text String (Data)
This is a 10-byte read-only data area containing the ASCII text "READY" followed by five space characters (20H). It is used by the screen comparison routine at 53A0H–53ACH to detect whether the previous screen row already displays the READY prompt. The disassembler misinterprets these bytes as Z80 instructions, but they are pure ASCII data.
53BB
DEFM "READY " 52 45 41 44 59 20 20 20 20 20
ASCII text string: "READY" (52H 45H 41H 44H 59H) followed by five space characters (20H 20H 20H 20H 20H). Total length: 10 bytes. This string matches the READY prompt as it appears in video RAM, including the trailing spaces that fill the remainder of the display field. Used for comparison at 53A6H–53ACH.
53C5H – Keyword Dispatcher Entry Point
This is the main keyword dispatcher, reached after the line input routine returns a complete command line. The code first checks whether BREAK was pressed during input (CARRY flag set from 05D9H/05E3H), exiting to the BASIC command executor at 0375H if so. Otherwise, it saves the registers, backs up the text pointer, and calls RST 10H to fetch the first non-space character. If the character is a digit, the input is parsed as a bare line number (which is a syntax error if not followed by a statement). If the character is not a digit, control falls through to the keyword table lookup at 53DAH.
53C5
PUSH AF F5
Save Register Pair AF onto the stack. Register A holds the last character from the input line, and the CARRY flag indicates whether BREAK was pressed during the line input routine (CARRY set = BREAK pressed).
53C6
If the CARRY FLAG is set (BREAK was pressed during the line input at 05D9H or 05E3H), JUMP to 5450H which is JP 0375H, the BASIC command execution entry point. This aborts the command entry and returns to the normal BASIC input loop. [BREAK PRESSED → exit to BASIC]
53C9
PUSH DE D5
Save Register Pair DE onto the stack. DE holds context from the caller (the line number or display parameters).
53CA
PUSH BC C5
Save Register Pair BC onto the stack. BC holds the key value and line counter from the display logic.
53CB
PUSH HL E5
Save Register Pair HL onto the stack. HL points to the current position in the input buffer.
53CC
DEC HL 2B
DECrement HL by 1. This backs up the text pointer by one position so that RST 10H (which increments HL before reading) will read the current character rather than the next one.
53CD
RST 10H D7
Call the RST 10H restart vector, which fetches the next non-space character from the BASIC text pointed to by HL into Register A. Blanks (20H) and control codes 09H/0BH are skipped. The CARRY flag is set if the character is a digit (30H–39H).
53CE
If the NO CARRY FLAG is set (the first non-space character is NOT a digit — it is alphabetic or special), JUMP forward to 53DAH to enter the keyword table lookup. [NON-DIGIT → keyword lookup]
The first character is a digit, so the input is a bare line number. Parse it with the ROM expression evaluator. If the line number is followed only by a carriage return (no BASIC statement), it is a syntax error — a line number alone on the direct-mode command line is not valid here.
53D0
GOSUB to ROM routine at 1E5AH, which converts the ASCII decimal string pointed to by HL into a 16-bit integer in DE. On return: DE holds the parsed line number, HL points past the last digit, and A holds the next character after the number.
53D3
CP 0DH FE 0D
Compare Register A (the character following the line number) against 0DH (carriage return). If the line number is followed by CR, there is no statement to execute — just a bare number, which is invalid in this context.
53D5
If the NZ FLAG is set (the character after the line number is NOT a carriage return — there is a statement following), JUMP forward to 544DH to restore the saved registers and execute the line. [LINE NUMBER + STATEMENT → execute]
53D7
JUMP to ROM routine at 1997H, the BASIC "?SN ERROR" (Syntax Error) handler. A bare line number on the command line without any statement text is a syntax error. [BARE LINE NUMBER → ?SN ERROR]
53DAH – Keyword Table Lookup
This routine looks up the input text against the keyword table at 54B2H. It compares the input characters (after uppercasing via CALL 57BAH) against each keyword entry in the table. Each table entry consists of the keyword's ASCII characters (with the byte AFTER the last character having bit 7 set as a terminator/flag), followed by a 2-byte handler address. If a keyword match is found, the handler address is loaded into BC and the flag byte determines the dispatch path. If no keyword matches, control falls through to the syntax error path at 544DH.
53DA
EX DE,HL EB
Exchange DE and HL. DE now points to the current position in the input buffer (the first non-space character), and HL is free for use as the table pointer.
53DB
LD HL,54B2H 21 B2 54
Point Register Pair HL to 54B2H, the start of the keyword lookup table. This table contains the direct-mode command keywords (RENEW, RENUM, REF, DI, DU, AUTO, LIST, EDIT, DELETE) with their handler addresses.
[LOOP START — outer] The outer keyword loop. For each keyword entry in the table, the inner loop compares the input text character-by-character. If the keyword doesn't match, the code scans forward to the next entry. If the table is exhausted (00H sentinel), the lookup fails.
53DE
PUSH DE D5
Save Register Pair DE (the input text pointer) onto the stack. Each keyword comparison starts from the same input position, so the pointer must be saved and restored if the keyword doesn't match.
[LOOP START — inner] The inner character-matching loop. Each iteration reads one character from the input, uppercases it, and compares it against the current keyword table byte.
53DF
LD A,(DE) 1A
Fetch one character from the input buffer at the address in DE into Register A.
53E0
INC DE 13
INCrement DE by 1 to advance to the next input character.
53E1
GOSUB to 57BAH, the uppercase converter in BASIC/CMD. This converts the character in Register A to uppercase if it is a lowercase letter (61H–7AH → 41H–5AH). Keywords must be matched case-insensitively.
53E4
CP (HL) BE
Compare Register A (the uppercased input character) against the byte at (HL) (the current keyword table character). If they match, the Z FLAG is set.
53E5
If the Z FLAG is set (the input character matches the keyword table character), JUMP forward to 53F5H to advance to the next character in the keyword. [CHARACTER MATCH]
The character did not match. Scan forward through the keyword table until a byte with bit 7 set is found (the terminator/flag byte), then skip the 2-byte handler address to reach the next entry.
53E7
BIT 7,(HL) CB 7E
Test bit 7 of the byte at (HL). The keyword terminator/flag byte has bit 7 set. Characters within the keyword have bit 7 clear.
53E9
INC HL 23
INCrement HL by 1 to advance to the next byte in the keyword table.
53EA
If the Z FLAG is set (bit 7 was clear, meaning this byte is still part of the keyword text), JUMP back to 53E7H to check the next byte. [SCAN — skip remaining keyword chars]
53EC
INC HL 23
INCrement HL by 1. HL now points past the first byte of the handler address (skip address low byte).
53ED
INC HL 23
INCrement HL by 1. HL now points past the second byte of the handler address (skip address high byte). HL is now positioned at the start of the next keyword entry (or the 00H end sentinel).
53EE
POP DE D1
Restore Register Pair DE from the stack. DE is reset to the start of the input text (saved at 53DEH) so the next keyword can be compared from the beginning of the input.
53EF
LD A,(HL) 7E
Fetch the first byte of the next keyword entry (or 00H if the table is exhausted) into Register A.
53F0
OR A B7
OR Register A with itself to test for 00H. If A is 00H, the Z FLAG is set, indicating the end of the keyword table has been reached with no match.
53F1
If the NZ FLAG is set (the byte is not 00H, meaning there are more keywords to try), JUMP back to 53DEH to try the next keyword entry. [LOOP — try next keyword]
53F3
JUMP forward to 544DH. No keyword matched — restore registers and fall through to the BASIC command executor. The input line will be handled by the standard BASIC tokenizer/executor. [NO MATCH → BASIC executor]
53F5H – Keyword Match: Character Advance and Completion Check
When a character matches during the keyword lookup, this code advances to the next table byte and checks whether the keyword is fully matched (bit 7 set on the next byte). If not fully matched, it loops back to compare the next character. When fully matched, it extracts the 2-byte handler address into BC and the flag byte into A, then dispatches based on the flag bits: bit 6 controls whether this is an EDIT-style command (bit 6 set) or a DI/DU/other command (bit 6 clear), and bit 5 distinguishes DI/DU (bit 5 set) from LIST/EDIT/DELETE/AUTO (bit 5 clear).
53F5
INC HL 23
INCrement HL by 1 to advance to the next byte in the keyword table after the matched character.
53F6
LD A,(HL) 7E
Fetch the next keyword table byte into Register A. This is either another keyword character (bit 7 clear) or the terminator/flag byte (bit 7 set).
53F7
BIT 7,A CB 7F
Test bit 7 of Register A. If bit 7 is set, the keyword has been fully matched and A contains the flag byte. If bit 7 is clear, there are more characters to match.
53F9
If the Z FLAG is set (bit 7 is clear — more characters remain in the keyword), JUMP back to 53DFH to compare the next input character against the next keyword character. [LOOP — match next character]
[KEYWORD FULLY MATCHED] The entire keyword has been matched. Register A holds the flag/terminator byte (bit 7 set, plus additional flag bits in bits 6 and 5). The next 2 bytes in the table are the handler address. Extract them into BC.
53FB
INC HL 23
INCrement HL by 1. HL now points to the low byte of the handler address in the keyword table.
53FC
LD C,(HL) 4E
Fetch the low byte of the handler address from (HL) into Register C.
53FD
INC HL 23
INCrement HL by 1. HL now points to the high byte of the handler address.
53FE
LD B,(HL) 46
Fetch the high byte of the handler address from (HL) into Register B. BC now holds the 16-bit handler address for the matched keyword.
53FF
POP HL E1
Restore Register Pair HL from the stack (the input text pointer saved at 53DEH). HL now points to the position in the input buffer where the keyword started.
5400
BIT 6,A CB 77
Test bit 6 of Register A (the flag byte). Bit 6 distinguishes EDIT-style commands (bit 6 set: RENEW, RENUM, REF) from line-manipulation commands (bit 6 clear: DI, DU, AUTO, LIST, EDIT, DELETE).
5402
If the Z FLAG is set (bit 6 is clear — this is a DI, DU, AUTO, LIST, EDIT, or DELETE command), JUMP forward to 5413H for line-manipulation command handling. [LINE COMMAND → 5413H]
Bit 6 is set, meaning this is a RENEW, RENUM, or REF command. These commands invoke an overlay or a recovery routine. The handler address in BC is stored to 57B6H for later use, then the input buffer is filled with FFH followed by spaces (20H) to create a clean command line for the handler to process.
5404
LD (57B6H),BC ED 43 B6 57
Store Register Pair BC (the handler address from the keyword table) to memory locations 57B6H–57B7H. This saves the handler address where the EDIT/overlay dispatch code can retrieve it later.
5408
LD (HL),FFH 36 FF
Store FFH to the byte at (HL), which is the current position in the input buffer. FFH serves as a marker or separator in the command line buffer.
540A
INC HL 23
INCrement HL by 1 to advance to the next position in the input buffer.
540B
RST 18H DF
Call the RST 18H restart vector, which performs a 16-bit unsigned comparison of HL vs DE. The CARRY flag is set if HL < DE. This compares the current buffer position (HL) against the end-of-input position (DE) to determine if there is more input to process.
540C
If the NO CARRY FLAG is set (HL >= DE, meaning the buffer fill has reached or passed the end of the input), JUMP forward to 544DH to restore registers and execute the command. [BUFFER FILL COMPLETE]
540E
LD (HL),20H 36 20
Store 20H (space character) to the byte at (HL). This fills the remainder of the input buffer with spaces after the FFH marker.
5410
INC HL 23
INCrement HL by 1 to advance to the next buffer position.
5411
JUMP back to 540BH to check whether the buffer is full and continue filling with spaces. [LOOP — fill buffer with spaces]
5413H – Line Command Dispatcher: EDIT, LIST, DELETE, DI, DU, AUTO
This handler processes the line-manipulation commands. The flag byte in Register A (bit 5) distinguishes between DI/DU commands (bit 5 set → jump to 5453H for parameter parsing) and EDIT/LIST/DELETE/AUTO commands (bit 5 clear → parse a line number or period parameter, then scan for the end of the line). For EDIT/LIST/DELETE/AUTO, the code fetches the next character: if it is a digit, it is parsed as a line number; if it is a period, the current line number from 40ECH is used as the default; otherwise it is an error. The code then scans forward to find the end of the logical statement (looking for '=' which signals a different syntax, or CR which terminates the command).
5413
EX DE,HL EB
Exchange DE and HL. DE now points to the input text position (past the matched keyword), and HL is free for manipulation.
5414
DEC HL 2B
DECrement HL by 1. This backs up the text pointer so that RST 10H will re-read the current character.
5415
BIT 5,A CB 6F
Test bit 5 of Register A (the flag byte from the keyword table). Bit 5 distinguishes DI/DU commands (bit 5 set) from EDIT/LIST/DELETE/AUTO (bit 5 clear).
5417
If the NZ FLAG is set (bit 5 is set — this is a DI or DU command), JUMP forward to 5453H for DI/DU parameter parsing. [DI/DU → parameter parser]
This is an EDIT, LIST, DELETE, or AUTO command. Parse the parameter: a digit starts a line number, a period means "current line," anything else is an error.
5419
RST 10H D7
Call RST 10H to fetch the next non-space character from the text at HL. The CARRY flag is set if the character is a digit (30H–39H).
541A
If the CARRY FLAG is set (the character is a digit), JUMP forward to 5420H to scan forward to the end of the command. The digit will be part of a line number parameter. [DIGIT → scan to end]
541C
CP 2EH FE 2E
Compare Register A against 2EH (period). A period means "use the current line" (the last line listed, edited, or deleted), whose number is stored at 40ECH.
541E
If the NZ FLAG is set (the character is neither a digit nor a period — unrecognized parameter), JUMP forward to 544DH to restore registers and let BASIC handle it. [UNRECOGNIZED → BASIC executor]
The character is a digit or a period. Scan forward through the input text to find the end of the command line. Skip everything until a '=' (which indicates a different command syntax like CMD"F=...") or CR (end of line).
5420
INC HL 23
INCrement HL by 1 to advance to the next character in the input buffer.
5421
LD A,(HL) 7E
Fetch the next character from the input buffer at (HL) into Register A.
5422
CP 3DH FE 3D
Compare Register A against 3DH (decimal 61), the ASCII equals sign =. An equals sign indicates a CMD"F=" style command, which is handled differently.
5424
If the Z FLAG is set (the character is '='), JUMP forward to 544DH to pass the command to the BASIC executor for CMD"F=" handling. [EQUALS SIGN → BASIC executor]
5426
CP 0DH FE 0D
Compare Register A against 0DH (carriage return). CR marks the end of the command line.
5428
If the NZ FLAG is set (the character is not CR — more characters remain), JUMP back to 5420H to scan the next character. [LOOP — scan to end of line]
The end of the command line has been reached (CR found). Restore the saved registers from the stack and set up for command execution. The handler address in BC determines which routine processes the command.
542A
POP HL E1
Restore Register Pair HL from the stack (saved at 53CBH). HL holds the original input buffer position.
542B
POP DE D1
Restore Register Pair DE from the stack (saved at 53C9H). DE holds the line number or display context.
542C
LD A,D 7A
Load Register A with Register D (the high byte of DE, which holds the line number high byte or display parameter).
542D
EX AF,AF' 08
Exchange AF with the alternate register pair AF'. This saves the line number high byte and flags into the alternate accumulator for later retrieval.
542E
LD A,(BC) 0A
Fetch the byte at the address in BC into Register A. BC holds the handler address from the keyword table. The byte at this address is a parameter or dispatch value used by the command handler.
542F
DEC A 3D
DECrement Register A by 1. This adjusts the fetched parameter value for use in the subsequent calculation.
5430
ADD A,D 82
ADD Register D (the high byte of the display row count) to Register A. This combines the handler parameter with the display context to compute the target screen row.
5431
LD D,A 57
Store the computed value back into Register D.
5432
CP E BB
Compare Register A (the computed row) against Register E (the display column/line counter). This checks whether the command should proceed or abort.
5433
If the NO CARRY FLAG is set (the computed row exceeds the display limit), JUMP back to 53D7H which is JP 1997H, the syntax error handler. [OVERFLOW → ?SN ERROR]
The command parameters are valid. Set up the LDDR/LDIR block move to insert or rearrange the line in the BASIC program text.
5435
PUSH DE D5
Save Register Pair DE (the computed row/column values) onto the stack.
5436
PUSH HL E5
Save Register Pair HL (the line address) onto the stack.
5437
LD A,(BC) 0A
Fetch the byte at the address in BC into Register A. This reads the line length byte from the source line's data area.
5438
EX AF,AF' 08
Exchange AF with AF'. This retrieves the saved line number high byte from the alternate accumulator and swaps in the line length byte.
5439
INC BC 03
INCrement BC by 1. BC advances past the current byte to the next data position.
543A
PUSH BC C5
Save Register Pair BC (the advanced data pointer) onto the stack.
543B
LD C,A 4F
Copy Register A (the line length) into Register C. C will be used as the byte count for the block move.
543C
LD B,00H 06 00
Load Register B with 00H. BC now holds the line length as a 16-bit value (B=00, C=length).
543E
ADD HL,BC 09
ADD BC (the line length) to HL (the line address). HL now points to the byte just past the end of the source line data — the start of the area that needs to be moved.
543F
EX DE,HL EB
Exchange DE and HL. DE now holds the end-of-source address, and HL holds the row/column values.
5440
EX AF,AF' 08
Exchange AF with AF'. This retrieves the line length from the alternate accumulator.
5441
LD H,B 60
Load Register H with Register B (00H). H is cleared.
5442
LD L,A 6F
Load Register L with Register A (the line length byte from the alternate A). HL = 00:length.
5443
DEC L 2D
DECrement Register L by 1. This adjusts the length for the LDDR instruction which copies length+1 bytes.
5444
ADD HL,DE 19
ADD DE (the end-of-source address) to HL (the adjusted length). HL now points to the destination end address for the LDDR block move.
5445
EX DE,HL EB
Exchange DE and HL. DE now holds the destination end, HL holds the source end. These are the correct parameters for LDDR.
5446
LDDR ED B8
Execute the LDDR (Load, Decrement, Repeat) block move instruction. This copies BC bytes from (HL) to (DE), decrementing both HL and DE after each byte. The block move shifts program text downward in memory to make room for the inserted or moved line.
5448
EX DE,HL EB
Exchange DE and HL. After LDDR, DE pointed to the byte before the destination start. HL now holds that address.
5449
POP HL E1
Restore Register Pair HL from the stack (the saved BC data pointer from 543AH). HL now points to the source data to be copied into the gap.
544A
LD C,A 4F
Load Register C with Register A (the line length). BC was modified by LDDR; this restores the byte count for the LDIR copy.
544B
LDIR ED B0
Execute the LDIR (Load, Increment, Repeat) block move instruction. This copies BC bytes from (HL) to (DE), incrementing both HL and DE after each byte. The LDIR copies the new line data into the gap created by the LDDR above.
The line has been inserted or moved. Restore the remaining saved registers and fall through to the BASIC command executor at 5450H.
544D
POP HL E1
Restore Register Pair HL from the stack (saved at 53CBH or 5436H depending on the path). HL holds the input buffer pointer or line address.
544E
POP BC C1
Restore Register Pair BC from the stack (saved at 53CAH or 5435H). BC holds the key value pair or line count.
544F
POP DE D1
Restore Register Pair DE from the stack (saved at 53C9H). DE holds the line number or display context.
5450
JUMP to ROM routine at 0375H, the BASIC command execution entry point. This passes the input line to the standard BASIC tokenizer and executor for processing. The BASIC interpreter will tokenize the input, store it as a program line if it has a line number, or execute it immediately if it is a direct statement. [EXIT → BASIC command executor]
5453H – DI/DU Parameter Parser
This handler parses the parameters for the DI (Delete and Insert) and DU (Duplicate) commands. The syntax is: DI aaaaa,bbbbb or DU aaaaa,bbbbb (or DI .,bbbbb / DU .,bbbbb where period means "current line"). The code parses the source line number (aaaaa), the comma separator, and the destination line number (bbbbb), validates both, then performs the line move/copy operation. The flag byte's low bits distinguish DI (delete original) from DU (keep original).
5453
LD (54A1H),A 32 A1 54
Store Register A (the flag byte from the keyword table) to memory location 54A1H. [SELF-MODIFYING CODE] This overwrites the operand of the LD A,00H instruction at 54A0H, so that when the DI/DU execution code reads back this value, it can distinguish between DI (delete) and DU (duplicate) modes.
5456
RST 10H D7
Call RST 10H to fetch the next non-space character from the input at HL. The CARRY flag is set if the character is a digit.
5457
If the CARRY FLAG is set (the character is a digit — the source line number starts here), JUMP forward to 5464H to parse the source line number. [DIGIT → parse source line number]
5459
CP 2EH FE 2E
Compare Register A against 2EH (period). A period means "use the current line" (the last line listed, edited, or deleted).
545B
If the NZ FLAG is set (the character is neither a digit nor a period), JUMP back to 544DH to restore registers and pass to the BASIC executor. [UNRECOGNIZED → BASIC executor]
545D
LD BC,(40ECH) ED 4B EC 40
Load Register Pair BC with the 2-byte value at 40ECH, the current BASIC line number (the most recently listed/edited/deleted line). BC now holds the source line number for the DI/DU operation using period notation.
5461
RST 10H D7
Call RST 10H to fetch the next non-space character (should be a comma following the period).
5462
JUMP forward to 5469H to check for the required comma separator. [PERIOD PATH → check comma]
5464
GOSUB to ROM routine at 1E5AH to convert the ASCII decimal string at HL to a 16-bit integer in DE. On return: DE holds the parsed source line number, A holds the next character.
5467
LD B,D 42
Copy the high byte of the source line number from D into B.
5468
LD C,E 4B
Copy the low byte of the source line number from E into C. BC now holds the source line number.
5469
CP 2CH FE 2C
Compare Register A (the character after the source line number) against 2CH (comma). DI/DU requires a comma between the source and destination line numbers.
546B
If the NZ FLAG is set (the character is not a comma — missing separator), JUMP back to 544DH. [MISSING COMMA → BASIC executor]
546D
RST 10H D7
Call RST 10H to fetch the next non-space character after the comma (the start of the destination line number).
546E
If the NO CARRY FLAG is set (the character is NOT a digit — the destination line number must start with a digit), JUMP back to 544DH. [NON-DIGIT DESTINATION → BASIC executor]
5470
GOSUB to ROM routine at 1E5AH to parse the destination line number. On return: DE holds the destination line number, A holds the next character.
5473
CP 0DH FE 0D
Compare Register A (the character after the destination line number) against 0DH (carriage return). The command must end with CR — no additional parameters are allowed.
5475
If the NZ FLAG is set (the character after the destination line number is not CR — extra characters on the line), JUMP back to 544DH. [EXTRA CHARS → BASIC executor]
Both parameters have been parsed successfully: BC = source line number, DE = destination line number. Now clean up the stack (6 POPs to remove the saved registers from 53C5H–53CBH and earlier pushes) and execute the DI/DU operation.
5477
POP AF F1
Discard a saved register pair from the stack (stack cleanup, iteration 1 of 6).
5478
POP AF F1
Discard a saved register pair from the stack (stack cleanup, iteration 2 of 6).
5479
POP AF F1
Discard a saved register pair from the stack (stack cleanup, iteration 3 of 6).
547A
POP AF F1
Discard a saved register pair from the stack (stack cleanup, iteration 4 of 6).
547B
POP AF F1
Discard a saved register pair from the stack (stack cleanup, iteration 5 of 6).
547C
POP AF F1
Discard a saved register pair from the stack (stack cleanup, iteration 6 of 6). The stack is now clean — all saved registers from the keyword dispatcher entry have been removed.
547D
PUSH DE D5
Save Register Pair DE (the destination line number) onto the stack for later use by the line insertion routine.
547E
LD D,B 50
Copy Register B (high byte of source line number) into Register D.
547F
LD E,C 59
Copy Register C (low byte of source line number) into Register E. DE now holds the source line number.
5480
GOSUB to ROM routine at 1B2CH, which searches the BASIC program for the line with line number DE. On return: BC points to the found line, CARRY is set if the line was found, CARRY clear if not found.
5483
If the NO CARRY FLAG is set (the source line was NOT found in the program), JUMP to ROM routine at 1ED9H, the "Undefined Line Number" error handler. [SOURCE LINE NOT FOUND → ?UL ERROR]
The source line was found. BC points to it. Now copy the source line's tokenized text into the line input buffer (40A7H), then call the ROM line insertion routine to insert it at the destination line number.
5486
LD DE,(40A7H) ED 5B A7 40
Load Register Pair DE with the line input buffer address from 40A7H. DE points to the destination buffer where the source line's text will be copied.
548A
LD H,B 60
Copy the high byte of the source line address from B into H.
548B
LD L,C 69
Copy the low byte of the source line address from C into L. HL now points to the source line in the BASIC program.
548C
DEC DE 1B
DECrement DE by 1. This adjusts the buffer pointer to leave room for the line number bytes that the ROM insertion routine expects at the start of the buffer.
548D
DEC DE 1B
DECrement DE by 1 again. DE now points 2 bytes before the buffer start, creating space for the 2-byte destination line number.
548E
PUSH DE D5
Save Register Pair DE (the adjusted buffer pointer) onto the stack.
548F
PUSH BC C5
Save Register Pair BC (the source line address) onto the stack.
5490
LD BC,0004H 01 04 00
Load Register Pair BC with 0004H (decimal 4). This is the offset from the start of the line to the first byte of tokenized text: 2 bytes for the link pointer + 2 bytes for the line number = 4 bytes of header.
5493
ADD HL,BC 09
ADD BC (4) to HL (source line address). HL now points to the first byte of the tokenized BASIC text, past the 4-byte line header.
LOOP START
Copy the tokenized text from the source line to the buffer. Each byte is copied until a 00H terminator is found. BC is incremented to track the total byte count.
5494
LD A,(HL) 7E
Fetch the next byte of tokenized text from the source line at (HL) into Register A.
5495
OR A B7
OR Register A with itself to test for 00H (the line terminator). The Z FLAG is set if the byte is 00H.
5496
LD (DE),A 12
Store the byte from Register A to the destination buffer at (DE). The byte is copied regardless of whether it is 00H (the terminator is also copied).
5497
INC HL 23
INCrement HL by 1 to advance to the next source byte.
5498
INC DE 13
INCrement DE by 1 to advance to the next destination position.
5499
INC BC 03
INCrement BC by 1 to count the number of bytes copied.
549A
If the NZ FLAG is set (the byte was not 00H — more text to copy), JUMP back to 5494H to copy the next byte. [LOOP — copy next byte]
LOOP END
The source line text has been copied to the buffer. DE now holds the total size (BC was counting from 0004H, and DE = BC after the loop due to parallel incrementing). Now check the DI/DU flag to determine whether to delete the source line (DI) or keep it (DU).
549C
LD D,B 50
Copy Register B (high byte of byte count) into Register D.
549D
LD E,C 59
Copy Register C (low byte of byte count) into Register E. DE now holds the total size of the copied data (header + text + terminator).
549E
POP BC C1
Restore Register Pair BC from the stack (the source line address saved at 548FH).
549F
PUSH DE D5
Save Register Pair DE (the byte count) onto the stack.
54A0
LD A,00H 3E 00
Load Register A with 00H. [SELF-MODIFYING CODE TARGET] The operand at 54A1H is overwritten by the LD (54A1H),A at 5453H with the DI/DU flag byte. When 00H: DU mode (duplicate, do not delete source). When the DI flag value: DI mode (delete source).
54A2
RRCA 0F
Rotate Register A right through carry. Bit 0 of A goes into the CARRY flag. This extracts the least significant bit of the DI/DU flag to determine the mode.
54A3
DU MODE → skip delete
If the NO CARRY FLAG is set (bit 0 was 0 — DU mode, keep the source line), JUMP forward to 54ABH to skip the deletion.
DI mode: delete the source line before inserting at the destination. Call ROM routines to remove the original line from the program.
54A5
GOSUB to ROM routine at 2BE4H, which deletes the BASIC program line pointed to by BC. This removes the source line from the program text and closes the gap by shifting subsequent lines upward in memory.
54A8
GOSUB to ROM routine at 1AF8H, which relinks the BASIC program line chain after the deletion. This updates the link pointers of the remaining lines to maintain the linked list integrity.
54AB
POP BC C1
Restore Register Pair BC from the stack (the byte count saved at 549FH).
54AC
POP HL E1
Restore Register Pair HL from the stack (the adjusted buffer pointer saved at 548EH). HL points to the buffer containing the copied line text.
54AD
POP DE D1
Restore Register Pair DE from the stack (the destination line number saved at 547DH).
54AE
DEC HL 2B
DECrement HL by 1. This adjusts the buffer pointer to align with the format expected by the ROM line insertion routine at 1AA7H.
54AF
EXIT — insert line and return to BASIC
JUMP to ROM routine at 1AA7H, the BASIC line insertion routine. On entry: DE holds the destination line number, HL points to the tokenized line text in the buffer, BC holds the text length. This routine inserts the line into the BASIC program at the correct position (sorted by line number), updating the linked list.
54B2H – Keyword Lookup Table (Data)
This is the keyword lookup table used by the keyword dispatcher at 53DAH. Each entry consists of the ASCII characters of the keyword, followed by a flag/terminator byte with bit 7 set, followed by a 2-byte handler address (low byte first). The flag byte's lower bits encode additional information: bit 6 set indicates an overlay-style command (RENEW, RENUM, REF) that stores the handler address and fills the buffer; bit 6 clear indicates a line-manipulation command. Bit 5 set indicates DI/DU mode. The table is terminated by a 00H byte. The disassembler misinterprets all bytes in this table as Z80 instructions, but they are pure data.
Keyword Table Entries (54B2H–54C5H)
Each entry format: [ASCII chars] [flag byte with bit 7 set] [handler address low] [handler address high]
54B2
DEFM "RENEW" / C0H / 01H,01H 52 45 4E 45 57 C0 01 01
Renew
Keyword "RENEW" (5 chars). Flag byte C0H: bit 7 set (terminator), bit 6 set (overlay command). Handler address: 0101H (ROM recovery routine). RENEW recovers a BASIC program after the NEW command by restoring the link pointers.
54BA
DEFM "RENUM" / C0H / 4FH,01H 52 45 4E 55 4D C0 4F 01
Renum
Keyword "RENUM" (5 chars). Flag byte C0H: bit 7 set (terminator), bit 6 set (overlay command). Handler address: 014FH (ROM routine that loads and executes SYS11, the RENUM overlay). RENUM renumbers the BASIC program lines.
54C2
DEFM "REF" / C0H / 2EH,01H 52 45 46 C0 2E 01
Ref
Keyword "REF" (3 chars). Flag byte C0H: bit 7 set (terminator), bit 6 set (overlay command). Handler address: 012EH (ROM routine that loads and executes SYS12, the REF overlay). REF cross-references variables and line numbers.
Extended Command Table (54C8H–54E3H)
The entries below use a different format with the last ASCII character having bit 7 set as the terminator (combined flag+char), followed by additional parameter bytes and handler addresses. The first byte at 54C6H (2EH) and 54C7H (01H) serve as a spacing or prefix for the extended entries.
54C6
DEFB 2EH,01H 2E 01
Prefix bytes for the extended command table. 2EH may serve as a period-notation flag, and 01H is a parameter count or offset value.
54C8
DEFM "DI" / A1H / 00H,00H 44 49 A1 00 00
Di
Keyword "DI" (2 chars: D=44H, I=49H). Flag/terminator A1H: bit 7 set, bit 5 set (DI/DU mode). Handler address: 0000H. DI deletes a line and inserts it at a new line number.
54CD
DEFM "DU" / A0H / 00H,00H 44 55 A0 00 00
Du
Keyword "DU" (2 chars: D=44H, U=55H). Flag/terminator A0H: bit 7 set, bit 5 set (DI/DU mode). Handler address: 0000H. DU duplicates a line at a new line number without deleting the original.
54D2
DEFM "A" / 80H / F5H,54H 41 80 F5 54
Auto
Keyword "A" (single char match: A=41H). Flag/terminator 80H: bit 7 set. Handler address: 54F5H (but note: the 'A' alone would match any keyword starting with 'A' — the actual match logic uses the full keyword from the extended table entries that follow). Handler 54F5H is within the AUTO handler area.
54D6
DEFM "D" / 80H / EEH,54H 44 80 EE 54
Delete Prefix
Single character "D" with flag 80H. Handler address: 54EEH. This serves as a prefix dispatcher — the "D" matches DI, DU, and DELETE, with further disambiguation in the handler.
54DA
DEFM "E" / 80H / E9H,54H 45 80 E9 54
Edit Prefix
Single character "E" with flag 80H. Handler address: 54E9H. Matches EDIT command.
54DE
DEFM "L" / 80H / E3H,54H 4C 80 E3 54
List Prefix
Single character "L" with flag 80H. Handler address: 54E3H. Matches LIST command.
54E2
DEFB 00H 00
End of Table
00H sentinel byte marking the end of the keyword lookup table. When the scanner reaches this byte, the keyword search has failed.
Handler Parameter Data (54E3H–54F9H)
The following bytes are parameter data referenced by the handler addresses in the extended command table. Each handler address points into this area, where the first byte is a parameter value read by LD A,(BC) at 542EH, followed by additional command-specific data.
54E3
DEFB 04H 04
List Handler Parameter
Parameter value 04H for the LIST command. This is the "screen lines per page" or similar display parameter read at 542EH.
54E4
DEFM "LIST" / 0DH 4C 49 53 54 0D
List Command Text
ASCII text "LIST" followed by 0DH (carriage return). This is the command string that is fed to the BASIC interpreter when the 'L' prefix matches, causing the standard BASIC LIST command to execute.
54E9
DEFB 04H 04
Edit Handler Parameter
Parameter value 04H for the EDIT command.
54EA
DEFM "EDIT" / 06H 45 44 49 54 06
Edit Command Text
ASCII text "EDIT" followed by 06H (a control byte or sub-parameter). This is the command string for the EDIT handler.
54EF
DEFM "DELETE" / 04H 45 4C 45 54 45 04
Delete Command Text
ASCII text "ELETE" followed by 04H. Combined with the 'D' prefix at 54EFH, this forms "DELETE" + parameter byte 04H.
54F6
DEFM "AUTO" 41 55 54 4F
Auto Command Text
ASCII text "AUTO". This is the command keyword text for the AUTO command handler area.
54FAH – AUTO Command Handler
This routine implements the AUTO command for automatic line numbering during program entry. It retrieves the saved BC from 57B6H (containing any prior handler context), clears the LOAD/SAVE flag at 57B7H, then uses RST 10H to check for parameters. If no parameters are present (indicated by the INC A / JR Z sequence at 5504H–5505H producing a zero), the handler enters a loop via DJNZ to clean up and return. Otherwise, it processes the AUTO parameters (start line, increment) and initiates the auto-numbering loop through ROM routines.
54FA
PUSH HL E5
Save Register Pair HL onto the stack. HL points to the current position in the input buffer after the AUTO keyword.
54FB
LD BC,(57B6H) ED 4B B6 57
Load Register Pair BC with the 2-byte value stored at 57B6H. This retrieves the handler address or context data that was saved by the keyword dispatcher at 5404H.
54FF
XOR A AF
Set Register A to 00H and clear all flags.
5500
LD (57B7H),A 32 B7 57
Store 00H (Register A) to memory location 57B7H, clearing the LOAD/SAVE control flag. This ensures that the AUTO handler does not interfere with LOAD/SAVE operations.
5503
RST 10H D7
Call RST 10H to fetch the next non-space character from the input buffer. A holds the character, CARRY is set if it is a digit.
5504
INC A 3C
INCrement Register A by 1. If A was FFH (from RST 10H returning end-of-line), INC A produces 00H and sets the Z flag. This tests for "no parameters after AUTO."
5505
NO PARAMETERS → Default to AUTOIf the Z FLAG is set (A was FFH before INC, meaning no parameters were found after AUTO), JUMP forward to 5511H for the default AUTO behavior.
5507
POP HL E1
Restore Register Pair HL from the stack.
5508
POP BC C1
Restore Register Pair BC from the stack.
5509
POP AF F1
Restore Register Pair AF from the stack.
550A
RET C D8
Return to the caller if the CARRY flag is set. This is a conditional exit — if the calling context had CARRY set (indicating a specific operating mode), the AUTO handler returns without executing.
550B
GOSUB to 6382H, the guard flag save-and-clear routine in BASIC/CMD. This saves the current guard flag state and clears it, disabling the single-step debugger during AUTO mode execution.
550E
EXIT → BASIC recovery
JUMP to 5DB8H in BASIC/CMD. This enters the error/recovery path that handles the transition back to normal BASIC operation after the AUTO/EDIT/DI/DU command completes.
5511
DECrement Register B and JUMP back to 5507H if B is not zero. This loops to pop the remaining stack frames and clean up. B controls how many stack frames are popped.
5513
POP AF F1
Discard a saved register pair from the stack (stack cleanup 1 of 4).
5514
POP AF F1
Discard a saved register pair from the stack (stack cleanup 2 of 4).
5515
POP AF F1
Discard a saved register pair from the stack (stack cleanup 3 of 4).
5516
POP AF F1
Discard a saved register pair from the stack (stack cleanup 4 of 4).
5517
RST 10H D7
Call RST 10H to refetch the next character from the input buffer (after the stack has been cleaned).
5518
LD DE,1A25H 11 25 1A
Load Register Pair DE with 1A25H, a ROM address. This is the return address for the AUTO handler — after setting up the auto-numbering state, execution will continue at 1A25H in the ROM which is part of the BASIC line input/auto-numbering loop.
551B
PUSH DE D5
Save Register Pair DE (1A25H) onto the stack. This sets up a "return" to the ROM auto-numbering continuation point when the current handler finishes.
551C
LD A,C 79
Load Register A with Register C (the low byte of BC, which holds a command parameter or subfunction code).
551D
CP 20H FE 20
Compare Register A against 20H (decimal 32). This tests the subfunction code: values below 20H are special commands (like RENEW = 01H), while values 20H and above are standard AUTO/EDIT commands.
551F
STANDARD COMMAND → 5531H
If the NO CARRY FLAG is set (C >= 20H — this is a standard command, not a special subfunction), JUMP forward to 5531H to handle the standard AUTO/EDIT path.
The subfunction code in C is less than 20H. This is a special internal command. The code checks for specific values to determine the action.
5522
DEC A 3D
DECrement Register A by 1. If A was 01H (RENEW subfunction), DEC A produces 00H and sets the Z flag.
5523
UNRECOGNIZED SUBFUNCTION → ?SN ERROR
If the NZ FLAG is set (the subfunction is not RENEW), JUMP to ROM routine at 1997H for a syntax error. Unrecognized subfunctions are invalid.
The subfunction is RENEW (C was 01H). Execute the RENEW recovery: set the first byte of the BASIC program to FFH (which marks it as "recovered"), then call the ROM relink routine and restart BASIC.
5526
LD HL,(40A4H) 2A A4 40
Point Register Pair HL to the start of the BASIC program by loading the address from 40A4H.
5529
LD (HL),FFH 36 FF
Store FFH to the first byte of the BASIC program at (HL). FFH serves as a "program present" marker that the ROM recovery routine at 1AF8H recognizes when relinking the line chain after a NEW command.
552B
GOSUB to ROM routine at 1AF8H, the BASIC program relink routine. This walks the program text, rebuilds all link pointers, and restores the program structure after the FFH marker signals recovery is needed.
552E
EXIT — RENEW complete, restart BASIC
JUMP to ROM routine at 1B59H, which completes the BASIC initialization and enters the BASIC command loop. The RENEW operation is complete — the program has been recovered.
5531
LD DE,641EH 11 1E 64
Load Register Pair DE with 641EH, the address of the "step size 18H" routine in BASIC/CMD. This sets up the return address for the AUTO command loop — after each auto-numbered line is entered, execution returns to 641EH to advance the line number.
5534
PUSH DE D5
Save Register Pair DE (641EH) onto the stack as a return address for the AUTO command loop.
5535
RST 28H EF
Call the RST 28H restart vector, the SVC (Supervisor Call) dispatcher. The SVC function code follows immediately after this instruction. This invokes a DOS service to set up the AUTO mode state.
5536
DEFB 00H 00
SVC function code 00H (inline parameter for RST 28H). SVC function 00H performs a system initialization or state reset that prepares the DOS for AUTO mode operation.
5537H – NOP Padding
The remainder of the SYS18/SYS overlay from 5537H through 56E7H is filled with NOP instructions (00H bytes). This is unused reserved space that pads the overlay to its full allocated size within the SYS file structure. The overlay's executable code ends at 5536H (the RST 28H inline parameter).
5537–56E7
NOP × 433 00 × 433
Reserved/unused area — 433 bytes of 00H (NOP instructions) filling the remainder of the SYS18/SYS overlay space from 5537H through 56E7H. This padding ensures the overlay occupies its full allocated region without affecting other memory areas when loaded.