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.
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.
| Property | Value |
|---|---|
| Resolution | 256 × 192 pixels |
| Cells | 32 × 24, each 8 × 8 pixels |
| Bitmap size | 6144 bytes |
| Attribute size | 768 bytes |
| Colours | 8, each in a normal and a bright shade |
| Colours per cell | 2 (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 bit | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Holds | 0 | 1 | 0 | y7 | y6 | y2 | y1 | y0 | y5 | y4 | y3 | x7 | x6 | x5 | x4 | x3 |
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:
| Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|
| Meaning | FLASH | BRIGHT | PAPER (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).
| Value | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|---|---|---|---|---|---|---|---|---|
| Colour | Black | Blue | Red | Magenta | Green | Cyan | Yellow | White |
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.
| Area | Address | Size | Contents |
|---|---|---|---|
| Display file | 16384 (0x4000) | 6144 bytes | The 256×192 one-bit bitmap, interleaved. |
| Attributes | 22528 (0x5800) | 768 bytes | One colour byte per 8×8 cell, in row order. |
| End | 23296 (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.