Multi Tape

This file is part of CATS Library Tape 8, ISTUG Public Domain Library 5, and Timex Sinclair Public Domain Library Tape 2003. Download the collection to get this file.
Date: 1986
Type: Program
Platform(s): TS 2068

This program catalogs tape headers from both TS2068 and Spectrum cassettes, storing the results in three parallel arrays: a numeric array `c(400,4)` for data length, start address, auto-start line, and program/vars length; a string array `n$(400,13)` for tape names/sides; and a string array `t$(400,28)` for header type and program name. A 53-byte machine code routine is POKEd into RAM starting at address 64000 and called via `RANDOMIZE USR 64000` to read raw tape header bytes into memory around address 64060, which BASIC then inspects with `PEEK` to decode header fields. The catalog can hold up to 400 entries and supports searching by program name or tape name, listing all programs, displaying full header details, and saving the catalog back to tape. The program requires a `CLEAR 63999` before reloading for the “continue cataloging” option (option 4) to preserve the arrays already in memory.


Program Analysis

Program Structure

The program is organized into distinct functional blocks accessed via a numbered menu at line 60. Lines 1–4 serve as a one-time instruction screen, after which line 5 sets a global error handler and line 9 jumps to the main menu at line 55. The menu at lines 60–98 polls INKEY$ in a tight loop and dispatches to subroutines for each option.

LinesFunction
1–4First-run instructions (intended to be deleted)
10–40Option 1: List all programs (brief format)
50SAVE with auto-start at line 55
55–98Main menu and dispatcher
100–140Option 2: Search by program name
200–240Option 3: List programs on a specific tape
300–340Raw header dump (all fields)
400–440Option 7: Show full header detail for one entry
500–540Option 8: Show unique tape names (also a subroutine for option 3)
9850–9865Option 4: Continue cataloging (with CLEAR 63999 check)
9870–9875Shared machine code POKE and tape-name input for option 4
9970–9995Option 5: Fresh catalog start; machine code load and header reading loop
9980–9982DATA statements containing the 53-byte machine code routine

Machine Code Routine

The core of the cataloging mechanism is a 53-byte Z80 machine code routine POKEd into addresses 64000–64052 via a FOR/READ/POKE/NEXT loop at lines 9870 or 9970. It is invoked with RANDOMIZE USR 64000 at line 9982. This routine reads a tape header block and deposits the raw bytes into memory starting around address 64060, which BASIC then reads back using PEEK.

The DATA bytes span lines 9980–9982 (27 + 26 = 53 bytes, with the loop running 64000 TO 64052, giving 53 iterations). The first byte, 55 (decimal), disassembles as Z80 PUSH HL, and the routine references I/O port 244 (the cassette EAR port area) and port 255, consistent with tape reading on this hardware. The result byte at address 64060 encodes the header type (0=PROGRAM, 1=NUMERIC ARRAY, 2=CHARACTER ARRAY, 3=BYTES).

Data Storage Arrays

Three parallel arrays are dimensioned at line 9972 for up to 400 tape entries:

  • c(400,4) — numeric: data length, start address, auto-start line, prog/vars length
  • n$(400,13) — string: tape name/side label (user-supplied)
  • t$(400,28) — string: header type (columns 1–17) and program name (columns 18–27)

The structured slicing of t$ is used consistently: t$(q,16 TO 27) gives the type+name region for brief listings, t$(q,18 TO ) gives the program name alone for searches. The type field is padded to 17 characters so that name data always starts at column 18.

Header Parsing

After the machine code call, BASIC reads header fields by sequential PEEK operations starting at address 64060. The variable a is used as a pointer, advancing through the header structure:

  1. PEEK 64060 — header type byte (stored in s)
  2. PEEK 64061 to PEEK 64070 — 10-character program name
  3. Two-byte little-endian word: data length → c(n,1)
  4. Two-byte little-endian word: start address (BYTES) or auto-start (PROGRAM) → c(n,2) / c(n,3)
  5. Two-byte little-endian word: prog/vars length → c(n,4)

The little-endian decode idiom used throughout is PEEK a + 256 * PEEK (a+1), standard for this platform.

Key BASIC Idioms and Techniques

  • Error handling: Line 5 uses ON ERR RESET (TS2068 extension) as a global guard. Line 55 resets it to ON ERR GO TO 5 so tape-read errors restart the menu rather than crashing.
  • INKEY$ polling loop: Lines 85–98 loop without a PAUSE, relying on the fast polling of INKEY$; this is a busy-wait menu, which means only one keypress is needed (no ENTER required).
  • Dual PRINT/LPRINT: Nearly every display line has a paired LPRINT statement on the next line number, allowing simultaneous screen and printer output throughout all listing options.
  • Subroutine reuse: The tape-name listing block at lines 500–540 doubles as a subroutine (called via GO SUB 500 from line 200) and a standalone option. The dir flag at line 535 controls whether it returns or falls through to STOP.
  • Array persistence: Option 4 relies on the arrays remaining in memory after a tape load. The program instructs the user to CLEAR 63999 before loading, which sets RAMTOP just below the machine code area, preserving the arrays at higher addresses while allowing the program itself to reload.

