REMIZE

Developer(s): Edwin Schoen
Date: 1987
Type: Program
Platform(s): TS 2068
Tags: Utility

REMIZE is a utility that embeds a binary tape file (such as a SCREEN$ or text editor output) inside a BASIC program as a line 9999 REM statement, allowing the binary data to be transmitted over modem as if it were ordinary BASIC source code. The program operates in two modes selected by the user: “L” loads a bytes-format cassette file and appends its data after a REM token in a newly created line 9999, while “S” saves the contents of an existing line 9999 REM back to tape as a binary file. The machine code, stored in the REM statement at line 9999, uses XROM calls for tape I/O, calls ROM routines to insert space into the BASIC program area, and constructs the line 9999 header (line number, size word, REM token, carriage return) manually in memory. A notable feature is that multiple line 9999 entries can coexist in the program, with the WRITE routine (USR 26860) processing only the first one found; the user can delete each after saving by typing 9999. The code also demonstrates techniques such as using HALT in a loop to count 60 interrupts for a one-second delay, calling the ROM’s error-reporting RST 08 mechanism, and using LDIR to copy a default tape header name.


Program Structure

REMIZE consists of a short BASIC loader (lines 1–40) and a large REM statement at line 9999 that serves as both documentation and the container for machine code. The BASIC portion handles user interaction and mode selection, while all substantive work is performed by machine code invoked via USR calls.

Line(s)Purpose
1REM containing embedded machine code (disguised in REM token stream)
5CLS and program title/copyright display
10Prompt user for L (Load) or S (Save) mode; INPUT and validation
20Save port 244 state, select Load mode: call USR 26750 (hex 687E), print result
30Select Save mode: RANDOMIZE USR 26860 (hex 68EC)
40Restore port 244, STOP
9999REM: extensive documentation followed by full assembly listing of embedded machine code

Machine Code Layout

The machine code resides beginning at address 26750 (hex 685B). The assembly listing embedded in the line 9999 REM documents every byte. The code is organized into well-defined subroutines:

  • CALX at 685B: Enables XROM, calls a routine pointed to by HL, saves horizontal select port state.
  • RELX at 686F: Restores home ROM, re-enables interrupts — the complement of CALX.
  • LOAH at 687E: Entry point for Load mode (USR 26750); reads a 17-byte tape header via XROM R_TAPE, then inserts a new line 9999 into the BASIC program area and loads the tape data bytes into it.
  • SAVT at 68EC: Entry point for Save mode (USR 26860); locates line 9999, extracts size and address of data following the REM token, writes a header then data block to tape via XROM W_TAPE.
  • HEDR at 68DB: 17-byte tape header buffer (type byte + 10-byte name + size + address + end flag).
  • ELSN at 6951: Default 11-byte header name “E.L.SCHOEN”.

XROM Interface

All tape operations go through the XROM rather than directly calling the home ROM tape routines. CALX enables the XROM by setting bit 7 of port FF and setting port F4 to 1, preserving the prior state of F4 in the byte labeled SVF4. RELX reverses this, restoring the saved F4 value and clearing bit 7 of port FF, then issues EI and RET. The XROM R_TAPE entry is at address 00FC and W_TAPE at 0068. The carry flag convention mirrors the home ROM: SCF before the call means Load (not Verify); the return carry flag signals success.

BASIC Program Insertion Technique

The Load routine manually constructs a new BASIC line 9999 in memory. It calls ROM routine at address 12BB to make room in the BASIC program area at the VARS pointer (vars = 5C4B). It then writes the line header fields directly:

  1. Two bytes for line number 9999 (hex 270F): 27h, 0Fh.
  2. Two bytes for line length (file size minus overhead).
  3. One byte EAh = REM token.
  4. Data bytes loaded from tape fill the body.
  5. Final byte 0Dh (carriage return) terminates the line.

The size field accounts for the overhead by performing four DEC BC operations before writing the length word, and two more before loading data to subtract the REM token and carriage-return bytes.

Save (Write) Routine Details

The Save entry point calls ROM routine 16D6 with HL = 270Fh (9999) to locate line 9999. If not found, RST 08 with error code 07 is executed to invoke the ROM’s standard error-reporting path (“End of file”). When found, the routine reads the line’s size word and advances past the REM token to obtain the data start address and byte count, stores them in SIZE (68E6) and ADRS (68E8), copies the default header name via LDIR, opens channel K (FDh) via ROM call 1230, prints a message using ROM call 073F, and calls ROM 11CF to wait for a keypress. Then it writes the header block, waits one second using a HALT loop, and writes the data block.

