← THE BUILD LOG
001RETRO

269 bytes that made a 1983 machine ten times faster

The set rendered on an Oric Atmos: one bit per pixel, black and white, the chunky edges of a 1983 screen.
The set rendered on an Oric Atmos: one bit per pixel, black and white, the chunky edges of a 1983 screen.

What it is

A Mandelbrot set renderer for the Oric Atmos, the 8-bit machine that was my first computer in 1985. The program is BASIC. The inner loop, the part that runs for every pixel, is 6502 machine code, written with an agent rather than by hand.

In pure BASIC a full render takes five to six hours. With the machine code in place it takes about 35 minutes. The machine code is 269 bytes.

Why I built it

To find out how far I could push an agent against a problem I had already solved years ago, on hardware it could not possibly have been trained to care about. I knew what the BASIC version did and how long it took, so I had a number to beat and no way to fool myself about the result.

Three questions, really. How much does Claude actually know about 6502 and Oric BASIC. How much faster would the machine-code version be than my BASIC-only one. And underneath both: what does it take to point modern agentic tooling at equipment that has no network connection and no way of ever getting one.

Mandelbrot is a good choice for this because the maths is simple and the work is enormous. There is nowhere to hide a slow decision, because whatever you do gets done tens of thousands of times.

The problem

The 6502 has no multiply instruction and no floating point. A Mandelbrot iteration is nothing but multiplication, so the interesting part is everything you do instead.

That means fixed-point arithmetic, a scale chosen so the intermediate values still fit, multiplication built out of shifts and adds, and constant attention to whether a value has quietly overflowed into nonsense. None of it is difficult in the sense of being clever. It is difficult in the sense of being unforgiving, because the processor will not tell you that you were wrong. It will just draw the wrong picture.

What I learnt

The order of difficulty was backwards from what I expected.

The machine code worked straight away. Hand-rolled fixed-point arithmetic, on a processor with no multiply and no floating point, first time. It knew considerably more 6502 than I thought it would.

What it could not do was Oric BASIC. It kept writing BBC BASIC, which looks close enough to pass a glance and differs in the places that matter, because that is the dialect it has seen most of. No amount of being told produced a lasting fix.

What fixed it was the manual. I gave it the one that came with the machine and wrote an agent rule saying use this and nothing else. Most of the trial and error stopped there. A model that has read a thousand pages about a family of dialects needs the primary source for the one in front of it, and needs to be forbidden the rest.

The second fix was a loop. I taught it the development cycle over MCP, so it could load a program, run it, save the result and look at what came back. Once it could try, it stopped needing to be right first time, which is a much lower bar and a much better one.

So the hard-looking part was a reasoning problem it was good at, and the easy-looking part was a documentation problem it could not reason its way out of. I would not have predicted that, and it is the thing I would carry to the next piece of old hardware.

Ten times faster from 269 bytes is also worth remembering the next time somebody proposes rewriting a system in a different language for performance. The gain came from doing the arithmetic properly in the place it was already happening.

What’s next

The renderer is done. The picture at the top of this page is its actual output rather than something I made to stand in for it.

The question underneath it is not. An emulator is a soft target, because the file system is right there and an agent can reach it. Real hardware from that era cannot be reached at all: no network, no shared disk, nothing to attach to. After this I worked out how I would do it on the IBM XT sitting in the same room, by intercepting the keyboard and the screen buffer, so an agent types and reads through the only two channels the machine has. I have not built it. Knowing how I would is a different thing from having done it, and this log is for the second one.


Built with BASIC, 6502 assembly, Python
JOHN · #AlwaysBuildingSomething