EXHIBIT 002 · HOME COMPUTING
Sixty-four kilobytes.
The best-selling computer ever made. Its processor runs here, one instruction at a time. Type a program into it.
PLAY
WATCH
Eleven programs, each one real 6502 machine code assembled with ACME. Pick one and it runs on the processor below. BASIC is the one you type at; Snake is the one you play.
PROGRAM nothing loadedINSTRUCTIONS 0STATE stopped
Click the screen, then use the arrow keys or W A S D, and space to fire. These work without clicking.
Your own .prg file is read in this browser and never uploaded. A program that calls a KERNAL routine other than $FFD2 will stop and say so, because there is no ROM here to call into.
Character output ($FFD2 CHROUT)
(no character output)
IF YOU HAVE NEVER USED ONE
How to play it.
- Press BASIC, then type
PRINT 2+2and press RETURN. Then tryPOKE 53280,2— that turns the border red, and it is the first thing most people ever typed into one of these. - Press Snake for the game. It starts straight away and the keyboard is handed to the screen.
- Steer with the arrow keys or W A S D. On a phone, use the pad under the machine. Eat the discs; the wall and your own tail both end it. Space or FIRE starts the next game.
- If keys stop working, click the screen once. The dot beside the pad tells you the screen has the keyboard.
- Then try Input test and press things. It shows the matrix coordinate of the key you are holding, which joystick switches are closed, and echoes what you type.
- SAVE "NAME"
- Keeps your program in this browser.
LOAD "NAME"brings it back,DIRlists what you have saved. It stays on this computer and is never sent anywhere. - Download program
- Takes the program out as an ordinary
.prgfile, which Load a .prg reads back. - Sound on
- Switches the SID on. Nothing makes a noise until you press it. Try Sound, or
POKE 54296,15from BASIC and go from there. - BASIC
- Type at it. Number a line and it is kept —
LISTshows the program,RUNruns it,NEWthrows it away. - Snake, Input test
- You drive these.
- Sprites, Maze, Scroller, Hi-res, Characters
- These run until you stop them. Nothing to press.
- Charset, Screen, Hello, Primes
- These finish by themselves, and the line under the machine then reads program returned.
- Stop
- Freezes the processor where it is, and lets go of every key.
- Reset
- Wipes all 64K and returns to a cold machine, as if the power had been switched off.
- Larger screen
- Fills the window with the machine. Escape, or the same button again, brings it back.
- Character output
- Opens a pane showing every byte a program sent through the KERNAL. Only Hello, Primes and Input test put anything in it; the others write to the screen directly, which is the point of the difference.
- Load a .prg
- Runs a Commodore 64 program from your own computer. It is read in this browser and never uploaded.
WHAT TO TYPE AT BASIC
- HELP
- The machine lists everything it understands.
- PRINT 2+2
- Works out sums.
?is short for PRINT. - POKE 53280,2
- Writes 2 into the border colour register. Try 0 to 15.
- PRINT PEEK(53280)
- Reads a byte of memory back out.
- 10 PRINT "HI"
- A line with a number in front is kept, not run.
- RUN
- Runs the lines you have kept, in number order.
- LIST
- Shows them.
NEWthrows them all away. - 10 FOR I=1 TO 5
- …then
20 PRINT I,30 NEXT, thenRUN. AddSTEP 2to count in twos, orSTEP -1to count down. - A$="WORLD"
- A name with a
$holds words instead of numbers, up to 32 characters.PRINT "HELLO "+A$joins them. - 10 INPUT "NAME";N$
- Stops and waits for you to type an answer.
INPUT Aasks for a number instead. - GOSUB 100
- Runs the lines at 100 and comes back when it reaches
RETURN. - LEN(A$) ASC(A$)
- How long a word is, and the code of its first letter.
CHR$(65)andSTR$(42)go the other way.
Retype a line with the same number and it replaces the old one; type the number on its own and the line is deleted. SAVE "NAME" keeps a program in this browser and LOAD "NAME" brings it back; DIR lists them. Storage belongs to this browser alone.
The keyboard is wired the way the hardware is: your keys close switches in an eight-by-eight matrix on CIA 1, and the arrow keys and space also close the five switches of a joystick in port 2. A program can read any of it — the matrix, the ports, or characters through the KERNAL. If a program stops with a message about ROM, it asked for something Commodore wrote, and this exhibit ships no Commodore code. The notes below explain why.
WHAT IS REAL HERE
The processor.
A 6502 core written for this exhibit: all 56 documented mnemonics, 151 opcodes, every addressing mode, the indirect-jump page-boundary bug, and decimal mode.
It is tested against py65, an independent 6502 implementation, on 3,624 differential vectors — every opcode, 24 randomised trials each, comparing the program counter, all registers, the observable status bits, the cycle count and every memory write. All 3,624 agree.
The cycle comparison found something. py65 declares DEC absolute as three cycles, where it is six. The evidence is inside py65 itself: it has DEC zero page at five, DEC zero page,X at six, DEC absolute,X at seven, and INC absolute — the exact mirror — at six, along with every other absolute read-modify-write. One entry is out of step with all of its neighbours. So the reference is corrected for that opcode rather than this core being bent to match it, and the correction asserts py65's wrong value before patching it, so it fails loudly if py65 is ever fixed.
Every one of the thirteen programs is then run on both implementations and compared field by field: instruction count, cycle count, all registers, the hash of the whole 64K, the video matrix, colour RAM, the sprite registers, the sprite pointers, the border and background, and the bytes sent to CHROUT. All thirteen agree on all of it.
Snake is tested by playing it: a harness reads the screen, finds the head and the food, steers the joystick, and checks that the score rises, that the length is always four plus the score, that the border kills it, and that fire starts a new game.
BASIC is tested by typing at it. Seventy-eight cases push characters through the keyboard buffer and read the answers off the video matrix — arithmetic and precedence, string variables and concatenation and comparison, LEN, ASC, CHR$ and STR$, variables, POKE and PEEK, storing and replacing and deleting program lines, LIST, RUN, nested loops, STEP in both directions, GOSUB nested, INPUT answered at the keyboard, and each error message. Nothing is checked by looking inside the interpreter; it has to put the right thing on the screen.
Status bits 4 and 5 are excluded from the register comparison because they are not physical register bits on a 6502; they exist only inside a pushed status byte, and those bytes are compared.
WHAT IS NOT HERE
No Commodore ROM.
There is no BASIC ROM, no KERNAL ROM and no character ROM in this exhibit. They are Commodore copyrights and are not included — and the company dissolving in 1994 did not change that, because copyright is an asset that gets sold rather than voided. The 2025 revival of the Commodore name covers the brand and its trademarks; who holds the original software copyrights is not something this exhibit can establish, which is a reason for caution rather than for helping itself.
Four KERNAL entry points are reimplemented in JavaScript — $FFD2 CHROUT, $FFE4 GETIN, $FF9F SCNKEY and $FFE7 CLALL — and any other call into ROM space halts the machine with a message rather than executing whatever happens to be in RAM.
The BASIC here is GE97's own, written for this exhibit in 6502 and containing no Commodore code. It takes its shape from the books rather than from any ROM: Mapping, at location 512, describes the loop it implements — "type in a line of characters, those characters are stored here … and either stores it or executes the line, depending on whether or not it started with a line number" — which is also where the 80-character line and the buffer address come from.
It is a real but small BASIC. PRINT, POKE, PEEK, SYS, LET, IF … THEN, FOR … TO … STEP, NEXT, GOTO, GOSUB, RETURN, INPUT, REM, END, LIST, RUN, NEW, SAVE, LOAD, DIR, and the functions ABS, RND, PEEK, LEN, ASC, CHR$ and STR$. Variables are the 26 single letters, and the 26 strings A$ to Z$, each holding up to 32 characters.
What it does not have: floating point — numbers are 16-bit unsigned integers, so there are no fractions and 65535 + 1 is 0 — and arrays, DATA, ON … GOTO, MID$ and the rest of the string functions, and user-defined functions. Lines are kept as the text you typed rather than tokenised, which is why LIST gives back exactly what went in. A typed program lives at $2000, because $0801 is where the interpreter itself sits, and the string variables sit above the program at $7F00 — a line that would reach them is refused with ?OUT OF MEMORY rather than quietly overwriting one.
The characters are GE97's own 8×8 glyphs, drawn for this exhibit. 127 of the 256 screen codes have one — every code below 128 except 96, which Appendix B prints as a space — and 128 to 255 are those reversed, which is what the same appendix says they are.
For the graphics codes that is not a reading of the book but a measurement of it. A tool finds each printed cell on a scan of pages 377 and 378, insets it by the median thickness of the cells' own printed outlines, and reports the ink at each of the 64 dot positions. The drawings are made from those measurements, and a test checks every drawn glyph back against them — that the drawing has ink where the page has ink and nowhere else, to within the page's own resolution.
The page has a limit, and the exhibit would rather name it than paper over it. A rule one dot wide prints about as wide as the measuring bins are, so two codes whose rules sit one dot apart can measure the same. Four pairs do: screen codes 64 and 67, 70 and 82, 84 and 101, 66 and 93. Each family of eight rules is therefore ranked by the measured centre of its ink, and where two codes fall within a quarter of a dot of each other the lower code takes the earlier position. That tie-break is a convention rather than a measurement, and it is the only place in this font where the source ran out.
The VIC-II is modelled as far as the exhibit needs. $D018 is honoured, so the video matrix and the character set can be moved anywhere in the VIC's 16K, and $DD00 chooses which 16K that is. A character set in RAM is read from RAM, eight bytes to a character, which is what the Characters program uses. $D011 bit 5 gives standard bit map mode — 320 by 200 dots, the colours taken from the video matrix rather than colour RAM, the upper nybble for the set bits and the lower for the clear ones — and bit 4 blanks the display. The eight sprites have their positions, colours and expansion, and their pointers follow the video matrix wherever it goes. A raster counter advances with the processor's own cycles.
What is absent: multicolour text and multicolour bit map, extended background colour mode, fine scrolling, sprite collision detection, sprite priority against the background, and raster interrupts. Where a real machine has its character ROM — $1000 and $1800 of banks 0 and 2 — this exhibit puts GE97's own glyphs, because it ships no Commodore ROM; anywhere else is ordinary RAM and is read as such.
The SID is here, and it makes a noise: three voices, the four waveforms, the gate, and attack, decay, sustain and release with the sixteen rates from the book's own table. What is not modelled is the filter, the pulse width (a pulse is a plain square wave), ring modulation, oscillator sync, the test bit, and reading voice 3 back. Sound is off until you switch it on, because a browser will not let a page make a noise unasked.
FOLLOW THE EVIDENCE
Addresses, from the books.
The sound chip is the book's too. The SID base at 54272, the volume at register 24 "anywhere between 0 and 15", the frequency conversion Fn = Fout / .06097, the control bits for triangle, sawtooth, pulse and noise, and Table 2's sixteen envelope rates all come from the Programmer's Reference Guide, pages 184–187 and Appendix O. The book prints attack and decay as two columns and the scan is unreadable in two places — but every decay rate is exactly three times its attack across all sixteen entries, which settles the two that are not legible.
The memory map is taken from period documentation rather than memory. The video matrix at $0400–$07E7, sprite pointers at $07F8 with a data block at pointer × 64, colour RAM as "1000 locations … start at 55296 ($D800) … 4 bits wide", the sprite registers at $D000–$D02E, and the raster register at $D012 with its ninth bit in $D011 all come from the Commodore 64 Programmer's Reference Guide (first edition, eighth printing, 1983). $FFD2, $FFE4 and the rest of the KERNAL jump table come from Leemon's Mapping the Commodore 64 & 64C (1987), pages 244–245.
The keyboard is the same story. Mapping gives the eight-by-eight matrix on CIA 1 on page 173 — write a zero to the Port A bit for the column you want, then read Port B, where a zero means the key in that row is down — and prints all 64 matrix codes again at location 203. Two tables in one book, and they agree on every position, which is how this exhibit knows which key sits where. The same page is emphatic about the trap that "Controller Port 1 is read from Data Port B, and Controller Port 2 is read from CIA #1 Data Port A", and the Programmer's Reference Guide (page 343) gives the five joystick switches and the fact that a bit reads zero while a switch is closed.
Which glyph belongs at which screen code, and the conversion from PETSCII, were read off Appendix B (page 377) against the CHR$ table in Appendix C (page 380). That is how the two diagonal strokes of the maze were placed at codes 77 and 78.
Both books independently give the KERNAL SAVE vector at $0332, which is corroboration rather than one source quoted twice. Two numbers here are not from these books and are marked as such in the source: the PAL figures of 63 cycles a raster line and 312 lines a frame, which pace the machine.
Historical guidance from Mark · 6502 development with Commodore · research with Spirit.
Programs, processor core, character set and exhibit code written for GE97. Commodore, C64, VIC-II and KERNAL are Commodore names.