The machine, and four games to break it
- Memo
- #003
- Date
- 1 November 2026
- From
- Viljami
A fantasy computer is easy to design on paper.
You find out what's wrong with it when someone tries to write a game on it.
So that's what I did. I designed the CPU, the assembler and the emulator, and then had four games written against the manual. They broke it in pretty useful ways.
As with everything in this project, the code is written with AI assistance (memo #001 explains why). The design decisions are mine.
The manual is the spec
The UNC 64 has a Programmer's Reference Guide, like every machine of its era. It's also the single source of truth.
If the manual says an instruction takes 4 cycles, it takes 4 cycles and a test checks it. Every assembly listing in the manual is assembled and run by the test suite. The instruction table in the appendix is generated from the same table the CPU executes.
When the manual and the machine disagree, a test goes red. No exceptions.
The CPU
The UNC-1 is in the 6502 family, cleaned up the way you would if you designed it today and still wanted it to fit in your head:
- Fixed cycle costs, 2 to 6 per instruction. No page-crossing penalties, no surprises. You can count a loop's cycles on paper and be exactly right, which is what makes cycle leaderboards fair.
- A regular encoding. Opcodes sit in rows and slots, so the table reads like a grid instead of a ransom note.
- No decimal mode. On purpose. More on that below.
- A fast page instead of zero page: the first 256 bytes, with short addresses.
- Unassigned opcodes jam the CPU instead of doing something random. The undocumented ones come later, and they'll be discovered, not listed.
Memo #001 promised about 35 instructions. Rev A has 55.
Was that a mistake? Not really. It's a working draft that is too big on purpose: it's much easier to cut instructions nobody uses than to guess which ones you'll miss. The cutting happens before anything gets frozen.
The clock is 1 MHz. A frame is 312 raster lines of 64 cycles: 19,968 cycles, fifty times a second. That number is the budget every game lives inside.
The emulator
The core is a Rust library with zero dependencies.
It's deterministic: the same program and the same key presses give the same machine, byte for byte, every time. The arithmetic instructions are tested exhaustively against every possible input. The same core runs in three places: inside the Godot game, in the browser as WebAssembly on the showcase and headless in the tests.
The screen is 40 by 25 characters in UNSCII, a character set I designed for it. The font is just memory: point a register at your own 2K and every character changes. There's also a 320 by 200 bitmap, because I wanted the lines and circles I had on my Amiga 500 as a kid.
The tape deck is real hardware too. You type LOAD, press PLAY and the program arrives at about 600 bytes a second, with loading stripes in the border. (ORBIT takes ten seconds to load. Authentic!)
The assembler
I wanted it to feel like a good 1980s cross-assembler that got a few more years to mature: local labels, repeat blocks and expressions with real precedence.
Tables get generated in the source instead of pasted from a script. sin(), cos() and sqrt() are built in and use integer maths only, no floating point anywhere. The sine comes from a quarter-wave table computed to 200 bits, so the same source gives the same bytes on every machine, forever.
Overkill? Probably. I don't care. 😅
Four games

To put the machine through its paces I asked for four classic genres, each with a twist of its own:
- SNAKE, in text mode with custom characters.
- STACK, falling blocks with three-cell pieces and a bomb every eighth piece.
- ORBIT, rocks to shoot around a small planet with real gravity, in the bitmap.
- DEBUG, a marching formation of bugs that drop exceptions, with a profiler in the border that shows where the frame goes.
Like the rest of the project, the games were written by AI agents (Claude Code, mostly). I handed them the manual and asked for games, the way a kid in 1984 had the manual and nothing else.
It turned out to be the best test I could have run.
An agent reads the manual literally. Every gap, every ambiguity and every awkward routine shows up in its code as a workaround.
What did they find?
Every single finding was a design bug in the machine. Zero were bugs in the code:
- All four games rubbed out the cursor after printing a number. The ROM drew a cursor every time it printed a character. Now the cursor belongs to BASIC's line editor and only shows while it waits for you to type, like on the C64.
- Printing a score needed workarounds. The ROM's number routine had no width, no leading zeros and stopped at 65,535. There are now two routines: one turns a 24-bit number into digits, one prints them padded.
- Every game seeded its random numbers by poking memory and guarding against zero. Now there's a seed call and a noise register to feed it.
- Sound stalled the games. The beeper could only click, so a sound meant a loop of clicks: STACK's bomb burned about 1,400 cycles a frame just rumbling. The beeper now works the way the IBM PC's did: a timer drives the speaker and a note costs nothing while it plays.
- The keyboard could only report one held key. You couldn't turn and fire at once. There's now a keyboard matrix with a bit for every key.
- DEBUG kept 768 bytes of pre-shifted sprites to draw at any pixel. A small hardware shifter fixed it: DEBUG got 535 bytes smaller, and its screen is identical to the old version on every frame of a recorded game.
Then all four games were rewritten to use everything. Three of them grew a little (mostly sound tables) and DEBUG got smaller. They all have sound now and they're all on the showcase, running on the same core as the game.
Why no decimal mode?
The 6502 had a decimal mode for exactly one job: scores.
I left it out. Converting a binary number to decimal on the UNC costs hundreds of cycles, so a game whose score changes every frame keeps it as a row of digits and adds with carry, one digit at a time. That's 34 cycles a hit, plus 30 for each carry. It's in the manual with a tested listing, under "Keeping score fast".
Two of the four games ended up doing exactly that.
I like constraints that teach you something the moment you hit them.
Anyways, next up is the story. The four games turn out to be the uncle's tapes.
Viljami