TRS-80 DOS - NEWDOS/80 v2.0 for the Model III - SYS20/SYS Disassembled
Page Customization
Page Index
SYS20/SYS
Other Navigation
SYS20/SYS - NEWDOS/80 v2.0 BASIC Extension Overlay (Model III)
Program Overview
SYS20/SYS is one of the BASIC/CMD overlay modules for NEWDOS/80 v2.0 on the TRS-80 Model III. It occupies the shared overlay space at 5200H-56E7H and is loaded on demand when any of its resident statements or functions are invoked. SYS20 contains a diverse collection of BASIC statement handlers and functions that extend the ROM BASIC capabilities with disk I/O features.
The overlay provides seven distinct functional components: (1) the OPEN statement parameter decoder, which parses the five disk I/O modes (Input, Output, Extended, Random, and Direct access) and configures the FCB accordingly; (2) the LSET and RSET string assignment handlers for left-justified and right-justified field assignment within random-access file buffers; (3) the MID$ assignment statement (left-side MID$) for substring replacement within string variables; (4) the HEX$ function for converting numeric values to hexadecimal string representation; (5) the INSTR function for searching within strings; (6) the INPUT# statement handler for reading comma-separated fields from sequential disk files with full quote-delimited field support; and (7) a memory integrity checker that uses XOR-based fill/verify with self-relocating code to test RAM without destroying the overlay itself.
Like its companion overlays SYS18 and SYS19, SYS20 begins with a two-byte presence test stub at 5200H (CP A / RET) that returns with the Z flag set, allowing callers to detect whether the overlay is currently loaded. Only one overlay can occupy the 5200H-56E7H address range at a time; loading SYS20 overwrites any previously resident overlay (SYS18, SYS19, or SYS21).
The CMD“F=” keyword dispatcher at 52E2H handles the extended file command syntax, routing to subcommand handlers via a keyword table at 592BH (in the main BASIC/CMD module). This allows commands like CMD“F=S” (which routes to 4405H in SYS0) and CMD“F=xxx” for other file subcommands.
The memory integrity checker at 5223H-52E1H is a self-relocating routine: it copies itself from the overlay area into high memory (above 7100H), then tests the entire address range from 0000H through the top of memory using an XOR A5H fill-and-verify pattern. The XOR approach allows testing without permanently destroying the tested memory contents - each byte is XORed with A5H, then XORed again to restore the original value. The routine relocates to avoid testing memory that contains the test code itself.
Memory Map
Address ranges and functional areas within SYS20/SYS.
| Address Range | Size | Function |
|---|---|---|
| 5200H-5201H | 2 | Overlay presence test stub (CP A / RET) |
| 5202H-5221H | 32 | Main entry: OPEN/CMD dispatcher with DOS-CALL (4419H) and error routing |
| 5223H-5299H | 119 | Memory integrity checker: stack setup, XOR fill/verify, self-relocation to 7100H+, and post-test FCB restore via SVC |
| 529AH-52E1H | 72 | Memory test subroutines: A5H fill loop, XOR cipher, page-boundary comparator, and verify loop |
| 52E2H-5315H | 52 | CMD“F=” keyword dispatcher: routes to subcommand handlers via 592BH table lookup |
| 5316H-5348H | 51 | NEXT/FOR stack frame handler: stack pointer relocation and variable passing (CMD“F”,NEXT) |
| 534AH-545CH | 275 | LSET / RSET / MID$ (left-side) statement handlers: string field assignment for random-access buffers and substring replacement |
| 545DH-5503H | 167 | HEX$ function (hex string conversion) and INSTR function (string search) |
| 5504H-55D3H | 208 | OPEN statement parameter decoder: parses file mode (I/O/E/R/D), record length, and field width, stores to FCB work area at 5700H |
| 55D4H-55E7H | 20 | INPUT# statement handler entry: guard flag save, expression type check, dispatch to field reader |
| 55E8H-5606H | 31 | PRINT# / PRINT USING# extension: string expression evaluation with ROM PRINT dispatch |
| 560EH-561FH | 18 | LINE INPUT# handler: file setup, FIELD evaluation, and ROM 2169H cleanup dispatch |
| 5621H-56ADH | 141 | INPUT# field reader: CSV parser with quote-delimited field support, CR/LF handling, comma separation, and overflow detection |
| 56AEH-56E7H | 58 | NOP padding (unused overlay space) |
SYS20 - Variables and Self-Modifying Code
| Address | Initial Value | Written By | Purpose |
|---|---|---|---|
| 5272H | 0000H | 5236H | Available memory size (SP − string stack end), used by memory test to determine test range |
| 5275H | Part of LD HL,(5275H) at 5245H | External / context | Base address for memory test source pointer calculation |
| 5278H | Part of LD BC,(5278H) at 522FH | External / context | Memory test comparison base (overlay load address or similar) |
| 528FH-5290H | 0000H | 5224H | Saved SP value; restored after memory test completes at 528FH (operand of LD SP,0000H) |
| 52C9H | 0000H | 522CH | Relocated code destination address (SP − 192), base of the relocated test routine in high memory |
| 5386H | 0000H | 5368H, 53AAH | Saved HL pointer for LSET/RSET/MID$ target string descriptor address |
| 5716H | (FCB work area) | 5691H | Position parameter byte - set to 01H when INPUT# encounters an unquoted, non-comma, non-CR field terminator (signals partial record read) |
Major Routine Reference
Entry points, subroutines, and dispatch targets within SYS20/SYS, with cross-references to callers and the BASIC/CMD jump table.
| Address | Name | Description |
|---|---|---|
| 5200H | Overlay Stub | CP A / RET - presence test, returns Z flag set |
| 5202H | Main Entry | OPEN/CMD dispatcher: POP BC, extract HL, check for ‘=’ (3DH), set 428AH bit 7, DOS-CALL 4419H, error routing |
| 5223H | Memory Test Setup | Save SP, calculate relocated destination (SP − 192), compute available memory, check for out-of-memory |
| 5251H | Memory Test Relocator | Copy overlay code via LDIR to high memory, then jump to relocated copy |
| 5271H | Relocated Memory Test Core | Zero-fill source, LDIR copy overlay to 5200H, jump to relocated 527FH |
| 527FH | Post-Relocation Entry | Set SP to 43FCH, call XOR test, restore SP, check for errors |
| 529AH | Memory Fill (A5H) | Fill 64 bytes at (52C9H) with A5H pattern |
| 52A4H | XOR Memory Test | XOR-cipher 7100H range with relocated base, verify 64-byte integrity block |
| 52C8H | XOR Cipher Engine | XOR each byte at (HL) with corresponding byte at (DE), page-boundary loop with AF′ counter |
| 52E2H | CMD“F=” Dispatcher | Parse character after ‘=’: ‘S’ routes to 4405H, ‘F’ routes to keyword table at 592BH |
| 5316H | Stack Frame Handler | FOR/NEXT stack cleanup: set return to 5346H, relocate SP below 40A0H, dispatch to 1D25H |
| 5324H | FOR Statement Extension | Search FOR stack via ROM 1936H, check for token 91H, ADD HL,BC+4 for stack frame skip |
| 5334H | Variable Passing | Evaluate optional string expression, check token via ROM 1936H, dispatch to 1D25H |
| 534AH | LSET/RSET Entry | Evaluate file number (5824H), push context, read string descriptor, check for ‘(’ (MID$ path) |
| 535FH | MID$ Assignment Path | RST 08H ⇒ 28H, evaluate second file# (5831H), store descriptor, call ROM 2888H or 5CB7H |
| 539EH | LSET/RSET Common Path | RST 08H ⇒ D5H, evaluate string via ROM 2337H, check end-of-statement, dispatch to ROM 2819H |
| 53F2H | INSTR Function | RST 10H, evaluate string via ROM 2335H, RST 20H type check, search via ROM 2B1FH |
| 5462H | HEX$ Function Entry | RST 10H, RST 08H ⇒ 28H, parse hex digits, accumulate in DE via shift-and-add |
| 54C5H | Hex Digit Parser | Convert ASCII hex digit to binary: 0-9 and A-F, with overflow check |
| 5504H | OPEN Mode Decoder | Evaluate string expression (6190H), check single-character mode: I (0128H), O (8448H), E (8248H), R (80ECH), D (01ECH) |
| 5531H | OPEN Parameter Store | EX (SP),HL to save mode word, parse file number (62C0H), set up FCB (6087H), parse record length |
| 55C9H | OPEN Finalize | Store DE to 5702H (record offset), store BC to 5700H (FCB status), JP 2169H (ROM cleanup) |
| 55D4H | INPUT# Entry | Save guard flag (6382H), RST 20H type check, set D=03H (string) or D=05H (numeric), dispatch to field reader |
| 55E8H | PRINT# Extension | RST 08H ⇒ 89H (USING token), call ROM 2828H, check for ‘#’, dispatch to 560EH or ROM PRINT path |
| 560EH | LINE INPUT# Handler | Call 5F36H (file setup), 5E7BH (FIELD eval), push ROM 2169H return, dispatch to 5621H |
| 5621H | INPUT# Field Reader | CSV parser: read bytes via 60F2H, handle spaces (leading skip), quotes (toggle mode), CR/LF (record end), commas (field separator), with 256-byte buffer overflow detection |
| 56A7H | File Read Helper | Call 60F2H, RET Z on EOF, else POP AF and jump to field termination at 569AH |
Disassembly
5200H - Overlay Presence Test Stub
Two-byte stub that allows callers to detect whether SYS20 is currently loaded in the overlay space. CALL 5200H returns with the Z flag set if SYS20 is resident.
5202H - Main Entry: OPEN / CMD Dispatcher
Primary entry point for SYS20. This routine handles the OPEN statement and CMD command dispatching. It receives context on the stack and in HL, checks whether the command includes an ‘=’ sign (for CMD“F=” syntax), and either dispatches to the CMD“F=” handler or executes the command via DOS-CALL (SVC 4419H).
On entry, the stack contains a return address pushed by the caller, and HL points into the command text being parsed. The routine saves the current position in DE, advances HL to check the next character, and branches based on whether it finds an ‘=’ sign.
Standard Command Path
If the character is not ‘=’, this is a regular DOS command. The routine sets bit 7 of 428AH (the DOS state flags) to indicate that a BASIC-initiated DOS command is in progress, executes the command via DOS-CALL at 4419H, then clears the bit and processes the return status.
If the return code is exactly 38H (“Illegal while in MINI-DOS”), execution falls through here. The code at 5222H (not shown - this is actually 5223H, the memory test setup) handles this case, which means the “Illegal in MINI-DOS” warning is silently ignored and processing continues.
5223H - Memory Integrity Checker Setup
Initializes the memory integrity test by saving the current stack pointer, calculating a safe relocation address in high memory (SP − 192 bytes), computing the available memory range to test, and checking that sufficient memory exists. The test routine will be copied to high memory via LDIR so it can test the overlay region without destroying itself.
On entry, HL contains the BASIC text pointer. The routine saves SP, then computes the destination address for the relocated test code as SP − C0H (192 decimal). The test will XOR every byte in the range 0000H through top-of-memory with A5H, verify integrity, then XOR again to restore. Because the test code itself resides in the overlay area (5200H-56E7H), it must first copy itself out of the way.
Second Boundary Check
The routine now performs an additional check to ensure that the overlay source region (starting at 5275H) plus the overlay size does not extend past the string stack pointer. This prevents the LDIR copy from reading beyond allocated memory.
Memory Test Relocation
Both boundary checks have passed. The routine now copies the test code from the overlay area to high memory (the destination at 52C9H), then jumps to the relocated copy. The LDIR copies the code, and then the relocated version runs the actual XOR fill/verify test.
5271H - Relocated Memory Test Core
This block of code is copied via LDIR to high memory (the address stored at 52C9H) before execution. Once relocated, it zero-fills the original overlay space at 5200H, copies the overlay data back using LDIR, and then jumps to the post-relocation entry at 527FH. The LD HL,0000H at 5271H has its operand patched by the self-modifying code at 5236H to hold the available memory size.
When this code executes, it is running from its relocated position in high memory, not from 5271H. The addresses shown are the original overlay addresses; the actual execution addresses are offset by the relocation delta. The code zeros out the original overlay area, restores the overlay content from a saved copy, then transfers control to the post-test handler.
527FH - Post-Relocation Memory Test Entry
After the overlay code has been restored to its original location, this routine sets up a temporary stack, runs the XOR-based memory verification, checks for errors, restores the original stack pointer, and returns the test result to the caller.
At this point, the overlay area has been restored and execution is back in the normal 5200H address range. The routine sets SP to a safe temporary value (43FCH, within the DOS workspace), then calls the XOR verification to check whether any memory bit errors were detected during the test.
529AH - Memory Fill (A5H Pattern)
Fills 64 bytes starting at the address stored in 52C9H (the relocation destination) with the byte value A5H. This creates the integrity verification block that will be checked after the memory test to confirm the relocated code area was not corrupted.
Loop Start (64 Iterations)
Loop End
52A4H - XOR Memory Test Verification
Performs the XOR-based memory test by ciphering the memory range from 7100H (or the computed range) with the relocated code block, then verifies the 64-byte integrity block at (52C9H) by checking that each byte still contains A5H. Returns Z flag set if all bytes verified, NZ if corruption was detected.
Integrity Verification Phase
The XOR cipher has now been applied to all testable memory (below and above the integrity block). The next step verifies that the 64-byte integrity block still contains the A5H pattern. If any byte has changed, a memory fault has been detected.
Loop of 64 iterations Start
Loop End
52C8H - XOR Cipher Engine
Core memory test routine that XORs each byte at (HL) with the corresponding byte at (DE), processing 64-byte pages at a time. The AF′ (alternate accumulator) register serves as the page counter. The cipher loop runs from the starting address (DE) up to but not including the boundary address in BC (high byte in B, low byte in C).
The XOR cipher is non-destructive when applied twice: XOR(XOR(x, key), key) = x. The first pass scrambles memory; the second pass restores it. By checking the integrity block between passes, the routine can detect single-bit memory faults.
Outer Loop Start
Inner Loop Start
Inner Loop End
Outer Loop End - Continues until Boundary Reached
Boundary Check (Low Byte)
The high bytes of DE and BC match. Now the low bytes are compared to determine if the cipher has reached the exact boundary address.
52E2H - CMD“F=” Keyword Dispatcher
Handles the CMD“F=xxx” extended file command syntax. The character after the ‘=’ sign has been identified. If it is ‘S’ (53H), the command routes to 4405H (SYS0). If it is ‘F’ (46H), the routine performs a keyword table lookup against the CMD“F=” subcommand table at 592BH. Any other character produces an “Illegal Function Call” error.
On entry, HL points to the character after the ‘=’ sign (the first character of the subcommand keyword). DE points to the original command text position (before the ‘=’), which was saved at 5203H-5204H. The routine first checks for single-character commands (‘S’ and ‘F’), then falls through to the keyword table scanner for multi-character subcommands.
CMD“F=F” Keyword Table Lookup
The command letter is ‘F’. The routine now scans the keyword table at 592BH (in the main BASIC/CMD module) to find a matching subcommand keyword. The table format is: [length byte] [keyword chars] [handler address low] [handler address high] [00H terminator]. Register C is decremented by 1 to adjust for the keyword comparison logic.
Loop Start - Keyboard Table Scan
Skip Non-Matching Entry
The length does not match. Skip past the keyword characters and the 2-byte handler address to reach the next table entry.
Skip Routine Loop Start
Skip Routine Loop End
Keyboard Table Scan Loop End
Keyword Character Comparison
The keyword length matches. Now compare each character of the keyword against the user’s subcommand text, one byte at a time.
Compare Loop End
Keyword Match Found
All characters matched. DE now points to the 2-byte handler address following the keyword in the table. Extract the address and dispatch to the handler.
5316H - NEXT/FOR Stack Frame Handler
Handles the CMD“F”,NEXT functionality by manipulating the stack to pass variable context through FOR/NEXT loops. The routine sets up a return address of 5346H on the stack, relocates the stack pointer below the BASIC program start (40A0H), and dispatches to ROM 1D25H for program execution with variable context preserved.
This routine is called when the program needs to transfer variable values across a CHAIN or overlay boundary. It manipulates the stack frame to ensure that the FOR/NEXT loop context and variable bindings survive the transition.
5324H - FOR Statement Extension
Extends the FOR statement handling by searching the stack for a FOR push (via ROM 1936H), verifying the presence of the expected token 91H (the FOR token in tokenized BASIC), and adjusting the stack by 4 bytes to skip the FOR loop context frame.
5334H - Variable Passing (String Expression Path)
Evaluates an optional string expression for variable passing, checks the next token via ROM 1936H, and dispatches to ROM 1D25H for program execution with the variable context intact. This routine handles the case where a string expression is provided as part of the CHAIN or variable-passing syntax.
534AH - LSET / RSET / MID$ Assignment Entry
Entry point for the LSET, RSET, and left-side MID$ assignment statements. LSET and RSET assign string values to random-access file buffer fields (left-justified or right-justified respectively). Left-side MID$ replaces a substring within an existing string variable. The routine evaluates the file number, reads the target string descriptor, and branches based on whether a ‘(’ follows (indicating MID$ assignment) or not (indicating LSET/RSET).
On entry, HL points to the BASIC program text at the statement being executed. The routine first evaluates the file number via 5824H, then examines the string descriptor to determine the target variable. If the byte following the descriptor is 28H (‘(’), this is a MID$(a$,n,m)=expr assignment. Otherwise, it falls through to the LSET/RSET common path.
MID$ Assignment Path
The character is ‘(’, so this is a MID$(target$, start [,length]) = source$ assignment. The routine parses the start position and optional length parameters inside the parentheses.
Numeric Start Position Path
The MID$ start position was specified as a numeric expression. The routine negates it (to create a negative stack offset), adjusts SP, and calls 5CB7H (the file status checker) to validate the operation.
539EH - LSET / RSET Common Path
Common processing for LSET and RSET (and the final stage of MID$ assignment after the parameters have been parsed). Expects an ‘=’ sign followed by a string expression. Evaluates the source string via ROM 2337H, verifies end-of-statement, and dispatches to ROM 2819H for the actual string field assignment.
String Expression Assignment
The source expression is a string. The routine now compares the source string length against the target field length and performs the LSET/RSET operation via ROM 2819H.
Self-Assignment Handling
The source and target descriptors are the same. A direct copy of the string into string space is required to avoid aliasing issues (the source would be overwritten during copy).
Numeric Value Handling
The expression was numeric. The routine reads the stack-saved type byte, and if the type is 03H (integer or special numeric), routes to 53C5H for the string space allocator. Otherwise, it copies the numeric value via 5CB7H.
534AH - LSET / RSET / MID$ Assignment Entry
Entry point for the LSET, RSET, and left-side MID$ assignment statements. LSET and RSET assign string values to random-access file buffer fields (left-justified or right-justified respectively). Left-side MID$ replaces a substring within an existing string variable. The routine evaluates the file number, reads the target string descriptor, and branches based on whether a ‘(’ follows (indicating MID$ assignment) or not (indicating LSET/RSET).
On entry, HL points to the BASIC program text at the statement being executed. The routine first evaluates the file number via 5824H, then examines the string descriptor to determine the target variable. If the byte following the descriptor is 28H (‘(’), this is a MID$(a$,n,m)=expr assignment. Otherwise, it falls through to the LSET/RSET common path.
MID$ Assignment Path
The character is ‘(’, so this is a MID$(target$, start [,length]) = source$ assignment. The routine parses the start position and optional length parameters inside the parentheses.
Numeric Start Position Path
The MID$ start position was specified as a numeric expression. The routine negates it (to create a negative stack offset), adjusts SP, and calls 5CB7H (the file status checker) to validate the operation.
539EH - LSET / RSET Common Path
Common processing for LSET and RSET (and the final stage of MID$ assignment after the parameters have been parsed). Expects an ‘=’ sign followed by a string expression. Evaluates the source string via ROM 2337H, verifies end-of-statement, and dispatches to ROM 2819H for the actual string field assignment.
String Expression Assignment
The source expression is a string. The routine now compares the source string length against the target field length and performs the LSET/RSET operation via ROM 2819H.
Self-Assignment Handling
The source and target descriptors are the same. A direct copy of the string into string space is required to avoid aliasing issues (the source would be overwritten during copy).
Numeric Value Handling
The expression was numeric. The routine reads the stack-saved type byte, and if the type is 03H (integer or special numeric), routes to 53C5H for the string space allocator. Otherwise, it copies the numeric value via 5CB7H.
53F2H - INSTR Function
Implements the INSTR(start, search$, target$) function, which returns the position of the first occurrence of search$ within target$ starting at position start. Evaluates the string arguments via ROM routines, performs the search via ROM 2B1FH, and returns the numeric result via ROM 27F8H.
The INSTR function syntax is: INSTR([start,] search$, target$). If the optional start position is omitted, the search begins at position 1. The routine evaluates the string expressions, pushes descriptors onto the stack, and calls the ROM search engine to find the match.
String Search Loop
The routine now reads the search string descriptor (B=length, DE=address), adjusts the start position (A) relative to the target string, and performs a byte-by-byte comparison. If a match is found, the position is returned; if the search string is longer than the remaining target, no match is possible.
Outer Search Loop Start
Inner Compare Routine Loop Start
Inner Compare Routine Loop END
Outer Search Loop End
545DH - Comma + String Expression Helper
Verifies a comma separator in the BASIC text, then evaluates the following string expression via ROM 2337H. Used by the INSTR function to parse its comma-separated arguments.
5462H - HEX$ Function
Implements the HEX$(n) function, which converts a numeric value to its hexadecimal string representation. Parses the argument within parentheses, converts each hex digit using a shift-and-accumulate algorithm, and returns the result as a BASIC string. Handles both decimal digits (0-9) and hex letters (A-F) in the input, with overflow detection via the Carry flag.
The HEX$ function accepts a numeric argument and returns a string of hexadecimal digits. The parsing loop accumulates the hex value in DE by shifting left 4 bits (multiply by 16) for each new digit, then adding the digit value. The routine handles up to 4 hex digits (16-bit value in DE).
54C5H - Hexadecimal Digit Parser
Parses a hexadecimal string character by character, accumulating the binary value in Register Pair DE. Each hex digit (0-9, A-F) is converted to its 4-bit binary equivalent and shifted into DE. Supports the ‘H’ prefix for hex mode and the ‘O’ prefix for octal mode. The accumulation loop shifts DE left by 4 bits (multiply by 16) and adds the new digit.
Digit Parse Loop Start
Hex Digit Accumulation Loop
The ‘H’ prefix has been detected. The following code reads hex digits one at a time, converts each to binary (0-15), and accumulates the value in DE by shifting left 4 bits and adding.
Digit Parse Loop End
Octal Prefix Check
The character was not ‘H’. Check for ‘O’ (octal mode) or treat as a regular numeric expression.
5504H - OPEN Statement Parameter Decoder
Decodes the mode parameter of the OPEN statement. Evaluates a single-character string expression to determine the file I/O mode: ‘I’ (Input), ‘O’ (Output), ‘E’ (Extended/append), ‘R’ (Random access), or ‘D’ (Direct access). Each mode maps to a specific 16-bit configuration word that encodes the FCB status flags and record length parameters. After determining the mode, the routine parses the file number, sets up the FCB, and optionally parses a record length and field width.
The OPEN statement syntax is: OPEN mode$, #filenum, filespec$ [,reclen]. The mode$ is a single-character string: “I” for input, “O” for output, “E” for extended (append), “R” for random access, “D” for direct access. Each mode sets different bits in the FCB status word and determines default record lengths.
Mode Character Cascade
The routine compares the mode character against each valid option and loads the corresponding configuration word into HL. The configuration word encodes: high byte = FCB status flags, low byte = default record length or buffer parameter.
Store Mode Configuration and Parse File Number
The mode character has been matched and the configuration word is in HL. The routine now pushes the configuration onto the stack (via EX (SP),HL), parses the comma separator and file number, sets up the FCB, and processes optional record length / field width parameters.
Record Length Parameter Parsing
A comma was found, so there is a record length parameter. The routine evaluates the string expression to determine the record length type, then branches based on the result.
Numeric Record Length Path
The record length was specified as a numeric expression. Validate that a record type has been specified (bit 7 of C), then evaluate the numeric value.
‘M’ (Move) Mode Check
The record type specifier was not ‘F’. Check for ‘M’ (move mode) or raise an error.
OPEN Finalization
Store the record offset (DE) and FCB status word (BC) to the FCB work area at 5700H, then dispatch to ROM 2169H for post-statement cleanup.
55D4H - INPUT# Statement Handler Entry
Entry point for the INPUT# statement. Saves the guard flag state via 6382H, checks the expression type via RST 20H, and dispatches to the INPUT# field reader at 5621H with the appropriate type indicator in Register D (03H for string, 05H for numeric).
55E8H - PRINT# / PRINT USING# Extension
Handles the PRINT# statement with optional USING format specifier. Checks for the USING keyword token (89H), evaluates the format string, then checks whether the output target is a file (‘#’) or the screen, and dispatches accordingly.
Screen Output Path
No ‘#’ was found, so the PRINT USING output goes to the screen. The routine evaluates the string expression to print, then dispatches to the ROM PRINT handler.
560EH - LINE INPUT# Handler
Handles the LINE INPUT# statement, which reads an entire line from a disk file into a string variable without any field parsing (no comma or quote interpretation). Sets up the file context via 5F36H, evaluates the FIELD expression via 5E7BH, pushes the ROM cleanup address 2169H as a return point, and dispatches to the INPUT# field reader at 5621H.
5621H - INPUT# Field Reader (CSV Parser)
The core field reader for INPUT# and LINE INPUT# statements. Reads bytes one at a time from the disk file via 60F2H, parsing comma-separated values (CSV format) with full support for quoted fields, leading space suppression, CR/LF record terminators, and buffer overflow detection. Register D controls the parsing mode: D=00H for LINE INPUT# (raw mode, no field parsing), D=03H for string INPUT#, D=05H for numeric INPUT#. The reader uses a state machine encoded in the bit flags of Register D to track whether it is inside a quoted field (bit 3), has seen a leading space (bit 0), or has processed a field delimiter (bit 2).
Register D Bit Flags (Field Reader State)
Bit 0
Leading-space-seen flag. When set, leading spaces are skipped (for numeric mode). Cleared after the first non-space character.
Bit 1
Quote-field mode active. Set when the opening quote of a quoted field is processed.
Bit 2
Space-after-field flag. When set, trailing spaces between the field data and the delimiter are being consumed.
Bit 3
Inside-quoted-field flag. Set when a closing quote is encountered inside a quoted field, signaling that the next character determines whether the field ends (comma/CR) or the quote was doubled (another quote).
Main Read Loop Start
Leading Space Check
The byte was read successfully (Z was set by 60F2H meaning a valid byte is in A). Check if it is a space (20H) and whether leading spaces should be suppressed (bit 0 of D).
Quote Character Check
Check if the byte is a double-quote (22H). If so, toggle the quoted-field state in Register D.
Carriage Return Check
Check if the byte is a carriage return (0DH), which indicates end-of-record in the file.
Space-After-Field Check
Check if the byte is a space when already in “trailing space” mode (bit 2 of D). If so, the space is consumed as a trailing delimiter.
Comma Check (Field Separator)
Check for comma (2CH), which separates fields in CSV format.
Line Feed Check
Check for LF (0AH), which typically follows CR in a CR/LF sequence.
Normal Data Character
The byte is a regular data character (not a space, quote, CR, LF, or comma in terminating context). Store it in the buffer and continue.
Trailing Space Consumption
After a non-quoted field value, consume any trailing spaces before the delimiter.
CR/LF End-of-Record Handler
A carriage return was found. Check if the previous character was LF (forming a LF+CR sequence, which is unusual but handled), and then look ahead for the expected LF that follows CR.
Unexpected Delimiter Handler
An unexpected character was found after the field data (not comma, CR, or LF). Set the position parameter flag at 5716H and issue a repositioning SVC to resync the file position.
Field Termination
The field has been completely read (terminated by comma, CR/LF, buffer overflow, or unexpected delimiter). Null-terminate the buffer, restore the buffer start pointer, and return.
56A7H - File Read Helper
Reads one byte from the currently open disk file via 60F2H. If the byte is successfully read and is not EOF (Z clear, meaning normal data), returns normally with the byte in Register A. If EOF is reached (Z set), returns with Z. On error, pops the return address from the stack and jumps directly to the field termination at 569AH, aborting the current field read.
56AEH-56E7H - NOP Padding
Unused overlay space filled with NOP instructions. This padding occupies the remainder of the SYS20 overlay region from 56AEH through 56E7H (58 bytes).