The ALU was latching its own next answer

/ DINO / updated 2026-10-06 / from dino-homebrew dino debug timing clock alu logic-analyzer oscilloscope

PROG_isa reads 0xB4 again. I hit RESET 20 times and then 15 more as fast as I could press it, and every one came back 0xB4. PROG_isasoak reads 0x00. The fix is one spare inverter: U47, the ‘373 that holds the ALU result, now takes its latch enable from ~CLK through U37 instead of straight off the CLK wire. It’s drawn in KiCad as its own net, CLK_ALU, and ERC has nothing new.

The 2026-10-01 entry left the machine failing at ADD or SUB (0x22 or 0x23) right after the interrupt core went in. It failed the same at 500 kHz and at 250 kHz, which turned out to be the most useful clue I had.

Catching the wrong byte on the LA

ADD shows up exactly once in PROG_isa, so a DSLogic pattern trigger on IR = 0x41 lands right on the failing subtest every run. My first capture was at 1 MHz, which is one sample per CPU clock and useless for reading the bus. At 100 MHz it’s about 100 samples per clock.

My clips were on backwards, and two channels were swapped at the LA end. It didn’t matter much: every opcode fetch has to put the same byte on the bus that lands in IR, so the 879 fetches in the capture gave the channel order back.

This is SUB’s last state on a failing run:

Time into the stateW bus
+570 ns0x29right answer, 0x5C - 0x33
+980 ns (CLK falls)0x6Dwhat A latched

0x6D is 0x29 with bits 2 and 6 taken from 0xF6, and 0xF6 is 0x29 - 0x33, the ALU’s next answer once A holds the result. NOT failed the same way, 0xA3 going to 0xAB.

Two latches on one edge

In a row like src=ALU dst=REG_A, two things happen as CLK falls:

PartClockWhat it does at CLK fall
U47 ‘373, ALU outputLE = CLKcloses, holds the result on W
U45 ‘373, TMP_A (the ALU’s copy of A)NOR(~REG_A_LOAD, CLK) on U50opens, takes the new A

When TMP_A opens, the ‘382s start computing new A minus B. If U47 hasn’t fully shut by the time that reaches its inputs, some bits of the next result get in. Which bits get in depends on the data, so the failing subtest moved around. Clock speed doesn’t change any of this, because both sides start on the same edge.

The scope put numbers on it. W2 and W6 went from low to 2.0 V 38 ns after CLK fell, with a fast driven edge. Then I probed CLK at both ends of the jumper:

ProbeCrosses 1.3 VCrosses 0.8 VShape
U27.5, CLK at the source0 ns+4 nsclean
U47.11, CLK at the ALU latch0 ns+22 nssits at 1.0-1.2 V for about 20 ns

TMP_A opens at the first crossing. U47 isn’t reliably shut until that shelf is gone. There’s only about 10 ns of margin to begin with, and the shelf ate it.

If you’re seeing a transparent latch take a mix of old and new bits, check whether something it feeds opens on the same clock edge, and scope the clock right at the latch pin.

Proving it, and getting lost for a bit

100 pF from LE_TMP_A to ground delays TMP_A opening. With it on, the failure moved from subtest 34 to subtest 63. With it off, it went straight back to 0x23 twice. A cap isn’t a fix, but that showed the race was real.

I also wandered off. Lifting the R29 tap that feeds the interrupt clock gave new failures in POPA, POPSPH and SUI_B (0x32, 0x3E, 0x6C). A 100R in the ALU CLK jumper made it fail 0x22 every time. Then a beep showed the ALU jumper had slipped from U27.5 to U27.6, which is ~CLK, when I put the 100R in. So the 100R and 250 kHz runs don’t count for anything. 100 pF on U47.11 moved the failure to SHL (0x2D), and I can’t explain that one yet.

Early on the LA made W2 look like it was flickering, and I chased that as a weak bus bit. The scope on the same pin showed a solid 0.2 to 0.4 V. The flicker came from the LA.

The fix is the SP clock lesson again

In August the stack pointer’s ‘169s double-counted because they took raw CLK on a clock pin at the end of a long stub, and R2 (100R) fixed that branch. U47 was the other part doing the same thing. Off the clock board, everything else gets CLK through a gate, which gives it a fresh edge right where it’s used.

BeforeAfter
U47.11 (LE)CLK, raw, end of the ALU jumperU37.10
U37.11 (spare inverter 5, MDR board)GND strap~CLK from U27.6
Net nameCLKCLK_ALU
PROG_isa0x22 / 0x230xB4, 35 of 35 resets

A settle row in the microcode couldn’t have fixed this. The feedback loop happens inside one row, so adding rows before or after doesn’t touch it.

On the PCB, U47’s enable comes off a gate output too.

Still open