Conway's Multiverse: a soft 6502 on the card runs eight Life universes while the IIe watches

/ Byte Hamr / updated 2026-09-11 / from project_byte_hamr coprocessor 6502 arlet kernel conway sdram

What I tried

The PicoPort’s PIO is driven by a small internal RISC-V, and that planted the question of whether the Byte Hamr could run its own processor next to the host. The ECP5 had the room. A 6502 made sense for this machine, so I put Arlet Ottens’ verilog-6502 in with its own block RAM and a $E000 write window that posts one SDRAM write through a two-client priority arbiter, monitor first, coprocessor second. Everything is one 25 MHz domain, no CDC.

C0 on 2026-06-08 was the steel thread: the coprocessor runs LDA #$42, STA $E000 from its own BRAM, the byte lands in SDRAM, and from the monitor B 000 then R 0040 prints 0040: 42. C1 the same day was a resident, hardware-protected kernel the host registers tasks into. C2 was a cooperative scheduler: two Merlin tasks race, the host reads 0102, retune the budgets and it reads 0201. C3 added a preemptive tick timer and an IRQ into the Arlet core, and a third task with no yields still gets sliced. C3.1 made the GO trigger a nonzero write so a stale count could not re-arm across runs. C-flash on 06-09 saves the task registry to flash and restores it on boot, with a magic-last header so a torn write fails safe. C4 the same day was async skill dispatch: a control-plane register block, a dispatcher inside the ISR, a slot mailbox ABI so a skill is reentrant, and CPLIB on the host with CP_CALL, POLL, WAIT and RESULT. Then a two-step $E004 to $E008 auto-increment read window, so the coprocessor can read SDRAM as well as write it. The demo needs that.

The demo is Conway’s Life, eight of them. LIFE8 is one registered skill that loops over eight independent universes in SDRAM forever, bit-packed cells, a three-row sliding window so each row is read once, wrap-around edges. The IIe picks a universe with the 0 to 7 keys, draws it, and otherwise does nothing. Switch away, come back, it has moved on.

Conway's Multiverse. Eight Life universes evolving in the card's SDRAM on the soft 6502; the Apple IIe is only the viewer.
Conway’s Multiverse. Eight Life universes evolving in the card’s SDRAM on the soft 6502; the Apple IIe is only the viewer.

What I measured

The Lo-Res version, since it is the one you can actually watch:

Gliders in flight, wrapping around the torus edges.
Gliders in flight, wrapping around the torus edges.
Channel 3 after the R-pentomino settled: beehives, blocks, blinkers and beacons.
Channel 3 after the R-pentomino settled: beehives, blocks, blinkers and beacons.
Soup that has organized. The box-and-bars structure is a period-2 oscillator, with beehives and a stray glider around it.
Soup that has organized. The box-and-bars structure is a period-2 oscillator, with beehives and a stray glider around it.
A different random seed mid-evolution, structures still resolving.
A different random seed mid-evolution, structures still resolving.

What broke or surprised me

Yosys will not infer a DP16KD with two write ports, so the kernel BRAM has one shared write port and a count-last rule. The Arlet core needed a registered synchronous data-in and a gate on SDRAM ready. A cooperative task has to end with JMP DONE and not RTS. Re-arming the count register is a level, so wait for DONE before re-arming or the kernel hangs.

The Gosper glider gun I seeded on channel 0 collapsed. On a torus the gliders come all the way round and hit the gun. Guns need an open field.

Lo-Res and Double Hi-Res are different memory formats. DHGR packs 7 pixels per byte so the render was a copy; Lo-Res is two stacked 4-bit color blocks per byte, so the renderer expands each cell bit into a $0 or $F nibble. And the double buffer that kept DHGR clean tears at Lo-Res speed, because the core laps the host inside one frame. The fix is a generation-stamped snapshot: copy the grid, check the generation counter did not change, retry if it did. Cloning the engine also broke on the row stride, which was a hand-written MUL80 and had to become MUL5 for 5-byte rows.

Next

Other things that run on the card without the host asking. A live database the IIe queries, or a game where the day passes and crops grow whether or not you are looking. That became the farm.