Relocate

Developer(s): Algis Gedris
Date: 198x
Type: Program
Platform(s): TS 2068

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 99009965. Lines 99009905 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 99259955 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:

DecimalHexZ80 Mnemonic(s)
17$11LD DE,nn
33$21LD HL,nn
34$22LD (nn),HL
42$2ALD HL,(nn)
50$32LD (nn),A
83$53LD D,E (false positive risk)
91$5BLD E,E (false positive risk)
115$73LD (HL),E (false positive risk)
194$C2JP NZ,nn
195$C3JP nn
196$C4CALL NZ,nn
202$CAJP Z,nn
204$CCCALL Z,nn
205$CDCALL nn
210$D2JP NC,nn
212$D4CALL NC,nn
218$DAJP C,nn
220$DCCALL C,nn
242$F2JP 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.

Content

Appears On

Library tape of the Indiana Sinclair Timex User’s Group.

Related Products

Related Articles

Related Content

Image Gallery

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

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

Scroll to Top