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 $D800, one byte per cell, completely apart from the characters. Colour a cell with a single byte, and meet the C64's own take on the attribute grid.

38% of Meet The Machine

Last unit ended on a mystery: one line, sta $D800, that "lit the block up" — with a promise to explain it. Here's the explanation, and it's the other half of how the screen works.

That line never touched $0400. The character code at $0400 says only which shape sits in the cell, never what colour it's drawn in. Colour lives in a separate map that starts at $D800 — one byte for each cell on the screen, laid out as the same grid. That byte sets the cell's colour and has nothing to do with the character code at all. Two maps, two jobs: $0400 for shape, $D800 for colour.

What you'll see by the end

A single red block in the top-left corner of the C64's screen.
The same top-left block, now red — the character never changed; only its entry in the separate colour map did.

The same top-left block as last unit — white then, red now. And the point is how: we didn't change the character at all. The stage-light line from last unit was a write to the colour map; change its value from 1 to 2 and the cell turns red. Shape and colour are genuinely separate things in genuinely separate memory.

One byte, one colour

; Meet the Machine - Unit 6: Colour Is a Separate Map
; Assemble with: acme -f cbm -o colour.prg colour.asm

*= $0801
!byte $0c,$08,$0a,$00,$9e,$32,$30,$36,$31,$00,$00,$00

*= $080d
        lda #$a0        ; a solid block ...
        sta $0400       ; ... at the top-left cell  (its SHAPE, in screen RAM)
        lda #2          ; red
        sta $d800       ; the colour map for that same cell  (its COLOUR)
loop    jmp loop

Two stores, two maps. The first puts the block's shape at $0400; the second puts its colour at $D800. The colour byte keeps only its low four bits — a number 0 to 15, one of the sixteen colours — and 2 is red.

Here the C64 is simpler than the Spectrum, which packs a cell's ink, paper, bright and flash into one busy "attribute" byte. The C64's colour map holds just one thing per cell: the colour the character is drawn in. The background behind it is a single colour for the whole screen, set once at $D021 (you met it in Unit 1's "try this"). One colour map, one job.

The map is a plain grid

Like the screen, the colour map is laid out sanely: $D800 is the top-left cell, $D801 the one to its right, $D800 + 40 = $D828 the cell directly below. In fact the two maps line up exactly — cell N of the screen at $0400 + N is coloured by byte N at $D800 + N. Shape and colour, same grid, different street.

There's a constraint hiding in here, and it's worth naming: a cell carries one colour for its whole 8×8 character. You cannot colour two halves of a single cell differently — the map has no room to say so. It's a gentler cousin of the Spectrum's "attribute clash," and you design around it the same way: think in cells.

In BASIC, choosing a COLOR (or poking the colour map) did this for you. Now you write the byte yourself — and it's the same sta addr store you've used since Unit 4.

Assemble and run

acme -f cbm -o colour.prg colour.asm

One red block, top-left: a shape from $0400, a colour from $D800.

Try this: pick your own colour

Change lda #2 to other values, 0 to 15, and predict the block before you run it: 5 green, 6 blue, 7 yellow, 1 white. Above 15, only the low four bits count — #$12 (18) shows the same as #2, because 18 mod 16 is 2.

Try this: four cells, four colours

Place a block in four neighbouring cells and colour each one differently:

; Meet the Machine - Unit 6: four cells, four colours
; Assemble with: acme -f cbm -o colour-block.prg colour-block.asm

*= $0801
!byte $0c,$08,$0a,$00,$9e,$32,$30,$36,$31,$00,$00,$00

*= $080d
        lda #$a0        ; a solid block ...
        sta $0400       ; ... in four cells: top-left
        sta $0401       ;     next right
        sta $0428       ;     row below, left
        sta $0429       ;     row below, right

        lda #2          ; red
        sta $d800       ; colour for cell $0400
        lda #5          ; green
        sta $d801       ; colour for cell $0401
        lda #6          ; blue
        sta $d828       ; colour for cell $0428
        lda #7          ; yellow
        sta $d829       ; colour for cell $0429
loop    jmp loop

Two across, two down — $0400/$0401, then $0428/$0429 a row below — each with its matching colour box at $D800/$D801, $D828/$D829. The two grids marching in step.

If it doesn't work

  • The block isn't coloured. Check the colour address is $D800, not $0400$0400 is the character map; colour lives at $D800.
  • No block at all to colour. The sta $0400 (the shape) is missing — a colour map byte only shows where a character's pixels are lit, and an empty cell has none. Put the block back.
  • Wrong colour. Only the low four bits of the colour byte are used. Re-check the value: 2 is red, 5 is green; values over 15 wrap.

What you've learnt

Colour is a separate map at $D800 — one byte per cell, holding just the cell's colour (0–15) — stored entirely apart from the character codes, and laid out as the same 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 6510; you compare, and you jump on the result. It's where your programs start making decisions.