Skip to content

The ULA

One Ferranti gate array: display, keyboard, sound and tape

The Uncommitted Logic Array (ULA) is the semi-custom Ferranti chip that generates the ZX Spectrum's picture, arbitrates its memory, scans its keyboard and drives its speaker, tape and border. Colour clash, contended memory and the one-bit beeper all come from it.

The ULA (uncommitted logic array) is the Ferranti chip that sits next to the Z80 in every Sinclair-era ZX Spectrum. An uncommitted logic array is a chip made as a standard grid of unconnected gates; each customer’s design is added as a single interconnection layer, which made custom logic affordable for a cheap home computer. Sinclair’s version generates the picture, decides when the processor may use memory, scans the keyboard, reads and writes the tape, drives the speaker and sets the border colour.

Sinclair engineer Richard Altwasser drew the logic design on paper and tested it on wire-wrapped TTL chips before it went to Ferranti. The chip was tight. Chris Smith, whose book reconstructs the ULA from its silicon, records that “very few gates would remain unused”, that the analogue video output had to borrow cells Ferranti intended for digital interfacing, and that the whole design had to fit in 40 pins. The first chips were made in the spring of 1982; the earliest known date code is from the week beginning 4 April, a few weeks before the Spectrum’s launch.

Most of what makes Spectrum programming distinctive comes from this one chip: attribute clash, contended memory, the one-bit beeper and the striped border during tape loading.

Fast facts

  • Manufacturer: Ferranti, to Richard Altwasser’s logic design for Sinclair Research. Amstrad replaced it with its own gate array on the +2A and +3.
  • Technology: Ferranti bipolar ULA: the 5000 series for the first two versions, a lower-power 6000 series from 1983.
  • Function: display, memory arbitration, keyboard, tape, beeper, border.
  • Video: luminance and colour-difference signals, encoded to PAL by an LM1889 chip and passed to the RF modulator; 256×192 pixels in a 32×24 attribute grid.
  • Colours: 8 colours at 2 brightnesses, giving 15 distinct colours because bright black is still black.
  • Timing (48K): 14 MHz crystal; 3.5 MHz CPU clock; 312 scanlines and 69,888 T-states per frame, about 50.08 frames a second.

Contention, as the silicon does it

Contended memory is usually described by its effect: the Z80 running slower in the lower 16K while the screen is being drawn. Smith’s reconstruction gives the mechanism.

When the ULA “detects a CPU address between 16384 and 32767 while it is reading video bytes, it immediately holds the Z80 clock high”. The contention controller “is divided into two parts: one that detects and controls memory contention, the other that detects and controls I/O contention”, and the two “combine to form the clock control signal that gates” the master clock “to produce the Z80 clock”. So the ULA does not ask the processor to wait. It stops the processor’s clock. For those few cycles the Z80 is simply not being clocked.

The address test is short. The first ULA’s “memory contention handler considers A14 and A15, looking for [an] address between 0x4000 and 0x7FFF”. Two address lines are enough to pick out that 16K block, which is why contention applies to the lower 16K of RAM and not to the upper 32K.

The design changed during production. The contention controller “has been the subject of several revisions” because “early ULA versions contained” design errors “that affected the reliability of the machine”. The first ULA mishandled I/O contention, and Smith writes that the fault was “first noticed by the erratic keyboard response of the first machine code games”. Early machines were fixed with a small add-on circuit nicknamed the “dead cockroach”, which the second ULA built in. Contention timing is therefore a family of behaviours, and timing-exact Spectrum emulation has to say which ULA it is modelling.

Snow, and the refresh register again

The “snow effect” (corrupted pixels flickering across the display) has a precise cause, and it involves a part of the Z80 most programs never touch.

The ULA does not treat a Z80 refresh address as a contention condition. Refresh cycles are housekeeping for dynamic RAM, not program accesses, so ignoring them is, as Smith puts it, “technically correct”. But if a refresh address falls in the lower 16K, the circuit that generates the CPU’s /RAS (row address strobe) signal treats it as a real access and asserts /RAS anyway. That collides with the /RAS the video generator is producing and corrupts the screen byte being fetched at that moment.

So snow is a disagreement between two parts of the machine about whether a refresh cycle counts as an access. Whether it happens depends on the Z80’s I register. Zilog’s manual says that “during refresh, the contents of the I Register are placed on the upper eight bits of the address bus”, so I decides which 256-byte page every refresh cycle lands in. Point it into 0x4000-0x7FFF, as a program might when setting up its own interrupt table, and the refresh cycles land in contended memory.

