Skip to content

Sinclair ZX81 and ZX Spectrum ​

The Sinclair machines use the Z80 (CPU families). On the ZX81 the CPU also generates the display. On the Spectrum, the ULA delays the CPU when both use contended memory. An instruction's timing therefore depends on where the ULA is in the frame. The contention tables differ by model. Spectrum games came mostly on tape, often with turbo or protected loaders.

Sinclair ZX81 ​

Hardware ​

FactValue
Years1981–1984; launched in the UK on 5 March 1981 at £69.95 assembled
SalesOver 1.5 million
CPUZ80A, 3.25 MHz (the source also says 3.5 MHz)
RAM1 KB, with a 16 KB pack
VideoFerranti ULA; the CPU generates the display

The CPU generates the display, so FAST mode blanks the screen to run faster (Wikipedia: ZX81).

How games were made and loaded ​

Games loaded from tape at roughly 250–300 bit/s (Wikipedia: ZX81).

Media and image formats ​

The ZX81's tape encoding differs from the Spectrum's. TZX does not describe it natively (TZX format).

Tools ​

EightyOne covers the ZX81 (debugger features not confirmed).

Projects to learn from ​

None listed yet.

For an exact reimplementation ​

  • Record whether the game runs in FAST mode or with the display on. The CPU time left for the game depends on it.

ZX Spectrum 48K, 128K, +2, +2A and +3 ​

Hardware ​

ModelLaunchCPURAM
48K23 April 1982Z80A, 3.5 MHz16 or 48 KB
128KSpain September 1985, UK January 19863.5469 MHz (not confirmed)128 KB as eight 16 KB pages
+21986 (Amstrad)As the 128K128 KB
+31987As the 128K128 KB
+2ALate 1988As the 128K128 KB

Sources: Wikipedia: ZX Spectrum, Sinclair Wiki: ZX Spectrum 128.

The ULA gives 256x192 pixels with 8x8 attribute cells. The 128K models add an AY-3-8912 sound chip.

Memory map and paging. The 48K map puts ROM at 0x0000–0x3FFF, the screen bitmap at 0x4000–0x57FF and the attributes at 0x5800–0x5AFF (not confirmed) (Sinclair Wiki). On 128K models, port 0x7FFD selects the RAM page at 0xC000, the shadow screen, the ROM and a lock bit. The +2A and +3 add port 0x1FFD for all-RAM modes (not confirmed) (Sinclair Wiki: ZX Spectrum 128).

Contended memory. The ULA delays CPU accesses to contended memory while it reads the screen. The delays differ by model (Sinclair Wiki: Contended memory).

ModelContended areaFirst contended T-stateDelay pattern per 8 T-statesT-states per line
48K0x4000–0x7FFF14335 after the interrupt6,5,4,3,2,1,0,0224
128K, +2Pages 1, 3, 5 and 714361As the 48K228
+2A, +3Pages 4 to 7, only when MREQ is active143637,6,5,4,3,2,1,0,0

"Late timing" ULAs run one T-state later than the 48K figure.

Frames. A frame lasts 69888 T-states on the 48K and 70908 on the 128K, with one maskable interrupt per frame. Most games use IM 2 (not confirmed) (World of Spectrum FAQ).

How games were made and loaded ​

Spectrum tapes carried turbo and protected loaders such as Speedlock and Alkatraz. A loader was often a BASIC stub followed by machine code that decrypts the next stage (not confirmed) (Sinclair Wiki: Tape protection schemes). The +3 used 3-inch disks protected with non-standard sectors (not confirmed) (CPCWiki: Copy protection).

Media and image formats ​

FormatWhat it holds
TZXTape with exact timing; keeps turbo and protected loaders
TAPOnly standard ROM-loader blocks
PZXTape (read by SkoolKit)
SNA, Z80Snapshots
SZXSnapshot with fuller machine state
RZXA recording of input for replay (not confirmed)

TZX was designed to keep turbo and protected loaders working. Revision 1.20 stores pilot, sync and bit timings in T-states at 3.5 MHz. It also stores pulse sequences, direct recordings and generalised symbol encodings. Block 0x10 is standard timing and 0x11 turbo. Block 0x13 is a pulse sequence used by some protections. Block 0x15 is a direct recording and 0x19 generalised data (TZX format). The snapshot formats are described on the Sinclair Wiki: file formats page (not confirmed).

Tools ​

  • SkoolKit reads TAP, TZX and PZX tapes and Z80 and SZX snapshots. It also plays RZX recordings. Its tap2sna.py simulates tape loading. Its trace.py traces execution and can write AY output as WAV (SkoolKit). SkoolKit is GPL-3.0.
  • Fuse (fuse-emulator.sourceforge.net), ZEsarUX (github.com/chernandezba/zesarux) and SpecEmu (specemu.zxe.io) have debuggers.
  • ZEsarUX has a remote protocol that a script can drive.
  • Ghidra has the Z80 built in. Unicorn has no Z80. For ground truth use a small core such as iz80 (CPU families).

The community references are Spectrum Computing (spectrumcomputing.co.uk), World of Spectrum (worldofspectrum.org) and the Sinclair Wiki (sinclair.wiki.zxnet.co.uk).

Projects to learn from ​

SkoolKit's published disassemblies include Skool Daze, Back to Skool, Contact Sam Cruise, Manic Miner, Jet Set Willy, Hungry Horace and the 48K ROM (SkoolKit disassemblies). Each one reassembles byte for byte to the original. A port can check its results against them. Before you copy anything from a disassembly, check whether it includes game bytes and what its licence is.

For an exact reimplementation ​

  • Record the model. The contention tables and the frame length differ between the 48K, the 128K and the +2A/+3.
  • Record whether the ULA has early or late timing.
  • Get past the loader in an emulator, then snapshot the game in memory (snapshot after the loader).
  • Keep the TZX image as the record of what shipped.
  • If the game must match frame timing, model the contention table for the model you chose.

Code: Apache 2.0. Content: CC0 1.0. No game material: bring your own copy.