Microcode decoder: two AT28C64s and four '138s

/ DINO / from dino-homebrew microcode eeprom control-word at28c64 backfill

Backfilled from a post on embedded.greygiant.com dated 2025-08-11.

What I tried

The control word generator as its own module. The timer state from the ring counter and the opcode from the IR go in as an address; two AT28C64 EEPROMs in parallel give a 16-bit word back, ROM 1 the high byte and ROM 2 the low byte. Four 74LS138s split twelve of the bits into the banks worked out in July, and four bits go straight out for signals that aren’t mutually exclusive with anything.

Microcode decoder sheet. Timer state and the IR bus through two '244s into the address pins of U9 and U15, a pair of AT28C64Bs, 16 control word bits out. U9 and U15 are still the microcode ROMs' designators today.
Microcode decoder sheet. Timer state and the IR bus through two ‘244s into the address pins of U9 and U15, a pair of AT28C64Bs, 16 control word bits out. U9 and U15 are still the microcode ROMs’ designators today.
The four '138 decoder banks on the control word: ALU ops on [11:9], PC and system control on [8:6], memory ops on [5:3], register ops on [2:0]. PULSE_REQ, PC_UP, PC_MAR_MUX and HALT are direct bits.
The four ‘138 decoder banks on the control word: ALU ops on [11:9], PC and system control on [8:6], memory ops on [5:3], register ops on [2:0]. PULSE_REQ, PC_UP, PC_MAR_MUX and HALT are direct bits.

The instruction set at this point: LDAI, LDBI, STA, STB, NOP, LDA, ADD, MOV, OUT, HLT. Enough to exercise memory both ways, the registers, one ALU op and the output.

Control word changes since July: bit 13 became PC_UP, bit 12 became PULSE_REQ, IR_LOAD moved into the ALU bank as code 111, and MDR_OUT, OUT_REG_LOAD and OUT_REG_OUT got slots in banks 3 and 2.

Two things I got wrong on paper

Boot

Microcode addresses 0x0000 to 0x000F are the boot sequence. In reset, a 74LS244 with its inputs tied to ground forces opcode 0x00 onto the IR bus and a 74LS73 JK flip-flop holds it there until reset is released. Row 0 clears the PC, row 0x0F increments it, and the IR only starts loading real opcodes after reset lets go.

What I measured

Test image, not real microcode: 0xDEAD at 0x0000, 0xBEEF at 0x0001, 0xBEEF at 0x0DED, 0xFEED at 0x0FED, everything else zero. A little C program writes the two .bin files, another reads them back and prints the bytes at those addresses so the burn can be checked against the file.

Two DIP switches standing in for the opcode and the timer state, jumpered into the ROM address pins. Outputs were read with a multimeter, one pin at a time.
Two DIP switches standing in for the opcode and the timer state, jumpered into the ROM address pins. Outputs were read with a multimeter, one pin at a time.

Two 8-way DIP switches set the address. A multimeter on each of the sixteen output pins, written into the journal, converted to hex, compared to the file. With the address static the LA had nothing to add. Burned with a T48 over minipro.

0x0000   DE AD
0x0001   BE EF
0x0DED   BE EF
0x0FED   FE ED

Took several rewire and re-burn rounds before all four matched.

The microcode board: the two EEPROMs with their address lines bussed in green, the '244s on the left.
The microcode board: the two EEPROMs with their address lines bussed in green, the ‘244s on the left.

Also drawn

The MDR, IR, memory and register sheets are all in KiCad now, before any of them is wired, so the datapath is consistent on paper first.

Next

MDR, then IR, then the memory module and registers.