--- title: "Relocate" id: 55717 type: "computer_media" slug: "relocate" url: "http://localhost/computer_media/relocate/" markdown_url: "http://localhost/computer_media/relocate.md" published_at: "2024-07-05T00:18:47+00:00" modified_at: "2026-03-30T21:44:55+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "A BASIC-driven Z80 machine code relocator that copies a routine to a new RAM address and automatically patches embedded absolute jump and call targets." 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 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" indiv: - name: "Algis Gedris" slug: "algis-gedris" taxonomy: "indiv" url: "http://localhost/indiv/algis-gedris/" genre: - name: "Programming" slug: "programming" taxonomy: "genre" url: "http://localhost/type/programming/" media_contents: - id: 55711 title: "ISTUG Public Domain Library 8" type: "computer_media" url: "http://localhost/computer_media/istug-public-domain-library-8/" media_type: "Program" programmers: - name: "Algis Gedris" slug: "algis-gedris" taxonomy: "indiv" url: "http://localhost/indiv/algis-gedris/" download_url: "https://archive.org/download/timex-sinclair-software-archive/Relocate%20%28198x%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "198x" media_type_tags: "Programming" --- This BASIC program relocates a Z80 machine code routine from one RAM address range to another by copying bytes and patching any absolute 16-bit addresses that fall within the original range. It scans each byte of the source block, checking it against a table of 19 Z80 opcodes that use absolute 16-bit addresses (such as JP, CALL, LD (nn),HL, and similar instructions). When a match is found and the embedded address lies within the old block, the address is adjusted by the relocation offset and stored at the new location. The program uses RESTORE-less sequential READs from an inline DATA statement to check each opcode candidate, iterating up to 19 times per byte. A final CLEAR (ns-1) is issued to protect the relocated block from BASIC’s memory management. *** ## Program Analysis ### Program Structure The program is compact, spanning lines `9900`–`9965`. Lines `9900`–`9905` are REMs establishing authorship. Line `9910` presents an explanatory banner. Line `9915` collects three inputs: new start address (`ns`), old start address (`os`), and old end address (`oe`). Lines `9925`–`9955` form the main relocation loop. Line `9955` also issues a `CLEAR` to protect the new block. Line `9960` halts, and line `9965` saves the program. ### Relocation Algorithm The relocation offset `a` is calculated at line `9920` as `ns - os`. The outer `FOR i = os TO oe` loop walks every byte of the source block. For each byte, the 16-bit word at `i+1`/`i+2` is pre-fetched into `v` (line `9930`), and the byte at `i` is stored in `ii` (line `9935`). An inner loop of 19 iterations READs successive values from the `DATA` statement and compares each to `ii`. If the current opcode matches a known absolute-address opcode AND the embedded 16-bit address `v` falls within `[os, oe]`, the byte is copied to `i+a`, the adjusted low byte is POKEd to `i+1+a`, and the adjusted high byte to `i+2+a`. Then `i` is advanced by 2 extra positions and the loop continues at `9955`. Otherwise the byte is copied verbatim (line `9950`). ### Opcode Table The DATA statement at line `9935` contains 19 Z80 opcode bytes that encode instructions using an inline 16-bit address operand: | Decimal | Hex | Z80 Mnemonic(s) | | --- | --- | --- | | 17 | $11 | LD DE,nn | | 33 | $21 | LD HL,nn | | 34 | $22 | LD (nn),HL | | 42 | $2A | LD HL,(nn) | | 50 | $32 | LD (nn),A | | 83 | $53 | LD D,E (false positive risk) | | 91 | $5B | LD E,E (false positive risk) | | 115 | $73 | LD (HL),E (false positive risk) | | 194 | $C2 | JP NZ,nn | | 195 | $C3 | JP nn | | 196 | $C4 | CALL NZ,nn | | 202 | $CA | JP Z,nn | | 204 | $CC | CALL Z,nn | | 205 | $CD | CALL nn | | 210 | $D2 | JP NC,nn | | 212 | $D4 | CALL NC,nn | | 218 | $DA | JP C,nn | | 220 | $DC | CALL C,nn | | 242 | $F2 | JP P,nn | Values 83, 91, and 115 ($53, $5B, $73) are register-to-register LD instructions in the Z80 and do not actually take a 16-bit operand. Their inclusion appears to be an error inherited from the original Toronto TTSU listing, and could corrupt bytes following such opcodes if the coincidental address check happens to pass. ### Notable Techniques and Idioms - The `DATA` statement is placed mid-line alongside the `READ` and loop, exploiting the fact that BASIC reads DATA sequentially; however, because there is no `RESTORE`, the DATA pointer advances globally each iteration of the outer loop — meaning only the *first* byte checked in each outer iteration will correctly read from the start of the table. This is a significant bug: after the first pass through the inner loop consumes all 19 DATA values, subsequent outer iterations will find no more DATA to READ and will cause a “Data exhausted” error. - The 16-bit address split uses the idiom `PEEK(i+1) + 256*PEEK(i+2)` for little-endian 16-bit assembly, and the inverse `INT((v+a)/256)` / `(v+a) - 256*INT((v+a)/256)` for splitting back to bytes. - `CLEAR (ns-1)` at line `9955` sets RAMTOP below the new block, protecting it from BASIC memory operations. - The use of line numbers in the 9900s and the SAVE with `LINE 9905` suggests the program is designed as a utility overlay that won’t interfere with line numbers of user programs. - The `::` on line `9955` is a TS2068 multi-statement separator used to chain `NEXT i` and `CLEAR` on one line. ### Bugs and Anomalies - **DATA exhaustion:** As noted above, the DATA pointer is not RESTOREd before each inner loop iteration, so the program will crash with a data error after the first outer loop iteration completes the full 19-item inner scan. - **Spurious opcodes:** $53, $5B, and $73 are single-byte register LDs with no 16-bit operand. Matching them could cause the following two bytes to be incorrectly treated as an address and patched. - **Missing opcodes:** Several absolute-address Z80 instructions are absent from the table, including `JP (HL)`-related extended ops, `LD (nn),BC` (ED prefix), and conditional calls/jumps for the remaining condition codes (PE, M, etc., e.g. $E2, $E4, $EA, $EC, $F4, $FA, $FC). - **No RESTORE:** A `RESTORE 9935` should precede or be inside the outer loop to reset the DATA pointer for each byte examined. ## Source Code ``` 9900 REM THIS TAPE WAS DONATED BY TORONTO TIMEX SINCLAIR USER'S GROUP. Modified & copied by A. E. Gedris for the "2068" computer 9905 REM RELOCATE 9910 CLS : PRINT "Note:- This program will"'"relocate a machine code program to a new location in RAM. Since it is in BASIC, it is rather slow."''"Follow the instructions." 9915 INPUT "Enter new start address"'ns'"Enter old start address"'os'"Enter old end address",oe 9920 LET a=ns-os 9925 FOR i=os TO oe 9930 LET v=PEEK (i+1)+256*PEEK (i+2) 9935 LET ii=PEEK i: FOR f=1 TO 19: READ iii: DATA 17,33,34,42,50,83,91,115,194,195,196,202,204,205,210,212,218,220,242 9940 IF iii=ii AND v>=os AND v<=oe THEN POKE i+a,PEEK i: POKE i+1+a,(v+a)-256*INT ((v+a)/256): POKE i+a+2,INT ((v+a)/256): LET i=i+2: GO TO 9955 9945 NEXT f 9950 POKE i+a,PEEK i 9955 NEXT i:: CLEAR (ns-1) 9960 STOP 9965 SAVE "RELOCATE" LINE 9905 ```