--- title: "Catalog" id: 56286 type: "computer_media" slug: "catalog" url: "http://localhost/computer_media/catalog/" markdown_url: "http://localhost/computer_media/catalog.md" published_at: "2024-08-04T10:49:46+00:00" modified_at: "2026-03-30T21:29:24+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "A machine-code powered tape cataloger that reads headers from a running tape, identifies file types and names, and estimates their physical position automatically." 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/" genre: - name: "Tape Directory" slug: "tape-directory" taxonomy: "genre" url: "http://localhost/type/tape-directory/" media_contents: - id: 56277 title: "Timex Sinclair Public Domain Library Tape 2001" type: "computer_media" url: "http://localhost/computer_media/timex-sinclair-public-domain-library-tape-2001/" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/Catalog%20%28198x%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/08/SCR-20260330-pbnw.png" media_type_tags: "Tape Directory" --- # Catalog This program scans a tape and catalogs the file headers found on it, printing each file’s type, name, and estimated tape position to both the screen and a printer. Machine code is loaded into RAM at address 64000 via a DATA block and called with RANDOMIZE USR 64000; the routine reads a tape header block using the ROM’s tape-loading entry points and stores the result in a small buffer at address 64060 onwards. The tape position estimate is calculated by dividing a counter accumulated in system variables 23672/23673 by a tunable `factor` constant (set to 130), giving an approximate location in seconds or tape units. After displaying each header, the program pauses for a duration proportional to the file’s length (derived from the two-byte value at 64071/64072) before looping back to search for the next header, allowing the tape to advance to the next file. *** ## Program Analysis ### Program Structure The program is organised into four broad phases: 1. **Initialisation (lines 20–60):** Clears memory above 63999, POKEs 53 bytes of machine code into addresses 64000–64052, and configures system variables. 2. **Machine-code call (line 80):** Executes the tape-reading routine via `RANDOMIZE USR 64000`. 3. **Header display (lines 90–150):** Reads the buffer written by the machine code and prints the file type, 10-character name, and estimated tape position to screen and printer. 4. **Pause and loop (line 170):** Waits a time proportional to the file’s data length, then jumps back to line 80 to catch the next header. ### Machine Code Routine The 53 bytes loaded at 64000–64052 form a Z80 routine. Reconstructing it from the DATA values: - `55` — SCF (set carry flag, signalling ROM tape loader to load rather than verify) - `62,0` — LD A,0 (request header block, type 0xFF in ROM terms — actually A=0 selects header) - `221,33,60,250` — LD IX,64060 (destination buffer for the 17-byte header) - `17,17,0` — LD DE,17 (length of a tape header block) - `205,14,250` — CALL 64014 (an inner sub-routine within the block, or the ROM LD-BYTES entry via a relay) - `201` — RET The second DATA line (line 50) contains the relay/counter sub-routine starting near 64027. It uses `243` (DI), `251` (EI), `219,255` (IN A,(255)) and `211,244/255` (OUT) sequences that interact with the tape input port and an EAR-sampling loop, incrementing the 16-bit counter stored in system variables 23672–23673 to track elapsed tape time. The ROM tape-loading entry point is invoked indirectly. The header data (flag byte, file type, 10-char name, length, and parameters) ends up at address 64060 onward, giving the BASIC program easy access via `PEEK`. ### Buffer Layout at Address 64060 | Address | Content | | --- | --- | | 64060 | File type byte (0=Program, 1=Numeric array, 2=Character array, 3=Bytes) | | 64061–64070 | 10-character filename | | 64071–64072 | Data length (2 bytes, little-endian) | ### Tape Position Estimation Lines 60 and 150 implement a software tape-position counter. `POKE 23673,0: POKE 23672,110` initialises the 16-bit counter in the system variable area to 110. After the machine code runs, the routine in line 150 reads back the counter with `PEEK 23672+256*PEEK 23673`, divides by `factor` (130), and rounds to the nearest integer to give an estimated position. The `factor` variable on line 70 is deliberately exposed so the user can calibrate it for their tape deck speed. ### Pause Duration Proportional to File Length Line 160 reads the two-byte data-length field from addresses 64071–64072. Line 170 then computes `PAUSE 300+p/3.6`, pausing roughly proportional to how long the file’s data block will take to load, so the machine-code loop is re-entered just as the next header becomes due. This is an elegant timing heuristic rather than a precise synchronisation. ### Dual Output Every PRINT statement on lines 100–150 is mirrored by a corresponding `LPRINT`, sending the catalog simultaneously to screen and to a printer. The `POKE 23692,255` on line 60 disables the scroll prompt (“scroll?”) so the screen output is never interrupted. ### Key BASIC Idioms - `RANDOMIZE USR 64000` — standard idiom for calling machine code without caring about the return value. - `LET loc=INT(.5+…)` — rounding to nearest integer via adding 0.5 before truncation. - Chained `IF b=n THEN …` statements (lines 100–130) used instead of a computed branch, since there are only four file types to handle. ### Potential Issues - If the tape routine fails (e.g., no signal or wrong block type), `RANDOMIZE USR 64000` may return an error or hang, as there is no error-trapping logic. - The `factor` calibration value of 130 is machine- and deck-specific; no guidance is provided in the program for adjusting it. - The counter initialisation in line 60 sets 23672 to 110 rather than 0; this appears intentional as a pre-offset to account for the time before the first header, but its exact purpose is not documented in the listing. ## Source Code ``` 10 REM save"catalog" line 10 20 CLEAR 63999: FOR a=64000 TO 64052: READ b: POKE a,b: NEXT a 30 CLS : PRINT "Run the tape to be scanned": PRINT AT 0,0; 40 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 50 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 60 POKE 23692,255: POKE 23673,0: POKE 23672,110 70 LET factor=130 80 RANDOMIZE USR 64000 90 LET a=64060: LET b=PEEK a: LET s=b 100 IF b=0 THEN LPRINT "Program: ";: PRINT "Program: "; 110 IF b=1 THEN LPRINT "Numeric array: ";: PRINT "Numeric array: "; 120 IF b=2 THEN LPRINT "Character array: ";: PRINT "Character array: "; 130 IF b=3 THEN LPRINT "Bytes: ";: PRINT "Bytes: "; 140 FOR a=64061 TO 64070: LET b=PEEK a: LPRINT CHR$ b;: PRINT CHR$ b;: NEXT a 150 LET loc=INT (.5+((PEEK 23672+256*PEEK 23673)/factor)): PRINT TAB 22;"at ";loc: LPRINT TAB 22;"at ";loc 160 LET p=PEEK 64071+256*PEEK 64072 170 PAUSE 300+p/3.6: GO TO 80 ```