--- title: "Program Merge" id: 57136 type: "computer_media" slug: "program-merge" url: "http://localhost/computer_media/program-merge/" markdown_url: "http://localhost/computer_media/program-merge.md" published_at: "2024-10-04T00:07:05+00:00" modified_at: "2026-03-30T21:19:37+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/10/85_Mrg.png" excerpt: "A machine code utility hidden inside a REM statement that can merge two or more BASIC programs together, working with any memory size configuration." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" genre: - name: "Utility" slug: "utility" taxonomy: "genre" url: "http://localhost/type/utility/" media_contents: - id: 56733 title: "Timex Sinclair Public Domain Library Tape 1002" type: "computer_media" url: "http://localhost/computer_media/timex-sinclair-public-domain-library-tape-1002/" media_type: "Program" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/10/85_Mrg.png" media_type_tags: "Utility" --- # Program Merge This program implements a BASIC program merger utility for the ZX81/TS1000, allowing two or more BASIC programs to be combined in memory. The machine code routine, stored as a REM statement at line 1, is invoked via RAND USR using the classic PEEK 16388+256*PEEK 16389 idiom to locate the start of BASIC regardless of RAM pack size. The REM data begins with the standard two-byte JP (0xC3) preamble at offset 2, making the machine code self-relocating and compatible with any memory configuration. Line 20 launches the routine directly at address 16516, which corresponds to the start of the REM statement’s data area in the default 1K RAM layout. *** ## Program Analysis ### Program Structure The program is brief by design — its real payload is the machine code embedded in the `REM` statement at line 1. The remaining lines handle display and invocation: 1. `Line 1` — REM statement containing the binary machine code routine (approximately 230 bytes) 2. `Line 10` — SAVE command to persist the program to tape 3. `Line 11` — Full-screen instructions printed at row 10 4. `Line 12` — Prompt printed at row 20 5. `Line 13` — Busy-wait keypress loop using `INKEY$` 6. `Line 20` — `RAND USR 16516` launches the machine code ### Machine Code Entry Point `RAND USR 16516` at line 20 jumps directly into the REM data area. Address 16514 is the start of the BASIC program area (RAMTOP on a stock 1K/16K machine), and 16516 is two bytes in — past the line number and length fields — placing execution exactly at the first byte of the REM’s content. The REM data begins with `\76\76` (two `LD (HL),H` NOPs effectively) followed by `\CD\E7\02`, a `CALL 0x02E7`, consistent with calling a ZX81 ROM routine. ### Relocation via PEEK 16388/16389 The user instructions at line 11 direct the operator to invoke the merger after loading a target program using `RAND USR(PEEK 16388+256*PEEK 16389)`. System variables at addresses 16388–16389 hold the `PROG` pointer — the address of the start of the BASIC program area. This idiom correctly locates the REM’s machine code regardless of which RAM configuration is in use, making the utility memory-size agnostic. ### Machine Code Highlights Disassembling the REM payload reveals several notable operations: - `\2A\04\40` — `LD HL,(0x4004)`: loads the `PROG` system variable, confirming the code operates on BASIC program memory directly. - `\ED\42` — `SBC HL,BC`: used for address arithmetic, likely computing program lengths. - `\ED\B0` — `LDIR`: block memory copy instruction, the core mechanism for merging program bytes. - `\DB\FE` / `\D3\FF` — `IN A,(0xFE)` / `OUT (0xFF),A`: keyboard read and display port access, used during the merge operation for user interaction or synchronisation. - `\CF` — `RST 8` (ZX81 error handler): called at several points, likely for controlled exits or triggering specific ROM behaviours. - Multiple `\1C` bytes at the end of the REM — `INC E` instructions — appear to be padding or a data table used by the routine. ### Key BASIC Idioms | Idiom | Location | Purpose | | --- | --- | --- | | `IF INKEY$="" THEN GOTO 13` | Line 13 | Busy-wait loop until any key is pressed | | `RAND USR 16516` | Line 20 | Jump into REM machine code at fixed address | | `PEEK 16388+256*PEEK 16389` | Line 11 (instructions) | Read `PROG` pointer to find machine code after reload | | `AT 10,0` / `AT 20,0` | Lines 11–12 | Positional text layout using `PRINT AT` | ### Notable Techniques Storing executable machine code inside a `REM` statement is a classic ZX81 technique: the BASIC interpreter skips REM content entirely, but the bytes remain in memory and are addressable. The fixed entry via `RAND USR 16516` assumes the program loads at the default BASIC start address (0x4045 / 17477 in decimal, with line 1 starting at 16514 and data at 16516). The additional invocation method documented in the instructions (`PEEK 16388+256*PEEK 16389`) adds two to the `PROG` pointer to skip the REM line’s header and reach the code, providing a portable entry point suitable for use after merging programs when the absolute address may shift. ### Bugs and Anomalies Line 10 saves before the program has been run or tested by the user; a user loading this from tape would need to be aware that running line 10 immediately on load would simply re-save the loader. This is a common pattern for self-distributing utilities and is not a functional bug. No other anomalies are present in the BASIC wrapper. ## Source Code ``` 1 REM \76\76\CD\E7\02\2A\04\40\01\E2\00\B7\ED\42\22\04\40\E5\01\0C\00\09\22\C7\40\22\E6\40\22\F6\40\22\00\41\22\19\41\E1\54\5D\2B\36\3E\2B\F9\2B\2B\22\02\40\21\BF\40\01\E2\00\ED\B0\C3\C3\03\CD\E7\02\FD\CB\21\86\CD\CB\40\18\FB\0E\01\06\00\3E\7F\DB\FE\D3\FF\1F\30\5A\17\17\38\67\10\F1\C1\FD\CB\21\46\20\5A\CD\CB\40\FD\CB\21\C6\79\17\30\F5\1E\05\21\3C\40\CD\CB\40\71\23\1D\20\F8\1E\6F\CD\CB\40\1D\20\FA\2A\3F\40\11\7D\40\B7\ED\52\C8\EB\2A\1C\40\01\80\00\09\E5\CD\CB\40\71\23\ED\4B\02\40\05\E5\ED\42\E1\30\19\1B\7A\B3\20\EB\36\80\E1\18\2E\3E\FF\32\27\40\FD\CB\3B\86\CF\0C\18\8E\CF\0D\CF\03\D5\1E\94\06\1A\1D\DB\FE\17\CB\7B\7B\38\F5\10\F5\D1\20\04\FE\56\30\E3\3F\CB\11\30\DE\C9\11\7D\40\7E\E6\C0\20\31\1A\13\BE\23\20\02\1A\BE\1B\2B\30\08\E5\EB\CD\F2\09\E1\18\EC\28\13\D5\CD\F2\09\E3\C5\2B\CD\9E\09\23\23\C1\D1\EB\ED\B0\18\D2\D5\CD\F2\09\EB\D1\18\CA\21\00\00\22\29\40\CF\FF\25\1C\1C\1C\1C\1C\1C\1C\1C\1C\1C\1C\1C\1C\1C\1C\1C\1C\1C\1C\1C\1C\1C\1C 10 SAVE "1008%5" 11 PRINT AT 10,0;"THIS PROGRAM WILL MERGE ANY TWO OR MORE PROGRAMS. IT WILL WORK WITH ANY SIZE MEMORY. TO USE ENTER RAND USR(PEEK 16388+256*PEEK 16389)" 12 PRINT AT 20,0;"PRESS ANY KEY TO RUN" 13 IF INKEY$="" THEN GOTO 13 20 RAND USR 16516 ```