A Finger on the Boxes
Stop baking the value into every instruction. Meet indexed addressing — X as a finger you rest on one entry of a table and slide along — the idea behind every lookup, message and animation a game does.
Every value you've loaded so far was baked into the instruction: lda #$16, the colour written into the code itself. That's fine for one value. But games are full of lists — a row of colours, the letters of a message, the frames of an animation — and you can't bake a fresh instruction for every item. You keep the list in memory and point at the one you want.
That pointing is indexed addressing. Pick up the X register again — earlier it just held a number; now we use it as a finger resting on one entry of a table:
ldx #3— rest the finger on entry 3 (counting from 0).lda colours,x— load fromcoloursplusX— the entry the finger is on.
The base colours stays put; X is the part that moves. lda colours,x with X at 3 reads the fourth entry. Change X, and the same instruction reaches a different item.
This is the NES programmer's daily bread. On a home computer you might slide a finger along the screen; here the screen fills through the auto-stepping PPU port (you saw it last unit's cousin, and use it next unit), so the finger's real job is reading the data tables a game is built from. Same idea, pointed at your data.
What you'll see by the end
A yellow screen — but we never wrote $28 (yellow) anywhere. We wrote a table of four colours and rested the finger on entry 3. Move the finger and the same instruction fetches a different colour.
Resting the finger on an entry
; ============================================================================
; Meet the Machine (NES) - Unit 11: A Finger on the Boxes
;
; Instead of baking a value into the instruction, keep a table of values and
; point a finger at one. X is the finger: lda table,x reads the entry it rests
; on. Here a table of four colours; the finger picks one.
; ============================================================================
.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
; ----------------------------------------------------------- YOUR CODE START
ldx #3 ; rest the finger on entry 3
lda colours, x ; read the colour the finger points at -> $28 yellow
; ------------------------------------------------------------- YOUR CODE END
sta $00
bit $2002
lda #$3f
sta $2006
lda #$00
sta $2006
lda $00
sta $2007
forever:
jmp forever
; a table of four colours, sitting in ROM
colours:
.byte $16, $2a, $12, $28 ; 0:red 1:green 2:blue 3:yellow
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
colours is a table of four bytes sitting in ROM — red, green, blue, yellow. ldx #3 rests the finger on the fourth of them; lda colours,x fetches it into A; and the harness shows it. The value the screen ends up painting was chosen by the index, not written into the load.
Assemble and run
ca65 index.asm -o index.o && ld65 -C nes.cfg index.o -o index.nes
A yellow screen — entry 3 of the table, picked by the finger.
Try this: move the finger
Change ldx #3 to ldx #0, #1, #2. The screen comes up red, green, blue, yellow as the finger slides along the table — and you never touched the lda colours,x line. One instruction, four results, because the index moved.
Try this: a longer table
Add two more colours to the table — .byte $16, $2a, $12, $28, $30, $0f (white and black on the end) — then rest the finger on #4 or #5. The table can be as long as you like; the finger reaches any entry by number. This is exactly how a game stores a palette, a tune, or the tiles of a level: a table, and a finger that walks it.
If it doesn't work
- The colour is wrong or random. Check the finger isn't reaching past the end of the table —
ldx #9on a four-entry table reads whatever bytes happen to follow it. Keep the index inside the table. ca65errors onlda colours,x. That exact form — load, the label, comma, lowercasex— is right. Check the comma and thex.- The screen is black. The
colourslabel and thelda colours,xmust spell the table's name identically — a typo means the assembler can't find it.
What you've learnt
X is a movable index: lda table,x reads the entry of table that the finger rests on, and changing X reaches a different entry — so one instruction can read all the way along a table of data. Lists of colours, letters, tiles, tunes: all read this way.
What's next
You moved the finger by hand, one entry at a time. To do something to every entry, you let the machine step the finger for you. Next — The Counted Loop — load a count, run the body, step on, branch back until they're all done. One loop paints a whole row of the screen.