One-Second Delay via HALT

Between writing the tape header and the data block, the code executes a loop:

  • LD B, 3Ch — load 60 into B.
  • HALT — suspend until the next interrupt (approximately every 17 ms).
  • DJNZ back to HALT — repeat 60 times ≈ 1020 ms ≈ 1 second.

This is a clean, CPU-idle delay that does not busy-wait, relying on the regular interrupt cadence.

BASIC Layer Techniques

Line 20 reads and saves the state of port 244 (IN 244), immediately outputs 0 to it, then calls the appropriate machine code routine. Line 40 restores the port state with OUT 244,c. The variable i$ is checked case-insensitively by testing both "L"/"l" and "S"/"s". Note that line 20 references I$ (uppercase) while line 10 assigns to i$ (lowercase); on this platform these are the same variable, so there is no bug.

Multiple Line 9999 Feature

The documentation in the REM deliberately notes that no check is made for a pre-existing line 9999 before the Load routine inserts one. This allows multiple line 9999 entries to accumulate, each carrying a different payload. The Save routine always processes the first one found; subsequent ones can be accessed by deleting the just-saved line (typing 9999 at the command prompt) and repeating RANDOMIZE USR 26860. This is described as intentional design.

Notable Anomalies

Line 1 is a REM whose content appears to be the raw machine code bytes interpreted as BASIC keyword tokens — a common technique for storing machine code in a REM at the start of a program. However, the working machine code documentation in line 9999 places the actual routines starting at address 685Bh (26715), while the BASIC calls reference USR 26750 (687Eh, LOAH) and USR 26860 (68ECh, SAVT). Line 1’s REM content as rendered includes many BASIC keywords, consistent with binary machine code bytes coinciding with keyword token values.

The assembly listing in line 9999 contains one apparent typographical error in the documentation: the DJNZ instruction is rendered as DJNZ,SA1S with a comma, which is non-standard Z80 assembly syntax but does not affect the actual machine code.

The header buffer’s last two bytes are documented as 00 80 (“end header flag=8000H”), but the byte at 68EA is 00 and 68EB is the ADD A,B opcode (80h) — this byte is shared with the start of the SAVT label’s LD HL,270F instruction, suggesting the header overlaps with the beginning of the Save routine. The 68EB: 80h byte serves dual purpose as both the header’s end-flag high byte and the first byte of the SAVT entry is actually at 68EC after the full LD HL,270F sequence, so the two-byte overlap is intentional layout optimization.

Image Gallery

