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.
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
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—$0400is 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:
2is red,5is 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.