Bugs and Anomalies

  • Line 9974 uses uppercase N as the loop variable (FOR N=1 TO 400), but lines 9977, 9988, 9989, 9994 reference lowercase n. On this platform BASIC variable names are case-sensitive for numeric variables only in some implementations; this may function correctly if the interpreter treats them as the same variable, but it is inconsistent coding.
  • The loop at line 9974 runs FOR N=1 TO 400, but there is no explicit n counter that advances beyond the NEXT n at line 9995. The NEXT n at line 9995 increments the loop variable and then jumps back to GO TO 9975, bypassing the FOR statement — this effectively makes the loop counter increment on each pass but the GO TO re-enters the loop body directly, which may cause unexpected behavior if the loop counter ever reaches 400.
  • Lines 300–340 (raw full header dump) are defined but not reachable from the menu; no menu option dispatches to line 300.
  • The t$ array is dimensioned with 28 columns, but the type strings “NUMERIC ARRAY” (13 chars) and “CHARACTER ARRAY” (15 chars) padded to column 17 plus the 10-character name fit within 27 characters, leaving the 28th column unused.

Content

Appears On

Capital Area Timex Sinclair User Group’s Library Tape.
Library tape of the Indiana Sinclair Timex User’s Group.
One of a series of library tapes. Programs on these tapes were renamed to a number series. This tape contained

Related Products

Related Articles

Related Content

Image Gallery

Multi Tape

