Colour Lives in a Palette
Open up the stage light. On the NES, a tile's colour isn't stored with the tile — it lives in a separate little table, and the tile only points at it. Change the palette and the same block changes colour, with no touch to the screen at all.
Last unit the block came out white, and we never said white — we just wrote two mystery bytes to $3F00 and called them the stage light. Time to open it up.
Here's the idea that catches every newcomer to the NES: a tile carries no colour of its own. The byte you wrote to the nametable was a tile number — a shape. The shape's colour is decided somewhere else entirely, in a separate little table called the palette. The tile's pixels don't say "white"; they say "colour 1", and colour 1 is whatever the palette currently says it is. Change the palette, and every pixel pointing at that slot changes with it — though you never touched the screen's memory.
This is the opposite of how it feels in BASIC, where a thing you draw is a colour. On the NES, shape and colour are two separate maps, and the tile is just a pointer from one into the other.
What you'll see by the end
A red block on a light-blue screen. The tile write is identical to Unit 5 — same number, same cell. The only thing that changed is the palette, and that changed both the block's colour and the colour of everything behind it.
A background palette is four colours
The PPU's palette table starts at $3F00. A background palette is four entries:
| Address | Role |
|---|---|
$3F00 | the backdrop — the colour behind everything, and what "colour 0" draws |
$3F01 | colour 1 |
$3F02 | colour 2 |
$3F03 | colour 3 |
Every background pixel is two bits — a number from 0 to 3 — picking one of these four. Our solid block is made entirely of "colour 1" pixels, so it draws in whatever sits at $3F01. Last unit that was white; this unit it's red ($16). The blank tiles everywhere else are all "colour 0", so they draw in the backdrop at $3F00 — light blue ($21) this time. Same four pour-throughs of the window you already know:
lda #$21 ; $3F00 backdrop = light blue
sta $2007
lda #$16 ; $3F01 colour 1 = red (the block)
sta $2007
lda #$27 ; $3F02 colour 2 = orange
sta $2007
lda #$30 ; $3F03 colour 3 = white
sta $2007
(Colours 2 and 3 aren't used by our block — it's all colour 1 — but a palette is always four entries, so we fill them in. We'll use the other slots once a tile has more than one colour in it, next unit.)
The program
The tile write in the middle is exactly Unit 5's. Only the palette at the top has changed:
; ============================================================================
; Meet the Machine (NES) - Unit 6: Colour Lives in a Palette
;
; The block's colour does not live in the tile. It lives in a separate little
; table - the palette - and the tile only points at it. Change the palette and
; the same tile changes colour, with no change to the screen's memory at all.
; ============================================================================
.segment "HEADER"
.byte "NES", $1a
.byte 2
.byte 1
.byte $00, $00
.segment "CODE"
reset:
sei
cld
ldx #$40
stx $4017
ldx #$ff
txs
inx
stx $2000
stx $2001
stx $4010
warm1:
bit $2002
bpl warm1
warm2:
bit $2002
bpl warm2
; --- the palette: a small table of colours the tiles point at ---
bit $2002
lda #$3f
sta $2006
lda #$00
sta $2006 ; aim at palette address $3F00
lda #$21 ; $3F00 backdrop = light blue
sta $2007
lda #$16 ; $3F01 palette-0 col 1 = red (the block's colour)
sta $2007
lda #$27 ; $3F02 palette-0 col 2 = orange (unused here)
sta $2007
lda #$30 ; $3F03 palette-0 col 3 = white (unused here)
sta $2007
; --- the same block as last unit: tile 1 at the top-left cell ---
bit $2002
lda #$20
sta $2006
lda #$00
sta $2006
lda #$01
sta $2007
; --- square the picture up and turn it on ---
bit $2002
lda #$00
sta $2006
sta $2006
sta $2005
sta $2005
lda #$1e
sta $2001
forever:
jmp forever
nmi:
rti
irq:
rti
.segment "VECTORS"
.word nmi
.word reset
.word irq
.segment "CHARS"
.byte $00,$00,$00,$00,$00,$00,$00,$00
.byte $00,$00,$00,$00,$00,$00,$00,$00
.byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
.byte $00,$00,$00,$00,$00,$00,$00,$00
.res 8192 - 32, $00
That's the whole point this unit makes: colour and shape are independent. You recoloured the block by editing a table that has nothing to do with the screen's memory.
Assemble and run
ca65 palette.asm -o palette.o && ld65 -C nes.cfg palette.o -o palette.nes
A red block on a light-blue field. Prove the independence to yourself: the nametable write is unchanged from last unit, yet the colour is completely different.
Try this: recolour without touching the screen
Change the $3F01 value — lda #$16 — to another NES colour and run: $2a green, $30 white, $28 yellow, $12 blue. The block changes colour each time, and you never went near the nametable. Shape stays; colour moves.
Try this: change the world behind it
Now change the $3F00 backdrop — lda #$21 — instead. The whole field changes colour, because every blank cell is colour 0, which is the backdrop. Set it to $0f and the background goes black, throwing the block into sharp relief. One byte repaints everything behind your tiles.
Try this: four palettes, and the catch
The NES has four background palettes ($3F00, $3F04, $3F08, $3F0C), so different parts of the screen can use different four-colour sets. Which palette a cell uses isn't stored in the cell, though — it's chosen in coarse 16×16-pixel blocks by a separate attribute table. That's why neighbouring tiles often have to share colours: a famous NES constraint, and a cousin of the Spectrum's attribute clash. We lean on just palette 0 in the Primer; the attribute table is a game's concern.
If it doesn't work
- The block is invisible.
$3F01probably matches$3F00— colour 1 is the same as the backdrop, so the block blends in. Give them different values. - The colours look wrong or washed. Check you wrote the four palette bytes in order through
$2007after aiming at$3F00, and that you didn't swap a digit — NES colour codes run$00–$3F. - Nothing shows at all. As ever, check the picture is turned on (
lda #$1e/sta $2001) at the end.
What you've learnt
Colour lives in the palette, separate from the screen. A background palette is four entries from $3F00; a tile's pixels point at one of them by number, so the same tile draws in whatever colour the palette currently holds. Change the palette and the picture recolours without a single write to the nametable.
What's next
We keep calling tile 1 "a solid block" — but where does that shape come from? Next — Where the Shapes Come From — we open the last mystery in the harness: the pattern table, the 8×8 shapes the PPU draws from. And you'll draw your own.