An Intel 8008 in the card, and a whole 8008 toolchain that lives on the Apple IIe

/ Byte Hamr / updated 2026-09-10 / from project_byte_hamr 8008 b8008 assembler merlin toolchain fusesoc

What I tried

The 8008 core is the cycle-exact one from my Intel 8008 VHDL project. GHDL synthesizes it to a Verilog netlist and Yosys takes that unmodified, so the Byte Hamr build never needs VHDL support. On 2026-07-07 I dropped it into gateware/rev2/b8008_hamr/ using the SDRAM monitor’s bus idiom: the bootstrap FSM that jams RST 0 at T1I, ported verbatim from the core’s monitor top; 64-deep TX and RX FIFOs on IN 1 and OUT 9 with USART snapshot-and-pop semantics; an OUT 31 checkpoint latch; reset and go controls; live PC registers; ID $B8 at $C0CF. The 256-byte slot ROM is the whole glass terminal in 122 bytes, so PR#4 drops you at the 8008 monitor prompt with no OS in the loop. Ctrl-Q exits, Ctrl-R reboots the 8008 alone.

PR#4 from the BASIC prompt drops into the slot ROM terminal and the 8008 monitor answers. H lists the whole command set: dump, write, load hex, go.
PR#4 from the BASIC prompt drops into the slot ROM terminal and the 8008 monitor answers. H lists the whole command set: dump, write, load hex, go.

I wanted to write the 8008 code on the Apple itself. The first leg was MAC8008, the 8008 instruction set as Merlin macros generated from the ISA JSON, with semicolon two-operand arguments like MOV A;B. B8RUN reads a ProDOS BIN whose aux type is the ORG, turns it into Intel hex and streams it through the FIFO to the monitor’s L command. B8CMP byte-compares two files through the MLI. The second leg, 07-08, was ASM8, a native 8008 assembler written in 6502 that takes true 8008 syntax, MOV A,B and MVI C,41h, with a table generated from the same ISA JSON. A8 wraps it: an 80-column full-screen editor, ^A assembles in memory and jumps the cursor to an error line, ^G streams the object into the card and drops into the monitor, ^Q comes back to the editor with the buffer intact. On 07-10 the vendored netlist went away and FuseSoC generates it at build time from the core repo.

A8 after ^A on HELLO8R.ASM, the verbatim upstream ASL source in 8008new syntax. The status row reports OK $01C9 AT $2040: 457 bytes of object at the ORG, the same size as the ASL reference. ^G streams it into the card.
A8 after ^A on HELLO8R.ASM, the verbatim upstream ASL source in 8008new syntax. The status row reports OK $01C9 AT $2040: 457 bytes of object at the ORG, the same size as the ASL reference. ^G streams it into the card.
^G from A8, then the run. The editor streams Intel hex into the 8008 monitor's L command, one dot per record, the monitor answers OK, and A8 hands the screen over as a TTY with the G address printed. It stops there on purpose. I typed G 2040, the 8008 printed HI and 0123456789 B8008-OK, and the monitor came back.
^G from A8, then the run. The editor streams Intel hex into the 8008 monitor’s L command, one dot per record, the monitor answers OK, and A8 hands the screen over as a TTY with the G address printed. It stops there on purpose. I typed G 2040, the 8008 printed HI and 0123456789 B8008-OK, and the monitor came back.

What I measured

What broke or surprised me

B8RUN’s first bench run went wild. The FIFO put routine clobbered X and Y, the record loop ran off the end, and a 64K read sweep walked straight through the $C0xx soft switches: garbled screen, and the slot 6 drive motors came on in write mode. I checked the floppies afterwards. The driver preserves X and Y now, and I found five more 6502-side bugs the same session, none needing a reflash: the MLI prefix is empty at boot so raw MLI calls fail with $40 until you set it; an error printer that destroyed the code before printing it; lowercase input that ProDOS rejects; an unattended load that overflowed the 64-byte TX FIFO and dropped the monitor’s OK, fixed by draining TX to the screen per record.

Merlin Pro on the IIe loaded the whole 200-line macro file and defined every macro, then threw Operand too long on the generator’s 72-column header comment. Merlin Pro enforces line width and Merlin32 does not. Every generated source is clamped to 40 columns now. Real Merlin also scopes local labels between globals, so self-modifying loops use global labels only, and #',' will not parse, so it is #$2C.

The monitor’s W command chokes on trailing text. My first freeze was annotations typed in with the listing, which the monitor faithfully wrote as garbage into a $00 HLT wall. A program that waits silently for input also reads as hung; the first ECHO8 run got Ctrl-R’d during its own input wait.

Next

SCELBAL as a second personality, a direct load and readback port for RAM snapshots, and merging the block device so the card boots itself. None of it started.