The Cassette I/O Challenge

The ZX Spectrum does not have a dedicated tape controller chip. All tape reading and writing is achieved through software routines that precisely control the timing of a single I/O line, which is one of the most demanding tasks for the Z80 CPU.

The Principle: Data is encoded using Pulse Width Modulation (PWM), where the duration of the tone (the pulse width) determines whether the CPU sends a binary ‘0’ or a binary ‘1’.

Output (Writing Data to Tape)

Writing data requires running a tight timing loop and sending the signal through Bit 4 of the `FEH′ I/O port (Part 72).

Writing a ‘0’ vs. a ‘1’:

Bit Value Pulse Width Timing Loop
Binary 0 Shorter ON/OFF pulse duration. Requires a shorter T-state delay loop.
Binary 1 Longer ON/OFF pulse duration. Requires a longer T-state delay loop.

The Header Block: Every data block starts with a slow Pilot Tone (a very long series of ‘1’ bits) and a Sync Pulse to give the tape recorder time to stabilize and synchronize the timing before the data begins.

Input (Reading Data from Tape)

Reading is much harder than writing because the CPU must constantly poll the EAR socket line for changes in the signal voltage.

The Input Port: The Spectrum reads the voltage level of the EAR socket through Bit 6 of the `FEH′ I/O port.

The Decoding Routine:

IO_PORT    EQU 0FEH
EAR_BIT    EQU 40H          ; 01000000B (Bit 6)

READ_BIT_LOOP:
    ; 1. Poll until the EAR bit (Bit 6) changes state (edge detection).
    CALL POLL_FOR_EDGE

    ; 2. Start a timer, then wait for the next edge.
    ; The duration of the pulse (the time between the two edges) determines if it was a '0' or '1'.
    
    ; 3. If the pulse duration is SHORT, decode as '0'.
    ; 4. If the pulse duration is LONG, decode as '1'.
    
    JP   DECODE_NEXT_BIT

Utilizing the ROM Routines

Since these timing routines are so incredibly precise and complex (requiring exact T-state counts), most assembly programmers do not write their own. Instead, they rely on the robust routines already present in the Spectrum’s System ROM.

Key ROM Entry Points:

Address Function Purpose
`0556H′ LOAD The main routine for loading a program from tape.
`04D0H′ SAVE The main routine for saving a block of memory to tape.

Usage: The assembly program loads the necessary parameters (start address′, length′, filename′) into specific registers and then executes CALL 0556H′ to hand off control to the proven ROM code.