NDBusEthernetII.cs — Interrupt & Timer Wiring Validation vs. Schematics¶
Cross-check of E:\Dev\Repos\Ronny\RetroCore\Emulated.HW\ND\CPU\NDBUS\NDBusEthernetII.cs
(state of 2026-07-23, 4027 lines) against the print-G schematics
(../EthIIImages/, netlist in EthII-interrupt-clock-netlist.md) and the technical
manual ND-12.055.1 EN (original PDF).
Verdicts: CONFIRMED = code matches hardware. MISMATCH = code differs from hardware (impact noted). GAP = hardware behavior with no code path. UNVERIFIED = could not be settled from schematic+manual (PAL equations etc.). Line numbers refer to the file as read on 2026-07-23. No code was changed.
A. CONFIRMED — correctly wired¶
| # | Item | Code | Evidence |
|---|---|---|---|
| A1 | 68k IPL map: 2=LANCE, 3=MFP vectored, 4=console, 5=MERR, 6=OPCOM, 7=power NMI | Cpu_OnInterruptAck dispatch (669-699) |
LS148@19F wiring = manual p.12 |
| A2 | MFP on level 3, vector from MFP (HandleMFPInterruptAck, 706), spurious when none pending |
706-730 | IAK901 from PAL 453-00; MK68901 protocol |
| A3 | MFP vector set 117/116/114/113/112/111/107/105₈ with VR base 0x40; 107=GPIP5 LANERROR, 116=GPIP6 NCINT, 117=GPIP7 WRIV | comments + TriggerMFPVector (839-871) |
GPIP wiring S3 = manual p.27-28, standard 68901 channel map |
| A4 | Level-6 IACK clears the OPCOM interrupt (823) | HandleOPCOMInterruptAck |
= hardware CLROPCOM0 from PAL 453-00 |
| A5 | Level-5 IACK clears the level-5 interrupt (799) | HandleParityErrorInterruptAck |
= hardware CLRMERR0 (for the MERR part; see M1 for the STC part) |
| A6 | MFP INTR modeled as level (assert+deassert) → level 3 | Mfp_OnIRQ (2443-2457) |
901INTR is a level |
| A7 | ND-100 status word: bank<<8, bit5 halt, bit4 reset, bit2 = asserted INT12, bit0 = enable | Read 1160-1234 |
manual p.30; bit2 = RFT·RIE per schematic — and the code deliberately not exposing the pending latch in bit 2 (1176-1181) is hardware-CORRECT |
| A8 | SCIP fired while enable off stays pending and asserts when enable is set | MemoryMap_OnNDInterrupt (877-903) + delivery on enable (1318-1332) |
RFT FF clocks regardless of RIE; BINT12 = RFT·RIE |
| A9 | IDENT clears BOTH the INT12 latch and the interrupt enable | IDENT override (1439-1460) |
Schematic settles the open C-1 question: RFT and RIE flip-flops BOTH have R̄ = CLINT0 = (DCL OR PIDENT). The current behavior is hardware-correct; fix-plan C-1 ("clear only RFT") would be WRONG. After IDENT, status bit 0 reads 0 until the next control write — also matches code |
| A10 | Control bits re-captured on every write (not edge-detected) for enable/halt/reset/power-low levels | 1293-1306 | RIE FF + LS175@86 are re-clocked on every OCW |
| A11 | Reset rising edge resets card state incl. pending SCIP; vectors fetched on falling edge | 1342-1367 | manual p.18/29 (Master Clear sets RESET+HALT; restart fetches SSP/PC from DRAM[0..7]) |
| A12 | ND-interrupt (bit 2) delivered to MFP GPIP I6 through the MFP's AER/IER edge logic, not a forced level-3 | 1369-1384 (A4 fix) | NCINT0 → I6; vector 116₈ |
| A13 | MFP timer clock 3.125 MHz | 2153 (SetTimerClock(3_125_000), C-4 applied) |
3CLK = 12.5/4, sheet-1 note |
| A14 | Timer C = RTC → MFP level 3 vector 105₈, no SCIP side effect | Mfp_OnTimerInterrupt (2483-2488) |
Timer C has no external pin; RTC ≈ 128.07 Hz |
| A15 | ETHSTAT (EF00B8-BF): bit0 = live LANCE INTR state, bit2 = transceiver power, active-low | 3729-3752 | S244@9E sheet 5; manual p.22 |
| A16 | LANRESET (EF00B0-B7) actually resets the LANCE (C-5 applied) | 3754+ | LS139@5D Y2, OR-ed with system reset |
| A17 | Power-low NMI wired to level 7 (C-5): control bit 6 → level 7 | 1389-1397 | LS148 in7 — but see M4 for the gating semantics |
| A18 | ND-100 side: 4 thumbwheel positions → 140360/64/70/74₈, ident 2240-2243₈, level 12 | ctor 487-530 | IDENT PROMs 089-00/01 + comparators; libnd.js |
| A19 | 68000 vectors fetched from DRAM start (no EPROM) | LoadRom/reset flow | manual p.20: EPROM sockets empty; p.18: SSP/PC from first 8 bytes of DRAM |
B. MISMATCH — code differs from the hardware¶
M1. The "STC / Timer Controller" does not exist [HIGH, known but not yet removed]¶
Code: stcArmed/STC_PERIOD_TICKS=2000/timerConfigReg (3155-3177), STC tick in
Clock (3408-3437), config-write arming (3524-3534), OnTimerInterrupt → level 5
(2256-2266), timer branches in the level-5 and level-6 IACK handlers (788-792,
812-816), and the header comment "STC shares level 5 with MERR" (778-780).
Hardware: the F138@106 has two enables (IOSPACEL/IOSPACEH), so EF01xx is a pure mirror of EF00xx. EF0140=MERRSTAT, EF0160=EAREN, EF0120=EPROMMODE, EF01A0=LANCE RDP. A level-5 ISR reading EF0140/EF0160 is the memory-parity-error handler reading error status + captured error address. There is no timer chip; level 5 = MERR only. This confirms fix-plan items B-REV-1/2/3 (2026-07-08, still unchecked) with gate-level evidence. TPE test 12 failing is the real-hardware outcome. Also remove/rename: the "AM9519 EOI" interpretation — a 68k write to EF0100-011F lands in "not used"/PROFF on real hardware and does not ring SCIP; only EF0080-9F / EF0180-9F accesses clock the RFT FF.
M2. NCINT (control bit 2) is a strobe-qualified pulse, not a stored level [MEDIUM]¶
Code (1378): MFP.GPIO_6 = !ND_interrupt — I6 follows the bit between control writes;
a second write with bit2=1 (without an intervening bit2=0 write) produces no new edge.
Hardware: NCINT0 = NAND(BND02, OCW-strobe) — I6 pulses low for every control write
with bit 2 = 1, then returns high. Each such write is a fresh falling edge to the
MFP. Fix shape: on every control write, if bit2=1 pulse I6 low→high (or model the
strobe), instead of holding the level. Impact: back-to-back doorbells from the ND-100
driver are lost; also firmware polling GPDR between doorbells reads a stuck-active pin.
M3. OPCOM re-trigger on repeated writes [MEDIUM]¶
Code (1399-1405): level 6 asserted only on the 0→1 edge of bit 3 across writes
(startOpcom && !previousStartOpcom).
Hardware: the OPCOM FF is clocked by every control write with bit3=1; after a
level-6 IACK cleared it (CLROPCOM), the very next write with bit3=1 sets it again even
though the bit never went to 0 in between. Fix shape: trigger on every write with
bit3=1 (the FF + IACK-clear already handles dedup). Impact: a second OPCOM kick with
the bit held at 1 is silently dropped.
M4. Control bit 6 is a power-low ENABLE, not a trigger [LOW-MEDIUM]¶
Code (1393-1397): writing bit 6 = 1 immediately fires the level-7 NMI.
Hardware: bit 6 sets PLOWE (a level in the LS175); the NMI fires on
PLOWE AND Master-Clear (gate 5F → PAL 455-02). The manual's power-fail sequence
(p.18) is: ND-100 detects power fail → asserts MCL → card (with PLOWE set) takes the
NMI, saves registers, self-halts; SCIP/RFT+RIE are cleared 200 µs later by Delayed
Clear. Impact: a driver setting bit 6 as an enable during init would spuriously NMI
the 68000 in the emulator. If SINTRAN/TPE never set bit 6 outside an actual power-fail
path, current behavior is benign — worth a trace check before changing.
M5. Level 7 is never deasserted [LOW]¶
HandlePowerFailureInterruptAck (829-834) acks but never calls
InterruptControllerSetInterrupt(7, false) — after one NMI the level-7 request stays
asserted in the interrupt controller (depending on Cpu68K core semantics this can
suppress or re-deliver NMIs). Hardware: LEV7INT is a registered PAL output that
follows its terms (deasserts when PLOW drops). Fix: deassert on ack or on control
writes with bit6=0.
M6. LANCE INTR modeled as edge + IACK-clear instead of level [MEDIUM]¶
Code: Lance_OnIRQ (2459-2464) only asserts; HandleLANCEInterruptAck (755-765)
clears level 2 on IACK.
Hardware: LANINTR is a level — it stays asserted while any unmasked CSR0 cause is
set, and IACK does not clear it; only a firmware CSR0 write (clearing the cause or
INEA) or LANRESET releases it. Consequences in the emulator: (a) if a second LANCE
event is pending at IACK time, hardware re-interrupts immediately, the emulator stays
silent until the LANCE core happens to raise OnIRQ again; (b) ETHSTAT bit 0 (live pin
via GetLANCEInterruptState) can read "interrupt active" while the CPU-level request
was already cleared — the two views of the same pin diverge. Fix shape: drive level 2
from the LANCE core's INTR-state (assert+deassert callback), drop the IACK-clear.
M7. Pending SCIP flushed by a control write with enable=0 [MEDIUM — known, deliberate]¶
Code (1333-1338): a control write with bit0=0 discards scipPending.
Hardware: RFT is cleared only by IDENT-answer or Delayed Clear; writing the control
word (any value of bit 0) does not touch it. A disable-then-enable sequence would, on
real hardware, re-assert INT12 from the still-latched RFT. The code comment documents
that the hardware-true latch regressed TPE tests 12/24/25/26 in the 2026-07-07 attempt
— but that attempt likely interacted with the STC block (M1) and the C-1 experiment
(now shown wrong by A9). Recommendation: after removing the STC (M1), retest the
hardware-true model as one holistic change: RFT persists across control writes; BINT12
and status bit 2 = RFT·RIE; IDENT clears both FFs (current A9 behavior).
C. GAP — hardware paths with no emulator wiring¶
G1. LANERROR (MFP I5, vector 107₈) never driven by DMA failures¶
Hardware: a LANCE memory cycle stopped by protect violation, bus error, or
address-out-of-range pulls LANERROR0 → MFP I5 (manual p.27). In the code GPIO_5 is
initialized inactive (2160-2164) and only the manual test helper TriggerMFPVector(107)
ever drives it; Lance_OnReadDMA/OnWriteDMA out-of-bounds paths (2409-2439) return
false without raising it. Firmware error recovery for DMA faults can therefore never
be exercised.
G2. WRIV (MFP I7, vector 117₈) never driven by protect violations¶
Hardware: a 68000 user-mode write into a protected 512-byte segment yields bus error +
WRIV0 → MFP I7 (manual p.19). Only TriggerMFPVector(117) drives GPIO_7. If the
protect table is enforced in NDEthernetMemory, the violation path should also assert
I7.
G3. Console interrupt (level 4) never asserted¶
HandleConsoleInterruptAck exists (770-776) but no code path ever raises level 4.
Hardware: RREDY/TREDY (USART ready pins) → level 4 autovector when the CONSPRES strap
is fitted. Impact: none for SINTRAN operation (PCT is a service console); needed only
if the test console is emulated interactively.
G4. MFP not reset by ND-100 reset bit / Master Clear¶
Hardware: MK68901 RESET pin ← PMCL0, which is asserted by power-on MCL and by
control-word bit 4 (PRES chain) — an ND-100-commanded reset also hardware-resets the
MFP (and pulses LANCE reset). In the code, the reset rising edge calls
memoryMap.Reset() (1345); whether that resets the MFP register file was not verified
— the nearby comment (595-599) warns MFP wipes break firmware reinit for the RESET
instruction (which indeed must NOT reset peripherals on this card: the 68000's RESET
output pin is not wired to the MFP — only PMCL is). Verify memoryMap.Reset() resets
the MFP; the RESET-instruction no-op stays correct.
D. UNVERIFIED / notes¶
- PAL 453-00
CLRREDY/PRI/IAKEand PAL 455-02 exact equations: inferred (no dumps). - BERR bus-timeout (~1.3 µs shifter) is not modeled; the emulator raises bus errors immediately on unmapped access — acceptable simplification.
- 68000 clock: print-G schematic runs the MC68HC000-12 at 12.5 MHz (manual p.11
says 10 MHz — earlier print).
CPU68K_CYCLES_PER_ND100_TICK=1(921) is a tuned, known-good ratio; if ever recalibrated, target 12.5 MHz, not 10. - Manual-internal contradiction: p.27 "PCT interrupts on level 5 via the MFP" is wrong (p.12 table + LS148: console = level 4 direct; MERR = level 5).
- The OCR'd manual
Reference-Manuals\Devices\ND-12.055.1 EN Ethernet II Controller.mdcontains at least one hallucinated section (an "optical properties of materials" block around lines 85-118). Use the original PDF for load-bearing facts.
E. Suggested order of work (report only — nothing changed)¶
- M1 — delete the STC block (= fix-plan B-REV-1/2/3, now gate-level-proven); accept TPE test 12 failing as real-hardware behavior.
- M6 — LANCE INTR as level (assert/deassert from CSR0 state, no IACK-clear).
- M2 + M3 — strobe semantics for NCINT and OPCOM (re-trigger on every write with the bit set).
- M7 — retest hardware-true RFT latch semantics (persist across control writes) after 1-3, as one change, against TPE 1-12 and the SINTRAN ENNS0 boot.
- G1/G2 — wire LANERROR and WRIV into the DMA-fault and protect-violation paths.
- M4/M5 — power-low enable gating + level-7 deassert (verify with a SINTRAN trace whether bit 6 is ever set outside power-fail first).