Spectrum Images

The ZX Spectrum has one screen mode: a fixed 256×192 bitmap held in a single block of memory, with colour applied over it on a coarse 8×8 grid. The pixels and the colours live in two separate areas, so the whole picture is a full-screen image with the famous two-colours-per-cell limit.

Spectrum Images

Overview

The screen is 256 pixels across and 192 down, a single full-screen bitmap. Every pixel is one bit: set (ink) or clear (paper). The colour of each pixel is not stored with it. Instead the screen is divided into a grid of 32×24 character cells, each 8×8 pixels, and one attribute byte per cell says which two colours that cell's ink and paper bits mean. So a cell can show only two colours at once, the source of the Spectrum's colour clash.

PropertyValue
Resolution256 × 192 pixels
Cells32 × 24, each 8 × 8 pixels
Bitmap size6144 bytes
Attribute size768 bytes
Colours8, each in a normal and a bright shade
Colours per cell2 (one ink, one paper)

The display file

The bitmap, called the display file, is 6144 bytes starting at address 16384 (0x4000), the base of screen memory. Each byte holds eight horizontal pixels, the most significant bit on the left. A one draws the cell's ink colour, a zero its paper colour.

The 6144 bytes are not laid out as simple top-to-bottom rows. The screen is split into three equal thirds of 64 pixel rows each (the top, middle and bottom eight character rows). Within a third, the rows are interleaved: all the top scanlines of the character rows come first, then the second scanlines, and so on. This is why a straightforward top-to-bottom fill appears to paint the screen in eight interleaved passes.

Pixel address layout

For a pixel at column x (0 to 255) and row y (0 to 191), the byte holding it sits at an address whose bits are rearranged from y. Writing y as bits y7..y0 and taking the character column x>>3:

Address bit1514131211109876543210
Holds010y7y6y2y1y0y5y4y3x7x6x5x4x3

Bits 15 to 13 are fixed at 010, which places the block at 0x4000. Bits 12 and 11 (y7 y6) select the third; bits 10 to 8 (y2 y1 y0) select the scanline within a character row; bits 7 to 5 (y5 y4 y3) select the character row within the third; and bits 4 to 0 (x7..x3) select the character column. The pixel within the byte is x & 7, counted from the top bit.

The attribute area

The 768 attribute bytes follow the bitmap, starting at address 22528 (0x5800), one byte per character cell in plain left-to-right, top-to-bottom order (no interleaving). The attribute for cell column cx, cell row cy is at 0x5800 + cy * 32 + cx. Each byte packs the two colours and two flags:

Bit76543210
MeaningFLASHBRIGHTPAPER (0–7)INK (0–7)

INK is the colour of the set pixels, PAPER the colour of the clear pixels. BRIGHT lifts both to the bright shade. FLASH swaps ink and paper about twice a second. Because one byte covers a whole 8×8 cell, every pixel in that cell shares the same two colours.

Colour and clash

There are eight base colours, numbered 0 to 7, each with a normal and a bright version, giving fifteen distinct shades (bright black equals black).

Value01234567
ColourBlackBlueRedMagentaGreenCyanYellowWhite

The colour is a direct RGB triple: bit 0 is blue, bit 1 red, bit 2 green, so the eight values are every on/off mix of the three primaries. The single BRIGHT bit scales the whole cell. The two-colours-per-cell rule means art that places two ink colours in one cell cannot be shown; moving objects that cross a cell take on that cell's colours, which is colour clash. Careful designs align detail to the 8-pixel grid to avoid it.

Memory map

Screen memory is a contiguous 6912-byte block at the bottom of the 16K RAM bank.

AreaAddressSizeContents
Display file16384 (0x4000)6144 bytesThe 256×192 one-bit bitmap, interleaved.
Attributes22528 (0x5800)768 bytesOne colour byte per 8×8 cell, in row order.
End23296 (0x5B00)First byte after the screen.

A saved SCREEN$ is exactly these 6912 bytes in this order, which is why a Spectrum screen file is always 6912 bytes long.