The ZX81 used the same register on purpose: its refresh cycles, with I pointing at the character set, supply half the address for every character on screen. On the Spectrum, the same register pointed at the wrong page damages the picture instead.

Chip variants

Machine Part number Master clock How the CPU is held
16K / 48K Ferranti 5C102E (issue 1, 1982), 5C112E (issue 2, 1982), 6C001E (from 1983) 14 MHz Clock stopped by the ULA
128K / grey +2 7K010E 17.7345 MHz Clock stopped by the ULA
+2A / +2B / +3 Amstrad 40077 gate array 17.7345 MHz WAIT line

Smith describes the 128’s 7K010E as “almost identical” to the 48K’s ULA, with changes mainly to the video signal and the extra clocks the new machine needed. The grey +2 kept almost the same components as the 128. The +2A and +3 were a different design: Amstrad’s 40077 gate array replaced the ULA and much of the other logic, and it controls contention through the Z80’s WAIT line, “for this reason, the contention pattern of the +2A/+3 machines differs from the earlier Sinclair designed machines.”

The redesign also removed a side effect some games relied on. On the Sinclair machines, reading an I/O port that nothing answers returns whatever is on the data bus, and while the ULA is drawing the screen that is the byte it has just fetched. Programs used this “floating bus” to find out where the beam was and time their drawing to it; Alessandro Grussu’s Spectrumpedia names Arkanoid, Cobra, Short Circuit and Sidewize. On the +3 that port reads nothing useful, and some of those games fail there.

Display generation

The ULA fetches pixel and attribute data from RAM and turns it into a video signal. The regions are fixed:

Memory region Size Purpose
$4000-$57FF 6,144 bytes Pixel bitmap (256 × 192 at 1 bit per pixel)
$5800-$5AFF 768 bytes Attribute data (32 × 24 cells, one byte each)

The screen address quirk

The pixel data is not stored in screen order. It is interleaved by character row within each third of the display:

Code
addr = $4000
     | ((y & 0xC0) << 5)    ; which third (top / middle / bottom)
     | ((y & 0x07) << 8)    ; pixel row within character
     | ((y & 0x38) << 2)    ; character row within third
     | (x >> 3)             ; column

The reason is in the way the ULA reads memory. It fetches each pixel byte and its attribute byte together, in one fast “page-mode” burst from the dynamic RAM, and that only works if the two addresses share the same 7-bit row address. In Smith’s words, “both the display byte and attribute byte addresses must share the same 7-bit row address”. A plain row-by-row layout breaks that rule, so the three pixel-row bits are moved into the middle of the address. The result is awkward for game code, which cannot use address + y * 32, so Spectrum games typically keep a lookup table of row addresses.

Attribute format

Each 8 × 8 pixel cell has one attribute byte at $5800 + row*32 + col:

Bit Purpose
7 FLASH: swaps ink and paper every 16 frames
6 BRIGHT: affects both ink and paper
5-3 PAPER colour (0-7)
2-0 INK colour (0-7)

This one-byte-per-cell scheme is the origin of the Spectrum’s colour clash: a 1 in the bitmap shows in INK, a 0 in PAPER, and each 8 × 8 cell can only have those two colours. A sprite that crosses a cell boundary either changes the colour of what is behind it or changes colour itself.

Memory contention

The ULA and the Z80 share the lower 16K of RAM. While the ULA is fetching pixel or attribute data, during the lines of the picture, a Z80 access to that memory has to wait. This is contention:

  • The Z80 is delayed only when it accesses contended memory ($4000-$7FFF on a 48K machine) while the ULA is fetching.
  • The delay depends on where in an 8-T-state cycle the access falls:
Code
T-state within group:  0  1  2  3  4  5  6  7
CPU delay (T-states):  6  5  4  3  2  1  0  0

So code and data in the upper 32K ($8000-$FFFF on a 48K machine) run at full speed, and performance-critical code usually lives there. The 128 and grey +2 delay by the same 1 to 6 T-states. The +2A and +3 delay by 1 to 7, at slightly different points.

I/O ports

The ULA looks at only one address line when deciding whether an I/O access is meant for it: A0. Smith: “any port address that has A0 low, or put another way, any even numbered address, will select the ULA I/O port.” Software uses port $FE (254) and keeps the other low address bits high so that peripherals on other ports are not selected by accident.

