Header5

Developer(s): Bill Ferrebee
Date: 198x
Type: Program
Platform(s): TS 2068
Tags: Header, Tape

Header is a TS2068 utility that reads and displays the contents of cassette file-header blocks, reporting metadata such as file type, filename, data length, start address, and auto-start line number. It uses a 53-byte machine code routine POKEd into RAM at address 64000 that interfaces with the cassette hardware to read a 17-byte standard header block. Both screen and printer output are supported simultaneously via paired PRINT and LPRINT statements. The program decodes the Spectrum-compatible header format, recognizing all four block types: BASIC program (0), numeric array (1), character array (2), and bytes (3). Array variable names are recovered by masking the stored identifier byte with modulo-32 arithmetic and adding 96.


Program Analysis

Program Structure

The program is organized as a tight, single-pass loop across a handful of high-numbered lines (9969–9999), consistent with a utility designed to sit in upper memory without conflicting with user programs. The flow is:

  1. 9969 — Set up error trap, display splash/credit screen, wait for keypress.
  2. 9970 — Allocate memory, dimension the filename buffer b$, and DATA-load the machine code routine.
  3. 9971 — DATA statement holding the 53-byte machine code payload.
  4. 9975 — Prompt user to insert tape and press PLAY.
  5. 9982 — Call machine code; parse and display the decoded header fields.
  6. 9983 — Conditional branch: print array identifier for types 1 and 2.
  7. 9988 — Print data length; for type 3 (BYTES), print start address.
  8. 9991–9994 — For type 0 (BASIC), optionally print auto-start line and PROG/VARS length.
  9. 9995 — Loop back to 9982; the REM contains dead code for an interactive stop prompt.
  10. 9996 — Error handler: ON ERR RESET : STOP — catches BREAK or tape errors and halts gracefully.

Machine Code Routine

The 53-byte routine is POKEd into address 64000 (FA00h) and invoked via RANDOMIZE USR a0. The DATA values decode to Z80 instructions that interface directly with the cassette hardware. Key observations from the byte sequence:

  • 55EX AF,AF' (preamble state save)
  • 62,0LD A,0 (select header block type)
  • 221,33,60,250LD IX,FA3Ch (pointer to the 17-byte header buffer at a0+60)
  • 17,17,0LD DE,17 (header block length)
  • 205,14,250CALL FA0Eh (self-referential call within the routine — actually calls the ROM tape-load routine via a trampoline, or is an internal subroutine)
  • 201RET
  • 211,244 / 219,255OUT (0F4h),A / IN A,(0FFh) — direct I/O port access for the TS2068 cassette interface
  • 203,191 / 203,255RES 7,A / SET 7,A — bit manipulation of the port value
  • 251EI (re-enable interrupts after cassette operation)
  • 243DI (disable interrupts during sensitive I/O)
  • 241POP AF / 233JP (HL) (indirect jump, likely into ROM tape routines)

After the call returns, the header data is read starting at a0+60 (FA3Ch): byte 0 is the file type s, bytes 1–10 are the 10-character filename stored into b$(), and subsequent bytes hold length, parameter 1, and parameter 2 words in little-endian format.

Header Block Decoding

The standard Spectrum-compatible cassette header is 17 bytes (plus flag and checksum bytes managed by the loader). The program maps the relevant fields as follows:

Offset from a0+60FieldBASIC variable
0File type (0–3)s
1–10Filename (10 chars)b$(1)…b$(10)
11–12Data length (little-endian)PEEK a + 256*PEEK(a+1)
13–14Parameter 1 (start/auto-start)b = PEEK(a+2)+256*PEEK(a+3)
15–16Parameter 2 (PROG/VARS length)PEEK(a+4)+256*PEEK(a+5)

Key BASIC Idioms

Line 9982 uses the Boolean string multiplication idiom characteristic of Sinclair BASIC: ("BASIC PROGRAM: " AND (s=0)) evaluates to the string if the condition is true, or an empty string otherwise. The four such terms are concatenated with b$ to form the labelled filename line in a single expression, avoiding a multi-branch IF/THEN structure.