Source Code

    1 REM NEXT PRINT FLASH COPY  THEN COPY OPEN #COPY FLASH POKE 2nh>OPEN #POKE LET DIM PRINT :nhOPEN #POKE FLASH COPY  THEN IN OPEN #COPY LET CLS <>INVERSE !FLASH h!DRAW >7 STEP [h STEP oh0FOR *K\GO SUB KNEW hFOR RESTORE STR$ FOR RESTORE  OR  STEP SQR STR$ LLIST RESTORE +6
    5 CLS :PRINT AT 21,0;"REMIZE ©1987 by Edwin L. Schoen"
   10 PRINT "Enter L to Load code to create"; TAB 0;" 9999 REM"; TAB 0;,,"or",,,,"Enter S to Save contents of"; TAB 0;"line 9999 REM":INPUT i$:IF i$ <>"L" AND i$ <>"l" AND i$ <>"S" AND i$ <>"s" THEN STOP 
   20 LET c= IN 244:OUT 244,0:IF I$="L" OR i$="l" THEN LET a= USR 26750:PRINT a:LPRINT a:GO TO 40
   30 IF I$="S" OR i$="s" THEN RANDOMIZE USR 26860
   40 OUT 244,c:STOP 
 9999 REM  ▜▜REMIZE▗▜▜        This machine code program is for the purpose of adding a text file to the body of a BASIC program so that it may be transmitted over modem to someone else just like a BASIC program, which it really is. It is accomplished by creating a REM statement as line 9999 and following the REM token with the text file as read from cassette tape in "bytes" format. The secondary purpose is to create such a tape text file when given the above mentioned REM line.▜▜        RAND USR 26750 will load the first file found on cassette tape, create a REM statement as line 9999 and append the cassette data to it. RAND USR 26860 will take such a REM statement and save the data following it onto tape for future loading into some text editors.▜▜        The intended steps to utilize this program are as follows. Firstly create a binary tape file (SCREEN$ or output of an enditor). Next load this program intothe 2068. Rewind the tape with the SCREEN$ or text file; press PLAY and then type RANDOMIZE USR 26750. Next SAVE the BASIC program you have just created on any medium. Now LOAD MTERM II or facsimile and LOAD your new BASIC program into it's buffer. The rest is really up to you to use XMODEM or other means of modem transmission.  When the receiver gets your BASIC program he should put his tape recorder of RECORD and type RANDOMIZE USR 26860 to SAVE the SCREEN$ or text file to his tape. Also he should keep a copy of the actual BASIC program (which contains the code below). It is good practice to type 9999 before running the LOAD portion of my program since no check is made when LOADing to see if line 9999 already exists. This is a feature, not a bug, which CAN allow you to create several line 9999's for transmission. However, be aware that when using the WRITE (26860) portion of my program only the FIRST 9999 will have it's contents written to tape. If several exist do several RAND USR 26860's each one followed by typing 9999 to delete the line just saved. ▜▜        This program shows how to call ROM routinex in the XROM, how to print to the screen, how to create a BASIC line, how to have the ROM print an ERROR report and how to have the ROM wait for a key to be pressed before proceeding. It also shows how to wait for 60 interrupts to provide a wait of 1 second by use of the HALT instruction. Interrupts occur approximately every 17ms so 60*17=1020ms=1.02seconds. Finally, it shows how to make room (insert) space into the body of a BASIC program.▜▜        My personal motive in giving this program into the public domain is to foster more machine code programming on the TS2068 and TS1000. (Note that all application ROM calls have their counterparts in the TS1000 ROM also.) Previously I have put programs on te NiteOwl to allw scannin te eyboard and finding a variables via ROM calls. Please feel free to use the ideas presented here and the program for non commercial purposes.▜▜▜685B F3       CALX DI           Enable XROM; call HL pgm▜685C F5            PUSH AF      ▜685D DBFF          IN A,(FF)▜685F CBFF          SET 7,A      Enable XROM▜6861 D2FF          OUT (FF),A▜6863 DBF4          IN A,(F4)▜6865 326E68        LD (SVF4),A▜6868 3E01          LD A,01▜686A D3F4          OUT (F4),A▜686C F1            POP AF▜686D E9            JP (HL)▜686E 00       SVF4 NOP          Save Horiz Sel status▜686F F5       RELX PUSH AF      Restore home ROM & Ints.▜6870 3A6E68        LD A,(SVF4)▜6873 D3F4          OUT (F4),A▜6875 DBFF          IN A,(FF)▜6877 CBBF          RES 7,A▜6879 D3FF          OUT (FF),A▜687B F1            POP AF▜687C FB            EI▜687D C9            RET▜687E DD21DB68 LOAH LD IX,HEDR   Entry to load tape to 9999▜6882 111100        LD DE,0011   Size of Header=17 bytes▜6885 21FC00        LD HL,00FC   Adrs. of XROM R_TAPE▜6888 3E00          LD A,00      Tell XROM it's a Header▜688A 37            SCF          Really LOAD not VERIFY▜688B CD5B68        CALL CALX    Read the Header▜688E CD6F68        CALL RELX    Release XROM▜6891 30EB          JR NC,LOAH   XROM error: go retry.▜6893 2A4B5C        LD HL,(vars) Adrs to insert=Variables▜6896 ED4BE668      LD BC,(SIZE) Prog. size from Header▜689A 110600        LD DE,0006   line no.(2),size(2),REM(1),C/R(1)▜689D EB            EX DE,HL▜689E 09            ADD HL,DE    Total line size▜689F E5            PUSH HL▜68A0 C1            POP BC▜68A1 EB            EX DE,HL     HL= adrs of VARS▜68A2 E5            PUSH HL▜68A3 C5            PUSH BC▜68A4 CDBB12        CALL 12BB    ROM call to make room▜68A7 C1            POP BC▜68A8 E1            POP HL▜68A9 E5            PUSH HL▜68AA 09            ADD HL,BC    Point past new area▜68AB 2B            DEC HL       Point to C/R loc.▜68AC 360D          LD (HL),0D   End line with C/R.▜68AE E1            POP HL▜68AF 3627          LD (HL),27   Make line no. 9999▜68B1 23            INC HL▜68B2 360F          LD (HL),0F▜68B4 23            INC HL▜68B5 0B            DEC BC       Form correct line 9999 size▜68B6 0B            DEC BC▜68B7 0B            DEC BC▜68B8 0B            DEC BC▜68B9 71            LD (HL),C▜68BA 23            INC HL▜68BB 70            LD (HL),B▜68BC 23            INC HL▜68BD 36EA          LD (HL),EA   Add REM to line.▜68BF 23            INC HL▜68C0 0B            DEC BC       Remove REM & C/R from size▜68C1 0B            DEC BC▜68C2 C5            PUSH BC▜68C3 E5            PUSH HL▜68C4 DDE1     LOAD POP IX       XROM wants IX=adrs to load to.▜68C6 3EFF          LD A,FF      Tell XROM load DATA▜68C8 D1            POP DE       XROM WANTS DE=bytes to load▜68C9 D5            PUSH DE▜68CA DDE5          PUSH IX▜68CC 37            SCF          Tell XROM to Load not Verify▜68CD 21FC00        LD HL,00FC▜68D0 CD5B68        CALL CALX▜68D3 CD6F68        CALL RELX▜68D6 C1            POP BC▜68D7 E1            POP HL▜68D8 30EA          JR NC,LOAD   Error=go reload data▜68DA C9            RET▜68DB 03       HEDR INC BC       Tape header; type=3▜68DC 00            NOP          These 10 bytes=ascii name▜68DD 00            NOP▜68DE 00            NOP▜68DF 00            NOP▜68E0 00            NOP▜68E1 00            NOP▜68E2 00            NOP▜68E3 00            NOP▜68E4 00            NOP▜68E5 00            NOP▜68E6 00       SIZE NOP          Byte size of file▜68E7 00            NOP▜68E8 00       ADRS NOP          Address to load to▜68E9 00            NOP▜68EA 00            NOP          end header flag=8000H▜68EB 80            ADD A,B▜68EC 210F27   SAVT LD HL,270F   HEX FOR 9999.▜68EF CDD616        CALL 16D6    Rom call for adrs of 9999.▜68F2 2802          JR Z,SFND    Found it!▜68F4 CF            RST 08       Print End of file if no 9999.▜68F5 07             ERROR #8▜68F6 23       SFND INC HL       Found 9999. point to size▜68F7 23            INC HL▜68F8 4E            LD C,(HL)    Get size of line 9999.▜68F9 23            INC HL▜68FA 46            LD B,(HL)▜68FB 23            INC HL▜68FC 23            INC HL       Point past the REM▜68FD 0B            DEC BC       Lower size by REM & C/R.▜68FE 0B            DEC BC▜68FF ED43E668      LD (SIZE),BC▜6903 22E868        LD (ADRS),HL▜6906 E5            PUSH HL▜6907 215169        LD HL,ELSN   Point to default header name▜690A 11DB68        LD DE,HEDR▜690D D5            PUSH DE▜690E 010B00        LD BC,000B   Type + name = 11 bytes▜6911 EDB0          LDIR         Move type & name to header▜6913 3EFD          LD A,FD      Open channel K▜6915 CD3012        CALL 1230    Rom call to open channel▜6918 AF            XOR A        Message index 0 ▜6919 11893C        LD DE,3C89   Mesg. tbl. adrs.▜691C CD3F07        CALL 073F    Print the message▜691F 213C5C        LD HL,TV-FLAGS▜6922 CBEE          SET 5,(HL)   Show must clear screen▜6924 CDCF11        CALL 11CF    Wait for key press.▜6927 DDE1          POP IX       Adrs of Header ▜6929 111100        LD DE,0011   Size of header= 17 bytes▜692C AF            XOR A▜692D 216800        LD HL,0068   XROM W_TAPE address.▜6930 E5            PUSH HL▜6931 CD5B68        CALL CALX    Write header to tape▜6934 CD6F68        CALL RELX▜6937 063C          LD B,3C      Count 60 ints.▜6939 76       SA1S HALT         Allow 60 ints to occur▜693A 10FD          DJNZ,SA1S▜693C ED5BE668      LD DE,(SIZE)▜6940 3EFF          LD A,FF▜6942 E1            POP HL▜6943 DDE1          POP IX▜6945 CD5B68        CALL CALX    Write DATA to tape.▜6948 F3            DI           Insure against kbd. int.▜6949 CD6F68        CALL RELX    Release XROM; enable ints.▜694C C9            RET▜6951 03       ELSN INC BC       Default 11-byte header▜6952 45            DEFW "E.L.SCHOEN"▜ ▜▜   

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