ANALYSIS — Tang "masked level-10 grant": root-cause investigation (SOLVED 18-JUL-2026)¶
SOLVED 18-JUL-2026 - kept as the root-cause record. The root cause was found and directly confirmed on silicon (section 3e): a stale-INTRQN panel pulse taken as a macro interrupt, reading an empty vector that defaults to level 10 - NOT an Am2914 masked grant. The Tang Nano 20K now boots SINTRAN III (24-AUG-2026). Trimmed 28-SEP-2026 to the mechanism (1), the root cause (3e), the fix (3f) and what was reverted (4); the experiments in between (old sections 2, 3, 3b-3d) are in git history. In short: Verilator did NOT reproduce the fault (experiment A,
-DND120_PROBE_VEC17inrunSim), and theTANG_GRANT_CAPTUREon-chip capture on silicon (experiment B1,grant_capture.py) caught the cause-less dispatch to CS 000017 at step 18 of a single-step from P=0.
Full path: Verilog/fpga/tang-nano-20k/ANALYSIS-cga-intr-masked-grant-root-cause.md
Status: ROOT CAUSE FOUND AND CONFIRMED ON SILICON (18-JUL, section 3e). An
earlier trap-side guard was written and then REVERTED (18-JUL) at Ronny's
direction — it treated the symptom, not the cause, and it deviated from the
schematics; the real cause is in section 3e.
1. The mechanism (measured + source-verified — this part stands)¶
The Tang "masked level-10 grant" is a cause-less trap dispatch, not an Am2914 grant:
INTRQN(CGA/INTR p.74,CGA_INTR.vMEMORY_2) = a one-MCLK-delayed register ofPAN | IRQ(D = NAND(IRQN,PANN); async clear CLIRQN; no hold feedback — schematic-confirmed by Ronny 18-JUL).- The trap break trigger is
IFETCH & INTRQ(CGA/TRAP/BRKDET p.103,INTRNAND — schematic-confirmed: exactly two inputs). - The panel-vs-macro classification is the 5-input NAND (CGA/TRAP/TVGEN p.104,
GATES_6→L3V0_FF): inputs VTRPN, IFETCH, INTRQ, PAN, DSTOPN — schematic-confirmed: exactly five, no IRQ/claim input. PAN up → trap vec 16 (panel); PAN down → trap vec 17 (macro interrupt). - Trap vec 17 microcode does
PIC,RVECT(CS 000017). With nothing claiming the read returns 0, and the interrupt vector tableITSRV(CS 003740) maps entry 0 → Q=12 octal = level 10.
So a dispatch taken off the lagged INTRQN, after its cause dropped, is
classified "macro interrupt" (live PAN=0), reads an empty vector = 0, and
switches to level 10. Measured signature (piltrace.log): PIL 0→10, PIE=0,
P never advanced (instruction stream not involved). A genuinely pending level-10
would read 010 octal → level 14, not 10 — confirming the read was empty.
Schematic validation (Ronny, 18-JUL): all four transcription points above (TBUF inverters, TVGEN 5-input NAND, BRKDET INTR NAND, INTRQN FF D-cone) match the original DELILAH sheets. The window exists in the design as drawn. So the trap logic is NOT where a transcription bug lives.
3e. ROOT CAUSE — DIRECTLY CONFIRMED ON SILICON (18-JUL)¶
Via the on-chip capture (grant_capture.py, TANG_GRANT_CAPTURE), stepping to the hang and reading a debug word = {PAN, IRQ, INTRQ, PICV, MIREQ}. Measured sequence around the dispatch:
PAN=1 IRQ=0 INTRQ=1 PICV=0 MIREQ=0 <- PAN pulses; INTRQN asserts (from PAN)
PAN=0 IRQ=0 INTRQ=1 PICV=0 MIREQ=0 <- PAN GONE, INTRQN STILL asserted = THE LAG
PAN=0 IRQ=0 INTRQ=0 PICV=0 MIREQ=0 <- INTRQN clears
Summary: PAN pulsed=True, IRQ never asserted, INTRQ asserted, max PICV=0 (empty), MIREQ never nonzero.
THE ROOT CAUSE (proven, not inferred):
1. A PAN (panel request) PULSE sets the INTRQN flip-flop (CGA_INTR.v
MEMORY_2, d = PAN | IRQ). PAN here is a panel/PRQ pulse from console
activity (the MOPC/PRQ output path - NOT a maskable interrupt).
2. INTRQN is a registered snapshot (holds a full MCLK period, cleared only
by CLIRQ), so it OUTLIVES the PAN pulse - the measured PAN=0 INTRQ=1.
3. There is NO real interrupt: IRQ never asserts, MIREQ/IREQ are empty, PICV
is always 0 (measured across the whole window and in two prior dedicated
captures).
4. The trap unit fires on the stale INTRQN, but the panel-vs-macro
classifier (CGA_TRAP_TVGEN_P2 GATES_6) uses live PAN, which is now 0 ->
it dispatches a MACRO interrupt (trap vector 17), not a PANEL interrupt
(vector 16).
5. Trap-17 microcode does PIC,RVECT -> reads the empty vector {PD=0,PICV=0}
= R1=0 -> ITSRV+0 -> PIL level 10 (Agent C's table; level 10 is the
default decode of "grant with empty vector").
So the "masked level-10 grant" is a stale-INTRQN panel pulse mis-taken as a macro interrupt, reading an empty vector that defaults to level 10. It is NOT an Am2914 masked grant, NOT a real level-10 source, NOT metastability (deterministic; it is the registered-snapshot lag), and NOT IOXERR/RTC/conkick (all disable-tested with no effect - because the PAN source is the general panel/PRQ path, confirmed by TANG_NO_PAN breaking the console entirely).
Why Verilator never shows it: the lag (INTRQN holding after PAN drops) exists in the RTL in both worlds, but on silicon the real cadence (9600-baud console PRQ pulses, real MCLK/TCLK phases) deterministically lands a PAN-pulse's lag window on the JAZ instruction fetch (step 18, CSA 00214 CONTINUE). Zero-delay Verilator's aligned delta-cycles + fast-UART cadence never place the lag window on an instruction boundary, so the stale-INTRQN is always re-evaluated consistently. This is the "real-timing effect zero-delay sim collapses" class.
Structural fault (Agent D): INTRQN (the grant, latched) is not interlocked
with the live panel-vs-macro classifier or the live vector read (PICV, strobed
by S). The fix must make the trap act on a cause that is still valid - which is
exactly what the reverted CGA_TRAP guard (intrq & (pan | IRQ)) did. Fix
options (Ronny's call, faithfulness constraint):
- (a) the CGA_TRAP live-cause guard (schematic deviation, directly blocks it);
- (b) latch PAN alongside INTRQN so trigger and classifier use one snapshot
(a faithful interlock);
- (c) address the un-original console PRQ/conkick pulse generation so panel
pulses are not manufactured the way the real 68705 never did.
3f. The real MC68705U3 behavior + the FAITHFUL FIX (18-JUL)¶
Agent read the U3 firmware analysis AND the sheet-40 schematic
(Code/68705/3202D_PANCAL_SHEET40.png). Findings:
- STAT3 = PB4, a firmware-HELD LEVEL: set at panel-command completion, cleared
at idle, ACKed by the CPU reading PANS (TRA PANS / EPANS/MIPANS). Not a
hardware one-shot; the DGA A282/A283 turns its rising edge into PRQ.
- The 68705 is a command/response SLAVE: it raises STAT3/PRQ ONLY as the tail of
an LDPANC command the CPU itself issued. Its timer/RTC ISR raises no CPU
attention.
- At cold start it raises NO panel request (boot sets PB4=0, idle loop keeps
it low).
- It has no connection to the console UART - a console output character never
touches it and would never toggle STAT3.
CONCLUSION: the recreation's conkick (IO_37.v: pulse STAT3 once per console-TX
character) is un-faithful - it manufactures PRQ->PAN edges the real chip
never generates, including at cold start. Those spurious PAN pulses are what the
CGA_INTR/CGA_TRAP INTRQN lag mis-dispatches as a phantom macro-interrupt ->
level 10. So the phantom grant is, in normal (free-run) operation, an
emulation artifact of the conkick.
FAITHFUL FIX (prototype, 18-JUL): IO_37.v now drives STAT3 from real panel
activity only (IO_PANCAL) by DEFAULT; the old console-speedup conkick is behind
opt-in ND120_CONKICK_CONSOLE_SPEEDUP (default OFF). This matches the real
68705: STAT3 low at cold start and during console I/O. Cost: OPCOM console
output reverts to the slower RTC-tick pacing (the conkick's original purpose) -
the correct place to speed console output is the console/UART path, which on
real hardware does NOT go through the panel; that is a separate follow-up.
VALIDATION (must be FREE-RUN, not single-step): single-stepping injects its own panel Stop/Continue PAN pulses, so it cannot test the conkick fix. A fresh free-run cold start (400$ autostart, or MACL+P=0+run) has no panel-step ops, no console output yet, and no RTC tick in the first ~tens of us - so with the conkick gone there is no PAN pulse at the P=21 hang point. If 400$ now boots past the hang, the conkick was the free-run trigger and the faithful fix cures the real-operation failure.
RESIDUAL / belt-and-suspenders: the INTRQN lag (a real RTL structural bug, see 3e) still makes ANY brief PAN pulse (a legitimate panel op, an RTC tick landing on a fetch) potentially fatal. For full robustness, ALSO add the interlock so the CGA_TRAP panel-vs-macro classifier and the INTRQN trigger use one consistent snapshot (or hold PAN as a level like the real STAT3). The faithful STAT3 fix removes the un-original trigger; the interlock hardens against legitimate ones.
4. What was reverted (for the record)¶
The trap-side guard INTRQ := INTRQ & (PAN | IRQ) in CGA_TRAP (+ IRQ port wired in
CGA.v, + tb golden) was implemented, passed all sim gates, then reverted — it is
a schematic deviation and a symptom patch. The three files are back to their
committed state (verified git diff empty). The S3 HVE/LVE int-req-enable gate in
CGA_INTR_CNTLR_IRGEL_HIRL.v / _LORL.v was committed later (in cd9b94f,
23-JUL-2026); it is Am2914-ground-truth-correct but is NOT this bug's cure (the
claim was already empty).