Source Code

    1 PRINT "If you have numerous programs on a tape,e.g.LIST library tapes, this progam may help. It uses   the header reader from SYNTAX   and saves the data in arrays c, n$, t$" 
    2 PRINT '"The first time use option 5 from menu. Thereafter use option 4  BUT you must clear 63999 before loading the tape to use option 4! You can stop reading headers  anytime by pressing BREAK." 
    3 PRINT '"Program will read both 2068 and Spectrum headers but will only  run on a 2068"
    4 PRINT '"If program stops with an error  enter GOTO 55 (Do not use RUN)  DELETE lines 1 to 4 when you arefamiliar with these instructions"
    5 ON ERR RESET 
    6 PRINT ''''''"multi tape by RWM": PRINT '''"Press any key for menu": PAUSE 0
    9 GO TO 55
   10 CLS : FOR l=1 TO n
   20 PRINT l;TAB 3;t$(l,16 TO 27),n$(l)
   21 LPRINT l;TAB 3;t$(l,16 TO 27),n$(l)
   30 NEXT l
   40 STOP 
   50 SAVE "multi tape" LINE 55
   55 ON ERR GO TO 5
   56 LET dir=0
   60 CLS : PRINT '"Choose your option by number"
   65 PRINT '"1. List all programs "
   68 PRINT '"2. Find a specific program"
   72 PRINT '"3. List all programs on a          specific tape"
   75 PRINT '"4. Continue cataloging tapes"
   78 PRINT '"5. Start cataloging tapes" 
   80 PRINT '"6. SAVE"
   81 PRINT '"7. See header readings"
   82 PRINT '"8. Show names of tapes"
   83 PRINT '"0. STOP"
   85 IF INKEY$="1" THEN GO TO 10
   88 IF INKEY$="2" THEN GO TO 100
   90 IF INKEY$="3" THEN GO TO 200
   92 IF INKEY$="4" THEN GO TO 9850
   93 IF INKEY$="5" THEN GO TO 9970
   94 IF INKEY$="6" THEN SAVE "multi tape" LINE 1
   95 IF INKEY$="7" THEN GO TO 400
   96 IF INKEY$="8" THEN GO TO 500
   97 IF INKEY$="0" THEN PRINT "  Enter  GOTO 55   to Restart": ON ERR RESET : STOP 
   98 GO TO 85
  100 CLS : INPUT "Name of program? ";s$
  110 FOR q=1 TO n
  120 IF t$(q,18 TO (LEN s$+17))=s$ THEN PRINT q;TAB 5;t$(q,18 TO );n$(q): PRINT 
  121 IF t$(q,18 TO (LEN s$+17))=s$ THEN LPRINT q;TAB 5;t$(q,18 TO );n$(q)
  130 NEXT q
  140 STOP 
  200 CLS : LET dir=1: GO SUB 500: INPUT "Name/side of tape? ";s$ 
  210 FOR q=1 TO n
  220 IF n$(q, TO LEN s$)=s$ THEN PRINT q;TAB 4;t$(q,18 TO );n$(q);t$(q, TO 3)
  221 IF n$(q, TO LEN s$)=s$ THEN LPRINT q;TAB 4;t$(q,18 TO );n$(q)
  230 NEXT q
  240 STOP 
  300 CLS : FOR l=1 TO n
  310 PRINT l;TAB 3;t$(l)
  311 LPRINT l;TAB 3;t$(l)
  320 NEXT l
  330 STOP 
  340 STOP 
  400 INPUT "Number Please? ";b
  410 CLS : FOR l=1 TO n
  420 IF l=b THEN PRINT 'l;TAB 4;t$(l): PRINT '"Data Length ";c(l,1): PRINT '"Start Address ";c(l,2): PRINT '"Auto Start at ";c(l,3): PRINT '"Prog/Vars Length ";c(l,4)
  421 IF l=b THEN LPRINT 'l;TAB 4;t$(l): LPRINT '"Data Length ";c(l,1): LPRINT '"Start Address ";c(l,2): LPRINT '"Auto Start at ";c(l,3): LPRINT '"Prog/Vars Length ";c(l,4)
  430 NEXT l
  440 STOP 
  500 CLS : PRINT n$(1)
  501 LPRINT n$(1)
  510 FOR l=2 TO n
  520 IF n$(l)<>n$(l-1) THEN PRINT n$(l)
  521 IF n$(l)<>n$(l-1) THEN LPRINT n$(l)
  530 NEXT l
  535 IF dir=1 THEN LET dir=0: RETURN 
  540 STOP 
 9850 CLS : INPUT "Did you remember to CLEAR 63999 before loading this tape? Y/N ";c$
 9855 IF c$="Y" OR c$="y" THEN GO TO 9870
 9860 IF c$="N" OR c$="n" THEN PRINT AT 10,1;"Please CLEAR 63999 and reload this tape": ON ERR RESET : STOP 
 9865 GO TO 9850
 9870 RESTORE : FOR a=64000 TO 64052: READ b: POKE a,b: NEXT a
 9873 INPUT "Name/Side of tape ";p$: GO TO 9975
 9970 CLS : CLEAR 63999: FOR a=64000 TO 64052: READ b: POKE a,b: NEXT a
 9971 REM c(n,1)=DataLength, c(n,2)=Start Address, c(n,3)=Auto Start, c(n,4)=Prog/vars length
 9972 DIM c(400,4): DIM n$(400,13): DIM t$(400,28)
 9973 INPUT "Name/Side of tape ";p$
 9974 FOR N=1 TO 400
 9975 CLS : PRINT ''''"LOAD A TAPE AND PRESS""PLAY"""''''
 9977 LET n$(n)=p$
 9980 DATA 55,62,0,221,33,60,250,17,17,0,205,14,250,201,33,252,0,205,34,250,58,33,250,211,244,219,255
 9981 DATA 203,191,211,255,251,201,0,243,245,219,255,203,255,211,255,219,244,50,33,250,62,1,211,244,241,233
 9982 RANDOMIZE USR 64000
 9983 LET a=64060: LET b=PEEK a: LET s=b
 9984 IF b=0 THEN PRINT "PROGRAM: ";: LET t$(n, TO 17)="PROGRAM"
 9985 IF b=1 THEN PRINT "NUMERIC ARRAY: ";: LET t$(n, TO 17)="NUMERIC ARRAY"
 9986 IF b=2 THEN PRINT "CHARACTER ARRAY: ";: LET t$(n, TO 17)="CHARACTER ARRAY"
 9987 IF b=3 THEN PRINT "BYTES: ";: LET t$(n, TO 17)="BYTES"
 9988 FOR a=64061 TO 64070: LET b=PEEK a: PRINT CHR$ b;: LET t$(n,a-64043)=CHR$ b: NEXT a: PRINT 
 9989 LET b=PEEK a+256*PEEK (a+1): PRINT "DATA LENGTH: ";b: LET c(N,1)=b
 9990 LET a=a+2: LET b=PEEK a+256*PEEK (a+1): IF s=3 THEN PRINT "START ADDRESS: ";b: LET c(n,2)=b
 9991 IF s<>0 THEN GO TO 9995
 9992 IF b<1 OR b>9999 THEN GO TO 9994
 9993 PRINT "AUTO START AT: ";b: LET c(n,3)=b
 9994 LET a=a+2: LET b=PEEK a+256*PEEK (a+1): PRINT "PROG/VARS LENGTH: ";b: LET c(n,4)=b
 9995 PAUSE 200: NEXT n: GO TO 9975

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

People

No people associated with this content.

Scroll to Top