TRS-80 DOS - NEWDOS/80 v2.0 for the Model III - SYS19/SYS Disassembled
Page Customization
Page Index
SYS19/SYS
Other Navigation
Introduction / Summary
NEWDOS/80 v2.0 – SYS19/SYS – RUN/LOAD/MERGE/SAVE/DELETE Overlay
SYS19/SYS is a BASIC/CMD overlay module for the TRS-80 Model III NEWDOS/80 v2.0 Disk Operating System. It occupies the shared overlay region at 5200H–56E7H (1,256 bytes; 1,105 bytes of active code, 151 bytes of NOP padding). The overlay entry point is 5200H, which contains a CP A / RET presence-detection stub identical to SYS18.
SYS19 implements four major BASIC statement extensions:
| Feature | Description |
|---|---|
| Run/Load With V Option | RUN "filespec",V and LOAD "filespec",V load a new BASIC program while preserving all existing variables, DEFFN definitions (except those in the deleted range), and open file areas. The V option works by relocating the existing variable/array/string data upward in memory via LDDR before loading the new program, then compacting everything back via three-stage LDIR after the load completes. The R option (RUN "filespec",R) is also handled, providing run-after-load without variable preservation. |
| Merge | MERGE "filespec" merges lines from a disk file into the currently loaded BASIC program. Supports both ASCII text files (read byte-by-byte via 60F2H, tokenized via ROM 1BC0H) and packed/tokenized program files (read sector-by-sector via SVC 4436H). The merge algorithm walks both the old program and the new file simultaneously, comparing line numbers and inserting lines in sorted order. Duplicate line numbers in MERGE mode trigger an "Illegal Function Call" error. MERGE can be executed as a direct statement or as a program statement (with restrictions). |
| Cmd“F”,Delete | CMD"F",DELETE ln1-ln2 dynamically deletes a range of BASIC program lines during program execution. Variables are retained (except DEFFN variables in the deleted range). String variables whose data resided in the deleted text area are relocated to the string space. The operation rebuilds the program using the merge/compaction engine. CMD"F",DELETE must be executed as a program statement (not direct), must be the last statement on its line, and must be followed by a continuation line where execution resumes. |
| Save | SAVE "filespec" and SAVE "filespec",A save the current BASIC program to disk. The default (no option) saves in packed binary format with an FFH start marker. The A option saves in ASCII text format. Both paths use the DOS file write routines at 4439H and 6370H. |
Memory Map
Address ranges and functional areas within SYS19/SYS
| Address | Description |
|---|---|
| 5200H-5201H | Overlay presence stub (CP A / RET). |
| 5202H-5254H | RUN/LOAD/MERGE entry point and option parser (R/V detection, mode flag storage, FCB mode check, keyboard intercept configuration). |
| 5255H-526EH | Mode branch: V-option path (ROM 1DF8H init, LDDR relocation setup) vs standard path (ROM 1B4DH fresh init). |
| 5271H-5288H | Common file load sequence (enable guard, set 4289H bit 6, SVC 4436H read, error dispatch). |
| 5289H-52CFH | MERGE post-load memory calculation (SP safety margin, LDDR block move, pointer updates, line chain walk init). |
| 52D0H-530EH | Merge main line copy loop for packed data (INC L / CALL Z page crossing, line header read, 53B4H comparison, byte-by-byte text copy). |
| 5310H-5331H | End-of-merge finalization and post-load mode dispatch (3-way: 00H→1A19H warm start, 01H→1D1EH V-option run, 02H→5322H CMD"F",DELETE continuation). |
| 5334H-5358H | CMD"F",DELETE entry point (direct-mode prohibition, line range parsing, mode 02H). |
| 535BH-53B2H | MERGE-from-file line reader (byte-by-byte file I/O via 60F2H, CR/LF handling, line number parse via 1E5AH, tokenization via 1BC0H, 53B4H insertion). |
| 53B4H-53CCH | Line number comparison and insertion routine (SBC HL,BC comparison, 4-byte header write with H-byte link placeholders). |
| 53CDH-53ECH | Duplicate line handler (FFFFH sentinel check, mode 02H error, old line skip, next-line advance via 53EEH). |
| 53EEH-53FCH | Old program line header reader (link/linenum read, FFFFH sentinel injection on end-of-program). |
| 53FEH-543CH | Copy old program lines to output until insertion point (multi-line copy with header writes, byte counting at 5429H). |
| 543EH-5475H | Merge compaction: three-stage LDIR (relocate merged text, variables, string stack; update 40F9H/40FBH/40FDH; relink via 1AF8H; set reset vector via 6497H). |
| 5478H-5494H | Delta accumulator updater (output-source distance, conditional variable relocator call, delta accumulation via 562AH). |
| 5495H-54B1H | Memory region size calculator (string stack / variable-array / gap sizes into self-modifying LDIR operands). |
| 54B2H-54C7H | Page boundary / sector read handler (SVC 4436H, merge-source boundary check, out-of-memory exit). |
| 54C8H-54DEH | Merge pointer initialization (set 4 pointers, zero delta, compute sizes, jump to compaction). |
| 54DFH-54F1H | Variable relocation entry (clear 40F0H, save continuation address, disable guard, ROM 1B8FH reinit, self-modifying JP). |
| 54F2H-5526H | Variable/string pointer relocator (walk variable table 40F9H-40FBH, check type nibble, bit 7 string flag, CALL 555BH for string relocation). |
| 5527H-5556H | String descriptor stack walk (40FBH-40FDH, type 03H sub-records, ROM 0BAAH string copy). |
| 5558H-559BH | String descriptor reader/relocator (range check via 5641H/5649H, delta adjust, string space allocation via ROM 28BFH, LDIR copy). |
| 559CH-55C2H | CMD"F",DELETE range parser (RST 08H comma check, B6H DELETE token, ROM 1B10H range parse, ROM 1B2CH line search, merge/compact/relocate flow). |
| 55C5H-55E4H | SAVE/MERGE ASCII file handler (A option, SP−384 memory check, 5710H buffer limit, JP 2B2EH ASCII I/O). |
| 55E5H-561DH | Default SAVE path (FFH marker, SVC 4439H write loop, 6370H terminator, JP 2169H cleanup). |
| 5620H-5629H | Merge delta accumulator initializer (zero 5642H, return HL=543EH). |
| 562AH-5637H | Delta accumulation and return (add 557AH to 5642H, restore DE/HL). |
| 5638H-5640H | Delta zero and variable relocate (zero 5642H via BC, JP 54F2H). |
| 5641H-564EH | Range comparison utilities (lower and upper bound checks, out-of-range exit to 5599H). |
| 5651H-56E7H | NOP padding (151 bytes of 00H). |
SYS19 — Variables and Self-Modifying Code
Self-Modifying Code Locations
SYS19 makes extensive use of self-modifying code for mode switching, pointer tracking, and parameter passing. The following locations have their operand bytes modified at runtime.
| Address | Description |
|---|---|
| 5255H | Branch override opcode. Operand of JR Z,526BH at 5255H. Written by: 5228H. Initial value: 28H (JR Z). Runtime values: 18H (JR unconditional, for default/R mode - always branches to standard path at 526BH), 3EH (LD A,nn for V mode - consumes 14H displacement byte and falls through to V-option path at 5257H). |
| 5315H | Mode flag. Operand of LD A,00H at 5314H. Written by: 5220H, 5355H. Values: 00H = standard load (no option), 01H = R or V option, 02H = CMD"F",DELETE mode. Read by: 5316H (post-load dispatch), 53D3H (duplicate line handler), 5242H (V-option validation). |
| 5429H | Current program position byte count. Operand of LD BC,0000H at 5428H. Written by: 52C3H, 5437H, 54CEH. Values: the accumulated byte count of old program lines copied during the merge. Read by: 548AH (delta updater). |
| 5442H | Merge output position. Operand of LD DE,0000H at 5441H. Written by: 52E6H, 535FH, 5408H, 54D2H. Values: the current write address in the merge output area. Read by: 547BH (delta updater), 543EH (compaction). |
| 5459H | Variable/array area size. Operand of LD BC,0000H at 5458H. Written by: 54AEH (via 5495H). Values: 40FBH − 40F9H. Used by: second LDIR in merge compaction at 545FH. |
| 5466H | String stack size. Operand of LD BC,0000H at 5465H. Written by: 549FH (via 5495H). Values: 40FDH − 40FBH. Used by: third LDIR in merge compaction at 546CH. |
| 547FH | Merge source start. Operand of LD DE,0000H at 547EH. Written by: 52C6H, 5404H, 54CBH. Values: the start address of the current block of old program text being processed. Read by: 5478H (delta updater). |
| 5488H | String space start snapshot. Operand of LD DE,0000H at 5487H. Written by: 54A7H (via 5495H). Values: 40F9H value at time of calculation. Read by: 5487H (delta updater), passed to 54F2H. |
| 5512H | String relocation mode flag. Operand of LD A,00H at 5511H. Written by: earlier variable walker code. Controls whether the string descriptor relocator at 5513H performs relocation or read-only scanning. |
| 5565H | Relocator lower bound (string space start). Operand of LD HL,0000H at 5564H. Written by: 54F8H (via 54F2H). Read by: 5564H (string descriptor relocator). |
| 556CH | Relocator upper bound reference (program position). Operand of LD HL,0000H at 556BH. Written by: 54F5H (via 54F2H). Read by: 556BH (string descriptor relocator). |
| 5574H | Relocation flag. Operand of OR 00H at 5573H. Written by: 54F2H. Values: nonzero if relocation delta should be applied, 00H if not. Read by: 5573H. |
| 5576H | String length. Operand of LD A,00H at 5575H. Written by: 5560H. Values: the byte length of the current string being relocated. Read by: 5575H. |
| 557AH | Merge delta (output − source distance). Operand of LD HL,0000H at 5579H. Written by: 5484H (via 5478H). Values: the signed distance between the merge output and source positions. Read by: 5579H (string address adjustment), 562DH (delta accumulation). |
| 53DCH | Current merge position. Operand of LD HL,0000H at 53DBH. Written by: 52B2H, 53EEH, 54C8H. Values: the address of the current position in the old program data during the merge walk. Read by: 53FEH, 5444H, 54BEH. |
| 54F0H | Variable relocation continuation address. Operand of JP 0000H at 54EFH. Written by: 54E6H. Values: the address to jump to after BASIC reinit (file load sequence for V-option, post-delete handler for CMD"F",DELETE). |
| 5642H | Delta accumulator (running total). Operand of LD BC,0000H at 5641H. Written by: 5623H, 5632H, 563AH. Values: the cumulative relocation delta across all merge iterations. Read by: 5641H (lower bound range check), 562AH (delta accumulation). |
External Writes to BASIC/CMD Addresses
SYS19 modifies several locations in the BASIC/CMD main module (5700H-684BH range) and DOS/BASIC system RAM to control mode switching, keyboard interception, and program state.
| Address | Description |
|---|---|
| 4289H Bit 6 | DOS state flags. SET at 5277H to signal that a program load is in progress. |
| 4478H | Execution hook byte. Written at 5252H. Values: C3H (JP enables keyboard intercept hook for V-option), C9H (RET disables hook for standard/ASCII loads). |
| 40F0H | BASIC program line chain head pointer. Cleared to 0000H at 54E2H to empty the program before variable-preserving reload. |
| 40F9H | String space start pointer. Updated at 52B8H (MERGE relocation), 5454H (compaction stage 1). |
| 40FBH | Array end / variable top pointer. Updated at 52BDH (MERGE relocation), 5461H (compaction stage 2). |
| 40FDH | String stack pointer. Updated at 52AAH (MERGE relocation), 546EH (compaction stage 3). |
| 5710H | SYS19 communication byte in FCB work area. Written at 55D5H (ASCII SAVE buffer limit) and 55EDH (packed SAVE file start). Read by file I/O routines to determine buffer boundaries. |
| 5FA8H | Close-all-files return byte. Written at 5224H. Values: C9H (RET makes close-all return unconditionally, preserving open files for V-option), C8H (RETZ normal close behavior). |
| 63FAH | Keyboard intercept flag. Written at 524EH. Values: C9H (RET enable intercept for V-option), 00H (disable for standard/ASCII). |
| 6427H | Reset vector. Written at 52DAH. Value: 543EH (merge compaction handler address, installed as the reset handler during merge operations). |
Major Routine Reference
Entry points and functional units within SYS19/SYS.
| Address | Routine | Description |
|---|---|---|
| 5200H | Overlay Presence Stub | CP A / RET. Returns with Z set to confirm SYS19 is loaded. |
| 5202H | Main Entry Point | RUN/LOAD/MERGE option parser. Parses R/V options, stores mode flags to 5315H/5FA8H/5255H, branches to V-option or standard path. |
| 5255H | Mode Branch | Self-modifying JR Z/LD A. Splits V-option path (5257H: ROM 1DF8H, LDDR relocation) from standard path (526BH: ROM 1B4DH fresh init). |
| 5271H | Common File Load | Enable guard, set 4289H bit 6, SVC 4436H read, error dispatch (1CH→5314H, other→5DEFH). |
| 5289H | Merge Memory Calculation | Compute total memory requirement, SP−160 safety check, LDDR block move upward, update 40F9H/40FBH/40FDH. |
| 52C0H | Initialize Merge Line Walk | Set pointers 5429H/547FH, begin reading old program link/linenum chain. |
| 52E6H | Merge Main Loop (Packed) | Walk old program with INC L / CALL Z,54B2H page crossing, read line headers, call 53B4H, copy text bytes. |
| 5314H | Post-Load Mode Dispatch | 3-way dispatch: 00H→ROM 1A19H, 01H→ROM 1D1EH, 02H→5322H. |
| 5322H | CMD"F",DELETE Post-Delete Handler | Read continuation line from 57B8H, search via ROM 1B2CH, execute at found line. |
| 5334H | CMD"F",DELETE Entry | 40A2H direct-mode check, CALL 5D78H, FCB mode adjust, store mode 02H, enter merge flow. |
| 535BH | Merge-From-File Reader | Byte-by-byte file read via 60F2H, CR/LF line assembly, parse line number (1E5AH), tokenize (1BC0H), insert via 53B4H. |
| 53B4H | Line Comparison and Insertion | SBC HL,BC comparison of old vs new line numbers. Less: old line first (53BFH). Equal: duplicate handler (53CDH). Greater: insert new line (53FEH). |
| 53EEH | Old Line Header Reader | Save position to 53DCH, read link/linenum, inject FFFFH sentinel on end-of-program. |
| 53FEH | Copy Old Lines Until Insertion | Loop: write old line header + text to output, count bytes in 5429H, advance via 53EEH, compare until old ≥ new. |
| 543EH | Merge Compaction | Three-stage LDIR: (1) merged text from 53DCH to 5442H, (2) variable/array area (5459H bytes), (3) string stack (5466H bytes). Update 40F9H/40FBH/40FDH, relink via 1AF8H, JP 6497H. |
| 5478H | Delta Accumulator Updater | Calculate 5442H−547FH, store to 557AH, conditional CALL NZ 54F2H, JP 562AH accumulate. |
| 5495H | Region Size Calculator | Compute 40FDH−40FBH → 5466H, 40FBH−40F9H → 5459H, 40F9H → 5488H. |
| 54B2H | Page Boundary Handler | SVC 4436H sector read, merge boundary check (53DCH−256 vs DE), out-of-memory at 54C5H. |
| 54C8H | Merge Pointer Init | Set 53DCH/547FH/5429H/5442H, zero delta via 5638H, compute sizes via 5495H, JP 543EH. |
| 54DFH | Variable Relocation Entry | Clear 40F0H, save continuation at 54F0H, CALL 6392H disable guard, CALL 1B8FH reinit, self-modifying JP. |
| 54F2H | Variable/String Relocator | Walk variable table (40F9H-40FBH), check type nibble and bit 7 string flag, CALL 555BH for string relocation. Walk string stack (40FBH-40FDH), handle type 03H with sub-records via ROM 0BAAH. |
| 5558H / 555BH | String Descriptor Reader/Relocator | Read 3-byte descriptor, range check via 5641H/5649H, apply delta from 557AH or allocate new string via ROM 28BFH + LDIR copy. |
| 559CH | CMD"F",DELETE Range Parser | RST 08H ⇒ 2CH, CP B6H DELETE token, ROM 1B10H range parse, ROM 1B2CH line search, CALL 54C8H + 54DFH, JP 5322H. |
| 55C5H | ASCII SAVE/MERGE Handler | Comma check, RST 08H ⇒ 41H (A option), SP−384 memory check, store 5710H, JP 2B2EH. |
| 55E5H | Packed SAVE Path | FFH marker at (40A4H−1), SVC 4439H write loop, restore original byte, 6370H terminator, JP 2169H. |
| 5620H | Delta Initializer | Zero 5642H, return HL=543EH. |
| 562AH | Delta Accumulation | Add 557AH to 5642H, POP DE/HL, RET. |
| 5638H | Delta Zero + Relocate | Zero 5642H, JP 54F2H. |
| 5641H / 5649H | Range Check Utilities | Lower/upper bound comparisons for string relocation range. Out-of-range exits via 564EH to 5599H. |
ROM Routines Called
| Address | Routine | Description |
|---|---|---|
| 5200H | Overlay Presence Stub | CP A / RET. Returns with Z set to confirm SYS19 is loaded. |
| 5202H | Main Entry Point | RUN/LOAD/MERGE option parser. Parses R/V options, stores mode flags to 5315H/5FA8H/5255H, branches to V-option or standard path. |
| 5255H | Mode Branch | Self-modifying JR Z/LD A. Splits V-option path (5257H: ROM 1DF8H, LDDR relocation) from standard path (526BH: ROM 1B4DH fresh init). |
| 5271H | Common File Load | Enable guard, set 4289H bit 6, SVC 4436H read, error dispatch (1CH→5314H, other→5DEFH). |
| 5289H | Merge Memory Calculation | Compute total memory requirement, SP−160 safety check, LDDR block move upward, update 40F9H/40FBH/40FDH. |
| 52C0H | Initialize Merge Line Walk | Set pointers 5429H/547FH, begin reading old program link/linenum chain. |
| 52E6H | Merge Main Loop (Packed) | Walk old program with INC L / CALL Z,54B2H page crossing, read line headers, call 53B4H, copy text bytes. |
| 5314H | Post-Load Mode Dispatch | 3-way dispatch: 00H→ROM 1A19H, 01H→ROM 1D1EH, 02H→5322H. |
| 5322H | CMD"F",DELETE Post-Delete Handler | Read continuation line from 57B8H, search via ROM 1B2CH, execute at found line. |
| 5334H | CMD"F",DELETE Entry | 40A2H direct-mode check, CALL 5D78H, FCB mode adjust, store mode 02H, enter merge flow. |
| 535BH | Merge-From-File Reader | Byte-by-byte file read via 60F2H, CR/LF line assembly, parse line number (1E5AH), tokenize (1BC0H), insert via 53B4H. |
| 53B4H | Line Comparison and Insertion | SBC HL,BC comparison of old vs new line numbers. Less: old line first (53BFH). Equal: duplicate handler (53CDH). Greater: insert new line (53FEH). |
| 53EEH | Old Line Header Reader | Save position to 53DCH, read link/linenum, inject FFFFH sentinel on end-of-program. |
| 53FEH | Copy Old Lines Until Insertion | Loop: write old line header + text to output, count bytes in 5429H, advance via 53EEH, compare until old ≥ new. |
| 543EH | Merge Compaction | Three-stage LDIR: (1) merged text from 53DCH to 5442H, (2) variable/array area (5459H bytes), (3) string stack (5466H bytes). Update 40F9H/40FBH/40FDH, relink via 1AF8H, JP 6497H. |
| 5478H | Delta Accumulator Updater | Calculate 5442H−547FH, store to 557AH, conditional CALL NZ 54F2H, JP 562AH accumulate. |
| 5495H | Region Size Calculator | Compute 40FDH−40FBH → 5466H, 40FBH−40F9H → 5459H, 40F9H → 5488H. |
| 54B2H | Page Boundary Handler | SVC 4436H sector read, merge boundary check (53DCH−256 vs DE), out-of-memory at 54C5H. |
| 54C8H | Merge Pointer Init | Set 53DCH/547FH/5429H/5442H, zero delta via 5638H, compute sizes via 5495H, JP 543EH. |
| 54DFH | Variable Relocation Entry | Clear 40F0H, save continuation at 54F0H, CALL 6392H disable guard, CALL 1B8FH reinit, self-modifying JP. |
| 54F2H | Variable/String Relocator | Walk variable table (40F9H-40FBH), check type nibble and bit 7 string flag, CALL 555BH for string relocation. Walk string stack (40FBH-40FDH), handle type 03H with sub-records via ROM 0BAAH. |
| 5558H/555BH | String Descriptor Reader/Relocator | Read 3-byte descriptor, range check via 5641H/5649H, apply delta from 557AH or allocate new string via ROM 28BFH + LDIR copy. |
| 559CH | CMD"F",DELETE Range Parser | RST 08H ⇒ 2CH, CP B6H DELETE token, ROM 1B10H range parse, ROM 1B2CH line search, CALL 54C8H + 54DFH, JP 5322H. |
| 55C5H | ASCII SAVE/MERGE Handler | Comma check, RST 08H ⇒ 41H (A option), SP−384 memory check, store 5710H, JP 2B2EH. |
| 55E5H | Packed SAVE Path | FFH marker at (40A4H−1), SVC 4439H write loop, restore original byte, 6370H terminator, JP 2169H. |
| 5620H | Delta Initializer | Zero 5642H, return HL=543EH. |
| 562AH | Delta Accumulation | Add 557AH to 5642H, POP DE/HL, RET. |
| 5638H | Delta Zero + Relocate | Zero 5642H, JP 54F2H. |
| 5641H/5649H | Range Check Utilities | Lower/upper bound comparisons for string relocation range. Out-of-range exits via 564EH to 5599H. |
ROM entry points (0000H-37FFH) used by SYS19
| Address | Description |
|---|---|
| 0BAAH | String block copy (string descriptor stack relocation, at 5545H). |
| 1997H | BASIC syntax error handler, ?SN ERROR (at 521CH, 5352H, 55A0H, 55CDH). |
| 197AH | Out of memory error handler, ?OM ERROR (at 54C5H, 55DDH). |
| 1A19H | BASIC warm start / command loop (at 5317H, mode 00H exit). |
| 1AF8H | BASIC program relink routine (at 5472H, merge compaction). |
| 1B10H | Line number range parser (at 55A5H, CMD"F",DELETE). |
| 1B2CH | BASIC line search by line number in DE (at 5326H, 55ACH). |
| 1B4DH | BASIC init routine, clear variables and files (at 526EH, standard path). |
| 1B8FH | BASIC system reinitialization (at 54ECH, variable relocation entry). |
| 1BC0H | BASIC line tokenizer (at 53A3H, MERGE-from-file). |
| 1D1EH | Program execution with variable preservation (at 531FH, 532EH). |
| 1DF8H | BASIC runtime init preserving variables (at 5257H, V-option). |
| 1E4AH | "Illegal Function Call" error (at 53D8H, duplicate line in DELETE mode). |
| 1E5AH | BASIC expression evaluator, ASCII to integer (at 5393H). |
| 2169H | Post-SAVE cleanup (at 561DH). |
| 28BFH | String space allocation (at 5588H, string relocator). |
| 2B2EH | ASCII SAVE/LOAD processing (at 55E2H). |
BASIC/CMD Routines Called (SYS0 Range)
Routines in the BASIC/CMD main module (4000H-56FFH range, accessed via the SYS0 page) called by SYS19.
| Address | Description |
|---|---|
| 4436H | Read disk sector / move logical record from FCB buffer (at 527CH, 54B6H). |
| 4439H | Write without verify a sector to disk (at 5602H, packed SAVE). |
| 5D78H | Line+Var routine (at 533DH, 55B7H). |
| 5DB8H | Error/recovery path (at 5390H). |
| 5DBBH | Error exit (at 53D0H, end-of-merge sentinel match). |
| 5DEFH | Error translator (at 5283H, 54B9H, 5606H). |
| 6240H | DOS operation (at 5610H, SAVE finalize). |
| 6368H | Comma checker (at 5206H, 55C5H). |
| 6370H | File write + filter (at 5617H, SAVE terminator). |
| 6386H | Enable guard (at 5271H). |
| 6392H | Disable guard (at 526BH, 54E9H). |
| 6497H | Set reset vector (at 5475H, merge compaction exit). |
| 60F2H | File read (at 536CH, MERGE-from-file byte read). |
RST Vectors Used
| Vector | Description |
|---|---|
| RST 08H | Inline character match (at 559CH ⇒ 2CH comma, at 55CAH ⇒ 41H letter A). |
| RST 10H | Fetch next non-space character (at 521BH, 5351H, 538BH, 55A4H, 55B4H). |
| RST 18H | 16-bit compare HL vs DE (at 52A4H, 5503H, 552BH, 55DCH, 54C2H). |
Key Analysis Notes
Architectural observations and design patterns discovered during the disassembly analysis
- The overlay stub at 5200H (CP A / RET) is identical to SYS18. Both overlays share the same 5200H-56E7H address range and are loaded on demand. Only one can be resident at a time.
- The option parser at 5202H-5228H uses an elegant opcode-patching scheme: Register B carries the opcode byte (18H=JR, 3EH=LD A,nn) that will be written to 5255H. When 3EH, it converts the JR Z,526BH instruction into LD A,14H, consuming the branch displacement as an immediate operand and causing fall-through to the V-option path. This avoids a separate conditional branch instruction.
- The MERGE memory relocation uses a two-phase approach: (a) LDDR at 52AFH moves all existing data (variables, arrays, string descriptors, string stack) upward to create a gap at the program area for the merged lines, then (b) three-stage LDIR at 543EH-546EH compacts everything back down after the merge is complete. The SP−160 safety margin at 529BH and the 256-byte boundary check at 54BDH prevent the relocation from colliding with the stack.
- The merge line comparison at 53B4H-53BBH uses SBC HL,BC + ADD HL,BC to perform a non-destructive comparison. The SBC sets the carry and zero flags based on old_line − new_line, then ADD restores HL to its original value. Three outcomes: carry (old < new → copy old first), zero (duplicate → error or skip), neither (old > new → insert new line).
- The 4-byte line header written at 53C3H-53CAH and 541CH-5424H uses LD (HL),H for both link pointer bytes. This writes the current page address (H) as a temporary placeholder. The actual link pointers are fixed by ROM 1AF8H (relink) during the compaction phase at 5472H.
- The FFFFH sentinel (set at 52D3H and 53F9H) ensures that the merge algorithm terminates correctly when one program is exhausted before the other. Since FFFFH (65535) is higher than any valid BASIC line number (max 65529), any remaining lines from the other source will always compare as "less than" and be appended.
- The variable/string relocator at 54F2H-559BH is a sophisticated pointer-adjustment engine. It walks two data structures (variable table and string descriptor stack), identifies string pointers that fall within the relocated address range (using 5641H/5649H for lower/upper bound checks), and either adjusts the pointer by the merge delta (at 5579H) or allocates new string space (via ROM 28BFH at 5588H) and copies the string data (via LDIR at 5590H). This ensures that strings whose data resided in the deleted or relocated text area remain accessible after the merge/delete.
- The delta accumulator at 5642H tracks the cumulative address offset caused by all merge insertions. Each call to 5478H computes the local delta (output position − source position), stores it at 557AH, and the call to 562AH adds it to the running total at 5642H. The accumulated delta is used by the range check at 5641H to determine the correct lower bound for string pointer relocation.
- CMD"F",DELETE shares most of its code with MERGE. The mode flag at 5315H (value 02H) controls the behavioral differences: the post-load dispatch at 5314H routes to the continuation-line handler at 5322H, and the duplicate-line check at 53CDH raises an "Illegal Function Call" error instead of skipping the old line.
- The SAVE path at 55E5H-561DH temporarily writes FFH to the byte before the program start (40A4H−1), saves the original byte in C, writes the program data in 256-byte chunks via SVC 4439H, then restores the original byte. The FFH marker identifies the start of a packed BASIC program file.
- The INC L / CALL Z,54B2H pattern in the packed merge loop (52E6H-530EH) is an efficient page-boundary handler. INC L only affects the low byte of HL, so when L wraps from FFH to 00H, the Z flag triggers a sector read. This avoids a full 16-bit increment and comparison on every byte, at the cost of assuming page-aligned data boundaries.
- SYS19 is the companion to SYS18 (BASIC direct statement executor). SYS18 handles LIST, EDIT, DELETE (direct mode), DI, DU, AUTO, RENEW, and dispatches RENUM/REF. SYS19 handles the program-mode file operations: RUN/LOAD with options, MERGE, CMD"F",DELETE, and SAVE. Both share the 5200H overlay space.
Disassembly
5200H - Overlay Presence Stub
SYS19 Overlay Detection Stub. This two-byte sequence serves as a presence test for the SYS19 overlay. Callers execute CALL 5200H and test the Z flag on return. CP A always sets Z (any value compared against itself is equal), so if SYS19 is loaded, Z is set. If SYS19 is not loaded, the memory at 5200H contains whatever was previously there (from a different overlay or uninitialized RAM), and the test fails.
5202H - RUN/LOAD/MERGE Entry Point and Option Parser
Main entry point for SYS19. This routine handles the extended RUN, LOAD, and MERGE statements with optional V (variable-preserving) and R modifiers. On entry, the BASIC statement parser has already consumed the filespec and the comma separator; HL points to the next character in the BASIC text. The code parses any trailing option letter, stores mode flags into three self-modifying code targets (5315H, 5FA8H, 5255H), then branches to the V-option path (variable-preserving load) or the standard load path.
If the Z FLAG has been set (no comma found — no option letter follows the filespec), JUMP forward to 521AH to skip option parsing and proceed with default mode values in BC.
A comma was found after the filespec, and Register A now holds the first character of the option. Check whether it is R (52H) or V (56H).
If the Z FLAG has been set (the option letter is R), JUMP forward to 5215H. The R option uses the same C=C9H value as the default but sets D=01H to signal run-after-load. Register B retains its default 18H.
If the NZ FLAG has been set (the option letter is neither R nor V), JUMP forward to 521AH to treat the unknown character as end-of-statement. The defaults in BC remain unchanged.
The option letter is V (variable-preserving mode). Override the defaults: B = 3EH (the opcode for LD A,nn — a two-byte NOP that skips the next byte), C = C9H (RET Z opcode, same as default).
Load Register C with C9H, the opcode for RET. This is stored at 5FA8H (the close-all-files return in BASIC/CMD). For both the R and V options, 5FA8H receives C9H to keep the existing close-all behavior.
All paths converge here. Register D holds the mode flag (00H = no option, 01H = R or V option). Register C holds the close-all opcode (C8H or C9H). Register B holds the branch override opcode (18H = JR for default/R, 3EH = LD A for V). Now verify end-of-statement and store the mode values.
If the NZ FLAG has been set (additional characters remain after the option — the statement is malformed), JUMP to ROM 1997H, the BASIC Syntax Error handler (?SN ERROR). A valid RUN/LOAD/MERGE statement must end after the optional letter.
521FH - Store Mode Flags to Self-Modifying Code Targets
Stores the parsed option values (from Registers B, C, D) into three self-modifying code locations that control behavior throughout SYS19 and BASIC/CMD. Then checks the FCB status flags to determine whether variable-preserving mode can actually be applied.
Store Register A (the mode flag, 00H or 01H) to memory location 5315H. This is the operand of a LD A,00H instruction at 5314H. At runtime, 5314H will load this stored value into Register A to test which mode is active.
Store Register A (the close-all opcode, C8H or C9H) to memory location 5FA8H. This is a self-modifying code target in the BASIC/CMD close-all-files routine at 5FA7H. Writing C9H (RET) makes the close-all routine return unconditionally without closing files, preserving open file areas during RUN/LOAD with the V option. Writing C8H (RET Z) restores normal close behavior.
Store Register A (the branch override opcode, 18H or 3EH) to memory location 5255H. This is the opcode byte of the JR Z,526BH instruction at 5255H. When 18H (JR), the branch executes normally, skipping the V-option code at 5257H–526AH. When 3EH (LD A,nn), the branch is disabled: the 14H displacement byte becomes the immediate operand of LD A, and execution falls through to 5257H (the V-option path).
Now check the FCB status flags (IX+0EH) to determine whether this file is in a mode that supports variable preservation. The low 3 bits of IX+0EH encode the file access mode. A value of 06H means the file is open for both read and write (mode 6 = read+write+special), which is required for V-option behavior. Values below 06H indicate simpler access modes.
If the NO CARRY FLAG has been set (the file access mode is 06H or 07H — a packed file), JUMP forward to 5240H to check whether the V-option flag is set. Packed files can support variable-preserving mode.
The file access mode is less than 06H (an ASCII or simpler file mode). Check the DOS flags at 428CH to see if this is a MERGE operation (bit 6 set).
If the NZ FLAG has been set (bit 6 of 428CH is set — this is a MERGE operation), JUMP forward to 5255H. MERGE uses an ASCII file mode (not packed), so it skips the packed-file V-option logic and goes directly to the branch decision at 5255H.
Not a MERGE, and the file is not a packed program file. This is an ASCII LOAD. Disable the keyboard intercept and force standard (non-V) mode regardless of what was parsed, since ASCII loads cannot preserve variables.
JUMP forward to 524EH to store A=00H into the keyboard intercept flag at 63FAH and B=C9H into the execution hook at 4478H. This forces standard mode for ASCII file loads.
5240H - Packed File V-Option Validation
For packed BASIC program files (access mode >= 06H), this section validates whether the V-option can be applied. If the mode is exactly 06H and the V flag is set, the FCB access mode is decremented and the execution hook is configured for variable-preserving behavior. If the mode is not exactly 06H, execution falls through to the branch decision.
If the NZ FLAG has been set (the file access mode from the CP 06H at 5230H is not equal to 06H — it is 07H), JUMP forward to 5255H. Mode 07H (all three low bits set) indicates a special access mode that does not support V-option modification.
The file access mode is exactly 06H (packed program file, read+write). Check whether the V-option flag at 5315H was set by the parser.
If the Z FLAG has been set (no R or V option was specified), JUMP forward to 5255H. Without an explicit option, no variable-preservation modifications are needed.
The V-option (or R-option) was specified and the file is a packed program. Decrement IX+0EH to change the access mode from 06H to 05H, signaling to downstream routines that variable-preserving load is active. Then configure the execution hook for V-mode behavior.
Store Register A to memory location 63FAH, the Keyboard Intercept Flag in BASIC/CMD. For V-option mode, A=C9H (enabling the intercept). For ASCII loads forced to standard mode, A=00H (disabling the intercept).
Store Register A to memory location 4478H, the Execution Hook byte in BASIC/CMD. Writing C3H (JP) activates the hook as an unconditional jump to the handler address at 4479H–447AH. Writing C9H (RET) deactivates the hook, making it return immediately.
5255H - Mode Branch: V-Option vs Standard Load
This is the key decision point that splits execution between the V-option (variable-preserving) path and the standard (non-V) path. The opcode at 5255H is self-modifying: when the V-option is active, the opcode has been changed from 28H (JR Z) to 3EH (LD A,nn), which disables the branch and causes execution to fall through into the V-option initialization code at 5257H. When the V-option is not active, the original JR Z branches to 526BH for standard load behavior.
The opcode byte 28H at this address is overwritten by the value stored at 5228H. When B=18H (default/R mode): the opcode becomes 18H (JR 526BH), an unconditional jump to the standard load path. When B=3EH (V mode): the opcode becomes 3EH (LD A,14H), consuming the 14H displacement byte as an immediate operand and falling through to 5257H, the V-option path. The Z FLAG from the preceding LD (4478H),A at 5252H determines whether the original 28H (JR Z) branches or not — but only if the opcode has not been modified.
V-option path. The file is a packed BASIC program and the V-option was specified. Before loading the new program, save the current BASIC state. CALL 1DF8H initializes the ROM BASIC for a new program load while preserving variables. Then set up the merge pointers for variable-preserving reload.
GOSUB to 54DFH, the Variable Relocation routine. This routine clears the BASIC program line chain (writes 0000H to 40F0H), saves and restores the merge context, disables the guard flag via CALL 6392H, calls ROM 1B8FH for BASIC system reinitialization, then jumps to the entry address stored at 54F0H to complete the variable-preserving reload.
526BH - Standard Load Path (Non-V Mode)
Standard (non-variable-preserving) RUN/LOAD path. Disables the guard flag and calls ROM 1B4DH to initialize the BASIC runtime for a fresh program load, clearing all variables and closing all files. Then falls through to the common file-load sequence at 5271H.
5271H - Common File Load Sequence
Common path for both V-option and standard modes. Enables the guard flag, sets bit 6 of the DOS state flags at 4289H, then calls SVC 4436H to load the program file using the filespec at 570DH. On success (Z flag), continues to the MERGE path. On error 1CH (position error), redirects to the MERGE-after-load handler. On any other error, dispatches to the BASIC/CMD error translator at 5DEFH.
If the Z FLAG has been set (the file read completed successfully with no error), JUMP forward to 5289H to begin the MERGE post-load processing sequence.
The file read returned an error. Check whether it is error code 1CH (position error — before start of file), which is expected when the file has been fully read and the position is at EOF. Any other error is fatal.
If the NZ FLAG has been set (the error code is not 1CH — an unexpected error occurred during the file read), JUMP to 5DEFH, the Error Translator routine in BASIC/CMD. This translates the DOS error code in Register A to a BASIC error number and dispatches to the appropriate error handler.
5289H - MERGE Post-Load: Memory Size Calculation
After a successful file read (for MERGE), this section calculates whether enough memory is available to accommodate the merged program. It computes the total size of the new program text plus the existing data (variables, arrays, strings) and checks that the result fits below the current stack pointer with a safety margin of 160 bytes (A0H). If memory is sufficient, it performs an LDDR block move to relocate the existing data upward to make room for the merged text, then updates all the BASIC memory pointers (string space, variable start, array end, string stack).
Calculate the maximum safe memory address by subtracting 160 bytes (A0H) from the current stack pointer. This reserves 160 bytes of stack safety margin to prevent the relocated data from colliding with the stack during the LDDR move.
If the NO CARRY FLAG has been set (the string stack + 256 is at or above SP − 160 — there is not enough memory for the merge), JUMP to 54C5H. That address contains JP 197AH, which dispatches to the ROM Out of Memory error handler.
Memory check passed. There is enough room for the merge. Proceed with the LDDR block move to relocate the existing data (variables, arrays, string descriptors) upward in memory to make room for the merged program text. The move goes from high addresses to low addresses (LDDR = block move decrementing).
Source
HL = last byte of the old string stack area (40FDH − 1).
Destination
DE = last byte of the new string stack position (SP − 161).
Byte Count
BC = the projected total memory end from 5298H–529AH.
Direction
Decrementing (high to low). This moves the entire data block (variables, arrays, string descriptors, string stack) upward in memory to create a gap at the bottom for the merged program text. After completion, DE points to the byte before the first relocated byte, and HL points to the byte before the first source byte.
Store Register Pair DE (the new data base address after relocation) to memory location 53DCH. This is a self-modifying pointer variable used by the MERGE line chain walker as the Current Merge Position — the address where new merged line data will be inserted.
Update the BASIC memory management pointers to reflect the new data positions after the LDDR move.
52C0H - Initialize MERGE Line Chain Walk
After relocating the existing data upward, initialize the pointers for walking the BASIC program line chain during the MERGE operation. The code stores the program start address into the merge tracking variables at 5429H and 547FH, then begins reading the first line’s link pointer and line number from the program text.
Store Register Pair HL (the BASIC program start) to memory location 5429H. This self-modifying pointer variable tracks the Current Program Position during the merge — it records how much of the existing program has been copied to the merge output area.
Store Register Pair HL (the BASIC program start) to memory location 547FH. This self-modifying pointer variable holds the Merge Source Start — the beginning of the current block of existing program text that needs to be copied during the merge output phase.
Begin reading the first line of the OLD program (now relocated upward after the LDDR). The BASIC line structure is: [link_low][link_high][linenum_low][linenum_high][tokenized text...][00H]. HL points to the first byte of the relocated old program. Read the link pointer (2 bytes) and line number low byte.
52D0H - Complete Line Number Read and End-of-Program Check
Continues the BASIC line chain walk started at 52CAH. Loads the high byte of the current line number into Register B (completing BC = full 16-bit line number), then checks whether the link pointer was 0000H (end of program). If so, sets BC = FFFFH as a sentinel that will always compare higher than any real line number, ensuring that all remaining file lines are appended at the end. Pushes the line number and initializes the merge delta accumulator.
If the NZ FLAG has been set (the link pointer OR at 52CCH produced a nonzero result, meaning the program has more lines), JUMP forward to 52D6H to continue with the valid line number in BC.
The link pointer was 0000H (end of the old program). Set BC to the maximum sentinel value FFFFH (65535). This ensures that during the merge comparison, every remaining line from the merge file will have a line number less than FFFFH, so all file lines will be appended at the end of the merged output.
Store Register Pair HL (which holds 543EH, the merge compaction handler address returned by 5620H) to memory location 6427H, the Reset Vector in BASIC/CMD. This installs the merge compaction routine as the handler that will be called when the merge operation completes or when the system needs to finalize the merged program.
52DDH - PDRIVE Table Check: ASCII vs Packed Merge
Checks the first byte of the PDRIVE table at 4300H to determine whether the current operation is merging from an ASCII file or a packed file. If the first PDRIVE entry is not FFH (the table contains valid drive entries), the file is being read as a packed/tokenized program, and execution branches to the MERGE-from-file reader at 535BH. If the first entry is FFH (the default uninitialized state), the program data has already been loaded into the program area, and the merge proceeds inline.
If the NZ FLAG has been set (the PDRIVE table contains a valid entry — a file is being read from disk), JUMP to 535BH, the MERGE-From-File Line Reader. That routine reads lines from the open file one at a time and merges them into the existing program.
52E6H - Merge Main Line Copy Loop (Packed Data)
Main merge loop for packed (in-memory) program data. Walks the relocated old program line by line, reading each line’s link pointer and line number through a series of INC L / CALL Z,54B2H steps. The INC L advances through the 4-byte line header (link_low, link_high, linenum_low, linenum_high), while CALL Z,54B2H handles page boundary crossings (when L wraps to 00H, a new sector must be read). Once the line number is loaded into BC, calls 53B4H to compare it against the current merge file line and decide whether to insert the file line or copy the old program line. After the line comparison, copies the tokenized line text byte by byte to the merge output area at (DE), then loops back for the next line.
Store Register Pair DE (the current merge output write pointer) to memory location 5442H. This self-modifying variable tracks the Merge Output Position — where the next byte of merged program data will be written.
If the Z FLAG has been set (the link pointer is 0000H — all old program lines have been processed), JUMP forward to 5310H to finalize the merge and dispatch to the post-load mode handler.
LOOP BODY
Copy the tokenized line text byte by byte from the old program (at HL) to the merge output area (at DE). Each byte is read from (HL), checked for the end-of-line marker (00H), stored to (DE), and both pointers are advanced. The loop continues until a 00H terminator is found.
If the NZ FLAG has been set (the byte was not the 00H end-of-line terminator), JUMP back to 5304H to copy the next byte.
JUMP back to 52E6H to save the updated output pointer and begin processing the next old program line.
5310H - End of Merge / Merge Finalization
Reached when all old program lines have been processed (link pointer = 0000H at 52F5H) or when the MERGE-from-file reader finishes reading all file lines. Pops the saved line number, calls the merge compaction routine at 543EH to relocate the merged data back to its final position, then falls through to the post-load mode dispatch at 5314H.
5314H - Post-Load Mode Dispatch
After the file has been loaded (or merge completed), this dispatch reads the mode flag from self-modifying location 5315H and branches to the appropriate handler. Mode 00H (no option) goes to ROM 1A19H for a standard BASIC warm start. Mode 01H (V-option or R-option) goes to ROM 1D1EH for variable-preserving run continuation. Mode 02H (CMD"F",DELETE) goes to the RUN-after-delete handler at 5322H.
Load Register A with the mode flag. The operand byte at 5315H was written by 5220H (or 5355H for CMD"F",DELETE mode). Values: 00H = no option (standard load), 01H = R or V option (variable-preserving), 02H = CMD"F",DELETE mode.
If the Z FLAG has been set (mode = 00H, standard load with no option), JUMP to ROM 1A19H. This is the BASIC Warm Start entry that restarts the BASIC command loop after a successful program load. It displays the READY prompt and waits for user input.
Mode is nonzero (01H or 02H). Check which mode.
If the Z FLAG has been set (original mode was 01H — V or R option), JUMP to ROM 1D1EH. This ROM routine initiates program execution while preserving variables. HL points to one byte before the program text, and execution begins at the first line.
5322H - CMD"F",DELETE Post-Delete Run Handler
After CMD"F",DELETE has completed the line deletion (mode = 02H), this routine reads the continuation line number from the self-modifying variable at 57B8H, searches for that line in the BASIC program via ROM 1B2CH, and positions HL just before the found line for execution to continue. If the continuation line is not found exactly, it checks whether a higher-numbered line exists (for JP Z,1D1EH) or reports a syntax error.
Load Register Pair DE with the contents of memory locations 57B8H–57B9H. This is the LOAD/SAVE Flag storage in BASIC/CMD, which CMD"F",DELETE has repurposed to hold the continuation line number — the line number where execution should resume after the deletion.
If the NO CARRY FLAG has been set (the requested continuation line number is within or beyond the program range — 1B2CH found it or found a higher line), JUMP forward to 5331H. The CARRY FLAG is clear when 1B2CH found the line or a line beyond it.
If the Z FLAG has been set (the exact continuation line was found by 1B2CH, AND the CARRY FLAG is set meaning the line is before the end), JUMP to ROM 1D1EH to begin execution at the continuation line with HL pointing one byte before it.
JUMP to ROM 1997H, the BASIC Syntax Error handler (?SN ERROR). The continuation line specified after the CMD"F",DELETE range was not found in the program (it was deleted or never existed).
5334H - CMD"F",DELETE Entry Point
Entry point for the CMD"F",DELETE statement handler. This routine is reached from the BASIC/CMD CMD"F" dispatcher when the DELETE keyword is recognized. It checks whether 40A2H is FFFFH (indicating direct-mode execution, which is prohibited), parses the line number range parameters, adjusts the FCB access mode for V-option behavior, stores mode flag 02H to 5315H, and then jumps back to 5266H to enter the common merge/delete flow which will delete the specified lines by rebuilding the program without them.
If the Z FLAG has been set (40A2H = FFFFH — CMD"F",DELETE is being executed as a direct statement, which is prohibited), JUMP forward to 5350H. That path checks for end-of-statement and either processes the remaining parameters or reports a syntax error.
CMD"F",DELETE is being executed as a program statement (40A2H ≠ FFFFH). Parse the line number range parameters. CALL 5D78H to read the first line number and variable context.
If the NZ FLAG has been set (the file access mode is not 06H), JUMP forward to 534CH to skip the mode decrement.
5350H - Direct Mode CMD"F",DELETE Redirect
When CMD"F",DELETE is executed as a direct statement (prohibited per the manual), this path checks for end-of-statement. If valid end-of-statement, it falls through to store the mode flag. If not, it reports a syntax error. This allows certain limited direct-mode operations while blocking the full DELETE operation.
If the NZ FLAG has been set (additional characters remain — the statement is malformed for direct mode), JUMP to ROM 1997H, the BASIC Syntax Error handler (?SN ERROR).
Store Register A (the mode flag: 02H for CMD"F",DELETE, or 00H for direct-mode pass-through) to memory location 5315H, the self-modifying mode flag operand at 5314H.
JUMP back to 5266H, the CALL 54DFH instruction in the V-option path. This enters the common variable relocation and merge flow. For CMD"F",DELETE, the merge will rebuild the program without the deleted lines, then the post-load dispatch at 5314H will route to the CMD"F",DELETE handler at 5322H (mode 02H).
535BH - MERGE-From-File Line Reader
Handles MERGE when lines are being read from an open disk file (the PDRIVE table at 4300H had a valid entry). Decrements IX+17H to adjust the file position, reads lines from the file one byte at a time via CALL 60F2H (the BASIC/CMD File Read routine), assembles each line in the buffer at (40A7H), parses the line number, and calls 53B4H to insert the line into the merge output at the correct position in the sorted line chain. Loops until the file is exhausted.
Store Register Pair DE (the merge output pointer) to self-modifying location 5442H, the Merge Output Position tracker.
LINE READ LOOP START
Read one line from the merge source file, byte by byte, into the buffer at (40A7H). Register E serves as a byte counter (initialized to F0H = 240, the maximum line length). Each byte is read via CALL 60F2H and stored to the buffer.
If the NZ FLAG has been set (a file read error occurred), JUMP to 5310H to finalize the merge. Read errors at this point are treated as end-of-file — whatever lines have been successfully merged are kept.
If the Z FLAG has been set (the byte is 00H — a null byte from the file), JUMP back to 536CH to read the next byte, skipping null bytes.
If the Z FLAG has been set (the byte is 0DH, carriage return — end of line), JUMP forward to 5387H to null-terminate the buffer and process the assembled line.
If the NZ FLAG has been set (the byte is not a line feed), JUMP forward to 5383H to accept the byte and continue reading.
The byte is a line feed (0AH). If this is the very first byte read (E still equals F0H, meaning no other bytes have been stored), skip it — it is a trailing LF from the previous line’s CR+LF sequence. Otherwise, treat LF as a normal byte.
If the Z FLAG has been set (no bytes stored yet — this LF is a leading LF), JUMP back to 536CH to skip it and read the next byte.
If the NZ FLAG has been set (the byte count has not reached zero — the buffer is not full), JUMP back to 536CH to read the next byte.
The buffer is full (E reached 00H) or a carriage return was found. Null-terminate the buffer and process the assembled line.
538AH - Parse Assembled Line and Insert into Merge
After a complete line has been assembled in the buffer, parse the line number from the ASCII text, strip trailing spaces, tokenize the line via ROM 1BC0H, and insert it into the merge output via 53B4H. Then copy the tokenized line text byte by byte to the merge output and loop back for the next file line.
If the Z FLAG has been set (the assembled line is empty — only contained whitespace or was null-terminated immediately), JUMP back to 5366H to read the next line from the file, discarding this empty line.
If the NO CARRY FLAG has been set (the first non-space character is not a digit — the line does not start with a line number), JUMP to 5DB8H, the Error/Recovery Path in BASIC/CMD. A MERGE line must begin with a line number.
The line starts with a digit. Parse the ASCII line number into a binary value in DE.
Strip trailing spaces from the parsed line. The line number has been consumed; HL now points to the first character after the line number. Back up past any trailing spaces to find the true end of the line number field.
If the NZ FLAG has been set (the byte at (HL) is not a space), JUMP forward to 53A1H. HL points to the last non-space character before the line text.
If the Z FLAG has been set (another trailing space found), JUMP back to 539CH to continue stripping.
COPY LOOP
Copy the tokenized line text byte by byte from the tokenizer output (at HL) to the merge output area (at DE). Continue until the 00H terminator is found.
If the NZ FLAG has been set (the byte was not the 00H terminator), JUMP back to 53ABH to copy the next byte.
JUMP back to 535EH to save the updated output pointer and read the next line from the merge source file.
53B4H - Line Number Comparison and Insertion
Core merge insertion routine. Called with the new line number in BC (from the merge source) and the old program line number on the stack (pushed at 52D6H or re-pushed during the merge loop). Uses EX (SP),HL to access the old line number, compares it against BC via SBC HL,BC, and decides: if the old line is less than the new line, the old line’s 4-byte header is written to the output and control returns to copy the old line’s text. If the old line equals the new line (duplicate), execution branches to 53CDH for duplicate handling. If the old line is greater, execution branches to 53FEH to insert the new line first.
If the CARRY FLAG has been set (the old program line number is less than the new/file line number — the new line belongs AFTER the current old line), JUMP forward to 53FEH. That routine copies old program lines to the output until the correct insertion point is reached, then inserts the new line.
If the Z FLAG has been set (the old program line number equals the new/file line number — duplicate line), JUMP forward to 53CDH for duplicate line handling.
The old program line number is greater than the new/file line number. The new line should be inserted HERE, before the current old line. Write the 4-byte line header for the new line to the merge output: [link_placeholder_H][link_placeholder_H][linenum_low][linenum_high]. The link pointer is set to the high byte of the current output address as a placeholder (will be fixed by the relink at 1AF8H).
53CDH - Duplicate Line Number Handler
Reached when the old program line number equals the new/file line number (a duplicate). If BC = FFFFH (the end-of-program sentinel), this means both programs have been exhausted and the merge is complete — jump to the error exit at 5DBBH. Otherwise, check the mode flag at 5315H: if mode is 02H (CMD"F",DELETE), report an “Illegal Function Call” error since DELETE cannot process duplicate lines. For MERGE mode, skip the old program line (advance past its text) and re-enter the comparison loop with the NEXT old program line.
If the Z FLAG has been set (BC = FFFFH — both programs have ended with matching sentinel values), JUMP to 5DBBH in BASIC/CMD. This is an error recovery exit that handles the end-of-merge condition.
If the Z FLAG has been set (mode is CMD"F",DELETE and a duplicate line was encountered), JUMP to ROM 1E4AH, the “Illegal Function Call” error handler. The NEWDOS/80 manual states that MERGE must not contain a line with the same number as an existing line.
Duplicate line in MERGE mode. Skip past the old program line’s text to advance to the next line in the old program chain, then re-enter the comparison at 53B7H.
Load Register Pair HL with the address stored at 53DCH–53DDH. This is the Current Merge Position pointer, written by 52B2H, 53EEH, and 54C8H. At runtime, HL is loaded with the address of the current position in the old program data.
If the NZ FLAG has been set (the byte is not the 00H terminator), JUMP back to 53E2H to continue scanning past the line text.
The 00H terminator was found. HL now points to the start of the NEXT old program line. Read the next line’s header via CALL 53EEH, then re-enter the comparison loop.
JUMP back to 53B7H to re-enter the comparison loop with the new old-program line number in HL (which will be compared against BC).
53EEH - Old Program Line Header Reader
Reads the 4-byte header of the next old program line. Saves HL (start of line) to 53DCH, reads the 2-byte link pointer, and returns with A = line number low byte and HL pointing to the line number high byte. If the link pointer is 0000H (end of program), pops the caller’s return address and injects HL = FFFFH into the comparison loop at 53B7H, effectively ending the old program scan.
Store Register Pair HL (the start address of the current old program line) to memory location 53DCH, the Current Merge Position self-modifying variable.
The link pointer was 0000H (end of old program). Pop the caller’s return address and inject HL = FFFFH as the sentinel, jumping directly to the comparison at 53B7H.
JUMP back to 53B7H to re-enter the comparison loop with HL = FFFFH.
53FEH - Copy Old Program Lines to Output Until Insertion Point
Reached when the old program line number is less than the new/file line number (the old line should appear first in the output). Copies old program lines — including their full text and 4-byte headers — to the merge output, advancing through the old program chain until the old line number exceeds the new line number. At that point, writes the new line’s header and returns to the caller to copy the new line’s text.
Store Register Pair DE (the current merge output pointer, returned from the delta updater) to self-modifying location 547FH, the Merge Source Start pointer.
Store Register Pair DE to self-modifying location 5442H, the Merge Output Position.
If the CARRY FLAG has been set (the next old line is STILL less than the new line), JUMP forward to 541BH to write this old line’s header and copy its text, then loop back to check the following line.
The next old line number is greater than or equal to the new line number. The insertion point has been found. Pop the saved pointer and re-enter the comparison at 53B7H with this old line number, which will cause the new line to be written.
JUMP back to 53B7H to re-enter the comparison loop with HL = the next old line number. Since old >= new, the comparison will cause the new line’s header to be written.
The old line is still less than the new line. Write the old line’s 4-byte header to the output and copy its text.
Load Register Pair BC from the self-modifying operand at 5429H. This is the Current Program Position tracker, written by 52C3H, 54C8H, and 5437H. At runtime, BC holds the byte count accumulated during the line copy (initialized to 0000H and incremented for each byte).
LINE TEXT COPY LOOP
Count and copy the tokenized line text byte by byte. BC counts the total bytes (including the 4-byte header accounted for by the 5 INC BC instructions, plus the text bytes), and the bytes are copied from (HL) to (DE).
If the NZ FLAG has been set (the byte was not the 00H terminator), JUMP back to 542FH to count and copy the next byte.
Store Register Pair BC (the accumulated byte count for this line) to self-modifying location 5429H, the Current Program Position counter.
JUMP back to 5404H to update the merge pointers and check the next old program line.
543EH - Merge Compaction: Three-Stage LDIR
Final memory compaction routine called after all lines have been merged. Performs up to three LDIR block moves to relocate the merged program text, the variable/array area, and the string stack back to their final contiguous positions. Updates the BASIC memory pointers (40F9H, 40FBH, 40FDH), relinks the program line chain via ROM 1AF8H, and sets the reset vector via JP 6497H. The three LDIR moves correspond to: (1) merged data → string space, (2) variable/array area, (3) string stack. Each region’s size is loaded from a self-modifying operand set by 5495H.
Load Register Pair DE from the operand at 5442H, the Merge Output Position. At runtime, DE holds the address where the merged program data ends — this is the source for the first LDIR.
Source
HL = relocated data start (53DCH value).
Destination
DE = merge output end (5442H value).
Byte Count
BC = first region size.
Direction
Incrementing. Moves the first data block (merged program text) from the relocated position back to immediately after the merged output. After completion, DE points to the new string space start.
Load Register Pair BC from the operand at 5459H. This holds the variable/array area size (40FBH − 40F9H), calculated by 5495H and stored at 54AEH.
If the Z FLAG has been set (no variable/array data to move), JUMP forward to 5461H to skip the second LDIR.
Load Register Pair BC from the operand at 5466H. This holds the string stack size (40FDH − 40FBH), calculated by 5495H and stored at 549FH.
If the Z FLAG has been set (no string stack data to move), JUMP forward to 546EH to skip the third LDIR.
JUMP to 6497H, the Set Reset Vector routine in BASIC/CMD. This stores the current execution context into the reset vector at 6427H, completing the merge operation. Control then returns to the post-load dispatch or warm start.
5478H - Delta Accumulator Updater
Calculates the distance (delta) between the merge output pointer (5442H) and the merge source pointer (547FH), stores the result at 557AH, then conditionally calls the variable/string relocator at 54F2H if 5429H is nonzero. Exits via JP 562AH which accumulates the delta into 5642H and restores DE/HL from the stack.
Load Register Pair DE from the operand at 547FH, the Merge Source Start pointer. This is the position where the current block of old program text started.
Store the delta value to self-modifying location 557AH. This is used by the delta accumulation at 562AH and by the variable relocator.
Load Register Pair DE from the operand at 5488H. This holds the String Space Start value (40F9H) saved by 5495H, used as a parameter for the relocator.
5495H - Memory Region Size Calculator
Calculates the sizes of the three memory regions above the BASIC program (string stack, variable/array area, and the gap between them) and stores the results into self-modifying operands for the three-stage LDIR compaction at 543EH. Called during merge initialization at 5289H and during the merge pointer init at 54D9H.
Store the string stack size to self-modifying operand at 5466H (the third LDIR’s BC at 5465H).
Store the string space start value to self-modifying operand at 5488H (used by the delta updater at 5487H).
Store the variable/array area size to self-modifying operand at 5459H (the second LDIR’s BC at 5458H).
54B2H - Page Boundary / Sector Read Handler
Called conditionally (CALL Z) when INC L wraps from FFH to 00H during the merge line copy loop. Reads the next sector from the file via SVC 4436H, then checks whether the merge output has caught up to the merge source (53DCH), which would indicate an out-of-memory condition.
If the NZ FLAG has been set (file read error), JUMP to 5DEFH, the Error Translator.
If the NO CARRY FLAG has been set (the output has NOT caught up — sufficient space remains), RETURN to the caller to continue the merge.
JUMP to ROM 197AH, the Out of Memory error handler (?OM ERROR). The merge output has overtaken the source data, meaning there is not enough memory to complete the merge.
54C8H - Merge Pointer Initialization
Initializes all four merge tracking pointers (53DCH, 547FH, 5429H, 5442H) from the current HL/DE values, zeros the delta accumulator via CALL 5638H, calculates region sizes via CALL 5495H, then jumps to the merge compaction at 543EH. Called during V-option setup at 5263H and by the CMD"F",DELETE handler at 55BCH.
Store HL to 53DCH, the Current Merge Position.
Store HL to 547FH, the Merge Source Start.
Store HL to 5429H, the Current Program Position.
Store HL to 5442H, the Merge Output Position.
JUMP to 543EH, the Merge Compaction routine, to perform the three-stage LDIR relocation.
54DFH - Variable Relocation Entry
Entry point for the variable relocation sequence used by the V-option (variable-preserving RUN/LOAD) and CMD"F",DELETE paths. Clears the BASIC program line chain by writing 0000H to 40F0H, saves the merge context, disables the guard flag, reinitializes the BASIC system via ROM 1B8FH, and jumps to the address stored at 54F0H to continue execution.
Store HL to self-modifying location 54F0H. This is the operand of a JP instruction at 54EFH, setting the continuation address for after the BASIC reinit.
Jump to the address stored at 54F0H. This was set by 54E6H to the continuation address. For V-option RUN/LOAD, this is the address of the file load sequence. For CMD"F",DELETE, this is the address of the post-delete handler.
54F2H - Variable/String Pointer Relocator
Adjusts internal variable and string pointers that reference the BASIC program text, accounting for the address changes caused by the merge relocation. Walks the variable table (40F9H–40FBH) and string descriptor stack (40FBH–40FDH), adjusting any pointers that fall within the relocated range. Uses the self-modifying operands at 5565H, 556CH, 5574H, and 5576H to track the relocation parameters. Calls 555BH/5558H for individual string descriptor relocation, and ROM 0BAAH for string copy operations.
Store Register A (the high byte of the program position count from 548DH) to self-modifying location 5574H. This value is used as a flag/parameter by the string relocator at 5573H.
Store Register Pair HL (the program position from 5429H) to self-modifying location 556CH.
Store Register Pair DE (the string space start from 5488H) to self-modifying location 5565H.
VARIABLE TABLE WALK
Walk the variable table entries from 40F9H (string space start) through 40FBH (array end), checking each variable descriptor. The variable type is encoded in the low nibble of the first byte of each entry.
If the Z FLAG has been set (end of variable table), JUMP forward to 5527H to begin walking the string descriptor stack.
If the Z FLAG has been set (bit 7 clear — no string descriptor in this entry), JUMP to 551BH to check the variable type and skip the appropriate number of bytes.
Bit 7 is set — this entry contains a string descriptor. Call 555BH to relocate the string pointer if it falls within the relocated range.
Load A from self-modifying operand at 5512H. This flag controls the relocation mode. Written by earlier code.
5527H - String Descriptor Stack Walk
After the variable table walk completes, walks the string descriptor stack from 40FBH through 40FDH. Each string descriptor stack entry is a 5-byte record: [type][length][addr_low][addr_high][extra]. For type 03H (string), the entry contains a string count and multiple sub-records that need relocation via ROM 0BAAH (string copy).
If the NZ FLAG has been set (type is not 03H — not a string), JUMP back to 5526H to skip this entry and continue.
Type is 03H (string). Process the string sub-records. Each sub-record has: [length][addr_low][addr_high]. The count of sub-records is read, and each one is processed via ROM 0BAAH for string relocation.
If the NZ FLAG has been set (more sub-records remain), JUMP back to 5540H to process the next one.
If the NZ FLAG has been set (more strings to process), JUMP back to 554CH.
JUMP back to 5527H to continue walking the string descriptor stack.
5558H - String Descriptor Reader / Relocator
Reads a 3-byte string descriptor (length + 2-byte address) from (HL) and optionally relocates the string pointer if it falls within the relocated range. Entry at 5558H reads without relocating; entry at 555BH performs the full relocation check. Uses self-modifying operands at 5564H–5576H to store relocation parameters, and calls 5641H/5649H for range comparison.
Store the string length to self-modifying location 5576H.
Load HL from operand at 5565H (string space start, set by 54F8H).
Load HL from operand at 556CH (program position, set by 54F5H).
OR Register A with the value at 5574H (the relocation flag, set by 54F2H). If the flag is nonzero, the NZ FLAG is set.
Load A from operand at 5576H (the string length, set by 5560H).
If the Z FLAG has been set (relocation flag is zero — no adjustment needed), JUMP to 5580H.
The string address falls within the relocated range and needs adjustment. Add the relocation delta to DE.
Load HL from operand at 557AH (the merge delta, set by 5484H).
559CH - CMD“F”,DELETE Range Parser
Parses the line number range for the CMD"F",DELETE statement. Expects a comma separator (RST 08H ⇒ 2CH), then the DELETE keyword token (B6H), then the first line number, a dash separator, and the second line number. Searches for the start and end lines in the BASIC program chain, sets up the merge pointers, and enters the variable relocation and compaction flow to rebuild the program without the deleted lines.
If the NZ FLAG has been set (the token is not DELETE), JUMP to 1997H for Syntax Error.
If the NZ FLAG has been set (not end of statement), JUMP back to 55B4H to consume the remaining text.
JUMP to 5322H, the CMD"F",DELETE Post-Delete Run Handler. Searches for the continuation line and begins execution.
55C5H - SAVE / MERGE ASCII File Handler
Handles the SAVE and MERGE paths for ASCII format files. Checks for a comma and the “A” option (41H), verifies memory space, and either writes the program to a file (SAVE) or reads from a file and enters the BASIC editor (MERGE/LOAD ASCII). Uses 5710H to communicate the buffer limit address.
If the Z FLAG has been set (no comma — no option), JUMP to 55E5H for the default SAVE/MERGE path.
If the NZ FLAG has been set (additional characters after “A”), JUMP to 1997H for Syntax Error.
Store HL (the buffer limit) to memory location 5710H, the SYS19 Communication Byte in the FCB work area. This tells the file write routines the maximum address they can use for buffering.
If the CARRY FLAG has been set (buffer limit is below string space — not enough memory), JUMP to 197AH for Out of Memory error.
JUMP to ROM routine at 2B2EH for ASCII SAVE/LOAD Processing. This ROM routine handles the actual ASCII file I/O based on the context established by SYS19.
55E5H - Default SAVE Path (No Option)
SAVE without the “A” option (packed binary format). Reads the byte before the program start, temporarily writes FFH as an end-of-file marker, computes the file size, writes the program to disk via SVC 4439H, restores the original byte, and then writes a terminator record. Uses the DOS file write routine at 6370H to complete the save.
Store HL (the address of the FFH marker, one before program start) to 5710H. This tells the write routines where the file data begins.
If the NO CARRY FLAG has been set (file end >= file start — valid size), JUMP to 55FEH.
If the NZ FLAG has been set (write error), JUMP to 5DEFH for error handling.
If the NZ FLAG has been set (more data to write), JUMP back to 55EDH to write the next sector.
If the Z FLAG has been set (more bytes to write), JUMP back to 5617H.
JUMP to ROM routine at 2169H. This ROM routine performs post-SAVE cleanup and returns to the BASIC command loop.
5620H - Merge Delta Accumulator Initializer
Initializes the merge delta accumulator at 5642H to 0000H and returns HL pointing to 543EH (the merge compaction routine address). Called at 52D7H to set up the delta tracking before the merge loop begins.
Store 0000H to the delta accumulator at 5642H.
562AH - Delta Accumulation and Return
Adds the current merge delta (from 557AH) to the running total at 5642H, then restores DE and HL from the stack and returns. Called from the delta updater at 5492H.
Store the updated running total back to 5642H.
5638H - Delta Zero and Variable Relocate
Zeros the delta accumulator at 5642H by storing A (expected to be 00H) via BC, then calls the variable/string relocator at 54F2H. Called from 54D6H during merge pointer initialization.
Store BC (0000H) to the delta accumulator at 5642H, zeroing the running total.
5641H - Lower Bound Range Check
Checks whether the string address in DE is at or above the lower bound calculated from HL + BC. If DE is below the range, exits via 564EH which pops the return address and jumps to 5599H (skip relocation).
Load BC from operand at 5642H (the delta accumulator). This value is added to HL to form the lower bound.
5649H - Upper Bound Range Check
Checks whether the string address in DE is below the upper bound in HL. Complements the carry flag so that the exit logic at 564CH works consistently for both bounds.
5651H - NOP Padding
Unused/reserved area filled with NOP instructions (00H bytes). This padding extends from 5651H through 56E7H (151 bytes), filling the remainder of the SYS19 overlay space. The overlay occupies 5200H–56E7H (1,256 bytes total), matching the SYS18 overlay region.