The ON ERR keyword (TS2068 extension, represented as { in source) is used at line 9969 to trap errors including BREAK, redirecting to line 9996 where RESET (another TS2068 extension) clears the error state before STOP.

Array Identifier Recovery (Line 9983)

For array types (s=1 numeric, s=2 character), the variable name byte stored in the header encodes the letter in bits 4–0. The expression b - 32*INT(b/32) + 96 computes (b MOD 32) + 96, mapping the stored value back to a lowercase ASCII letter. A "$" suffix is appended for character arrays using the Boolean string idiom.

Auto-Start Detection (Line 9993)

For BASIC files (s=0), parameter 1 holds the auto-start line number, or 32768 (8000h) if no auto-start is set. The program checks b <> 32768 before printing the auto-start line, correctly suppressing the field when absent.

Dead Code

Line 9995 contains a GO TO 9982 followed by a REM statement. The text inside the REM is the remnant of an earlier interactive prompt (asking whether to stop or read another header) that was replaced by the unconditional loop. The prompt logic — including a variable q$ and string comparisons for "STOP" — is entirely unreachable.

Memory Layout

CLEAR (a0-1) at line 9970 sets the RAMTOP to 63999, protecting the machine code area from 64000 upward against BASIC heap expansion. The machine code buffer starts at FA00h and the header data buffer is placed at FA3Ch (offset 60), neatly separated from the executable code.

Content

Appears On

A compact sampler from the Chicago Area group — render a 3D isometric bar chart, hear Bach's Minuet in G in multi-voice polyphony, and explore a catalog of screen animation techniques all on one tape.

Related Products

Related Articles

Related Content

Image Gallery

Source Code

 9969 ON ERR GO TO 9996: CLS : PRINT "Header, a public-domain program published by T-S Horizons Dec.  1984 from T/S User Group in     Nashville, TN via Bill Ferrebee."'''"The program reads and reports   the contents of T/S 2068 cas-   sette file-header blocks using  screen and printer(if it's on.)": PRINT #0; FLASH 1;" Push any key to start ": PAUSE 0
 9970 LET a0=64000: CLEAR (a0-1): DIM b$(10): LET a0=64000: RESTORE 9971: FOR a=a0 TO a0+52: READ b: POKE a,b: NEXT a
 9971 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,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
 9975 CLS : PRINT #0; FLASH 1;"  Insert a tape and press PLAY  Hit BREAK AT ANY TIME TO STOP "
 9982 RANDOMIZE USR a0: CLS : LET a=a0+60: LET s=PEEK a: FOR c=1 TO 10: LET b$(c)=CHR$ PEEK (a+c): NEXT c: LET a$=("BASIC PROGRAM: " AND (s=0))+("NUMERIC ARRAY: " AND (s=1))+("CHARACTER ARRAY: " AND (s=2))+("BYTES: " AND (s=3))+b$: LPRINT 'a$: PRINT 'a$: LET a=a+c
 9983 IF s=1 OR s=2 THEN LET b=PEEK (a+3): LET b=b-32*INT (b/32)+96: LET a$="Array i.d.: "+CHR$ b+("$" AND (s=2)): LPRINT a$: PRINT a$
 9988 LET a$=" DATA LENGTH: "+STR$ (PEEK a+256*PEEK (a+1)): LPRINT a$: PRINT a$: LET b=PEEK (a+2)+256*PEEK (a+3): IF s=3 THEN LET a$="START ADDRESS: "+STR$ b: LPRINT a$: PRINT a$
 9991 IF s THEN GO TO 9995
 9993 IF b<>32768 THEN LET a$="AUTO START AT : "+STR$ b: LPRINT a$: PRINT a$
 9994 LET a$="PROG/VARS LENGTH: "+STR$ (PEEK (a+4)+256*PEEK (a+5)): LPRINT a$: PRINT a$
 9995 GO TO 9982: REM INPUT FLASH 1;"Enter  STOP (key or word) to end OR push any other key to read  another file header. ";q$: IF q$<>"STOP" AND q$<>"stop" AND q$<>" STOP " THEN GO TO 9975
 9996 ON ERR RESET : STOP 
 9999 SAVE "Header5" LINE 9969

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

Scroll to Top