Intel 8008 VHDL
An Intel 8008 in VHDL, built the way Intel drew it. Every box on the 1972 block diagram is its own module, fifty to a hundred lines, and none of them know what an instruction is. The timing and control unit is the only part that does. It runs on a Lattice ECP5-5G Versa, takes the datasheet’s T-states for every instruction, and one of the two builds powers on straight into SCELBI BASIC from 1976.
This is the third try. The first two ran, one of them on hardware, and both got thrown out. The story of why is in the logs.

Current state
As of 2026-09-10: The core is finished. Silicon-validated on the ECP5-5G Versa. Two FPGA builds share it. b8008_monitor boots to a machine monitor with D, W, L, G and H commands and Intel HEX loading over 115200 serial. b8008_basic boots straight into SCELBAL, with MON to drop to the monitor and G 1FB6 to come back with the program intact.
Period software that loads and runs from RAM: the SCELBI Mandelbrot renderer, the pi digit generator, HEXPAWN (1973), the SCELBI floating-point calculator (1974) and Shooting Stars from Byte, May 1976. The regression suite is 37 assembly programs with checkpoint verification, the hardware self-test ROM is 46 tests, and all 27 timing classes take exactly the datasheet’s T-states.
Every module has machine-checked verification that runs in CI on each push: SBY property proofs, synthesis round-trip equivalence, cocotb random walks, exhaustive sweeps of the decoder and ALU, and a differential fuzzer that runs random legal programs on the RTL and the round-tripped netlist under three oracles at once.
Last change was 2026-09-03: the LEDs moved to a memory-mapped RAM byte, DIP switches 2 to 8 were disconnected, and the Makefile grew targets for the serial console. The same core also runs inside the Byte Hamr card as an 8008 coprocessor for the Apple IIe, pulled in as a FuseSoC-generated netlist. The Ethernet monitor spec from July moved out to its own repo and became LiteX 8008 Node, which runs on the Versa and answers make login over the LAN.
Architecture
The core is about 27 modules, each one a box from the Intel block diagram: state timing generator, machine cycle control, instruction register, instruction decoder, register and ALU control, register file, temp registers, ALU, carry look-ahead, condition flags, address stack, stack pointer, interrupt and ready flip-flops, I/O buffer, memory mux. Each is 50 to 100 lines and does one thing. The stack pointer is 69 lines and knows two words, push and pop. It has no idea what CALL or RST or an interrupt is. The control unit is the only place instructions are understood.
There is no separate program counter, because the real chip doesn’t have one. The PC is whichever of the eight 14-bit address-stack registers the stack pointer selects. CALL is the SP moving on and the old slot keeps the return address. RET is the SP moving back. Seven nested returns, and the eighth CALL wraps onto the oldest. I built it with a separate PC first and a family of workaround flags grew around it. Rebuilding it as the diagram shows deleted all of them.
Every documented instruction takes the datasheet’s 5, 8 or 11 T-states. Fetch cycles of multi-cycle instructions end at T3, not-taken conditionals end early, and a regression counts simulated states per timing class against docs/isa.json. Interrupts are recognized only at instruction boundaries, per Figure 2 of the User’s Manual. READY parks the CPU in a real WAIT state between T2 and T3.
The ALU’s adder is the carry look-ahead block. For a while that block compiled and had a testbench and nothing instantiated it, and the toolchain was inferring the adder from numeric_std. It’s wired in now, with a 9-bit carry-out and an exhaustive sweep behind it.
The whole design runs in one 25 MHz clock domain. phi1 and phi2 are one-cycle enable pulses off a phase_clocks state machine, with the pulse widths parameterized so the 8008’s 0.8 and 0.6 microsecond phases hold at any system clock. The internal bus is a mux. An early version used tri-state signals internally and they turned out to be the critical path.

