Skip to content
Game 0 Unit 4 of 16 1 hr learning time

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.

25% of Meet The Machine

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

The C64's screen surrounded by a solid green border.
A green border proving a round trip: the value 5 stored out to a memory box, the register wiped, then fetched back from the box.

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

InstructionMeans
sta $c000store — put A's byte into the box at address $C000
lda $c000read — 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…Abox $C000
lda #55
sta $c00055
lda #005
lda $c00055

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 $c000 read is missing or mistyped, so A was still 0 from the wipe. Check there's no # on it — lda $c000, not lda #$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 and acme will 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.