--- title: "ZXLR8" id: 56753 type: "computer_media" slug: "zxlr8" url: "http://localhost/computer_media/zxlr8/" markdown_url: "http://localhost/computer_media/zxlr8.md" published_at: "2024-09-22T23:31:59+00:00" modified_at: "2026-04-04T20:17:47+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/09/ZXLR8_1.jpeg" excerpt: "A machine code cassette accelerator that pushes tape storage 6–10x faster than normal, with an interactive BASIC loader that patches timing and calibration values before handing off to the resident routine." 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: "G. Russell Electronics" slug: "g-russell-electronics" taxonomy: "post_tag" url: "http://localhost/tag/g-russell-electronics/" - 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: "Tape" slug: "tape" taxonomy: "genre" url: "http://localhost/type/tape/" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/ZXLR8%20%28198x%29%28Russell%20Electronics%29%28TS1000%29%28US%29%28Cassette%29.zip" mediadate: "198x" producer_company: - id: 10889 title: "G. Russell Electronics" type: "company" url: "http://localhost/company/g-russell-electronics/" images: - url: "http://localhost/wp-content/uploads/2024/09/ZXLR8_1.jpeg" - url: "http://localhost/wp-content/uploads/2024/09/ZXLR8_2.jpeg" - url: "http://localhost/wp-content/uploads/2024/09/ZXLR8.jpg" related_products: - id: 14670 title: "Z-XLR8" type: "product" url: "http://localhost/product/z-xlr8/" media_type_tags: "Tape" --- # ZXLR8 ZXLR8 is a machine code cassette storage accelerator that saves and loads data at 6 to 10 times the normal tape speed, with built-in error checking. The bulk of the program is a large machine code payload embedded in line 1’s REM statement, which is relocated and executed via RAND USR calls. The BASIC loader prompts the user for a timing value (POKEd to address 16961), a calibration value (POKEd to 17107), and a starting memory location, then patches several system variables and jump vectors before handing control to the machine code at address 18141. After setup, a NEW command clears the BASIC workspace, leaving only the resident machine code routine in memory. The error-checking routine is verified by testing USR 18520 against the value 8 after the initial load. *** ## Program Analysis ### Program Structure The program consists of two distinct layers: a large machine code payload hidden inside the `REM` statement at line `1`, and a BASIC loader spanning lines `9000`–`9082` that installs, configures, and then self-destructs. The REM data begins with `\00\C3\19\43` — a `NOP` followed by a `JP 4319h` — establishing an entry point immediately after the REM opcode byte itself. The machine code occupies several hundred bytes and implements the complete fast-tape save/load engine. ### Load and Verification Sequence Line `9001` calls `USR 18520` and checks whether the return value equals 8. Address 18520 (decimal) falls within the REM payload and acts as a checksum or integrity probe; a return value other than 8 triggers the `BAD LOAD` error message at lines `9002`–`9003` and halts execution. This provides a simple but effective post-load sanity check before any system modifications are made. ### User-Configurable Parameters The loader collects three values interactively: - **Timing value** — entered at line `9006`, POKEd to address `16961` (system variable area). This controls the bit-cell duration of the fast tape protocol. - **Calibration value** — entered at line `9014`, POKEd to address `17107`. This fine-tunes the read threshold or pulse discrimination for the tape input circuit. - **Starting location** — entered at line `9022` as variable `L`. A value of 0 aborts installation (`IF L=0 THEN STOP`). The separation of timing and calibration into two distinct parameters allows the routine to be tuned for different tape decks and recording conditions, which is the primary reason the speed improvement spans a range (6–10×) rather than a fixed multiplier. ### System Variable Patching Lines `9024`–`9050` perform the relocation setup. The target address `TA` is computed as `L + 1760`, and the high and low bytes are split and POKEd to addresses `16631` and `16630` respectively — the system variable `PROG` pointer, redirecting where the ZX81 believes BASIC starts. A further block of six POKEs to addresses `16450`–`16455` patches what appears to be a jump table or call vector inside the machine code itself, encoding the load address `L` as a 16-bit little-endian word at `16454`/`16455` and constants `131`, `64`, `23`, `72` at the preceding four bytes. ### Activation and Self-Removal Line `9080` uses `RAND USR 18141` to transfer control to the machine code entry point within the REM payload. On return (if the routine returns at all during normal operation), line `9082` executes `NEW`, wiping the BASIC program from memory. This leaves the fast-tape machine code resident as a standalone routine without the BASIC overhead, a classic self-installing loader pattern. ### Machine Code Architecture Highlights Inspection of the REM byte sequence reveals several notable Z80 constructs: - `ED B0` (`LDIR`) appears multiple times, indicating block memory moves used for code relocation or buffer transfers. - `DB FE` (`IN A,(254)`) is the standard ZX81 tape/keyboard port read instruction, appearing repeatedly in the tight timing loops that sample the EAR line. - `D3 FF` (`OUT (255),A`) drives the MIC output for tape writing. - `ED 53` / `ED 5B` (`LD (nn),DE` / `LD DE,(nn)`) are used extensively for 16-bit pointer manipulation, consistent with tracking tape buffer start/end addresses. - The alternating register set is used (`D9` = `EXX`) to preserve counters across interrupt-sensitive sections. - A substantial data table embedded near the end of the REM block (the sequence of bytes in the range `0x18`–`0x3E`) appears to be text or menu strings encoded with a fixed offset, possibly displayed during operation prompts. ### Address Reference Table | Address | Purpose | | --- | --- | | `16630`/`16631` | PROG system variable (low/high byte of BASIC program start) | | `16450`–`16455` | Machine code jump/address table patched by loader | | `16961` | Timing parameter storage | | `17107` | Calibration parameter storage | | `18141` | Main entry point of fast-tape routine (RAND USR target) | | `18520` | Integrity check entry point (USR returns 8 on good load) | ### Notable Techniques and Idioms - The 16-bit address split idiom `INT(X/256)` and `X - 256*INT(X/256)` is used for both the `TA` and `L` values, the standard ZX81 BASIC method for computing high and low bytes without bitwise operators. - Using `RAND USR` rather than `PRINT USR` discards the return value cleanly and avoids a screen print side-effect. - The `NEW` at line `9082` is the self-erasing loader pattern: once machine code is resident, the BASIC is no longer needed and its memory is reclaimed. - The `SAVE "%Z"` at line `9000` allows the loader itself to be re-saved to tape before installation begins, ensuring the distribution copy is always accessible. ## Source Code ``` 1 REM 0C31943CDDD40CD2BF2AC40233680E5CDB840E1FE76204CD23FC9FE7720B3602B7EFE762012B18E277237EFE7620DB2318D8CD2BF213B40CB7ECC292CB4628FCED4B2540CD4BFCDBD77EFE77C8FE76C8FE4030DCC92AC4011D6219142023B78B1C87EFE7628F636018F2216347227B40CDDD4061CDD45CD9040CDFF44170113E40EDB0CDDD4062CDD45CD9040CDFF447E324540237EFE31CA4642FE38CA3241C311413A4540FE37CA00FE27CA5341FE35CAA343FE29CAE343FE2CCA2B44FE2DCA3D44CDDD4063CD7241ED534740CDDD4064CD7241ED534940ED535840C38941CD7F417EFEDCC4E45C42B45C9CDD45CD9040CDFF44C9CDDD4065CD7F413EFD213C40772377CD7745324B40CD8145324C40325B40C3AB41DBFECDD541CDE54111110213C40CDF141CDFD41ED5B49402A4740CDF141CDD944CDDD4066CD7F41C9DBFE6611001B7AB320FB520F8C911E83CD6421B7AB320F8C97ECD13421B237AB3C2F141C91EFFCD6421D20FAC947DBFE78CD4042D3FFCD4042C9CD2742E87DC2742D4642DC21842CD642C947DBFE78CD4042CD4042CD4042D3FFCD4042CD4042CD4042C96FF520FDC9D9C5D5E53A4540FE2ECA9445FE27CA7142FE35CA4E44FE29CA7544FE2CCAC444FE2DCAD64463C5C35B43CDDD4063CD7241ED534740CDDD4065CD7F41CD9E42CD36432A47407CB5283225640CD4843CD6E43C39243CDD1421EF214D40CDE042FEFD20F9CDE042FEFD20F2CDE04277231DC2B442213E40114D40E71ABEC29E42D2313C2C542C9D9EFF1EFBD9C9D9E1E1E1D1C1D9C9D9CD46FD2D8426016FF15DBFEA7F2EB427BBADAE9427A91781747D2E942D9C9210281183401F87EDB0C921834011E02E1FA0EDB0C9F5D5C52A3B40E5CDF540E13E40A5283CD2BFC1D1F1C362B120F8C9214D401ED9786231D20FBBEC861DC35B432A5640ED5B5840CDE04277231B7AB3C24F43C9C5CDDD4067CDD45C17023C1CD9040C392432BED5B584097862B1B477AB378C274433278402A5B40227940ED5B5B40BBC861EC35B43D9E1D1C1D9CDD944CDDD4066CD7F41C911040ED5347402A1440A7ED5223224940225840CDDD4065CD7F413EFD213C40772377CD7745324B403E0324C40325B40CD8145ED44324C40325B40C3AB41CDDD4068CD7F41CD444235E2356ED53784023224740ED534940324640C389417ED62047237EFED3E80202CBF7B0472A10407EB8C8FE8020561FC35B43C5CDF29C1EB18ECED5BC40ED53474011D72ED534940C3894111020ED53474011018ED534940C38941CD5A44CD4843CD6E43C39243CDDD4065CD7F41CD9E42CD36432145403A5440BEC8620C35B43CDDD4068CD7F41CD444235E235623224740ED534940324640CD5A442146403A554086CB77286621C5C35B432A4940ED5B5840A7ED52306622C5C35B432A4740225640CD4843CD6E43C39243CD5A442AC40225640CD4843CD6E43C39243C34E44DBFE64C3D94150E52A7B401FF03E18EDB11520FB4E60EBE192B4713231AB8C87718F82AC4011F8219237EFE028FAC92AC4011D7219E5CDE044E11130019C9237EFE1C30FA2B2B1100EBC9CD1E45110CD6C451A0CD6C451640CD6C451E83CD6C4511027CD6C45EBC9CD1E45110CD6C451100CD6C45101CD6C451010CD6C45EB97C91A1BD61DD83C93D20FCC96D3E02386520FBC92A4740ED5B49403E0861B23477AB378C818F6E1D1C1223C40ED533E40ED434040C5D5E5CDDD4065CD7F41CDDD4069CDD45CDC8456ACDD45CDC845CDDA45CD934618F52AC40EB1321210191F72EDB0CDDD40C9CDD1421EF214D40CDE042FEFD20F9CDE042FEFD20F2CDE04277231D20F8CDA746CD1D46CD5246CD304611D0193A544077FE29205CD39463E0FE27203CDBC46C9CD304667114C4023131AFE80C8775C818F32AC402311D6219C9CD3046111C0193A5540E63FC62077233A5540CB77C836DC9CD30461113019224D40111027CD7B4611E83CD7B4611640CD7B4611A0CD7B461110CD7B46C92A58403E1B3CA7ED5230FA192258402A4D407723224D40C9D92A3C40ED5B3E40ED4B4040D91F00CD35FC91ED214D403E086231D20FB215A40BEC8E1C3DA452A5640225840CD3046111B019C359462A4640E5ED5B4240A7ED52224840C31748CDCC467EFEC3CA947FECDCA947E6C7FEC2CA947FEC4CA9477E121323ED4B4440A7E5ED42E138DAC333477E1213234E234623E52A4240A73ED42B30E2A4440A7ED423862A484094D44E1EB71237023EB18C82A4640118211936C9233647C351471936C923362A1117019362B23362BED5B46402A1440A7ED52D01BED53440C9761892E33353A3902B2E312A03326322A18A2E33353A3902834323226332918A2E33353A390262929372A383818A2E33353A390312A332C392D18B383926373903926352A18C3839343503926352A18E2A373734371872E33353A390292E3203B26372E2627312A1812B2E312A03326322A00393E352A00312A332C392D003839263739018033333333333333333333333333333333180ED5BB5421922B54222F145D12A4240C9282631310311F1928263131D1C2B1E2719312902D311B101D221F252211192E332802D3119E312131290102D31113E01947218340865FB78B17B2320F7604FC90FF0CF8202100EF0BF8008200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035 9000 SAVE "%Z" 9001 IF USR 18520=8 THEN GOTO 9004 9002 PRINT AT 10,11;"BAD LOAD" 9003 STOP 9004 CLS 9005 PRINT AT 10,7;"INPUT TIMING VALUE" 9006 INPUT N 9008 POKE 16961,N 9010 CLS 9012 PRINT AT 10,4;"INPUT CALIBRATION VALUE" 9014 INPUT N 9016 POKE 17107,N 9018 CLS 9020 PRINT AT 10,2;"INPUT Z-XLR8 STARTING LOCATION" 9022 INPUT L 9023 IF L=0 THEN STOP 9024 LET TA=L+1760 9030 POKE 16631,INT (TA/256) 9032 POKE 16630,TA-256*INT (TA/256) 9040 POKE 16450,131 9042 POKE 16451,64 9044 POKE 16452,23 9046 POKE 16453,72 9048 POKE 16455,INT (L/256) 9050 POKE 16454,L-256*INT (L/256) 9080 RAND USR 18141 9082 NEW ```