A Street of Numbered Boxes
Meet memory — one long street of numbered boxes, each holding a byte. Store a byte at an address and read it back, the same round-trip you used for registers, now through RAM.
A byte in a register is a byte you're holding in your hand. But there are only three registers, and you can't put a whole game in your hands. So where do bytes live the rest of the time?
In memory. Picture one long street of numbered boxes — 65,536 of them on the Commodore 64 (that's where the "64" comes from: 64K of them). Each box has an address — just a number, like a house number — and holds exactly one byte. Most of the street is yours: you can write a byte into a free box and read it back whenever you like.
You met this street in BASIC, through a side door — POKE to write a box, PEEK to read one. There, it felt like an advanced trick. Here it's your main tool, and it's two ordinary instructions.
What you'll see by the end
A green border — value 5. But as in Unit 2, the colour isn't the point: this 5 went out into memory and came back. We stored it at a box, wiped the register clean, then fetched it from the box again. The border is the proof; the real evidence is in the memory view — watch box $C000 fill with 5.
Store and read: two mirror-image instructions
| Instruction | Means |
|---|---|
sta $c000 | store — put A's byte into the box at address $C000 |
lda $c000 | read — fetch the box at $C000 back into A |
You already know lda — last unit it loaded a value (lda #5). Here it loads from a box (lda $c000). The difference is that little #: #5 means the number 5; plain $c000 means the box at address $C000. Forget the # and you load the contents of address 5 instead of the number — a mix-up worth meeting now, because it's the most common one there is.
(A note for Spectrum-trained eyes: there are no brackets here. The Z80 wrote ld (addr), a; the 6510 just writes sta addr — the address is the operand. Parentheses mean something different on this chip, and we'll meet that later.)
It's the same round trip you ran for registers in Unit 2 — but the value travels out to a memory box and back, instead of into X:
| After… | A | box $C000 |
|---|---|---|
lda #5 | 5 | — |
sta $c000 | 5 | 5 |
lda #0 | 0 | 5 |
lda $c000 | 5 | 5 |
The program
; Meet the Machine - Unit 4: A Street of Numbered Boxes
; Assemble with: acme -f cbm -o numbered-boxes.prg numbered-boxes.asm
*= $0801
!byte $0c,$08,$0a,$00,$9e,$32,$30,$36,$31,$00,$00,$00
*= $080d
lda #5 ; A = 5
sta $c000 ; store A into the box at $C000
lda #0 ; wipe A clean
lda $c000 ; read the box back into A
sta $d020 ; show it — green
loop jmp loop
We wipe A to 0 between storing and reading, so the green border can only mean the 5 came back from memory. sta $c000 is your POKE; lda $c000 is your PEEK.
Assemble and run
acme -f cbm -o numbered-boxes.prg numbered-boxes.asm
Load it with the memory view open, and watch box $C000 take the 5 before the border turns green.
Try this: any box will do
Change both $c000s to another free address — say $c100. Same green border. Nothing is special about $C000; any free box of RAM holds your byte just as well. The block from $C000 to $CFFF is a handy stretch of free RAM we'll use often. (Steer clear of three areas: $0801 upward, where the program itself lives; $0400, the screen, coming up next unit; and $D000 upward, where the hardware lives — write there and you change the machine, not memory.)
Try this: two boxes don't interfere
Store a different byte in two neighbouring boxes, then read one back:
; Meet the Machine - Unit 4: two boxes don't interfere
; Assemble with: acme -f cbm -o two-boxes.prg two-boxes.asm
*= $0801
!byte $0c,$08,$0a,$00,$9e,$32,$30,$36,$31,$00,$00,$00
*= $080d
lda #2
sta $c000 ; box $C000 gets 2
lda #5
sta $c001 ; box $C001 gets 5
lda $c000 ; read $C000 back — the 2
sta $d020 ; red
loop jmp loop
The border comes up red — we read box $C000 (which holds 2), and the 5 we put in $C001 sat there untouched. Change the read to lda $c001 and the border turns green instead. Two addresses, two independent boxes.
If it doesn't work
- The border is black, not green. The
lda $c000read is missing or mistyped, soAwas still 0 from the wipe. Check there's no#on it —lda $c000, notlda #$c000. - The border's a colour you didn't expect, like light grey. You probably wrote
lda #$c000(with the#) somewhere — that tries to load the number$C000, which doesn't fit in a byte. Drop the#when you mean a box. - Nothing in the memory view changes. Check the store is
sta $c000(no#). With the#it's not a valid store at all andacmewill complain.
What you've learnt
Memory is 65,536 numbered boxes, each holding one byte: sta addr stores A's byte at an address, lda addr reads it back, and the # is what separates a number from the box at that number.
What's next
Some of those boxes are special. Write a byte to the ones starting at $0400 and you don't change a quiet number — you put a character on the screen. Next — The Screen Is Memory — we find out the screen is just a stretch of this same street, and PRINT was poking boxes all along.