TRS-80 DOS - NEWDOS/80 v2.0 for the Model III - SYS11/SYS Disassembled
Page Customization
Page Index
SYS11/SYS
Other Navigation
Introduction / Summary
The handler operates in two passes over the BASIC program text, both driven by the dual-purpose byte-fetch routine at 5120H. The byte at self-modifying location 5121H selects the pass: 00H for the first pass (read-only scan) and 01H for the second pass (read-and-copy to output buffer).
First pass (5121H = 00H): The scanner walks the BASIC linked-list line by line. For each line it reads the four-byte line header (link pointer and line number) via four calls to 5120H. It then feeds every token through a 19-entry dispatch table at 4E8AH. The table routes each token to a specialised handler: quoted strings are skipped, USING and DEFSTR are skipped to end-of-statement, parenthesised argument lists (for NAME, KILL, LOAD, MERGE) are walked with a depth counter, and tokens that introduce a line-number argument (“GOTO-range” tokens, THEN, GET, PUT, CLOSE, FIELD) set a “line number found” flag at 4E81H before entering the line-number parser at 4E4CH. The parser accumulates a decimal value in DE using DE = DE × 10 + digit and records the digit count at 515EH. Every parsed line-number reference is looked up in a cross-reference table at 64A3H (128 two-byte entries, built by 5073H) using a binary search at 4EC3H followed by a linear-scan fallback at 4EEBH. When a match is found the replacement line number is written directly into the cross-reference table.
Concurrently with scanning, the first pass accumulates the maximum per-reference expansion (in decimal digits) at 5168H and counts unresolvable references at 515AH. At the end of the first pass, if any references are out of range, their source line numbers are displayed preceded by an ‘X’ marker; if a reference overflows the 65529 limit the marker is ‘S’.
Memory relocation (4FABH–4FFAH): Between passes the handler calculates how many extra bytes the renamed line numbers will require (worst-case expansion × estimated count), reserves that space, and uses LDDR to slide the BASIC program text upward in memory. The stack pointer is temporarily moved to the top of free memory during the block move to prevent overwriting the stack. After relocation the 128 entries in the cross-reference table at 64A3H are each incremented by the relocation delta.
Second pass (5121H = 01H): The byte-fetch routine at 5120H now copies each byte it reads into the output buffer (tracked by the self-modifying BC operand at 4EF6H) as well as returning it to the scanner. Line-number references are replaced in-place: the replacement value from the cross-reference table is formatted as a decimal string by 5153H/5D00H and spliced into the output stream. After the second pass, two further block moves (LDDR then LDIR) compact the program back to its original start address, and a final walk at 5050H rebuilds every line’s forward link pointer. The handler then displays DONE and re-enters BASIC via 1AE9H.
If at any stage the computed memory requirement exceeds available free memory the handler aborts with “Not Enough Memory” (error 0CH). If the program text is damaged during a second-pass block move the handler aborts with “FATAL ERROR. TEXT NOW BAD”.
SYS11 — Variables and Self-Modifying Code
RAM locations written at runtime, and operand bytes within SYS11 that are overwritten by the program itself during execution
| Address | Name | Description |
|---|---|---|
| 4D4CH | Cross-Reference Table Pointer | Two-byte LE operand of LD HL,nnnnH at 4D4BH. Initialized to 64A3H (start of the cross-reference table). Written by 4D65H (advance to next entry) and 4FEAH (reset for second pass). Read implicitly each time 4D4BH executes. |
| 4DE4H | Token Context Flag | One-byte operand of LD A,nnH at 4DE3H. Written 00H by 4DA8H (no line-number context) and 01H by 4DC3H (PUT/CLOSE context active). Read by the FIELD handler at 4DC5H and by 4DE3H. Controls whether comma-separated arguments following PUT, CLOSE, and FIELD are treated as line-number references. |
| 4DEDH | Current Line Number | Two-byte LE operand of LD DE,nnnnH at 4DECH. Written by 4D78H from the line header read (four calls to 5120H). Read by 4DECH when displaying the error line number. Holds the BASIC line number of the line currently being scanned, used in error output. |
| 4E81H | Line Number Found Flag | One-byte operand of OR nnH at 4E80H. Written 00H by 4DA4H (clear at start of each statement) and 01H by 4DD1H (GET handler) and 4DCDH (FIELD handler). Read by 4E80H: when 00H the OR produces Z (no line-number context); when 01H it produces NZ (a line-number reference is expected). |
| 4EF6H | Output Position (BC Copy) | Two-byte LE operand of LD BC,nnnnH at 4EF5H. Written by 4D34H (position store at start of each line) and 5007H (updated after each block copy segment). Read by 4EF5H. Tracks the current write position in the output buffer during the second pass. |
| 4F01H | Current Line Pointer | Two-byte LE operand of LD HL,nnnnH at 4F00H. Written by 4D38H (stored from HL at the start of each line). Read by 4F00H in the linear-scan fallback at 4EEBH. Holds the address of the start of the BASIC line currently being scanned. |
| 4FA6H | Error Header Printed Flag | One-byte operand of LD A,nnH at 4FA5H, also accessed directly via HL=4FA6H with BIT 0,(HL) at 4F61H and SET 0,(HL) at 4F65H. Initialized 00H; set to 01H the first time an error line is displayed. Controls whether the “ERROR LINES” header has been printed. |
| 5014H | Block-Copy Source Address | Two-byte LE operand of LD HL,nnnnH at 5013H. Written by 507BH (from binary search result). Read by 5013H at the start of each second-pass block-copy segment. Holds the address of the next source byte to be copied into the output buffer. |
| 5035H | Range-Start Destination (Reverse Copy) | Two-byte LE operand of LD DE,nnnnH at 5034H. Written by 50CAH (insertion point extracted from BASIC line scan). Read by 5034H in the final LDDR at 502FH. Holds the destination address for the reverse block move that compacts the output back to the program start area. |
| 50C0H | End Boundary | Two-byte LE operand of LD DE,nnnnH at 50BFH. Written by 5087H (from binary search for end of renumber range). Read by 50BFH. Holds the address of the last byte of the renumber range within the BASIC program text. |
| 50C8H | Insertion Point | Two-byte LE operand of LD DE,nnnnH at 50C7H. Written by 50AFH (from linear scan of BASIC lines). Read by 50C7H. Holds the address within the BASIC program where the renumbered text is to be written back. |
| 50F2H | Block Size (Expansion Reserve) | Two-byte LE operand of LD DE,nnnnH at 50F1H. Written by 50CDH (computed from maximum expansion × line count). Read by 50F1H in the memory-size calculator at 50F9H. Holds the number of extra bytes to reserve above the existing program for worst-case line-number expansion. |
| 50F7H | Memory Size Result | Two-byte LE operand of LD DE,nnnnH at 50F6H. Written by 5117H (result of free-memory fit loop). Read by 50F6H. Holds the computed value that is compared against available memory to determine whether enough space exists for the relocation. |
| 5121H | Pass-Select / Copy-Enable Flag | One-byte operand of LD A,nnH at 5120H. Written 01H by 4FDBH when the second pass is activated. Read by 4D42H, 4F44H, 4F57H, 4EEFH, and 50DCH to distinguish first pass from second pass; read by 5120H itself to decide whether to copy the fetched byte to the output buffer. 00H = first pass (scan only); 01H = second pass (scan and copy). |
| 515AH | Error Count Accumulator | Two-byte LE operand of LD HL,nnnnH at 5159H. Initialized 0000H by 4D30H; incremented by 5163H each time a line-number reference cannot be resolved. Read by 5159H. Counts the total number of out-of-range references found during the first pass. |
| 515EH | Digit Count | Two-byte LE operand of LD DE,nnnnH at 515DH. Written by 4E73H from the line-number parser after each reference is parsed. Read by 515DH. Holds the number of decimal digits in the most recently parsed line-number reference, used to calculate expansion or contraction relative to the replacement value’s digit count. |
| 5168H | Maximum Expansion Size | Two-byte LE operand of LD DE,nnnnH at 5167H. Updated by 516CH whenever a new maximum is found. Read by 4FB7H and 5167H. Tracks the worst-case increase in bytes across all line-number references in the program, used by the memory-reservation calculation at 50F9H. |
Major Routine Reference
Functional summary of every named entry point in SYS11, in address order
| Address | Name | Description |
|---|---|---|
| 4D0CH | Renum Entry Point | Command entry from NEWDOS/80. Stores the caller-supplied DE (new start line) and HL (first line of range) parameters into the BASIC program text, counts lines in the renumber range via the loop at 4D16H, then falls through to 4D25H. |
| 4D25H | Initialize Renumber Variables | Calls 5073H to validate the range and build the cross-reference table at 64A3H. Loads HL from the BASIC program start pointer at 40A4H, copies it to BC, clears the error-count self-mod at 515AH, and falls into the main scanner loop at 4D34H. |
| 4D34H | Position Store + Next Line | Saves the current BC (output position) to self-mod at 4EF6H and the current HL (line address) to self-mod at 4F01H, then falls into the main line scanner at 4D3BH. |
| 4D3BH | Main Line Scanner | Reads the two-byte link pointer at (HL). If zero, the program end has been reached; jumps to 4F97H. Otherwise, if the second-pass flag at 5121H is set, calls the cross-reference fixup at 4D48H to update the link field. Then falls to 4D6AH to read the line header. |
| 4D48H | Cross-Reference Address Fixup | Searches the cross-reference table at 64A3H (self-mod pointer at 4D4CH) for the current line address DE. When found, overwrites the table entry with the replacement BC value and advances the self-mod pointer. Called only during the second pass. |
| 4D6AH | Read Line Header | Calls 5120H four times to fetch the two-byte link pointer and two-byte line number, storing the line number in DE and then to self-mod at 4DEDH. Jumps to 4DA3H to begin statement-level scanning. |
| 4D7EH | Using / Defstr Skip | Fetches bytes via 5120H until a non-NZ result (end-of-statement byte 00H) is found, then jumps to 4D34H for the next line. Used for USING and DEFSTR tokens that take no line-number arguments. |
| 4D85H | Quoted String Skip | Saves the return address 4DADH on the stack, then calls the quote-match subroutine at 4D89H. On return, execution falls into the main dispatch re-entry at 4DADH, effectively resuming the token dispatch loop after the closing quote. |
| 4D89H | Quote Match Subroutine | Saves the opening quote character (22H) in E. Calls 5120H repeatedly until the same byte is returned (closing quote found) or until a 00H (end-of-line) terminates the scan. Returns to the caller when the string boundary is located. |
| 4D95H | General Statement Scanner | Checks the current byte: if 22H (double-quote), calls the quote-match subroutine at 4D89H; if 3AH (colon), exits to 4D34H for the next statement; otherwise fetches the next byte and loops. This is the fallback scanner for tokens with no line-number arguments. |
| 4D9AH | Goto-Range Statement Scanner | Fetches a byte via 5120H. If 00H or 3AH (end of statement/line), returns to 4D34H. Otherwise falls into the general statement scanner at 4D95H. Entry point for tokens in the GOTO range of the dispatch table. |
| 4DA3H | Token Dispatch Init | Clears the line-number-found flag at 4E81H and the token-context flag at 4DE4H (both to 00H), then falls into the dispatch fetch-and-lookup sequence at 4DADH. |
| 4DADH | Byte Fetch + Dispatch Entry | Calls 5120H to read the next byte, then falls into the dispatch table lookup at 4DB0H. |
| 4DB0H | Dispatch Table Lookup | Saves HL, loads HL with the base of the 19-entry dispatch table at 4E8AH. Reads each three-byte entry (handler address + threshold token), compares the current token A against the threshold: less-than skips via JR C back to 4DACH; equal dispatches to the handler address; greater advances to the next entry. |
| 4DC1H | Put / Close Handler | Loads A with 01H and jumps to 4DA8H, setting the token-context flag at 4DE4H to indicate that a PUT or CLOSE statement has been seen. This enables line-number parsing on subsequent comma-delimited arguments. |
| 4DC5H | Field Handler | Reads the token-context flag at 4DE4H. If 00H (no PUT/CLOSE context), jumps back to the dispatch loop at 4DADH. If 01H, loads A with 01H and jumps to 4DA4H to set the line-number-found flag, enabling line-number parsing for the FIELD argument list. |
| 4DCFH | Get Handler | Loads A with 01H and stores it to the line-number-found flag at 4E81H, signalling that the next numeric token should be treated as a line-number reference. Falls through to the digit-check and parse loop at 4DD4H. |
| 4DD4H | Line Number Check and Parse Loop | Calls the digit-check at 513BH. If no digit found, re-enters the dispatch loop at 4DB0H. If a digit is found, calls the line-number parser at 4E4CH, then skips whitespace via 511DH. If a comma follows, loops to parse the next argument; otherwise re-enters dispatch. |
| 4DE8H | Error Line Number Output Setup | Pushes AF, pops it (no-op pair preserving AF), loads A with 58H (‘X’), loads DE from self-mod at 4DEDH (current line number), and calls the error-output routine at 4F54H. Then decrements BC and HL and enters the EOS-check loop at 4E40H to skip remaining bytes on the line. |
| 4DF9H | Line Number Overflow Error | Pops HL, BC, and AF from the stack (unwinding the nested call chain), loads A with 53H (‘S’), and jumps to 4DECH to display the error using the self-mod DE (current line number) and the ‘S’ overflow marker. |
| 4E00H | Then Handler | Calls the line-number parser at 4E4CH to read the THEN target, then calls the digit-check at 513BH. If a digit follows (another line number in a multi-target THEN), loops. If the next token is in the range D2H–D6H (function tokens), skips it and loops. Otherwise re-enters dispatch at 4DB0H. |
| 4E12H | General Token Handler | Calls the digit-check at 513BH. If a digit is present, parses the line number via 4E4CH and skips whitespace via 511DH. Then checks for token CEH (ON ERROR GOTO); if found, jumps to the THEN handler at 4DD4H. Otherwise re-enters dispatch. |
| 4E23H | Name / Kill / Load / Merge Parenthesis Handler | Initialises a paren-depth counter in D (02H) and a comma counter in E (FFH). Fetches bytes via 4E40H, tracking open-paren depth increments, close-paren decrements, and commas. Exits when the depth returns to 01H and a comma is seen at the outermost level, then falls to the line-number check at 4DD4H. |
| 4E40H | Byte Fetch with EOS Check | Calls 5120H. If A is 00H or 3AH (end of statement), discards the top-of-stack return address and jumps to 4E10H (re-enter dispatch). Otherwise returns to the caller with the byte in A. |
| 4E4CH | Line Number Parser | Calls the digit-check at 513BH; if no digit, jumps to 4DE9H (error). Pushes BC. Accumulates a decimal value in DE using DE = DE × 10 + (A−30H), incrementing a digit counter in BC, until a non-digit is read. Overflow beyond 1998H (6552) jumps to the overflow error at 4DF9H. On completion, stores the digit count to 515EH, then calls 5153H to perform the cross-reference lookup and replacement. |
| 4E8AH | Token Dispatch Table | 19-entry data table, 57 bytes (4E8AH–4EC2H). Each entry is a two-byte handler address (little-endian) followed by a one-byte token threshold. The dispatch loop at 4DB0H walks this table to route each BASIC token to the correct handler. See the token dispatch table in the continuation instructions for the full entry listing. |
| 4EC3H | Binary Search for Line Number | Searches the 128-entry cross-reference table at 64A3H for the line number in DE, using a halving algorithm. Computes the midpoint, reads the two-byte entry, compares with DE, and halves the search range. When the range collapses, falls through to the linear-scan fallback at 4EEBH. |
| 4EEBH | Linear Scan Fallback | After the binary search converges, walks BASIC lines sequentially from the self-mod line pointer at 4F01H (loaded by 4F00H), comparing each line number against DE until a match or end-of-program is found. On match, falls to 4F1CH to extract the line address into DE. |
| 4F00H | Second-Pass Position Match | Entry point that loads HL from the self-mod operand at 4F01H (the current line’s start address). Falls immediately into the linear-scan loop body at 4F03H. |
| 4F03H | Linear Scan Loop Body | Reads the two-byte forward link from (HL), tests for end-of-program (00H link), reads the two-byte line number, compares against DE, and either loops or falls to the match exit at 4F1CH. |
| 4F18H | End-of-Program Handler | Sets the carry flag and extracts the end-of-program boundary address into DE from HL. Used when the binary/linear search reaches the program end without finding the target line. |
| 4F1CH | Search Exit | Extracts the matched line’s address from HL into DE, clearing the carry flag. Returns to the line-number parser at 4E4CH with DE = address of the matched BASIC line. |
| 4F22H | Line Number Replacement | Performs a binary search for the parsed DE line number in the cross-reference table, checks that it is within the renumber range, then calls 5159H (error-count accumulator) and 5153H (number-string copy) to splice the replacement number into the output. Out-of-range references jump to the error output at 4DE8H. |
| 4F43H | Output Unchanged Line Number | Dispatches on the pass-select flag at 5121H: during the first pass calls 5153H to record the number without replacement; during the second pass calls 5156H to copy the original digit string verbatim into the output buffer. |
| 4F54H | Error Line Number Output Routine | Entry from 4DE8H with the error-marker character in A. Calls the screen-position check at 4F70H, displays the marker character, a space, and the line number in DE using 5D00H/5D3DH. Increments the error count at 515AH. |
| 4F57H | Pass Check + Error Output | Reads the pass-select flag at 5121H. During the first pass, continues to the screen-position check at 4F70H. During the second pass, calls the fatal-error handler at 50E4H (an error on the second pass means the text is irreparably damaged). |
| 4F70H | Screen Position Check + Error Display | Reads the screen cursor position from 4020H. If the column is past 60 (3CH), outputs a carriage return via 5D52H and resets the column. Then checks whether the “ERROR LINES” header at 518CH has been printed (flag at 4FA6H); if not, prints it and sets the flag. |
| 4F97H | End-of-Scan Handler | Reached when the forward link pointer is 00H (end of BASIC program). During the first pass, falls to the memory-relocation setup at 4FABH. During the second pass, falls to the second-pass completion handler at 4FFDH. |
| 4FABH | Memory Relocation | Calculates the size of the BASIC program (end minus start), calls 50F1H to compute the expansion reserve, checks memory overflow, then uses LDDR to move the entire program text upward by the expansion amount. Temporarily relocates SP to the top of free memory during the block move to protect the stack. |
| 4FC1H | Expansion Padding | Adds a 256-byte safety margin to the expansion reserve before the memory-overflow check, ensuring that rounding errors in the digit-count arithmetic do not cause the output to overrun the reserved area. |
| 4FD1H | Memory Overflow Check | Compares the computed post-relocation top address against the BASIC memory ceiling at 40B1H. If the relocated program would exceed available memory, jumps to the “Not Enough Memory” error at 50EDH. |
| 4FDBH | Second Pass Activation | Writes 01H to the pass-select self-mod byte at 5121H, switching the byte-fetch routine at 5120H into copy mode. Then jumps to 4D2DH to restart the main scanner loop for the second pass. |
| 4FEDH | Cross-Reference Table Update Loop | Walks all 128 two-byte entries in the cross-reference table at 64A3H, adding the relocation delta (in DE) to each entry. This adjusts every recorded BASIC line address to reflect the program’s new position in memory after the LDDR block move. |
| 4FFAH | Restart Main Scan | Jumps to 4D2DH to begin the second pass. The BASIC program pointer at 40A4H is re-read and BC/HL are re-initialised from the (now relocated) program start. |
| 4FFDH | Second-Pass Completion Handler | After the second-pass scan finishes, calculates the size of the renumbered output, performs a final LDDR (reverse) block move to bring the output back to the original program start address, then an LDIR (forward) move to align the remainder. Falls through to the re-link routine at 5050H. |
| 5013H | Block Copy Loop | Self-modifying loop used during the second pass. Loads HL from self-mod at 5014H (source address), calls 5120H-based copy for each segment between line-number replacements, and updates the self-mod pointer after each segment. Recalculates the remaining byte count before calling the LDIR at 502FH. |
| 502FH | Final Block Copy | Executes the final LDDR (decrementing) block move of the completed second-pass output, followed immediately by an LDIR (incrementing) block move to copy any trailing program bytes that were not part of the renumber range. |
| 5050H | Re-link Basic Lines | Walks the BASIC program from its start address at 40A4H, rewriting each line’s two-byte forward link pointer to point to the start of the next line. Continues until a 00H link is found (end of program), then updates the BASIC memory-top pointer at 40B1H. |
| 5063H | Display “Done” + Exit | Calls the message-display routine at 5147H with the pointer to the “DONE” string at 5198H, outputs a carriage return via 5D52H, then jumps to 1AE9H (ROM BASIC warm-restart) to return control to BASIC. |
| 5073H | Range Calculation and Error Checking | Performs two binary searches in the BASIC program to locate the first and last lines of the renumber range. Validates that the range is non-empty and that the new line numbers do not overlap with existing lines outside the range. Fills the cross-reference table at 64A3H with the addresses of all line link fields within the range. Errors jump to 50D9H. |
| 5092H | Insertion Point Scan | Walks the BASIC linked list from the program start, comparing each line number against the range-start target. Stops at the first line whose number meets or exceeds the target. Falls through to 50ACH to store the result. |
| 50ACH | Insertion Point Extract | Stores the current HL (address of the located insertion-point line) to the self-mod operand at 50C8H. Returns to the range-calculation routine at 5073H. |
| 50D9H | Range Error Handler | Issues NEWDOS/80 error code 8CH. During the first pass this exits cleanly via 4409H. During the second pass this jumps to the fatal-error handler at 50E4H because the program text is partially modified. |
| 50E4H | Fatal Error Handler | Displays the message “FATAL ERROR. TEXT NOW BAD” from 5170H via 5147H, then exits via 4409H. Called when an unrecoverable error is detected during the second pass, after the program text has already been partially rewritten. |
| 50EDH | “Not Enough Memory” Error | Issues NEWDOS/80 error code 0CH (insufficient memory) and exits via 4409H. Reached from the memory-overflow check at 4FD1H when the relocated program would exceed the BASIC memory ceiling. |
| 50F1H | Memory Size Calculator Entry 1 | Loads DE from the self-mod operand at 50F2H (the expansion reserve in bytes), then falls into entry 2 at 50F6H. |
| 50F6H | Memory Size Calculator Entry 2 | Loads DE from the self-mod operand at 50F7H (the previously computed memory-size result), then falls into the calculator body at 50F9H. |
| 50F9H | Memory Size Calculator Body | Computes the amount of free memory between the current program end and the BASIC memory ceiling at 40B1H. Subtracts the expansion reserve. If the result is negative (insufficient memory), sets the carry flag, which the caller tests to branch to the overflow error. |
| 511DH | Whitespace Skip | Calls the raw-whitespace-skip routine at 512EH, then returns. A wrapper entry point used in contexts where the caller needs whitespace consumed before the next significant byte is examined. |
| 5120H | Dual-Purpose Byte Fetch | Reads the next byte from (HL) and increments HL. The self-modifying byte at 5121H selects the mode: 00H returns the byte in A with NZ set for non-zero bytes (first-pass, read-only); 01H additionally writes the byte to (BC) and increments BC (second-pass, copy mode). Sets Z if the byte is 00H. |
| 512BH | Whitespace Consume Loop | Reads the byte at (HL), checks it against the whitespace set (20H, 09H, 0AH, 0BH) using the raw-skip at 512EH, and loops if whitespace is found. Returns with the first non-whitespace byte in A. |
| 512EH | Raw Whitespace Skip | Compares A against 20H (space), 09H (tab), 0AH (line feed), and 0BH (vertical tab). If a match is found, calls 5120H to advance past the whitespace byte and returns. If no match, returns without consuming the byte. |
| 513BH | Digit Check | Calls the whitespace-skip at 512EH to skip any leading whitespace, then tests whether A is in the range 30H–39H (ASCII digits ‘0’–‘9’). Returns with the carry flag set if A is a digit, clear otherwise. |
| 5147H | Message Display | Displays a 03H-terminated string pointed to by HL, calling the ROM character-output routine at 0033H for each byte until the 03H terminator is reached. |
| 5153H | Number Output First Pass | Loads BC with 5D2AH (the BASIC number string buffer) and calls the number-string copy routine at 5D00H to convert the line number in DE to a decimal ASCII string. Then falls to 5156H. |
| 5156H | Number-String Copy | Calls 5D00H to copy the formatted decimal string, then calls 516CH to compare the new digit count against the running maximum at 5168H and update if a new maximum is found. |
| 5159H | Error Count Accumulator | Loads HL from the self-mod operand at 515AH (the running error count), increments it, and writes the new count back to 515AH. Called each time an unresolvable reference is encountered. |
| 5170H | String: “Fatal Error. Text Now Bad” | 03H-terminated ASCII message used by the fatal-error handler at 50E4H. Occupies 5170H–518BH. |
| 518CH | String: “Error Lines” | 03H-terminated ASCII message printed as the header before the first error line number is displayed. Occupies 518CH–5197H. |
| 5198H | String: “Done” | 03H-terminated ASCII message displayed on successful completion. Occupies 5198H–519CH. |
| 519DH | 16-Bit Comparison Utility | Subtracts BC from HL using SBC HL,BC (with carry cleared first), then calls RST 18H to set the standard comparison flags (carry if HL < BC, zero if HL = BC). Returns with flags set for a signed 16-bit comparison of the original HL vs. BC. |
| 51A2H | Nop Padding | 82 × NOP (00H) bytes filling 51A2H–51F3H. Unused space at the end of SYS11. |
Disassembly
4D0CH - RENUM Entry Point (Parameter Store and Line Count Loop)
RENUM Entry Point. SYS11 implements the RENUM (renumber) command for NEWDOS/80 BASIC. The entry point receives the parsed RENUM parameters in registers: HL = pointer to the BASIC program text start address (stored at 40A4H), DE = first new line number, BC = line count and increment. The code first stores these parameters into the BASIC program's line link pointers, then walks forward through the program lines, counting down the number of lines to renumber. When the count reaches zero or the program ends, the code falls through to the main renumbering pass.
LOOP START
Line-counting loop
This loop walks through the BASIC program text, following line link pointers, counting down E lines. Each BASIC line begins with a 2-byte link pointer (address of the next line), followed by a 2-byte line number, followed by the tokenized statement text, terminated by 00H.
LOOP - continue counting lines
LOOP END
4D25H - Initialize Renumber Variables
Initialize Renumber Variables. After the parameter loop completes, this section calls 5073H to calculate the line number ranges, then loads the BASIC program start address from 40A4H and initializes several self-modifying code locations that track state throughout the renumbering process. The main variables are: 515AH (error count), 4EF6H (current position in program), and 4F01H (line pointer for the current scan).
4D3BH - Main Line Scanner Loop
Main Line Scanner Loop. This is the outer loop that processes the BASIC program line by line. For each line, it checks the link pointer to detect end-of-program, then checks the cross-reference flag at 5121H (which is non-zero during the second pass when the program has been relocated). If the cross-reference flag is set, it performs the optional line address fixup. Otherwise, it falls through to the token-by-token scanning of the line's statement text, reading four bytes (link low, link high, line number low, line number high) via 5120H before entering the token dispatcher.
MAIN LOOP START
Process Each BASIC line
The line has a non-zero link pointer, so it is a valid BASIC line. Check whether the cross-reference fixup pass is active.
4D48H - Cross-Reference Address Fixup (Second Pass)
Cross-Reference Address Fixup. During the second pass (5121H is non-zero), the BASIC program text has been relocated in memory and the line link pointers need to be updated. This section searches through the cross-reference table at 64A3H (the SYS jump table area) to find entries whose old addresses match the current line's link pointer, and replaces them with the new address from BC. The search walks through the table entries comparing the stored old address (DE) against each entry, replacing matches with the current address (BC).
LOOP START
Cross-Reference Search
Both bytes match - this table entry's old address matches the current line. Replace it with the new address from BC.
LOOP END
4D6AH - Read Line Header and Enter Token Scanner
Read Line Header. This section reads the four header bytes of the current BASIC line (link pointer low, link pointer high, line number low, line number high) using the byte-fetch routine at 5120H. The line number is stored at 4DEDH as a self-modifying operand for later comparison. After reading the header, execution falls through to the main token dispatch loop at 4DA3H.
4D7EH - USING/DEFSTR Skip Handler (Token 92H-93H)
USING/DEFSTR Skip Handler. Dispatched from the token table for tokens 92H-93H (TROFF and DEFSTR). These tokens do not contain line number references, so the handler simply skips bytes until a 00H end-of-statement or 3AH colon statement separator is found, then re-enters the main scanner loop.
LOOP START
Skip until end-of-statement
LOOP END
4D85H - Quoted String Skip Handler (Token <= 22H)
Quoted String Skip Handler. Dispatched from the token table for characters up to 22H (the ASCII double-quote). When a quoted string is encountered, the handler reads bytes until the matching closing quote (22H) is found, or until end-of-statement. This prevents line number references inside string literals from being renumbered.
LOOP START
Scan for matching quote
End-of-statement (00H) reached without finding a closing quote. The string was unterminated. Discard the return address and go back to the main loop.
LOOP END
4D95H - General Statement Scanner (Token <= 88H / GOTO)
General Statement Scanner. Dispatched from the token table for tokens 3BH through 88H (which includes GOTO at 88H). This handler scans through the statement text looking for tokens that contain line number references. It checks for quoted strings (22H) and colon separators (3AH). Quoted strings are handled by calling the string skip subroutine at 4D89H. Colons cause a re-entry to the main dispatch loop. All other bytes are skipped by the byte-fetch loop.
LOOP START
Statement scan
If the NZ FLAG has been set (the character is not a colon), JUMP back to 4D95H to check for quotes and continue scanning.
4DA3H - Token Dispatch Initialization
Token Dispatch Initialization. This section initializes the token dispatch state variables and enters the dispatch table lookup. It clears the “line number found” flag at 4E81H and the “token context” flag at 4DE4H, then fetches the next byte from the BASIC text and looks it up in the dispatch table at 4E8AH. The table maps token ranges to handler addresses. If the token falls below an entry’s threshold, that entry’s handler is called; if it matches exactly, the handler is also called; if it is above the threshold, the next entry is checked.
The PUSH HL / POP HL sequence at 4DABH-4DACH is a deliberate no-operation. It serves as a JR target (4DACH) from the dispatch table scanner at 4DBAH: when a token falls below the current entry's threshold, execution jumps here to re-enter the main byte-fetch loop without dispatching.
LOOP START
Table Lookup
LOOP - continue table search
LOOP END
The token exactly matches this entry's threshold value (Z flag set). Dispatch to the handler address in DE.
4DC1H - PUT/CLOSE Handler (Tokens A0H-A1H)
PUT/CLOSE Handler. Dispatched for tokens A0H-A1H (PUT and CLOSE). These statements may be followed by line number expressions (e.g., ON ERROR GOTO context). The handler sets the “line number found” flag at 4E81H to 01H and re-enters the dispatch initialization at 4DA8H, which then proceeds to scan for line numbers in the statement's arguments.
4DC5H - FIELD Handler (Tokens 96H-9EH)
FIELD Handler. Dispatched for tokens 96H-9EH (DEFDBL through FIELD). These statements are checked for whether the token context flag at 4DE4H is already set (from a prior GOTO/GOSUB/THEN). If it is set, the code treats the content as a potential line number and routes to the line number check at 4DA4H. If not set, it sets the flag and falls through to the main dispatch at 4DADH.
4DCFH - GET Handler (Token 9FH)
GET Handler. Dispatched for token 9FH (GET). Sets the line number found flag at 4E81H to 01H and enters the line number check routine at 4DD4H. GET statements can contain file number and line number references.
4DD4H - Line Number Check (REM/GOTO/GOSUB Common Entry)
Line Number Check. This is the common entry point for tokens that may be followed by line number references (GOTO, GOSUB, THEN, RUN, RESTORE, RESUME, ON...GOTO, ON...GOSUB, etc.). It calls 513BH (digit check) to determine if the next character is a digit. If it is a digit, the code enters the line number parser at 4E4CH. If not a digit, it calls 511DH (whitespace skip) and checks for a comma separator. If a comma is found, the loop continues to look for the next potential line number.
The next character IS a digit. Parse it as a line number.
A comma was found. Check the token context flag to see if more line numbers are expected.
4DE8H - Error Line Number Output Setup
Error Line Number Output Setup. When a line number reference cannot be resolved (the target line does not exist), this section sets up the error reporting. It saves the current state, loads the error format code 58H (ASCII 'X'), and calls the line number output routine at 4F54H to display the error. After output, it continues scanning the BASIC text to find the next line number or end of statement.
LOOP START
Skip remaining tokens after error
LOOP END
Continue skipping until end-of-statement
4DF9H - Line Number Overflow Error
Line Number Overflow Error. Reached when the line number parser detects that the parsed number exceeds the maximum allowed value (65529, or 19998 in some configurations). The code unwinds the stack (three POPs to discard the parser's saved state) and falls through to output the error with format code 53H (ASCII 'S' for overflow/size error).
4E00H - THEN/Token Check with Digit Scan (Tokens B6H-C2H)
THEN/Token Check. Dispatched for tokens B6H through C2H, which includes THEN (C2H). The THEN token is significant because THEN can be followed by a line number (GOTO-like behavior). The handler calls the line number parser (4E4CH) and the digit checker (513BH) in a loop, processing line numbers found after THEN. Tokens in the range D2H-D6H are function tokens that do not contain line numbers and are re-routed to the scanner.
LOOP START
THEN line number check
LOOP
Parse next line number
The next character is not a digit. Check if it is a function token (D2H-D6H range) that should be skipped.
LOOP END
4E12H - General Line Number Token Handler (Tokens A6H-B5H)
General Line Number Token Handler. Dispatched for tokens A6H through B5H (LSET through CSAVE). These statements may optionally contain line number references. The handler calls the digit checker and, if a digit is found, parses the line number via 4E4CH and skips whitespace. It then checks for the GOTO/GOSUB token CEH to handle constructs like ON ERROR GOTO, routing to the line number check at 4DD4H if found.
4E23H - NAME/KILL Parenthesis Handler (Tokens A2H-A5H)
NAME/KILL Parenthesis Handler. Dispatched for tokens A2H through A5H (LOAD, MERGE, NAME, KILL). These statements can have parenthesized arguments that contain commas. The handler counts parentheses to correctly identify when a comma is a list separator (outside parentheses) rather than part of an argument expression. Register D counts the number of commas to expect (initialized to 02H for NAME which has two arguments), and Register E tracks parenthesis nesting depth.
LOOP START
Parenthesis scan
Nesting depth is zero (E = 00H after INC restored it). We are outside parentheses. Check if the character is a comma.
A comma was found outside parentheses. Decrement the expected comma count.
LOOP END
4E40H - Byte Fetch with End-of-Statement Check
This subroutine fetches the next byte from BASIC program text via the dual-purpose byte-fetch routine at 5120H and checks whether it is an end-of-statement marker (00H for end-of-line or 3AH for colon separator). If the byte IS an end-of-statement marker, the routine pops the caller's return address off the stack (discarding the immediate caller) and jumps to 4E10H to re-enter the dispatch table lookup, effectively abandoning the current token handler. If the byte is NOT an end-of-statement marker, it returns normally to the caller with the byte in Register A.
If the Z FLAG has been set (the fetched byte is 00H, an end-of-line marker), JUMP forward to 4E49H to pop the return address and re-enter the dispatch loop.
If execution reaches 4E49H, the fetched byte IS an end-of-statement marker (either 00H from the check at 4E43H, or 3AH from the compare at 4E46H). The routine discards its caller's return address and re-enters the dispatch loop.
4E4CH - Line Number Parser (Decimal Accumulator)
This routine parses a decimal line number from the BASIC program text. It accumulates the value digit-by-digit into Register Pair DE using the formula DE = DE × 10 + digit. Before each multiply, it checks for overflow against 1998H (decimal 6552); if DE exceeds this threshold, the next multiply-by-10 would overflow a 16-bit value, so the routine branches to the overflow error handler at 4DF9H. After the number is fully parsed, the routine stores the digit count at 515EH, checks whether the parsed number is zero, and tests the self-modifying “line number found” flag at 4E81H to determine whether this number is a line reference (requiring lookup/replacement) or just a numeric literal (to be skipped).
LOOP START - Decimal Digit Accumulation Loop
Each iteration processes one ASCII digit: it checks for overflow, multiplies DE by 10, adds the new digit, and fetches the next character. The loop continues as long as the next character is a digit.
If the CARRY FLAG has been set (DE exceeds 1998H, meaning the next multiply-by-10 would overflow), JUMP to 4DF9H, the line number overflow error handler. That routine unwinds the stack and outputs an S-type error marker.
The overflow check passed. Now multiply DE by 10 using the shift-and-add method: DE × 10 = DE × 2 × 2 + DE) × 2 = ((DE << 2) + DE) << 1. The code implements this by loading HL with DE, then computing HL = HL × 4 + DE, then HL = HL × 2.
If the CARRY FLAG has been set (RST 10H found another digit), JUMP back to 4E58H to accumulate this digit into the running total.
LOOP END - Decimal Digit Accumulation Loop
All digits have been parsed. DE holds the complete line number value. BC holds the digit count. The stack holds the updated BASIC text pointer.
Store Register Pair BC (the digit count - number of decimal digits that were parsed) to memory location 515EH, the self-modifying operand that records how many digits the parsed line number contains. This is used later during output to determine how many bytes of program text to replace.
The parsed line number is zero. Now check the self-modifying “line number found” flag at 4E81H to determine whether this zero was expected as a line number reference.
OR Register A with the immediate operand at 4E81H. The operand byte at 4E81H is a self-modifying code target: when set to 00H, this instruction is OR 00H which has no effect and the Z FLAG remains set. When set to 01H (written by the GET handler at 4DD1H or the FIELD handler at 4DCBH), this becomes OR 01H which clears the Z FLAG, signaling that a line number reference was found and needs processing.
4E8AH - Token Dispatch Table (19 Entries, 57 Bytes)
This is a data table, not executable code. It contains 19 three-byte entries used by the dispatch table lookup loop at 4DB4H. Each entry consists of a 16-bit handler address (low byte first, little-endian) followed by a 1-byte maximum token value. The scanner at 4DB4H reads each entry sequentially: if the current token in Register A is less than the max_token, the token falls below this entry’s range and is skipped via JR C,4DACH; if equal, the handler is dispatched; if greater, the next entry is checked. The table is terminated by an FFH sentinel entry that catches all remaining tokens.
Handler: 4D34H (Position Store + Next Line). Max Token: 00H (end-of-statement null byte). When the scanner encounters a 00H byte, it dispatches to 4D34H to store the current position and advance to the next BASIC line.
Handler: 4D85H (Quoted String Skip). Max Token: 22H (double-quote). When the scanner encounters a 22H byte (ASCII "), it dispatches to 4D85H to skip past the quoted string without scanning its contents for line number references.
Handler: 4DA3H (Token Dispatch Init). Max Token: 3AH (colon). Tokens/characters in the range 23H-39H (ASCII punctuation and digits that are not token codes) are skipped. When a 3AH colon (statement separator) is reached, dispatch to 4DA3H resets the context flags and begins scanning the next statement.
Handler: 4D9AH (GOTO Range Statement Scanner). Max Token: 88H (GOTO token). Tokens 3BH-87H are below the threshold and are skipped. Token 88H (GOTO) dispatches to the scanner that processes line number arguments for GOTO statements.
Handler: 4DD9H (Line Number Call). Max Token: 8DH (RETURN token). Tokens 89H-8CH (GOSUB through RESUME) are below threshold and skipped. Token 8DH (RETURN) dispatches to 4DD9H which calls the line number parser at 4E4CH for statements like RUN, RESTORE, and RESUME that take line number arguments.
Handler: 4DD4H (Line Number Check). Max Token: 8EH (REM token). Token 8EH (REM) dispatches to 4DD4H. Since REM causes the rest of the line to be treated as a comment, the digit-check at 513BH fails immediately and control falls through to skip the remainder.
Handler: 4DD9H (Line Number Call). Max Token: 91H (TRON token). Tokens 8FH-90H (STOP, ELSE) are below threshold. Token 91H (TRON) dispatches to 4DD9H for line number parsing.
Handler: 4D7EH (USING/DEFSTR Skip). Max Token: 93H (DEFSTR token). Tokens 92H (TROFF) is below threshold. Token 93H (DEFSTR) dispatches to 4D7EH which skips to the end of the statement without scanning for line numbers.
Handler: 4DD4H (Line Number Check). Max Token: 95H (DEFSNG token). Token 94H (DEFINT) is below threshold. Token 95H (DEFSNG) dispatches to the line number check handler.
Handler: 4DC5H (FIELD Handler). Max Token: 9EH (FIELD token). Tokens 96H-9DH (DEFDBL through LINE) are below threshold. Token 9EH (FIELD) dispatches to 4DC5H which checks the context flag to determine whether to parse line numbers in a comma-separated list.
Handler: 4DCFH (GET Handler). Max Token: 9FH (GET token). Token 9FH dispatches to 4DCFH which sets the line-number-found flag at 4E81H to 01H, enabling line number reference detection in subsequent parsing.
Handler: 4DC1H (PUT/CLOSE Handler). Max Token: A1H (CLOSE token). Token A0H (PUT) is below threshold. Token A1H (CLOSE) dispatches to 4DC1H which sets the token context flag and re-enters the scanner.
Handler: 4E23H (NAME/KILL Parenthesis Handler). Max Token: A4H (NAME token). Tokens A2H-A3H (LOAD, MERGE) are below threshold. Token A4H (NAME) dispatches to 4E23H which tracks parenthesis depth and comma positions for multi-argument statements.
Handler: 4E23H (NAME/KILL Parenthesis Handler). Max Token: A5H (KILL token). Token A5H dispatches to the same parenthesis handler as NAME.
Handler: 4E12H (General Token Handler). Max Token: B4H (CLOAD token). Tokens A6H-B3H (LSET through MID$) are below threshold. Token B4H (CLOAD) dispatches to 4E12H which checks for digits (ON ERROR GOTO pattern) and the CEH token (ERROR).
Handler: 4E12H (General Token Handler). Max Token: B5H (CSAVE token). Token B5H dispatches to the same general handler as CLOAD.
Handler: 4E03H (THEN post-handler). Max Token: C2H (THEN token). Tokens B6H-C1H are below threshold. Token C2H (THEN) dispatches to 4E03H which checks the next character for digits (implicit GOTO line number after THEN).
Handler: 4DD4H (Line Number Check). Max Token: CAH (TO token). Tokens C3H-C9H are below threshold. Token CAH (TO) dispatches to the line number check handler.
Handler: 4DADH (Byte Fetch + Dispatch Entry). Max Token: FFH. This is the catch-all sentinel entry. Any token with a value above CAH that has not matched a previous entry will match FFH here and dispatch to 4DADH, which simply fetches the next byte and re-enters the dispatch loop. This ensures all unrecognized tokens are consumed without error.
4EC3H - Binary Search for Line Number in Cross-Reference Table
This routine searches for a target line number (in Register Pair DE) within the cross-reference table at 64A3H. The table contains 128 two-byte entries (256 bytes total), where each entry holds the address of a BASIC line’s link field. The search uses a binary approach: it starts with an offset of 80H (128 bytes = 64 entries), halves the offset each iteration, and adjusts the table pointer up or down depending on whether the target is greater or less than the candidate. When the offset shrinks below 02H (one entry), the search switches to a linear scan of consecutive lines. The routine returns with DE holding the address of the matching line (or the insertion point), and the flags set: CARRY FLAG set if the line was not found (past end of program), Z FLAG set if an exact match was found.
LOOP START - Binary Search Loop
Each iteration: add offset to HL, dereference the table entry to get a BASIC line address, read the line number from that address, compare against the target in DE, and adjust HL accordingly.
HL now points to a BASIC line in program memory. The first two bytes at this address are the link pointer (address of the next line). The next two bytes (at HL+2 and HL+3) are the line number. First, check if this is a valid line (link pointer is not 0000H).
If the Z FLAG has been set (the link pointer is 0000H, meaning this table entry points past the end of the program), JUMP to 4EDEH to adjust the search position downward. The CARRY FLAG remains set from the SCF at 4ED3H, indicating “target is below this position”.
The link pointer is valid (non-zero). HL now points to the line number low byte. Compare this line’s number against the target in DE.
The target is less than the candidate (or past end of program). Move the table pointer back down by subtracting the current offset.
If the NO CARRY FLAG has been set (the offset is 02H or greater), JUMP back to 4EC9H for the next binary search iteration.
LOOP END - Binary Search Loop
The binary search has converged. HL points to the table entry nearest the target. Now switch to a linear scan through BASIC program lines to find the exact match.
Check the cross-reference flag at 5121H to determine whether we are on the first pass (scan only) or second pass (scan and copy). On the second pass, the program text has been relocated, so we need to compare against the output position to detect when the scan has caught up to the current write position.
Load Register A with the value at memory location 5121H, the cross-reference flag. This flag is 00H during the first pass (scan only) and 01H during the second pass (scan and copy to output buffer).
If the Z FLAG has been set (first pass, cross-reference flag is 00H), JUMP forward to 4F03H to begin the linear scan without the output-position check.
Second pass. Check if the current line pointer (HL) has caught up to the output buffer position stored at 4EF6H. If so, all remaining lines have already been processed.
Load Register Pair BC with the value at 4EF6H. The operand bytes at 4EF6H-4EF7H are a self-modifying code target, written at 4D34H and 5007H with the current output buffer position. During execution, this loads BC with the output position, not literal 0000H.
The current line address exactly matches the output buffer position. This means the scan has caught up to the write point. Load HL from the self-modifying operand at 4F01H, which holds the actual line pointer for the current position.
Load Register Pair HL with the value at 4F01H. The operand bytes at 4F01H-4F02H are a self-modifying code target, written at 4D38H with the address of the line currently being scanned. During execution, this loads HL with the actual line pointer, not literal 0000H.
LOOP START - Linear Scan Loop
Walk through consecutive BASIC lines starting from the position resolved by the binary search. For each line, check if it is the end of the program (link pointer is 0000H), then compare its line number against the target in DE.
If the Z FLAG has been set (the link pointer is 0000H, meaning end of the BASIC program), JUMP to 4F18H, the end-of-program handler.
If the NO CARRY FLAG has been set (the candidate line number is greater than or equal to the target), JUMP to 4F1CH. The search has found either an exact match (Z set) or the first line past the target (NZ set).
JUMP back to 4EEFH to repeat the linear scan with the next line. On the first pass, the cross-reference flag check at 4EEFH-4EF3H will branch directly to 4F03H. On the second pass, the output position comparison is performed first.
LOOP END - Linear Scan Loop
End-of-program path: the link pointer was 0000H. Advance HL past the null link and null line number to the body area, set carry to indicate “not found,” then extract the line address from the position just before the end marker.
4F22H - Line Number Replacement (Range Check and Output)
This routine is called when a non-zero line number has been parsed from the BASIC program text (from 4E7DH). It calls the binary search routine at 4EC3H to look up the line number in the program, then checks whether the line falls within the user-specified renumber range (stored at 4D04H-4D07H). If the line is within range, it is replaced with the new renumbered value; if outside the range, the original number is output unchanged. The routine also handles the case where the line number was not found in the program.
If the Z FLAG has been set (the binary search did not find an exact match for the line number in the program), JUMP to 4F43H to output the line number unchanged. The line number references a nonexistent line, so no renumbering is needed.
The line number was found in the program. Now check whether it falls within the user-specified renumber range. The “from” line number is stored at 4D04H-4D05H and the “to” line number is at 4D06H-4D07H. If the line is outside this range, output it unchanged.
If the Z FLAG has been set (no renumber range was specified - the entire program is being renumbered), JUMP to 4F57H. Since all lines are in range, the error marker path is skipped and the replacement proceeds for every line.
A renumber range was specified. Check if the parsed line number falls within the “from” to “to” boundaries.
If the CARRY FLAG has been set (the parsed line number is greater than the “to” boundary, meaning it is above the renumber range), JUMP to 4F42H to pop the error marker and output the line unchanged.
If the NO CARRY FLAG has been set (the parsed line number is greater than or equal to the “from” boundary, meaning it is within the renumber range), JUMP to 4F57H to proceed with the replacement.
The line number is either not found in the program, outside the renumber range, or the line-number-found flag was active with a zero value. Output the original line number digits without modification.
Load Register A with the value at memory location 5121H, the cross-reference flag. 00H = first pass (display only), 01H = second pass (write to program text).
If the Z FLAG has been set (first pass - display only), JUMP to 4F4FH to call the first-pass display routine.
4F54H - Error Line Number Output Routine
This routine outputs a line number that could not be renumbered (error/warning output). On the first pass (cross-reference flag at 5121H is 00H), it formats the display output showing the error type marker, the line number, and its context. On the second pass (flag is 01H), it jumps to the fatal error handler at 50E4H. The error type marker character is passed in Register A (58H=X for syntax errors, 53H=S for overflow, 55H=U for out-of-range). Register Pair DE holds the line number being reported.
Load Register A with the value at memory location 5121H, the cross-reference flag. 00H = first pass (display cross-reference report on screen), 01H = second pass (fatal error during program rewrite).
If the NZ FLAG has been set (second pass is active - the cross-reference flag is 01H), JUMP to 50E4H, the fatal error handler. Finding an unreferenced or invalid line number during the second pass (when the program text is actually being rewritten) is a fatal condition that corrupts the program.
First pass. Display the error/warning line on the screen. The format is: error marker / old line number / slash / error type character, followed by two spaces.
Now output the specific error line information. First check if the display cursor is near the right edge of the screen (column 56 or beyond, since the screen is 64 columns wide) and output a CR/LF if needed to prevent wrapping mid-entry.
4F97H - End-of-Scan Handler (First/Second Pass Router)
This routine is reached when the main line scanner at 4D3BH detects the end of the BASIC program (the link pointer is 0000H via the JP Z,4F97H at 4D3FH). It checks the cross-reference flag at 5121H to determine which pass just completed. On the first pass (00H), it checks for errors and proceeds to the memory relocation phase. On the second pass (01H), it jumps to the second-pass completion handler at 4FFDH. The routine also manages the transition between passes: after the first pass, it relocates the program text in memory to make room for the renumbered line numbers, then starts the second pass.
Load Register A with the value at memory location 5121H, the cross-reference flag. 00H = first pass just completed, 01H = second pass just completed.
If the NZ FLAG has been set (the second pass has completed), JUMP to 4FFDH to handle the second-pass completion, which includes the final output and re-linking of BASIC lines.
First pass just completed. Check the error flag at 4D0AH to see if any renumber errors were encountered during the scan.
If the NZ FLAG has been set (errors were found during the first pass), JUMP to 5063H, which displays the “DONE” message and exits without performing the renumber. The program text is left unmodified.
No errors on the first pass. Now check the error-header-printed flag at 4FA6H (bit 0 of the byte at 4FA5H+1). If any error lines were displayed, this flag is non-zero.
Load Register A with the immediate operand at 4FA6H. The byte at 4FA6H is the error-header-printed flag (written by 4F65H via SET 0,(HL)). If 00H, no error lines were displayed. If 01H, the “ERROR LINES” header was printed.
If the NZ FLAG has been set (error lines were displayed during the first pass), JUMP to 5069H. This outputs a CR/LF after the error report, loads the BASIC program start address, and exits to the ROM at 1AE9H without performing the renumber.
No errors at all. Proceed with memory relocation. The program text must be moved in memory to make room for any expansion caused by renumbered line numbers that require more digits than the originals. Calculate the new program size and perform the block move.
Load Register Pair HL with the 16-bit value at memory location 5168H, the expansion size calculated during the first pass. This is the number of additional bytes needed to accommodate the renumbered line numbers (which may be longer or shorter than the originals). A negative value means the program will shrink.
If the CARRY FLAG has been set (the 16-bit addition overflowed, meaning the relocated program would exceed the 64K address space), JUMP to 4FD1H which leads to the “Not enough memory” error at 50EDH.
If the CARRY FLAG has been set (the relocated program exceeds available memory), JUMP to 50EDH, the “Not enough memory” error handler.
Memory check passed. Now set up the stack pointer for the relocation operation and perform the LDDR block move to copy the program text to its new location.
Load the Stack Pointer with Register Pair HL (the memory top). This temporarily relocates the stack to the top of memory, well above the program area, to prevent the LDDR block move from overwriting the stack.
Store Register A (01H) to memory location 5121H, setting the cross-reference flag to indicate the second pass is now active. From this point on, the byte-fetch routine at 5120H will copy bytes to the output buffer in addition to reading them.
The program text has been relocated. Now update all 128 entries in the cross-reference table at 64A3H by adding the relocation delta (BC) to each entry. This ensures the table pointers still correctly reference their respective BASIC lines at the new locations.
Store Register Pair HL (64A3H) to memory location 4D4CH, resetting the self-modifying operand at 4D4BH to the table base. This reinitializes the cross-reference table position for the second pass.
LOOP START - Cross-Reference Table Update Loop
For each of the 128 entries, add the relocation delta (BC) to the 16-bit pointer value.
If the NZ FLAG has been set (the loop counter has not reached zero, meaning more table entries remain), JUMP back to 4FEDH to update the next entry.
LOOP END - Cross-Reference Table Update Loop
All 128 table entries have been adjusted. Restore the saved registers and restart the main scan loop for the second pass.
4FFDH - Second-Pass Completion Handler
This routine handles the completion of the second pass of the RENUM operation. At this point, the BASIC program text has been scanned and all line number references have been replaced with renumbered values. The routine reads two bytes from the program text to advance past the final null link, stores the output buffer position as the new string space start (40F9H), and then calls the range calculation routine at 5073H to determine the block move parameters. It then enters a loop that copies the renumbered program text back to its final location, inserting and removing bytes as needed to account for line number expansions and contractions.
Store Register Pair BC to memory location 4EF6H, updating the self-modifying operand at 4EF5H (the output position for the binary search second-pass check).
If the Z FLAG has been set (no memory available for the block move, meaning BC is zero), JUMP to 5050H to skip the copy loop and proceed directly to the re-link phase.
LOOP START - Block Copy Loop
Copy blocks of renumbered program text from the relocated buffer back to the final program area. Each iteration copies one block using LDIR, then checks if more blocks remain.
Load Register Pair HL with the value at 5014H. The operand bytes at 5014H-5015H are a self-modifying code target, written at 507BH with the source address for the block copy. During execution, HL holds the actual source address.
If the NZ FLAG has been set (more memory/data remains to be copied), JUMP back to 5013H for the next iteration of the block copy loop.
Now handle the final block: copy any remaining data using LDDR (reverse direction) to avoid overwrite conflicts when the source and destination overlap.
Load Register Pair DE with the value at 5035H. The operand bytes at 5035H-5036H are a self-modifying code target, written at 50CAH with the destination address for the reverse block copy.
If the NZ FLAG has been set (more data remains to be moved), JUMP back to 502FH for another iteration.
All data has been copied to its final position. Now re-link the BASIC program lines. The line numbers have been renumbered but the link pointers between lines still point to the old locations. Walk through all lines and rebuild the link chain.
If the Z FLAG has been set (the link pointer is 0000H, end of program), JUMP to 5063H to output the “DONE” message and exit.
JUMP back to 5053H to process the next line in the re-link loop.
Re-linking complete (or error exit). Display the “DONE” message and exit RENUM.
5073H - Range Calculation and Error Checking
This routine calculates the renumber range boundaries by looking up the user-specified start and end line numbers in the BASIC program. It calls the binary search routine at 4EC3H twice: once for the “from” line number (at 4D04H) and once for the “to” line number (at 4D06H, incremented by 1 to make it exclusive). The results are stored in self-modifying code locations for use by the block copy routines. The routine also validates the ranges and checks for overlap conditions that would prevent the renumber from proceeding.
Store Register Pair HL (the table entry address for the start-range line) to memory location 5014H, the self-modifying operand at 5013H. This sets the source address for the block copy in the second-pass completion handler.
Store Register Pair DE (the end-boundary line address) to memory location 50C0H, the self-modifying operand for the end boundary check.
Walk through the BASIC program from the start to find the insertion point for the renumbered lines. This linear scan finds the first line whose line number is greater than or equal to the start-range address.
If the Z FLAG has been set (end of program reached without finding the range start), JUMP to 50ACH.
Store Register Pair DE (the insertion point address) to memory location 50C8H, the self-modifying operand for the insertion point.
Load Register Pair DE with the value at 50C0H. The operand bytes at 50C0H-50C1H are a self-modifying code target, written at 5087H with the end-boundary line address.
Load Register Pair DE with the value at 50C8H. The operand bytes at 50C8H-50C9H are a self-modifying code target, written at 50AFH with the insertion point address.
Store Register Pair HL to memory location 5035H, the self-modifying operand for the reverse-copy destination address used in the second-pass completion handler at 5034H.
Store Register Pair BC to memory location 50F2H, the self-modifying operand for the block size in the memory size calculator at 50F1H.
The range parameters indicate an error condition (overlap or invalid range). Load the error code and check which pass we are on.
Load Register A with the cross-reference flag at 5121H. 00H = first pass, 01H = second pass.
If the Z FLAG has been set (first pass), JUMP to 5DE2H, the error store routine in BASIC/CMD. This stores the error code and returns to the BASIC error handler. On the first pass, the error is non-fatal and can be reported to the user.
Second pass. A range error during the second pass is fatal because the program text is already being modified.
50EDH - “Not Enough Memory” Error Handler
This short routine loads the error code for “Not enough memory” and branches to the error check at 50DBH, which determines whether to report the error (first pass) or trigger the fatal error message (second pass).
50F1H - Memory Size Calculator
This routine calculates the available memory for block copy operations. It has two entry points: 50F1H loads DE from the self-modifying operand at 50F2H (the block size), while 50F6H assumes DE is already loaded. The routine calculates the difference between the BASIC memory top (40B1H minus one page) and the string space start (40F9H), then iteratively adjusts BC to fit within the available space. Returns with Z FLAG set if BC is zero (no room), or NZ FLAG if BC is non-zero (room available).
Load Register Pair DE with the value at 50F2H. The operand bytes at 50F2H-50F3H are a self-modifying code target, written at 50CDH with the block size.
Load Register Pair DE with the value at 50F7H. The operand bytes at 50F7H-50F8H are a self-modifying code target, written at 5117H with the memory size result from the previous calculation.
If the NO CARRY FLAG has been set (A ≥ F0H, indicating an invalid or impossibly large block size), JUMP to 50EDH, the “Not enough memory” error handler.
LOOP START - Memory Fit Loop
Iteratively halve BC until it fits within the available block size, or reaches zero.
If the NO CARRY FLAG has been set (the block fits within available memory), JUMP to 5117H to store the result and return.
LOOP END - Memory Fit Loop
Store Register Pair HL (the remaining block size after subtracting BC) to memory location 50F7H, the self-modifying operand at 50F6H. This saves the result for the next call to 50F6H.
511DH - Whitespace Skip Routine
This routine skips whitespace characters in the BASIC program text. It calls the raw whitespace skip at 512EH, which advances past spaces (20H), tabs (09H), and line-feed/vertical-tab (0AH/0BH). Used by the line number check and other token handlers to find the next significant character after parsing.
5120H - Dual-Purpose Byte Fetch (Self-Modifying)
This is the central byte-fetch routine used throughout SYS11. It reads a byte from the BASIC program text at HL and advances HL. On the second pass (when the self-modifying flag at 5121H is 01H), it also copies the byte to the output buffer at BC and advances BC. On the first pass (flag is 00H), the byte is read but not copied. The dual behavior is controlled by the LD A,00H instruction at 5120H, whose immediate operand at 5121H is modified to 01H when the second pass begins.
Load Register A with the immediate operand at 5121H. The byte at 5121H is a self-modifying code target: when 00H (first pass), Register A is loaded with 00H. When modified to 01H at 4FDBH (second pass activation), Register A is loaded with 01H.
If the Z FLAG has been set (first pass - the flag at 5121H was 00H), JUMP to 5129H to skip the copy-to-buffer step. On the first pass, bytes are read but not copied.
512BH - Whitespace Consume Loop (Internal)
This is an internal entry point for the whitespace skip loop. It calls the byte-fetch routine at 5120H to read and optionally copy a whitespace character, then falls through to 512EH to check if the next character is also whitespace.
Fall through to the raw whitespace skip routine at 512EH to check the next byte.
If the Z FLAG has been set (the byte is a space), JUMP back to 512BH to consume it and check the next character.
JUMP back to 512BH. The byte is 09H or 0AH (tab or line feed), which are whitespace characters. Consume them and check the next byte.
513BH - Digit Check Routine
This routine checks whether the next non-whitespace character in the BASIC program text is an ASCII digit (30H-39H). It first skips whitespace by calling 512EH, then tests the character against the digit range. Returns with CARRY FLAG set if the character IS a digit, or NO CARRY FLAG if it is not. If the character is not a digit and is also below 30H, the routine falls through to 5120H for additional processing.
If the CARRY FLAG has been set (the character is below 30H, meaning it is not a digit and is some control or punctuation character), JUMP to 5145H.
5147H - Message Display Routine
This routine displays a 03H-terminated message string on the screen. It reads characters one at a time from the address in HL, sends each to the display routine at 5D3FH, and stops when it encounters a 03H terminator, at which point it calls the CR output routine at 5D52H.
JUMP back to 5147H to fetch and display the next character.
5153H - Number Output (First Pass) / Number-String Copy
These two entry points handle the output of a line number. 5153H is the first-pass entry, which displays the number on screen. 5156H is the second-pass entry, which copies the number string to the output buffer. Both use the number-string conversion routine at 5D00H (via 5D2AH) to convert the binary line number in DE to ASCII digits.
Load Register Pair HL with the value at 515AH. The operand bytes at 515AH-515BH are a self-modifying code target, written at 4D30H (initialized to 0000H) and at 5163H (updated with the running count). This holds the current error count.
Load Register Pair DE with the value at 515EH. The operand bytes at 515EH-515FH are a self-modifying code target, written at 4E73H with the digit count from the line number parser.
Store Register Pair HL (the updated expansion accumulator) to memory location 515AH, updating the self-modifying operand at 5159H for the next call.
Load Register Pair DE with the value at 5168H. The operand bytes at 5168H-5169H are a self-modifying code target, written at 516CH with the maximum expansion size encountered so far.
Store Register Pair HL (the new maximum expansion size) to memory location 5168H, updating the self-modifying operand at 5167H. This tracks the worst-case expansion across all line numbers, which determines how much memory must be reserved for the relocation.
5170H - Text Strings (Message Data)
This section contains three message strings used by the RENUM command for display output. Each string is terminated by 03H (with the fatal error string having an additional 0DH carriage return before the terminator).
519DH - 16-Bit Comparison Utilities
Two utility routines for 16-bit comparisons, used by the range calculation routine at 5073H for validating renumber range boundaries.
51A2H - NOP Padding
Unused space at the end of the SYS11 overlay module, filled with NOP (00H) bytes. This padding brings the overlay file to its full allocated size.