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

The Screen Is Memory

The big one. Discover that the screen is just a stretch of the same memory street — poke a byte to $0400 and a character appears. No PRINT, no magic: a box on screen holds one character code, and the chip draws it.

31% of Meet The Machine

This is the one the last two units were walking towards.

The boxes you met in Unit 4 don't all just hold quiet numbers. The 1,000 boxes starting at address $0400 are wired to the glass: each one is a cell on the screen, and the byte you write into it picks which character shows there. The screen isn't a special device you talk to — it's memory you write to, a stretch of the same numbered street. Every PRINT you ever ran in BASIC was poking these same boxes for you.

And here's the part that ties the whole Primer together: we need no new instruction to do it. It's the exact store from Unit 4 — sta addr — pointed at $0400 instead of $C000.

What you'll see by the end

A single solid white block in the top-left corner of the C64's screen.
A single white block written straight into screen memory — no PRINT, no border, just a byte poked to the screen.

A solid white block, top-left. You wrote a byte to a box and the chip drew a character there — straight into the screen, no border, no PRINT. (One of the two lines in the program is a "stage light" that makes the block visible; we'll come back to it.)

A box on the screen holds a character code

This is where the C64 parts ways with a pixel machine like the Spectrum. There, a screen byte was eight pixels — its bits were the dots. Here, a screen box holds a character code: a number that names one of 256 ready-made 8×8 shapes baked into the machine's character ROM. Write the code, and the chip looks up the shape and draws it. Code $A0 is a solid block. Code 1 is the letter A. Code 32 is a space.

; Meet the Machine - Unit 5: The Screen Is Memory
; Assemble with: acme -f cbm -o screen.prg screen.asm

*= $0801
!byte $0c,$08,$0a,$00,$9e,$32,$30,$36,$31,$00,$00,$00

*= $080d
        lda #$a0        ; screen code $A0 — a solid block
        sta $0400       ; the top-left box of the screen

        lda #1          ; white — a "stage light" so we can SEE it
        sta $d800       ; (the next unit explains what $D800 is)
loop    jmp loop

The first store is the one that matters: a byte into $0400, the top-left cell. ($0401 is the next cell to its right, $0402 the one after — so writing to consecutive boxes lays characters across the screen, left to right.) The second store, to $D800, is the stage light: it makes the block show up. Ignore how it works for now — that's exactly what the next unit is about. Without it, the block is still there in memory, just drawn in a colour you can't see.

A sane grid (count yourself lucky)

The screen is a plain 40-wide, 25-tall grid, laid out in the obvious order: 40 boxes per row, one row after another. The top-left is $0400; the cell directly below it is $0400 + 40 = $0428; the start of row 2 is $0450. No tricks, no hidden gaps. (Spectrum programmers meet a famously twisted screen layout at this point; the C64 spares you that.)

One wrinkle worth a sentence: these screen codes are not the same numbers as the letters in Unit 3. There, 'A' was 65 (its PETSCII code). In screen memory, A is code 1. Same letter, two numbering schemes — PETSCII for the keyboard and strings, screen codes for the boxes on the glass. The chip keeps them straight; you only need to know they differ.

Assemble and run

acme -f cbm -o screen.prg screen.asm

A solid white block sits in the top-left corner. You drew it by writing bytes straight into the screen's memory — no PRINT in sight.

Try this: a letter instead

Change lda #$a0 to lda #1 and run. The top-left corner now shows an A — screen code 1. Try #2 (a B), #3 (a C); the letters run upward from 1. Then #32, a space — which "draws" nothing, because a space is a character too, just an empty one.

Try this: a row of blocks

Load #$a0 back into A (the stage-light line left a 1 there), then add more shape-stores: sta $0401, sta $0402, sta $0403. The blocks are written — but only $0400 is lit, so only it shows. The rest sit in memory, invisible, each waiting for its own colour. That's the whole reason the next unit exists. And those near-identical lines? The repetition is exactly the itch Unit 10's loop will scratch.

If it doesn't work

  • Nothing appears. Check the address starts with $04 — the screen begins at $0400. A typo like $0500 writes to ordinary RAM and draws nothing.
  • A character appears but you can't see it. It's drawn in the cell's colour, and if that colour matches the background it hides. We take charge of cell colour in the next unit.
  • The wrong character appears. You're writing a screen code, not a PETSCII letter — $A0 is the block, 1 is A. Check the value.

What you've learnt

The screen is memory: the 1,000 boxes from $0400 are cells on the glass, each holding one character code, and writing a byte makes the chip draw that character — using the same sta you already know.

What's next

That second line — sta $D800 — is still a mystery: it lit the block, but we never said how. Next — Colour Is a Separate Map — we open it up. Colour lives in its own region of memory, one byte per cell, entirely apart from the characters. Two maps, two jobs.