Spectrum tape interface

From Sinclair Wiki
Jump to navigation Jump to search
  • This article is about the ZX Spectrum ROM load/save format. For the .TAP emulator format see TAP format

The Spectrum ROM routines save files to tape in two blocks, a header and a data block. Each of these blocks is encoded as a sequence of pulses.

There are also a wide variety of "custom loaders" which have been used for Spectrum software, for purposes such as copy protection or faster loading times. This article deals only with the format written by the Spectrum ROM.

Pulses

A 'pulse' here is either a mark or a space, so 2 pulses makes a complete square wave cycle.

Pilot tone: before each block is a sequence of 8063 (header) or 3223 (data) pulses, each of length 2168 T-states.

Sync pulses: the pilot tone is followed by two sync pulses of 667 and 735 T-states resp.

A '0' bit is encoded as 2 pulses of 855 T-states each.

A '1' bit is encoded as 2 pulses of 1710 T-states each (ie. twice the length of a '0')

The initial polarity of the signal does not matter - everything in the ROM loader is edge-triggered rather than level-triggered.

Speed

Due to the fact that the different bits take different time on tape, the Spectrum's tape routine does not have a well-defined speed. We can calculate some limits and typical values though; as noted above, a '0' bit takes 2 × 855 = 1710 T-states and a '1' bit takes 2 × 1710 = 3420 T-states. Assuming a 48K Spectrum which runs at 3.50 MHz (the 128K machines run at 3.54 MHz or about 1% faster; that difference is largely irrelevant here), this means:

  • A stream of pure '0' bits loads at 3500000 ÷ 1710 ≈ 2046 baud
  • A stream of pure '1' bits loads at 3500000 ÷ 3420 ≈ 1023 baud
  • A mixed stream with equal numbers of '0' and '1' bits loads at 2 × 3500000 ÷ (3420 + 1710) ≈ 1364 baud

Real world Spectrum data tended to have more '0' bits than '1' bits, so the typical baud rate was actually a bit higher than 1364 baud.

Blocks

On the tape every block start with a marker byte (0x00 for header and 0xff for data blocks) and ends with a checksum byte.

The checksum byte is not really a sum, but a binary XOR of all header/data bytes.

Header block

The header, which is 17 bytes long, is as follows:

Byte (decimal) Length Description
0 1 Type (0,1,2 or 3)
1 10 Filename (padded with blanks)
11 2 Length of data block
13 2 Parameter 1
15 2 Parameter 2

The type is 0,1,2 or 3 for a Program, Number array, Character array or Code file. A SCREEN$ file is regarded as a Code file with start address 16384 and length 6912 decimal. If the file is a Program file, parameter 1 holds the autostart line number (or a number >=32768 if no LINE parameter was given) and parameter 2 holds the start of the variable area relative to the start of the program. If it's a Code file, parameter 1 holds the start of the code block when saved, and parameter 2 holds 32768. For data files finally, the byte at position 14 decimal holds the variable name:

Bits 7 6 5 4 3 2 1 0 Description
Numeric array 1 0 0 x x x x x xxxxx = CODE(Name) - 0x60; e.g. DIM a() ⇒ 0x81, DIM y() ⇒ 0x99
String array 1 1 0 x x x x x xxxxx = CODE(Name) - 0x60; e.g. DIM a$() ⇒ 0xc1, DIM y$() ⇒ 0xd9

Data block

Arrays

Number and string arrays are stored on tape in the same format as in RAM [1] except that the very first byte (the name of the array) is absent. The name of the array stored in the second byte of Parameter 1 in header block.

For example data block of a 2×3 numeric array (with small integer numbers):

Byte (decimal) Length Example value Description
0 1 0x02 Number of dimensions - DIM(2,3)
1 2 0x02 0x00 Dimension 1 - 2
3 2 0x03 0x00 Dimension 2 (0x03 0x00 - 3)
5 5 0x00 0x00 0x6f 0x00 0x00 First number - 111
10 5 0x00 0x00 0x79 0x00 0x00 Second number - 121
... 5 .. .. .. .. .. ... number
30 5 0x00 0x00 0xd3 0x00 0x00 Last number - 211

Note: although the array name is saved, you cannot just LOAD "" DATA, you have to explicitly say where to load: e.g. LOAD "" DATA w(), but you can use any letter regardless of the original array name.

BASIC programs

Program files are stored as a sequence of lines each stored the same way it is in RAM:

Line number[2BE] Length[2] Text[] 0x0D[1]

Note that numeric literals will be stored in both text and binary (text[] 0x0E[1] zxfloat[5]).

CODE, SCREEN$ - bytes

Code files are stored as a flat sequence of bytes, in the order they appear in RAM.