Skip to content
Game 0 Unit 6 of 16 1 hr learning time

Colour Is a Separate Map

Find out where colour lives — a second map at $5800, one packed byte per cell, completely apart from the pixels. Colour a whole cell with a single byte and never touch a pixel.

38% of Meet The Machine

Your pixels last unit came out black on white. You never chose those colours — so where do they come from, and how do you change them?

Not from $4000. The pixels at $4000 say only which dots are lit, never what colour. Colour lives in a separate map that starts at $5800 — one byte for each 8×8 cell on the screen. That single byte sets the colours for the whole cell, and it has nothing to do with the pixel bytes at all. Two maps, two jobs: $4000 for shape, $5800 for colour.

What you'll see by the end

A single small red square near the top-left of the otherwise blank screen.
One red cell, top-left — drawn by a single attribute byte at $5800, with no pixels touched. Colour lives in its own map, apart from the pixels.

One red cell, top-left. And here's the point: we drew no pixels to make it. We wrote a single byte to the colour map, and the whole 8×8 cell turned red. Colour and pixels are genuinely separate things in genuinely separate memory.

The attribute byte

That colour byte is called an attribute, and it packs four things into eight bits:

 bit:  7      6      5  4  3      2  1  0
       FLASH  BRIGHT  P  P  P      I  I  I
                    └ PAPER ┘    └  INK  ┘
                     (0-7)         (0-7)
  • INK (bits 0–2) — the colour lit pixels show in.
  • PAPER (bits 3–5) — the background colour, where pixels aren't lit.
  • BRIGHT (bit 6) — a brighter shade of both.
  • FLASH (bit 7) — swap ink and paper on and off, twice a second.

So %00010111 ($17) means PAPER 2 (red), INK 7 (white), no bright, no flash. With no pixels set, the whole cell is just its PAPER — a solid red block.

; ============================================================================
; PRIMER — Beat 6: Colour Is a Separate Map
; ============================================================================
; The pixels live at $4000. Colour lives somewhere else entirely: a second
; map starting at $5800, one byte per 8x8 cell. That one byte holds BOTH
; colours for the cell, packed into its bits:
;
;     bit:  7      6      5 4 3      2 1 0
;           FLASH  BRIGHT  PAPER       INK
;                         (0-7)       (0-7)
;
; So $17 = %00010111 is PAPER 2 (red), INK 7 (white), no bright, no flash.
;
; We write ONE attribute byte and the whole top-left cell turns red — and we
; never touch a single pixel. Colour and pixels are stored separately. (That
; separation is exactly why "attribute clash" happens: a cell has only one
; ink and one paper, whatever its pixels are doing.)
;
; And unlike the pixels' peculiar layout (Beat 5), the colour map is laid out
; sanely: $5800 + row*32 + col. The top-left cell is just $5800.
; ============================================================================

            org     32768

start:
            ld      a, %00010111     ; PAPER 2 (red), INK 7 (white)
            ld      ($5800), a       ; colour the top-left cell — no pixels touched

.loop:
            halt
            jr      .loop

            end     start

Two consequences worth holding onto

This is the root of "attribute clash." A cell carries one ink and one paper for all 64 of its pixels. You cannot colour two pixels in the same cell differently — the colour map has no room to say so. Every Spectrum game works within that rule, and the good ones make a virtue of it.

The colour map is laid out sanely — unlike the pixels. Remember Beat 5's puzzle, where $4020 landed eight rows down? The attribute map has no such tricks: it's plainly $5800 + row × 32 + col. The top-left cell is $5800, the one to its right is $5801, and the cell directly below is $5820. Where the pixel map is famously twisted, the colour map is a plain grid.

In BASIC, INK and PAPER were writing these exact bytes for you. Now you write them yourself — and it's the same ld (addr), a store you've used since Beat 4.

Assemble and run

pasmonext --sna colour-map.asm primer.sna

One red cell, top-left, drawn with a single byte and no pixels at all.

Try this: mix your own colour

Change %00010111 to other combinations and predict the cell before you run it. PAPER blue, INK yellow is %00001110. PAPER black, INK green is %00000100. Work out the bits — three for paper, three for ink — then check. (Set BRIGHT, bit 6, and watch the shade lift.)

Try this: a 2×2 block, one cell bright

Colour four neighbouring cells, and make one of them BRIGHT so you can see the difference side by side — the single attribute write, grown to a 2×2 grid:

Four cells coloured, one with the BRIGHT bit set
+13-20
11 ; ============================================================================
2-; PRIMER — Beat 6: Colour Is a Separate Map
2+; PRIMER — Beat 6, "Try this: a 2x2 block, one cell BRIGHT"
33 ; ============================================================================
4-; The pixels live at $4000. Colour lives somewhere else entirely: a second
5-; map starting at $5800, one byte per 8x8 cell. That one byte holds BOTH
6-; colours for the cell, packed into its bits:
7-;
8-; bit: 7 6 5 4 3 2 1 0
9-; FLASH BRIGHT PAPER INK
10-; (0-7) (0-7)
11-;
12-; So $17 = %00010111 is PAPER 2 (red), INK 7 (white), no bright, no flash.
13-;
14-; We write ONE attribute byte and the whole top-left cell turns red — and we
15-; never touch a single pixel. Colour and pixels are stored separately. (That
16-; separation is exactly why "attribute clash" happens: a cell has only one
17-; ink and one paper, whatever its pixels are doing.)
18-;
19-; And unlike the pixels' peculiar layout (Beat 5), the colour map is laid out
20-; sanely: $5800 + row*32 + col. The top-left cell is just $5800.
4+; The colour map is linear: $5800 + row*32 + col. So a 2x2 block of cells is
5+; $5800 (top-left) $5801 (top-right)
6+; $5820 (bot-left) $5821 (bot-right) <- +32 is one cell row down
7+; Colour all four red; set the BRIGHT bit (bit 6, +$40) on the last one to
8+; see bright red against normal red.
219 ; ============================================================================
2210
...
2412
2513 start:
26- ld a, %00010111 ; PAPER 2 (red), INK 7 (white)
27- ld ($5800), a ; colour the top-left cell — no pixels touched
14+ ld a, %00010111 ; PAPER red, INK white
15+ ld ($5800), a ; top-left
16+ ld ($5801), a ; top-right
17+ ld ($5820), a ; bottom-left (one cell row down)
18+
19+ ld a, %01010111 ; same colours, BRIGHT bit set
20+ ld ($5821), a ; bottom-right, bright red
2821
2922 .loop:

The bottom-right cell is the same red as the other three but with bit 6 set — bright red against normal red. Notice the addresses: $5800, $5801 across, then $5820 a row down. The sane grid in action.

When it's wrong, see why

  • The cell isn't coloured. Check the address is $5800, not $4000$4000 is the pixel map; colour lives at $5800.
  • Wrong colour. Recount the bits: paper is bits 3–5, ink is bits 0–2 — a common slip is to swap them. %00010111 is paper red, ink white; flip to %00111010 and it's paper white, ink... work it out.
  • The whole cell flashes. You set bit 7 (FLASH). Clear it unless you meant it.

What you've learnt

Colour is a separate map at $5800 — one byte per cell, packing FLASH, BRIGHT, PAPER and INK — stored entirely apart from the pixels, and laid out as a plain grid.

What's next

You've now met everything the machine is: the toolchain, registers, bytes, memory, the screen and its colour. From here we turn to what the machine can do. Next — Test, Then Jump — there's no IF on the Z80; you compare, and you jump on the result. It's where your programs start making decisions.