Sequencer memory card (V2.1) with the EEPROM adaptor and the Sequencer4 firmware — theory of operation¶
The control store of the YACC1: 256 opcodes x 64 steps x 8 bytes of microcode in eight 62256 SRAMs, copied at every power-up from two I2C EEPROMs by an on-card ATmega328 that also receives new microcode over a serial port. It rides piggyback on the sequencer-logic card and has no backplane connector of its own.
Written 2026-09-23 from the YACC1-D tree.
Sources: hardware/cards/sequencer-memory/eagle/v2.1/Sequencer-Memory-V2.1.sch and .brd (parsed with Python's
xml.etree), eagle/v2.1/bom/Sequencer-Memory-V2.1.csv, hardware/cards/sequencer-memory/README.md, eagle/v2.1/Notes.md,
accessories/eeprom-adaptor/eeprom adaptor.sch and its README, hardware/FABRICATED.md, hardware/PROVENANCE.md,
hardware/DESIGN-REVIEW.md, hardware/DESIGN-REVIEW-NOTES-control-io.md (section 2), embedded/sequencer-card/README.md,
embedded/sequencer-card/sequencer4/{Sequencer4.ino,download.ino,uCodeRAM.ino,uCodeROM.ino,IO.ino},
embedded/sequencer-card/readback/README.md, tools/ucode_send.py, tests/sequencer/{run.py,mock_card.py,*.log},
firmware/microcode/README.md, firmware/microcode/yaccsignaldata2.h, firmware/microcode/ucode-generator2/controlLine.c,
docs/system/MACHINE.md, BACKLOG.md, docs/history/status-2021.md, media/sequencer memory v2.1 top.jpeg,
media/sequencer top.jpeg.
1. Purpose and place in the machine¶
A microcode step is one 8-byte word; a record (one opcode) is 64 words = 512 bytes; the whole store is 256 x 512 =
131,072 bytes = 1 Mbit. The store must be random-access at bus speed (the logic card presents a 14-bit address
CADDR0..13 = opcode:step and wants the word within one clock period) and non-volatile. The card meets both with two
memories and a small computer between them:
- eight 32K x 8 SRAMs (IC1..IC8, 62256) in parallel make a 32K x 64 store, addressed by
CADDR0..14and read by the logic card while it runs (A14 selects one of two 16K halves, of which the machine uses one); - two I2C EEPROMs (on the adaptor plugged into IC9's socket, 2 x 64 KB) hold the image;
- an ATmega328P (IC15, Arduino bootloader) with five MCP23017 I2C port expanders (IC10..IC14) — 80 GPIO lines — owns
the SRAM's address and data pins at boot, copies the EEPROM into the SRAM, verifies the copy, then turns all 80 lines
into inputs, ties the SRAM to "selected, output enabled", and raises
READY. The logic card turnsREADYinto-BUS-EN.
In DOWNLOAD mode the same ATmega receives a new image over its FTDI serial header and writes it into the EEPROMs.
FTDI (115200) ----> IC15 ATmega328P ----I2C (SDA/SCL, 400 kHz)----+---- IC9 socket: EEPROM adaptor
DTR ---(DTR-RESET, C19)---> /RESET | IC1 24LC512 @0x57 (ins 128..255)
UCODE switch (PC0), START (PC2) | IC2 24LC512 @0x56 (ins 0..127)
LEDs FAULT (PB3) READY (PB4) LOADING (PB5) |
PB0 -CMEMWR, PB1 -CMEMRD, PB2 -CMEMSEL ---------------------+ +---- IC10 MCP23017 @0x20: CADDR0..13
PD7 BUS-READY ----> SV1 pin 12 ----> logic card -BUS-EN | +---- IC14 @0x21: bytes 0,1 (RAM IC4, IC3)
| +---- IC13 @0x22: bytes 2,3 (RAM IC2, IC1)
logic card SV1: CADDR0..13 ======> A0..A13 of IC1..IC8 (A14 = jumper) | +---- IC11 @0x23: bytes 4,5 (RAM IC8, IC7)
logic card SV1/SV2/JP1 <====== I/O0..7 of IC1..IC8 = the 64 control bits | +---- IC12 @0x24: bytes 6,7 (RAM IC6, IC5)
-CS / -OE / -WE <---------------------+
Fabricated 2020-12-01 (V2.1, hardware/FABRICATED.md), in the machine with the adaptor fitted in IC9 (confirmed 2026-09-20,
docs/system/MACHINE.md). The photo media/sequencer memory v2.1 top.jpeg shows Alliance AS6C62256-55PCN SRAMs,
MCP23017-E/SP expanders, an Atmel ATmega328P-PU, and two Microchip 24LC512 on the orange adaptor board.
2. Signals¶
The card has no DIN 41612 connector; everything goes through SV1/SV2 (2 x 40 pins) and JP1 (2 x 2) to the logic card,
where the names get a U prefix. Direction is seen from this card.
| Header pins | Signal | Dir | What it is |
|---|---|---|---|
| SV1 14,16,...,38 (even), SV1 2 | CADDR0..12, CADDR13 | in (run) / out (load) | the microcode address from the logic card's step counter (0..5) and instruction register (6..13); in load mode the same lines are driven by IC10 |
| SV1/SV2, 60 pins | the 64 control bits minus SPARE3/SRC-ADDR/DEST-ADDR (see JP1) | out | the RAM data pins, read by the logic card's pipeline registers; in load mode they are driven by IC11..IC14 |
| JP1 1, 3, 4 | SPARE3, SRC-ADDR, DEST-ADDR | out | three control bits that travel over the 2x2 header instead of SV1/SV2 (RAM IC5 I/O5, IC6 I/O6, IC5 I/O0) |
| JP1 2 | -MEM-CPU-RESET | in | the ATmega's /RESET and all five MCP23017 /RESET (R4 10k pull-up, LOCAL-CPU-RESET button, C19 from the DTR jumper); the logic card's JP2 can drive it from SPARE3 (must stay open — docs/cards/sequencer-logic.md 3.2) |
| SV1 12 | BUS-READY (READY on the logic card) | out | ATmega PD7 ("READYLINE", Arduino pin 7): low from reset until the copy is verified, then high; the logic card's IC36D inverts it into bus -BUS-EN |
| SV1 39, 40; SV2 1, 2 | GND; VCC | in | power comes from the logic card through the headers (no other supply pin) |
Byte-to-chip map (yaccsignaldata2.h gives each signal as (chip, port, bit); the generator writes byte index
(chip-1)*2+port, controlLine.c; the firmware's writeGPIOAB puts byte 2n on GPA and 2n+1 on GPB of data chip n+1):
| Byte | Signals (bit 0 first) | RAM | MCP23017 (I2C address) port |
|---|---|---|---|
| 0 | -REG-FUNC-RD, -REG-FUNC-LD, REG-RD-ID0..3, REG-LD-ID0..1 | IC4 | IC14 (0x21) GPA |
| 1 | REG-LD-ID2..3, -REG-RD-LO, REG-LD-LO, -REG-RD-HI, REG-LD-HI, -REG-DN, -REG-UP | IC3 | IC14 GPB |
| 2 | -MEM-RD, -MEM-WR, -IO-RD, -IO-WR, -TMP-REG-RD0, -TMP-REG-LD0, -TMP-REG-RD1, -TMP-REG-LD1 | IC2 | IC13 (0x22) GPA |
| 3 | ADDR-REG-ID0..3, IOADDR0..3 | IC1 | IC13 GPB |
| 4 | -IO-ADDR-LD, -VMA, -ALU-FUNC, ALU0..3, -AC-LD-INV | IC8 | IC11 (0x23) GPA |
| 5 | -AC-RD, -AC-LD, -SR-LD, BR-TEST, -HL-SWAP, SOFT-HALT, OUT-OFF, OUT-ON | IC7 | IC11 GPB |
| 6 | -INTA, -SRC-ADDR, INT-LD-HI, INT-START, INT-EN, LD-INS-REG, UCODE-COUNT-RESET, OPERAND-CLK | IC6 | IC12 (0x24) GPA |
| 7 | -BRANCH-RD, BRANCH-LD-LO, SPARE3, BRANCH-LD-HI, -INT-JMP, INT-LD-LO, -2-BYTE-OPERAND-SEL, -DEST-ADDR | IC5 | IC12 GPB |
On RAM IC1..IC4 the table's bit n is on I/On; on IC5..IC8 the schematic wires the nets in reverse pin order (IC8 I/O0 =
-AC-LD-INV, I/O7 = -IO-ADDR-LD). It does not matter: the same MCP23017 pin writes and the same SV pin reads a given net, and
the SRAM does not care which of its eight data pins stores which bit. The 2026-09-21 review verified all 64 (signal ->
RAM pin -> SV pin -> logic-card D input) mappings (DESIGN-REVIEW-NOTES-control-io.md, "checked, no issue").
REG-LD-LO, REG-LD-HI, BRANCH-RD and -SRC-ADDR/-DEST-ADDR are stored with the polarity the table says (the
comments in yaccsignaldata2.h: "this active low on the bus"): the logic card inverts or gates them on its side.
3. Schematic walkthrough¶
Four sheets: 1 = the SRAM array, 2 = SV1/SV2/JP1, 3 = the ATmega, EEPROM, switches and LEDs, 4 = the five expanders.
3.1 Sheet 1 — the SRAM array (IC1..IC8)¶
Eight 62256P (Eagle memory-hitachi; fitted AS6C62256-55PCN, 55 ns) with all address pins paralleled: A0..A13 =
CADDR0..13 from SV1, A14 = CADDR14 from the on-card header (3.4). All three control pins are common and come
straight from the ATmega: !CS = -CMEMSEL (PB2), !OE = -CMEMRD (PB1), !WE = -CMEMWR (PB0). There are no
pull-ups on these three lines, so while the ATmega is in reset or in its bootloader (the ~1 s after power-up, or whenever
-MEM-CPU-RESET is low) the SRAMs see undefined -CS/-OE/-WE — harmless, because the copy that follows rewrites
everything, but it is why nothing on the bus should depend on the store before READY (DESIGN-REVIEW-NOTES-control-io.md 2.1).
The data pins are the 64 control nets of section 2. 62256 timing: with -CS and -OE low the outputs follow the address
after tAA (55 ns for the fitted part); the logic card gives them one clock period.
3.2 Sheet 4 — the port expanders (IC10..IC14)¶
Five MCP23017SP on the I2C bus (SDA/SCL with R2/R3 = 2.2k to VCC), !RESET = -MEM-CPU-RESET, addresses set on A0..A2:
| IC | A2 A1 A0 | Address | GPA | GPB |
|---|---|---|---|---|
| IC10 | 0 0 0 | 0x20 | CADDR0..7 | CADDR8..13 (GPB6/7 unused) |
| IC14 | 0 0 1 | 0x21 | byte 0 | byte 1 |
| IC13 | 0 1 0 | 0x22 | byte 2 | byte 3 |
| IC11 | 0 1 1 | 0x23 | byte 4 | byte 5 |
| IC12 | 1 0 0 | 0x24 | byte 6 | byte 7 |
The firmware's mcp[i].begin(i) (i = 0..4) matches this exactly (Sequencer4.ino setup(); ADDRESS_CHIP 0,
DATA_CHIP_START 1). No expander pin touches CADDR14: load and run address the same 16K half (3.4).
In load mode the expanders drive: setAddressOutput() / setDataOutput() make every pin an output (IO.ino); in run
mode setAddressInput() / setDataInput() make them inputs with the 100k internal pull-ups on — the review notes this is a
negligible load on the SRAM outputs and on the logic card's CADDR drivers. The MCP23017 outputs and the logic card's
IC15/IC35 (74*244 on CADDR, enabled by -BUS-EN) are on the same nets: the design relies on -BUS-EN being high (READY low)
while the ATmega drives the address. That is exactly what breaks when the bus tester asserts -BUS-EN from outside (6).
3.3 Sheet 3 — the ATmega328P, EEPROM socket, switches and LEDs¶
IC15 ATMEGA328P_PDIP, 16 MHz crystal Q1 with C16/C18 = 20 pF, AREF decoupled by C15, AVCC = VCC. Pin use (Arduino
numbering as in the sketch):
| ATmega pin | Arduino | Net | Use |
|---|---|---|---|
| PB0 | 8 | -CMEMWR | SRAM -WE, pulsed low/high by uCodeRamWritePulse() |
| PB1 | 9 | -CMEMRD | SRAM -OE (uCodeRamRead(true) = low) |
| PB2 | 10 | -CMEMSEL | SRAM -CS (uCodeRamSelect(true) = low) |
| PB3 | 11 | FAULT | red LED through R7 (330); blink codes (5) |
| PB4 | 12 | LED-READY | green LED through R8 |
| PB5 | 13 | LD | yellow LOADING LED through R9 |
| PD7 | 7 | BUS-READY | SV1 pin 12 -> logic card READY -> -BUS-EN |
| PC0 (ADC0) | A0 | N$30 | UCODE toggle: O = VCC (WRITEMEM = 1), S = GND (DOWNLOAD = 0), P common to PC0 |
| PC2 (ADC2) | A2 | N$39 | START push button to GND, R1 10k pull-up |
| PC4 / PC5 | A4 / A5 | SDA / SCL | I2C to the expanders and the EEPROM(s) |
| PC6 | /RESET | -MEM-CPU-RESET | R4 10k to VCC; LOCAL-CPU-RESET button to GND; C19 (100 nF) from the DTR-RESET jumper; JP1 pin 2; all MCP23017 /RESET |
| PD0 / PD1 | RX / TX | ARD-RXIN / ARD-TXOUT | JP3 FTDI header RXI / TXO |
JP3 is the 6-pin FTDI header (SparkFun FTDI_DEVICE: GND, CTS = GND, VCC = N$34, TXO, RXI, DTR = N$33). Two solder/pin
jumpers hang off it:
- DTR-RESET: pin 1 = N$33 (FTDI DTR), pin 2 = N$8 = C19 ->
-MEM-CPU-RESET. Closed, this is the ordinary Arduino auto-reset: opening the serial port pulls DTR low and the 100 nF edge resets the ATmega into its bootloader. The schematic, the.brd(signalsN$8= C19.1 + DTR-RESET.2;-MEM-CPU-RESETincludes C19.2) and the KiCad netlist all show C19 in circuit;DESIGN-REVIEW-NOTES-control-io.md2.2 ("nothing reaches /RESET and there is no series 100 nF") is contradicted by all three and by use:tools/ucode_send.pyandembedded/sequencer-card/readback/README.mdboth rely on the DTR reset (run the sender first, then press START; avrdude through the bootloader). The photo shows a blue cap on the DTR-RESET header. To verify: whether the review looked at an older netlist; the design as in the tree is fine. - FTDI-VCC: pin 1 = VCC, pin 2 = N$34 (the FTDI's 5 V). Closed, it would parallel the USB 5 V with the backplane rail through the logic card — leave it open when the card is in the machine (photo: open).
IC9 is the 8-pin socket for a 24P I2C EEPROM with A0 = A1 = A2 = VCC (device address 7 = 0x57) and WP = N$32 =
JP2 pin 2 (JP2: 1 = GND, 2 = WP, 3 = VCC — a jumper on 1–2 allows writes, on 2–3 protects). The BOM lists a 24AA01P
(128 bytes: a placeholder value); the machine has the EEPROM adaptor* in this socket (3.5). UCODE is a 9070-1W toggle,
START a tactile switch, LOCAL-CPU-RESET a 6.2 mm push button. The PWR LED is on R6 (330).
3.4 CADDR14 header¶
CADDR14 (SRAM A14) has R5 (10k) to VCC and a 2-pin header to GND. Jumper off: A14 = 1, the upper 16K x 64 half;
jumper on: A14 = 0, the lower half. Since neither the logic card nor the expanders drive A14, the half used for loading
is the half used for running — the other half is spare storage (a second microcode image, if a switch replaced the
jumper). The photo shows a cap on the header (lower half selected). To verify: on the card in hand.
3.5 The EEPROM adaptor (accessories/eeprom-adaptor/)¶
A 29 x 16 mm board with two AT24C*P footprints sharing SDA, SCL, VCC, GND and WP with the 8-pin plug that goes into IC9's
socket: IC1 with A0 = A1 = A2 = VCC (address 7, 0x57) and IC2 with A0 = GND, A1 = A2 = VCC (address 6, 0x56). It exists
because the microcode needs 128 KB and the largest 8-pin 24Cxx is 64 KB (24LC512): two of them, selected by the low
address bit of the device address, give one 128 KB store. Designed 2020-12-19/21, one OSH Park order (rmD8XYsD, 2024-06-19,
three boards), fitted (confirmed 2026-09-20). The photo shows two 24LC512 (one E/P, one I/P) on it. The mechanical design review
flags the adaptor's VCC/GND as "no source" — expected, the socket pins are its supply (hardware/DESIGN-REVIEW.md); it has
no decoupling of its own (the card's C1..C14 are nearby). docs/datasheets/24lc512.pdf is the part's datasheet.
The firmware's view (uCodeROM.ino): EEPROM_DEV_LO 0x56 holds instructions 0..127 (byte address = instruction x 512 +
offset, 0..65535), EEPROM_DEV_HI 0x57 holds 128..255 (the same 16-bit address after subtracting 65536); an instruction
never straddles a device. EEPROM_PAGE 128 is the 24LC512's page size. To verify: part numbers on the adaptor in the
machine (the photo shows 24LC512; the firmware comment also allows 24LC1025).
3.6 Sheet 2 — SV1, SV2, JP1¶
The two 2x20 headers and the 2x2 header carry the nets listed in section 2, in the same positions as on the logic card
(checked pin by pin in the 2026-09-21 review). SV1 pins 39/40 and SV2 1/2 are the card's only GND and VCC.
4. The Sequencer4 firmware (embedded/sequencer-card/sequencer4/)¶
Flashed 2026-09-21 (Arduino Uno target, ATmega328P through the FTDI at 115200); the previous Sequencer3 build that was in
the chip was read out first (readback/sequencer-flash-2026-09-21.hex, with the avrdude commands to restore it). Sequencer4
is Sequencer3 with: I2C at 400 kHz (set after the expanders' begin(), which resets the clock to 100 kHz), EEPROM reads
in 32-byte blocks and writes in page writes, the boot-time test-pattern fill removed, the whole copy read back and compared
before READY, and every string in flash (F()) because the plain-string build crashed with ~500 bytes of RAM left. Measured:
copy 16 s, verify 29 s, READY 54 s after reset (Sequencer3: 156 s, unverified).
4.1 Modes¶
setup() reads UCODESWITCH (A0) once: WRITEMEM (1, switch to VCC) or DOWNLOAD (0, switch to GND). Then it starts
the five expanders, sets the I2C clock, makes the LED and RAM-control pins outputs with -CMEMRD/-CMEMWR/-CMEMSEL high and
READYLINE low, and flashes FAULT, READY, LOADING once each (100 ms). In WRITEMEM mode it also prints the banner
Sequencer4 2026-09-21 (400 kHz I2C, block EEPROM reads, verified copy); in DOWNLOAD mode it stays silent so that nothing
but the prompt reaches the sender.
WRITEMEM (run) mode, loop():
EEPROM to RAM: LOADING on; address and data expanders as outputs; for each instruction 0..255 (WORKING_INSTRUCTION_SET)readCodeFromROM()(512 bytes, 16 I2C transactions of 32 bytes using the EEPROM's address auto-increment) thenwriteInstruction()(-CSlow; for each of the 64 lines:writeAddress(instruction*64 + line),writeData()= onewriteGPIOABper data chip, then-WEpulsed low/high;-CShigh). Progress every 32 instructions; LOADING toggles per instruction; "- done, 16 s".Verify RAM against EEPROM(VERIFY_COPY): data expanders as inputs,-OEand-CSlow; for each instructionreadInstruction()(address out, read GPA/GPB of the four data chips per line) and compare with the EEPROM 32 bytes at a time (readCodeFromROMPart(), because only ~500 bytes of stack are free). On a mismatch it prints the counts and the first bad instruction, the hintis -BUS-EN inactive? (the logic card drives the microcode address lines when it is asserted), deselects the RAM, and callsdoError("RAM verify failed", 6): FAULT blinks 6 forever, READY never rises.DISPLAY_MEM: dumps instructions 0, 1, 7, 124 and 255 (RAM then EEPROM, 64 lines of 8 hex bytes each) — the transcript thattools/ucode_send.py --boot-checkcompares withtest.hex.- Hand-over: address and data expanders to inputs,
-OElow,-CSlow (the SRAM now answers the logic card), LOADING off, READY LED on,READYLINEhigh,RAM copy complete and verified, READY!!!. - Monitor loop forever: once a second read the address the logic card presents (
readAddress()on IC10), and when instruction or line changed, printRAW=.. Addr=.. Seq=.. Ins=.. Line=.. Data= ..and the list of control bits that changed since the last print (sig=[n]=v, n = byte*8+bit). With the CPU single-stepped this is a live microcode monitor.
DOWNLOAD mode, loop(): LOADING on; wait for START to be pressed; then while (waitInstructionBegin()) downloadInstruction();
toggling LOADING per instruction; LOADING off; idle forever (a reset with the switch back in WRITEMEM starts the copy).
4.2 The serial download protocol (download.ino, the OLD section is the compiled one)¶
card -> host ">>\r\n" a prompt before every instruction
card flashLed(READY): READY LED on for 100 ms — the card is NOT reading during this time
host -> card "%" cc ii d0 d1 ... d511 '%' start, cc = 2-hex checksum (read and ignored),
ii = 2-hex instruction number, then 512 bytes as 2 hex digits each
'Z' in place of a byte = "the rest of this instruction is zero" (getCode fills with 0)
host -> card "!" after a prompt end of download; anything else at a prompt = doError("Unexpected Char", 5)
readHexNumber() waits for two characters (delay(1) polling, Serial.available()), upper-case hex only
(converCharToInt: '0'..'9', 'A'..'F'). The 64-byte hardware serial buffer of the ATmega and the 100 ms LED flash after
the prompt are the two constraints on the host: whatever is sent during the flash lands in the 64-byte buffer, and a
record is 1029 characters, so a sender that fires the record as soon as it sees >> at full speed loses its head and
the card then waits forever for the missing bytes (observed 2026-09-22 at 1 ms/char). tools/ucode_send.py therefore
waits --settle 250 ms after every prompt and paces characters at --delay 2 ms (the Processing sender used 25 ms/char,
which hid the problem). The trailing - of each test.hex record is not sent (the card reads exactly 512 values; a
stray - would be an Unexpected Char, FAULT blinking 5).
test.hex format (firmware/microcode/README.md, ucode_send.py load_records()): 256 lines %ccii<1024 hex digits>-
in instruction order, then a line !. test.hexz is byte-identical (the Processing sender's file name); cache is what
was last sent — the loader sends only records that differ from it and rewrites it as it goes, so an interrupted load
resumes; --all sends everything (what the 2026-09-22 reload used: "six records differed, all 256 sent").
Host-side sequence (ucode_send.py docstring): UCODE to DOWNLOAD, reset the card (LOADING comes on), start the sender
(opening the port resets the ATmega through DTR — hence sender first), press START, wait; then UCODE back to WRITEMEM,
reset, and ucode_send.py --boot-check captures the run-mode boot and compares its five dumps with test.hex.
tests/sequencer/run.py exercises the sender against mock_card.py (a fake card on a pty: differential send, --all, and
the dump comparison on the 2026-09-21 transcript, where only the pre-fix PUSHR record $07 may differ).
4.3 EEPROM access (uCodeROM.ino) and the write path¶
writeCodeToROM(instruction, data[512]): page writes of WRITE_CHUNK = 30 bytes (the AVR Wire buffer of 32 minus the two
address bytes), never crossing a 128-byte page (room = EEPROM_PAGE - ((addr + done) % EEPROM_PAGE)), delay(5) per
transaction for the EEPROM's write cycle. Records start page-aligned (512 = 4 x 128). Sequencer3 wrote one byte per
transaction with a 5 ms wait each — 512 x 5 ms = 2.6 s per instruction, which is where its 156 s came from.
i2c_eeprom_read_byte() is kept for anything that still wants single-byte access.
4.4 LEDs and blink codes¶
| LED | Pin | Meaning |
|---|---|---|
| LOADING (yellow) | PB5 | on while waiting for START in DOWNLOAD mode; toggles per instruction during a download or a copy |
| READY (green) | PB4 | 100 ms flash after every >> prompt (download); steady on after the verified copy (run) |
| FAULT (red) | PB3 | doError(msg, code): blinks code times, 2 s pause, forever (the message print is commented out). Codes: 3 = data written with the data expanders set to input, 4 = address written with the address expanders set to input, 5 = unexpected character at a prompt, 6 = RAM verify failed |
| PWR | – | 5 V present |
| all three | – | one 100 ms flash each at every reset (setup()) |
4.5 READYLINE and -BUS-EN¶
READYLINE (PD7) is low from reset until step 4 of the run-mode boot. On the logic card -BUS-EN = NOT READY
(IC36D), and -BUS-EN is the output enable of its pipeline registers and of its CADDR buffers, and goes to the backplane
(C28) where every other card gates its bus drivers with it. So for ~54 s after power-up the whole machine is tri-stated
except the 17 logic-card lines that ignore -BUS-EN (docs/cards/sequencer-logic.md section 4) — and the CADDR lines
belong to this card's IC10.
The interaction that bit on 2026-09-21 (tests/sequencer/boot-run-mode-2026-09-21.log versus -bus-quiet.log,
embedded/sequencer-card/README.md): the bus tester was still asserting -BUS-EN from the backplane while the card
copied. That enabled the logic card's IC15/IC35 onto CADDR0..13 against IC10's outputs; the address the SRAM saw was
0 (or whatever the fight resolved to), every write went to address 0, and the dumps came back all zero (Data= 00: 00: ...
in the first log's monitor line, versus 03 d4 ff 00 85 57 03 d1 — instruction 0 step 0 — with the bus quiet). Sequencer4's
verify pass now catches this (FAULT x 6, the -BUS-EN hint) instead of raising READY over a corrupt store. Rule: nothing
may drive -BUS-EN low while LOADING is on.
The run-mode boot on the Sequencer4 firmware (boot-run-mode-2026-09-21-sequencer4.log, and the identical
boot-run-mode-2026-09-22-reload.log after the H-1/H-2/BRUR reload): Copying Instruction 0 ... 224, - done, 16 s,
- 29 s, RAM == EEPROM for all 256 instructions, the five dumps, READY!!!, then the monitor line for the address the
logic card is presenting.
5. Jumpers, switches, LEDs, connectors — settings in the machine¶
| Item | Function | Setting |
|---|---|---|
| UCODE toggle (silk DOWNLOAD / WRITE MEM) | PC0: mode read once at reset | WRITE MEM to run the machine; DOWNLOAD only to load microcode |
| START button | PC2: starts the download after the prompt is awaited | – |
| LOCAL-CPU-RESET button | pulls -MEM-CPU-RESET (ATmega + expanders) low | use it to restart the copy (or to reflash if DTR fails) |
| DTR-RESET (2 pins) | FTDI DTR -> C19 -> reset | closed (photo: blue cap) so the sender and avrdude can reset the card |
| FTDI-VCC (2 pins) | FTDI 5 V -> card VCC | open in the machine (photo) |
| CADDR14 (2 pins) | SRAM A14 to GND (on) or 10k to VCC (off) | on (photo) = lower 16K half; To verify |
| JP2 (3 pins) | EEPROM WP: 1–2 = writable, 2–3 = protected | must be 1–2 for a download; To verify on the card |
| JP1 (2x2) | SPARE3, -MEM-CPU-RESET, SRC-ADDR, DEST-ADDR to the logic card | mated with the logic card's JP1 |
| SV1, SV2 | the store's address/data to the logic card | mated |
| JP3 (FTDI, 6 pins, silk BLK ... GRN) | GND CTS VCC RXI TXO DTR | the FTDI cable, black to BLK; port /dev/cu.usbserial-AB6WZCQX in readback/README.md |
| IC9 socket | I2C EEPROM | the adaptor with two 24LC512 |
| LEDs | PWR, LOADING, READY, FAULT | 4.4 |
6. Bring-up and test¶
How the card was proven.
- 2020-12:
embedded/sequencer-card/deprecated/test-eeprom-2020-12tested the on-card I2C EEPROM at 0x57 through the ATmega;sequencer2/sequencer3loaded the machine's microcode from 2020-12 and 2021-08 on. - 2026-09-21: the ATmega's flash was read out and identified as a Sequencer3 build (
readback/); a tree build of sequencer3 was flashed and read back byte-identical, then Sequencer4. Run-mode boot captured three times that day (tests/sequencer/): the clobbered copy with the tester asserting-BUS-EN(all zeros), the clean copy with the bus quiet (RAM == EEPROM ==test.hexfor every dumped instruction), and the Sequencer4 boot with its 256-instruction verify. EEPROM contents verified = the tree'stest.hexof that day. - 2026-09-22:
tools/ucode_send.py --allloaded the regenerated image (BRUR at $AD, the H-1 and H-2 fixes); the boot after it verified (boot-run-mode-2026-09-22-reload.log);cache==test.hex. - 2026-09-22/23: the CPU ran
tests/assembler/romcountovernight from the ROM on that store. tests/sequencer/run.py(no hardware) checks the sender's differential logic,--all, and the dump comparison.
If it misbehaves — what to look at.
- No banner on the FTDI at reset in WRITE MEM: baud 115200; the UCODE switch position (DOWNLOAD mode is silent by design); DTR-RESET closed (or press LOCAL-CPU-RESET after opening the port).
Copying Instructionstalls or the boot takes minutes: I2C — the expanders'begin()resetting the clock is handled, but a missing 2.2k pull-up or an adaptor EEPROM that does not ACK makesWire.requestFromreturn short reads (the code fills with 0xFF, which then fails the verify).readback/says the chip "may report not in sync" on flashing — retry with the reset button.MISMATCH ... first at instruction Nwith FAULT x 6: first suspect-BUS-ENdriven by something on the bus (the bus tester's firmware drives it push-pull fromsetup()); with the bus quiet, suspect the SRAM control lines (-CMEMSELon IC15 pin 16 low during the copy) or a bad SRAM (the first bad instruction tells which 16K address region).- READY on but the CPU does nothing: the logic card's
-BUS-EN(C28) should be low; the monitor loop'sRAW=line shows whether the logic card is presenting an address at all and whether the data on the RAM pins is the record you expect (compare withtest.hexline%..ii, byte offset step*8). - Download fails with FAULT x 5: a stray character before
%(the record's trailing-, or a sender that did not wait for the prompt); FAULT x 6 after a download is a verify failure of the copy, not of the EEPROM write — the EEPROM image itself can be read withdumpram(embedded/sequencer-card/dumpram/). - A record loads but the machine misbehaves on one opcode:
ucode_send.py --boot-checkcompares the five dumped instructions; for another opcode, edit thedumpInstruction()list inSequencer4.ino(it is one line per instruction) or read the RAM withdumpram.
7. Revision history and what the next revision should change¶
| Revision | Date | What | Source |
|---|---|---|---|
| gen-1 SEQUENCER-MEMORY-Prod-V1.0 | 2016 | the 2016 store (32-step format, v1 generator, 19200-baud senders) | archive/gen1-2015-2018/, embedded/sequencer-card/deprecated/sequencer1 |
| V2.0 | 2020-07-25 | the 2020 redesign for 64 steps x 8 bytes; "Move CPU reset to top edge of board" done; fabricated, retired 2021-01 | docs/history/general-notes/NOTES-Update from old project.md, eagle/deprecated/v2.0/ |
| V2.1 | 2020-12-01 | reworked the ATmega section and jumpers (README); Notes.md carries no change list |
hardware/FABRICATED.md; in the machine |
| EEPROM adaptor | design 2020-12-19/21, ordered 2024-06-19 | two 24LC512 in the IC9 socket = 128 KB (the 2021 status note's "Add second 512k EEPROM") | accessories/eeprom-adaptor/, docs/history/status-2021.md |
| firmware Sequencer3 -> Sequencer4 | 2021-08 -> 2026-09-21 | verified copy, 3x faster boot | embedded/sequencer-card/README.md |
A V2.2 should (from BACKLOG.md, the reviews and the 2026-09 sessions):
- Put the second EEPROM on the card (the adaptor's two footprints, or one 24LC1025 with its A2-tied-high convention) and fit the decoupling the adaptor lacks; keep JP2 (WP) but label it.
- Pull-ups on
-CMEMSEL/-CMEMRD/-CMEMWRso the SRAM idles deselected while the ATmega is in reset or in its bootloader (review 2.1), and a pull-down onBUS-READYso-BUS-ENis not asserted by a floating PD7 in that window. - Give the ATmega a way to see
-BUS-EN(one spare port pin to SV1 or JP1) so the loader can refuse to copy while something else owns the bus, instead of finding out at the verify. - Bring
CADDR14to a switch (two selectable microcode images) or drive it from the ATmega. - Correct the BOM (IC9 = 24LC512 x 2 on the adaptor, not 24AA01P) and record that DTR-RESET is a pin header, not the solder jumper the library symbol implies.
- Keep the 40-pin headers and JP1 as they are — the logic card depends on them pin for pin.
Related documents: docs/cards/sequencer-logic.md (what happens to the 64 bits), docs/system/MICROCODE.md (the
control-store format and the generator, when written), firmware/microcode/README.md (images, cache, regeneration),
embedded/sequencer-card/README.md (firmware history).