Port Read Write
$FE (in fact any even port) Keyboard half-row (bits 0-4) + EAR input (bit 6) Border (bits 0-2) + MIC (bit 3) + speaker (bit 4)

Port $FE: write

Bit Function
0-2 Border colour (0-7)
3 MIC out (tape signal)
4 Speaker
5-7 Ignored

The single speaker bit is the whole of the 48K Spectrum’s sound hardware. Beeper music is the art of making it sound like more than one voice.

Port $FE: read (keyboard)

The keyboard is 40 keys wired as eight half-rows of five. Each half-row is selected by pulling one of the upper address lines (A8-A15) low; the five keys in that half-row come back in bits 0-4, as 0 for pressed and 1 for not pressed.

Address read Keys returned in bits 0-4
$FEFE CAPS SHIFT, Z, X, C, V
$FDFE A, S, D, F, G
$FBFE Q, W, E, R, T
$F7FE 1, 2, 3, 4, 5
$EFFE 0, 9, 8, 7, 6
$DFFE P, O, I, U, Y
$BFFE ENTER, L, K, J, H
$7FFE SPACE, SYMBOL SHIFT, M, N, B

A QAOP control scheme, for example, reads $FBFE for Q, $FDFE for A, and $DFFE for O and P.

Border colour

Z80 assembly
        ld      a, 2            ; red
        out     ($fe), a        ; set border

Bits 0-2 of the byte written to port $FE set the border. The stripes during tape loading come from the ROM’s loader, which flips the border colour every time it detects an edge in the tape signal: red and cyan while it reads the leader tone, blue and yellow once the data starts. It writes the colour through bits 0-2, and the width of each stripe shows the length of each pulse.

Sources

  • Chris Smith, The ZX Spectrum ULA: How to Design a Microcomputer (ZX Design and Media, 2010): the Ferranti ULA as a bipolar uncommitted logic array (p. 31); customisation by a single interconnection mask (ch. 5, pp. 45-46); Altwasser’s paper design, the gate budget and the 40-pin limit (p. 73); the 14 MHz oscillator (ch. 10, p. 87); 312 lines per frame (p. 100); the flash clock and the 50.08 Hz frame rate (ch. 14, p. 135); video addressing and the shared 7-bit row address (ch. 15, pp. 137-142); the LM1889 and RF modulator (ch. 16, p. 147); contention (ch. 18, pp. 190-199); the +2A/+3’s use of WAIT (p. 207); port decoding on A0 and the keyboard matrix (ch. 19, pp. 211-216); 69,888 T-states per frame (p. 225); the snow effect (ch. 23, pp. 245-246); ULA versions, dates and the 7K010E (ch. 24, pp. 249-255).
  • Adrian Dickens, Spectrum Hardware Manual, 2nd edition (Melbourne House), ch. 8, “The Uncommitted Logic Array”: the ULA stops the CPU clock on a contended access.
  • Zilog, Z80 CPU User Manual (UM008011-0816), p. 4: the I register on the address bus during refresh.
  • Sinclair ZX Spectrum BASIC Programming (Steven Vickers, Sinclair Research, 2nd edn 1983), ch. 23 “IN and OUT”: the eight keyboard half-row addresses, bit 6 as the EAR input, and port 254’s speaker, MIC and border bits.
  • Ian Logan and Frank O’Hara, The Complete Spectrum ROM Disassembly (Melbourne House, 1983): the SA-LEADER loop (red/cyan border) and the LD-EDGE-1 routine at 05E7, which changes the border colour on each edge found (red/cyan, then blue/yellow) and masks it with AND 07.
  • Alessandro Grussu, Spectrumpedia, volume 1 (English edition, CC BY-NC-ND 4.0): 15 colours (p. 25); contention delays per model and the floating bus, with Arkanoid, Cobra, Short Circuit and Sidewize (pp. 110-111); the +2 keeping the 128’s components (p. 135); the 40077 gate array (p. 145); the loss of the floating bus on the +3 (p. 149).
  • Amstrad, ZX Spectrum +3 Service Manual, parts list: “IC1 Gate Array 40077”.
  • Sinclair Research, ZX Spectrum Service Manual: DRAM row address from address bits A6-A0; the LM1889 colour modulator (IC14).

See also

Checked. Verified against primary sources and signed off by a person.