Overview
The NES has 32 palette entries: 16 for backgrounds (4 palettes of 4 colours) and 16 for sprites. Colour 0 of each palette is shared as the universal background colour. Load palettes during VBlank by setting the PPU address to $3F00 and writing 32 bytes of colour data.
Code
; =============================================================================
; PALETTE LOADING - NES
; Load 32-byte palette into PPU memory
; Taught: Game 1 (Neon Nexus), Unit 1
; CPU: ~200 cycles | Memory: 32 bytes palette data
; =============================================================================
PPUSTATUS = $2002
PPUADDR = $2006
PPUDATA = $2007
.segment "CODE"
; Load palette data into PPU
; Call during VBlank or when rendering is disabled
load_palette:
bit PPUSTATUS ; Reset PPU address latch
lda #$3F
sta PPUADDR
lda #$00
sta PPUADDR ; PPU address = $3F00
ldx #0
@loop:
lda palette_data, x
sta PPUDATA
inx
cpx #32
bne @loop
rts
; Palette data: 4 background palettes + 4 sprite palettes
palette_data:
; Background palettes (colours 0-15)
.byte $0F, $00, $10, $20 ; Palette 0: black, dark grey, grey, light grey
.byte $0F, $06, $16, $26 ; Palette 1: black, dark red, red, pink
.byte $0F, $08, $18, $28 ; Palette 2: black, dark yellow, yellow, cream
.byte $0F, $0A, $1A, $2A ; Palette 3: black, dark green, green, lime
; Sprite palettes (colours 16-31)
.byte $0F, $30, $20, $10 ; Palette 0: black, white, light grey, dark grey
.byte $0F, $30, $16, $06 ; Palette 1: black, white, red, dark red
.byte $0F, $30, $12, $02 ; Palette 2: black, white, blue, dark blue
.byte $0F, $30, $14, $04 ; Palette 3: black, white, purple, dark purple
Typical initialisation sequence:
reset:
; ... standard reset code ...
@vblank1:
bit PPUSTATUS
bpl @vblank1
; Clear RAM
; ...
@vblank2:
bit PPUSTATUS
bpl @vblank2
; NOW safe to access PPU
jsr load_palette
; ... rest of setup ...
Trade-offs
| Aspect | Cost |
|---|---|
| CPU | ~200 cycles |
| Memory | 32 bytes palette data |
| Limitation | Must be done during VBlank |
When to use: During game initialisation and when changing colour schemes.
When to avoid: During active rendering (causes visual glitches).
Palette Layout
$3F00: Universal background colour (shared by all palettes)
$3F01-$3F03: Background palette 0
$3F05-$3F07: Background palette 1
$3F09-$3F0B: Background palette 2
$3F0D-$3F0F: Background palette 3
$3F11-$3F13: Sprite palette 0
$3F15-$3F17: Sprite palette 1
$3F19-$3F1B: Sprite palette 2
$3F1D-$3F1F: Sprite palette 3
Note: $3F04, $3F08, $3F0C, $3F10, $3F14, $3F18, $3F1C mirror $3F00.
NES Colour Reference
Common useful colours:
| Value | Colour |
|---|---|
$0F | Black |
$00 | Dark grey |
$10 | Light grey |
$20 | White-grey |
$30 | White |
$06 | Dark red |
$16 | Red |
$26 | Pink |
$02 | Dark blue |
$12 | Blue |
$22 | Light blue |
$0A | Dark green |
$1A | Green |
$2A | Light green |
Related
Patterns: NMI Game Loop
Vault: NES