DINO
D.I.N.O., Discrete Integrated NISC Operator, is an 8-bit CPU I built from 86 chips on breadboards, 81 of them 74-series, designed in KiCad. Three AT28C64B EEPROMs hold a 24-bit microcode word; program ROM is an AT28C256, RAM a 32K MCM60256. It started as a 25-instruction machine that could add two numbers and has grown, phase by phase, into a 174-instruction ISA with add-with-carry, a 16-bit stack pointer, CALL/RET, interrupts, execute-from-RAM, a 16K memory-mapped I/O window with eight card slots, a 16550 serial card, and a ROM monitor that loads hex over the wire and runs it. It runs SCELBAL, the 1974 BASIC for the 8008, out of the same ROM as the monitor. Most of the hard faults turned out to be analog stuff, not logic. The breadboard is at the end of what it can do at 1.024 MHz. Before the PCB, DMA gets built and tested on the breadboard and a perfboard.

Current state
As of 2026-10-06: DINO runs SCELBAL BASIC out of ROM, takes interrupts and does add-with-carry. Everything up through the serial card and the monitor works at 1.024 MHz, and all 32K of RAM works for data and for instruction fetch.
The next hardware is DMA, built on the breadboard and a perfboard before the PCB. That hasn’t started. The mainboard in KiCad is 4 layers with GND and +5V planes, placed but not routed.
Architecture
Horizontal microcode, no pipeline. Each opcode is a table of rows in a 24-bit control word held in three AT28C64B EEPROMs (U9, U15, U23), addressed by opcode and T-state. T0 is the fetch for every opcode, and a 74LS163 T-counter steps the rows until END. The control word is decoded in 3-bit ‘138 banks, so only one source can drive a bus at a time. Every load commits on CLK low, and the RAM write is held off in T-state 0, the one state where the instruction register is transparent. The machine is fully static, so the clock can stop.
Two buses. MDR0-7 is the internal bus (ROM, RAM, registers A/B/C, stack pointer halves, PC halves all drive it through ‘245s). W is the ALU and destination side. A ‘245 bridge (U25) joins them whenever any source is active: MAR and IR latch from W, registers from MDR. The ALU is a pair of 74F382s with ripple carry; all four flags latch in a ‘273 and update only when the ALU is the source.
Interrupts come in on one wire-OR’d ~IRQ line, which the serial card drives through its 7406. The interrupt core (U80-U87) takes the request at an instruction boundary, pushes PC and jumps to a single soft vector at 0x9090 in RAM. Whatever code enables interrupts plants a JMP to its own handler there.
Memory map: ROM at 0x0000-0x3FFF, an I/O window at 0x4000-0x7FFF split into eight 2K card slots, RAM at 0x8000-0xFFFF. The DIP switch is card zero at 0x4000 and the serial card is card one at 0x4800. A new card is a ‘138 on M11-M13 plus whatever chip does the work. Cards only read the address bus; there’s no DMA yet.
ISA: 174 instructions. Immediate and register ALU ops, add and subtract with carry, absolute and memory-indirect loads and stores, conditional branches on C and Z, PUSH/POP, CALL/RET, and OUT to an 8-LED latch. The high nibble of an opcode is its family, so a byte can be disassembled by hand at the bench.

Hardware
86 chips on breadboards: 81 74-series parts (18 ‘245s and 11 ‘373s are most of it), three AT28C64B microcode EEPROMs, an AT28C256 program ROM and an MCM60256 32K SRAM. The serial card adds a 74LS138, a 74LS245, a PC16550D and a 7406N.
Single +5 V rail, drawing 1.25 A to 1.34 A. A 4 MHz can divides down to 1.024 MHz, with a 500 kHz option for timing checks. The UART has its own 3.6864 MHz can and talks to the laptop through an FTDI cable.
Instruments: DSLogic Plus LA (16 channels at 100 MHz in buffer mode), Siglent SDS1204X-E, DMM, TL866 programmer. The ATmega2560 test rig and the FPGA twin are both retired.

Software
The ROM monitor takes D, W, O, L and G commands over 9600 8N1, so I can read and write memory, load hex and run it. The interrupt version reads the UART on its receive interrupt into a 16-byte ring and has Ctrl-C. SCELBAL shares the 16K ROM with it. A Python translator turns the 8008 source into DINO code, and its output is checked character for character against the original running on an 8008 emulator. G 0A00 starts it; PEEK, POKE and UDF were patched in. RAM programs load over serial, including a Mandelbrot set that draws 80x33 in 14 seconds.
Everything is generated from the KiCad schematics. A netlist oracle extracts gate equations, microcode_gen.py builds the ROM images with pinned CRCs, and a Python oracle runs the real microcode rows to say what the LEDs should read for every test image.
What the breadboard taught me
- Most of the hard faults were ground, a component value or a wire run. When a fault doesn’t care what program is running, I measure GND and VCC on every board before building a logic model. Starring the rails took the worst board from 460 mV of ground offset to 180 mV.
- Every external ground enters at the star point. The serial card was grounded through the FTDI for a while, and 250 mA of return current was leaving through the laptop.
- Raw CLK doesn’t go on a latch pin at the end of a stub. The stack pointer ‘169s double-clocked until R2 (100R) went in series, and the ALU output latch caught half its next answer until its LE came off a gate.
- RESET runs away from CLK and the buses. In the bundle it picked up 1.5 V runts and reset the UART at random.
- A component value is copper too. A 1 uF cap where 10 uF belonged gave a 0.8 ms runt instead of a power-on reset.
- If I build another one, every bus driver enable and memory strobe gets a spare input from day one, so DMA doesn’t turn into a retrofit.
Open problems
- Serial receive drops 1 bits to 0 unless there’s 22 pF on the UART’s A0 pin (U103.28). Why is open.
- The PCB power supply is undecided: the old ATX unit, a PicoPSU, or a plain 5 V brick with a supervisor chip.
- Never measured: CN+4 after a logic op on the ‘382 (the oracle refuses to guess), bus levels on a healthy machine, and whether run, idle and halt draw differ.
- 22 instructions and the 15-opcode OUT_ family have never run on silicon. They’re microcode-soft.
- 23 SETTLE rows cost a T-state each and were added for a fault that turned out to be ground. They come out at the next burn.
- Loose ends from bring-up: one halt in the middle of a serial payload on 09-29, seven boards still at 124 mV to 180 mV of ground offset, and why 100 pF on the ALU latch’s LE pin helped.
Links
- Repo: https://github.com/robertrico/dino-homebrew
- Schematics:
dino_v0_0_2/,dino_serial/anddino_io/in the repo (KiCad) - Coverage ROM table with expected OB per image:
roms/README.md - ISA roadmap:
docs/notes/dino_isa_for_basic.md