Skip to content

Bus driver card: theory of operation

The bus driver is a 2026 test card, modelled on the YACC1 bus tester. An Arduino Nano, talked to over USB, drives the whole System-5 bus through two MCP23017 I/O expanders. With the CPU card pulled it is the bus master: it runs memory and I/O cycles in the 1802's order, so each card can be tested on its own. With the CPU card in, it only watches.

  • Rev B (BUSDRV-B), hardware/bus-driver/kicad/rev-b/, generated from gen/netlist.py; ordered 2026-10-20. Rev A (2026-10-09) is scrap: routed on four layers, made from a two-layer zip.
  • Firmware: embedded/bus-driver/s5-bus-driver/ (Arduino sketch; the command list is in its header).
  • Host tool and card bring-up: software/busdrv/ (s5busdrv.py, bringup.py, BRINGUP.md).

Parts

Ref Part Job
A1 Arduino Nano (ATmega328P; Ken's CH340 clone needs the old bootloader) USB serial console; I²C master
U1 MCP23017 at 0x20 GPA0–6 = D0–D6, GPB0–6 = A0–A6, GPA7/GPB7 = SPARE1/2
U2 MCP23017 at 0x21 GPA0–6 = D7, A7, TPA, TPB, -MRD, -MRW, -VMA; GPB0–6 = Q, -RESET, -INT, -EF, N0, N1, N2; GPA7/GPB7 = SPARE3/4
J1 System-5 bus, 30 pins
J2 header SPARE1–4 (outputs only), +5 V, GND
R1, R2 4.7 kΩ I²C pull-ups to bus +5 V
R3 10 kΩ expander reset (XRST) pull-up
R4, R5 10 kΩ / 100 kΩ bus +5 V sense into A0
R6, D1 470 Ω, LED bus power
C1–C3 0.1 µF, 0.1 µF, 10 µF bypass and bulk

How it works

Expanders on the bus. All 28 bus signals sit on bidirectional expander pins (the MCP23017's GPA7/GPB7 are output-only on current silicon, so they are the spares). There are no buffers or series resistors: an expander pin is either an input (monitor) or drives the line.

Safety. At power-up every pin is an input: the card is a monitor. MASTER:1# takes the bus: it is refused if TPA/TPB are toggling (a CPU is running) or the bus has no power. It cannot tell a stopped CPU card from an empty slot, so pull the CPU card first. -RESET, -INT and -EF are open collector on the bus, so the card only pulls them low or releases them. While bus +5 V is off (sensed on A0) the expanders are held in reset and I²C is stopped, so nothing back-feeds them through the Nano's USB power.

Bus cycles. Each step is one I²C write at 400 kHz, so a byte takes about 1 ms: far slower than an 1802, but every edge comes in the 1802's order, which is all the static cards need.

Cycle Steps
Memory read A0–A7 = high byte; TPA high, low; A0–A7 = low byte; -VMA low; -MRD low; TPB high; sample D0–D7; TPB low; -MRD high; -VMA high
Memory write the same address steps; D0–D7 = data; -MRW low; TPB high, low; -MRW high; release D0–D7; -VMA high
OUT n D0–D7 = data; -MRD low; N = n; TPA pulse; TPB pulse; N = 0; -MRD high; release D0–D7
INP n N = n; TPA pulse; TPB high; sample D0–D7; TPB low; N = 0

TPB inside memory cycles is for the 6845 card (its E); -MRD low in OUT is how the IDE and IO cards tell an OUT from an INP. Both were added on 2026-10-11 (firmware banner io-2) after software/busdrv/fwsim.py, which runs these same steps against the cards' netlists, showed the earlier firmware failing on both cards.

The protocol

The host sends COMMAND:operand#; the card answers with Data: … lines, then Complete or Error: …, then the prompt >>. The main commands: STATUS, MASTER:0|1, SNAP (every bus line), WATCH:ms, RDMEM, WRMEM, RDBLK/WRBLK (up to 64 / 32 bytes), OUT, INP, INBLK/OUTBLK, single signals (TPA:1# …), N, SPARE, XRST. Full list: the sketch header.

Using it

python3 s5busdrv.py master on
python3 s5busdrv.py dump 0x7000 64
python3 bringup.py memory

The bring-up plans (memory, cf, video, all) and what each step proves are in software/busdrv/BRINGUP.md.