Hardware
The board is a Lattice ECP5-5G Versa development kit, so there’s no PCB of mine in this project. The 100 MHz oscillator goes through an on-chip PLL to 25 MHz, and everything runs on that. A T-state measures about 4.4 microseconds against the real chip’s 4 at 500 kHz.
Serial is the on-board FTDI at 115200 8N1, local echo off, DEL for rubout because that’s what the 1976 software expects. ROM and RAM are block RAM inside the FPGA. Firmware gets patched into the bitstream with ecpbram after place and route, which takes 0.66 seconds against a 4 minute resynthesis.
DIP switch 1 is reset. Switches 2 through 8 were disconnected on 2026-09-03 after too many sessions where the wrong resting position halted the CPU or put the LEDs into a capture mode. The seven user LEDs show one RAM byte, bit n to LED n, at 0x3FFF in the monitor build and 0x00FF in the BASIC build. LED0 is the CPU-running light.
There’s a logic analyzer header carrying INT, phi1, phi2, SYNC, the three state bits and the eight data lines, with a DSView config and Python decoders in the repo for reading traces back into instruction streams.
In January 2026 I tried an AT28C64B EEPROM as external ROM, the way the SIM8-01 did it. It executed code when it booted and boot was unreliable for months. That story has its own log.
Gateware and firmware
Toolchain is GHDL, Yosys, nextpnr-ecp5 and ecppack from OSS CAD Suite on macOS. 8008 assembly goes through the AS assembler in 8080 syntax. Everything goes through the Makefile.
b8008_monitor. ROM 4 KB at 0x0000, RAM 12 KB at 0x1000. The monitor has D (dump), W (write), L (Intel HEX load over the same serial line), G (go, through a JMP trampoline because the 8008 has no indirect jump) and H (help). Programs own 0x2000 to 0x3EFF. RST 1 through 7 vectors in ROM forward to 8-byte RAM slots at 0x3FC0 so a loaded program can install its own handlers. Output is OUT 9, input is IN 1 with bit 7 as the ready flag. The hardware self-test ROM runs 46 ISA tests on the board and reports each over serial.
b8008_basic. RAM 4 KB at 0x0000, ROM 12 KB at 0x1000 holding the monitor and SCELBAL. Three bytes of block-RAM initialization at address zero, JMP 1800h, land the CPU in BASIC at power-on. MON lives in an unused zero-filled slack region of SCELBAL’s keyword table and jumps to the monitor. G 1FB6 warm-enters BASIC’s executive without re-initializing.
The two builds are the same b8008_top with the memory map as generics.
Samples. RAM ports of Mandelbrot, pi, HEXPAWN, the SCELBI calculator, Shooting Stars, hello, a cylon LED sweep, and two front-panel interrupt tests. Each port’s changes are kept to the ORG, the serial shims and the exit, and the exact ledger is in the commit history.
Verification. SBY property suites for eleven modules plus a composition cluster, seven SBY miters and six EQY checks proving each module equivalent to its own Yosys write_vhdl round trip, seven cocotb runs including a whole-system bus-protocol monitor, the 37-program regression on both the RTL and netlist cores, and the differential fuzzer. Each checker was mutation-tested by planting a bug in the RTL and confirming it fails.
Decisions
- 2025-11-21: s8008 deprecated. It reached hardware before I understood its timing model was wrong.
- 2025-11-22: v8008 sunset. Too much shared logic and conditional soup to debug. b8008 starts from a clean slate with one module per block-diagram box, and every module gets its own testbench.
- 2025-12-23: AS assembler in 8080 syntax for all test programs.
- 2025-12-24: every regression program asserts its own state through OUT 31 checkpoints, and a check script verifies the log. No test passes by not crashing.
- 2026-01-02: internal bus is a mux. Tri-state signals inside the core caused synthesis trouble and later turned out to be the critical path.
- 2026-01-05: ROM default fill is 0x00. Yosys corrupted ROM contents on hardware with an 0xFF fill.
- 2026-04-20: phi1 and phi2 are clock enables on one master clock. The gated clock and the derived phi2 domain are gone.
- 2026-05-06: on-chip PLL to 25 MHz for everything, instead of multicycle path constraints against 100 MHz.
- 2026-07-01: ROM lives in block RAM inside the FPGA. External EEPROM is parked. When it comes back it will be direct 3.3 V drive on address and control and resistor dividers on data, with no auto-direction shifter near a memory bus.
- 2026-07-01: firmware changes go through ecpbram, and a full resynthesis is only for RTL changes.
- 2026-07-02: PC is a slot in the address stack, fetch is post-increment, interrupts are taken at instruction boundaries only. All three per the Intel block diagram and Figure 2.
- 2026-07-03: SCELBAL is kept faithful to Jim Loos’s build. I added an auto-SCR at cold entry and reverted it the same day.
- 2026-07-29: the carry look-ahead block is the ALU’s only adder. Every block in the diagram is real logic.
- 2026-08-08: the verification plan has zero gaps. Every spec claim is machine-checked or written down as a constraint.
- 2026-09-03: only DIP 1 (reset) is wired. Front-panel interrupt, READY hold and LED capture modes are removed from both board tops.
Open problems
- External ROM was never made reliable. The TXS0108E shifters were the wrong part and the redesigned wiring hasn’t been built.
- The bootstrap RST-0 jam consumes one stack level for good, so programs get six safe nesting levels instead of seven. Real silicon booted the same way does the same thing.
- It has never been run side by side with a real 8008. I own two. The plan is a shifter board and a socket, and then the same programs on both.
- No removable media. SD over SPI as a modern cassette was the idea.
Links
CI: https://github.com/robertrico/intel-8008-vhdl/actions/workflows/verification.yml
Build thread on VCF: https://forum.vcfed.org/index.php?threads/block-based-intel-8008-in-vhdl-seeking-fpga-advice.1255974/
Period software source, Mike Willegal’s SCELBI apps page: https://www.willegal.net/scelbi/apps8008.html
Same core inside the Apple IIe card: Byte Hamr
Timing table:
docs/isa.json. Spec stack:docs/SPEC.md,docs/MAS.md,docs/VPLAN.md,docs/BUS_PROTOCOL.md,docs/TIMING.md,docs/INTERRUPTS.mdReference: Intel 8008 datasheets (1972, 1978) and User’s Manual in
docs/, SIM8-01 schematicSame core on the network: LiteX 8008 Node