ND Ethernet II emulator - validated fix plan & TODO¶
Date: 2026-07-08. Target: E:\Dev\Repos\Ronny\RetroCore\Emulated.HW\ND\CPU\NDBUS\NDBusEthernetII.cs
(+ MC68901MFP.cs, Am2990Lance.cs, Cpu68K.Interrupts.cs).
Goal: ENNS0 START-NETWORK-SERVER completes and registers with XROUT; TPE ETHERNET-TWO
stays a faithful mirror of the real card (which means test 12 is EXPECTED to fail).
Built from two independent reviews + my own trace/Ghidra work, each item tagged with a
confidence and a cross-check so we don't fix things blindly:
- Schematic review: D:\OCR\ai\ND-324534-G1-EN\NDBusEthernetII-Schematic-Review.md
- Code/spec/firmware review: ...\stripped\docs\ND_EthernetII_Emulator_Correctness_Analysis.md
Confidence: [VERIFIED] = cross-checked against manual/schematic/trace; [LIKELY] =
one strong source, matches understanding; [NEEDS-TRACE] = must confirm dynamically.
0. Ground rules (how to work this)¶
- One change at a time. Rebuild
Emulated.HW, then rebuild+relaunch the HOST app. - Two oracles every step:
- Regression: TPE ETHERNET-TWO all-tests. Baseline BEFORE any change (tests 1-11
pass, 12 fails/
Timer exceed, 24/25/26 fail). Do not regress 1-11. - Goal:
RT ENNS0->START-NETWORK-SERVER ENNS0withDebugTrace 2 4; thenENCOS-MON STAT server 0 source O. Watch the trace after each step.
- Regression: TPE ETHERNET-TWO all-tests. Baseline BEFORE any change (tests 1-11
pass, 12 fails/
- Delete
%LOCALAPPDATA%\trace\file-trace.txtbefore each capture (append-mode). - Commit already made on branch
ethernet-ii-controller-fixes(baseline before these).
A. Already done this session and CONFIRMED CORRECT - do not touch¶
| Fix | Confidence | Cross-check |
|---|---|---|
| Status reg: read offset 0/2 = status word (drop 0xFF data stub) | [VERIFIED] | Review D; manual pp.44-45 |
| SCIP doorbell: 0xEF0080-9F write -> INT12 (BUG A) | [VERIFIED] | Both reviews; trace shows doorbell now reaches ND-100 |
| PROFF (0xEF0010-1F) + MODCR (0xEF0020-3F) no longer -> SCIP/INT12 | [VERIFIED] | Manual I/O map; review A6/A7; trace flood 1947->0 |
MC68000 STOP wakes on IRQ (&= ~WAIT) |
[VERIFIED] | Firmware reset_entry STOPs; review NOTE E |
LANCE SwapByteLanes + DmaIn/DmaOut big-endian |
[VERIFIED] | Review 2 section 1; LANCE now inits (IDON) |
B. My session mistakes to REVERT (I tuned to a test the real card fails)¶
These emulate hardware that DOES NOT EXIST on this card. The F138 decoder ignores A8, so EF01xx == EF00xx: EF0140=MERRSTAT, EF0160=EAREN, EF01A0=LANCE RDP (confirmed vs manual I/O map lines 780-781 + review A6). And the real ND-110 log shows TPE test 12 FAILS on physical hardware (freq ~12.5 MHz = CPU clock). So:
- [ ] B-REV-1 [VERIFIED] Remove the STC register block (0xEF0140/0160/01A0 handlers),
stcArmed/stcCountdown/STC_PERIOD_TICKS/timerTick32/timerConfigReg, the STC arming in the config-write path, and the STC periodic tick inClock. Let those addresses fall through to the real MERRSTAT/EAREN/LANCE-RDP decode. - [ ] B-REV-2 [VERIFIED] Revert the timer interrupt from level 5 back to the MFP Timer-C -> level-3 path (review BUG B: production RTC is MFP Timer C, level 3, vector 0x45, already wired). The level-5 STC path was for the non-existent chip.
- [ ] B-REV-3 [LIKELY] Accept TPE test 12 FAILING (as real HW does). Do NOT re-add STC logic to pass it. If a "diagnostic shim" is ever wanted, put it behind an explicit named flag, off by default.
Note: keep the AM9519/SCIP-channel HandleSCIPChannelAccess shim for now (TPE tests 5/6
lean on it) but flag it as non-hardware; revisit under C-6.
C. New fixes, in suggested order (each: change -> rebuild -> both oracles)¶
- [ ] C-1 [VERIFIED] IDENT must not clear
interruptEnabled(line ~1284). Hardware: IDENT/CLINT clears only RFT (the "interrupt set" latch), never RIE (enable). Change: inIDENT()removeinterruptEnabled = false;keepscipPending = false;. Expected: after SINTRAN enables interrupts once, every later doorbell asserts INT12 without needing a control rewrite. Likely removes the need for mostscipPendingjuggling. Validate: ENNS0 - does ND-100 now get INT12 on every 68K doorbell (not just the first)? TPE 1-11 unaffected.
- [ ] C-2 [VERIFIED] RFT is a latch until IDENT/master-clear; status bit 2 reads the latch.
Change:
scipPendingset on any SCIP write, cleared ONLY by IDENT and controller reset (not by the "next control-word write"). Status bit 2 =scipPending(already partly there). Remove the "consumed by next control write" flush. Validate AFTER C-1: re-test the indefinite-latch behavior that previously regressed TPE 12/24/25/26 - the reviews argue that regression was caused by C-1 still being present, so it should be clean now. If TPE 24/25/26 regress, stop and re-examine.
- [ ] C-3 [VERIFIED] Control bit 2 (ND interrupt) = level on MFP GPIP I6.
Change: on EVERY control-word write,
mfp.GPIO_6 = ((value & 4) == 0);(level follows the bit). Delete the rising-edgeSetMFPInterrupt()+ forcedmfp.TriggerInterrupt(6)and the never-calledClearMFPInterrupt(). The MFP coregpio_input()already does AER+IER edges. Validate: TPE test 11 (OPCOM/ND-calling-int); ENNS0 GPIP6 path (nd_host_interrupt_handler). Watch for missed/duplicated ND->68K interrupts.
- [ ] C-4 [VERIFIED] MFP timer clock 3.6864 MHz -> 3.125 MHz (line ~1728,
SetTimerClock). Schematic: 3CLK = 12.5 MHz / 4 = 3.125 MHz. Fixes RTC (~130-236 Hz seen in trace is ~18% fast) and any TPE frequency window. Validate: RTC tick rate in trace drops ~18%; TPE 1-11 unaffected.
- [ ] C-5 [LIKELY] Small self-contained:
- Power-low (control bit 6) -> raise 68K level 7 (autovector). (review A5)
- LANRESET (0xEF00B0-B7 access) ->
lance.Reset()instead of just logging. (review A9) Validate: no regression; only exercised by specific firmware/diagnostic paths.
- [ ] C-6 [NEEDS-TRACE] EF0080 GPDR alias + mirrored/direct split. Review says EF0080 is SCIP-only; GPDR alias has no hardware basis (MFP CS is EF00C0-FF). We currently keep the GPDR write on 0xEF0080 for TPE test 5. Decide: keep as a flagged diagnostic shim, or remove. Do LAST - needs a TPE test-5 trace to know what it relies on. Do not remove blind.
D. Verification-only tasks (confirm before deciding to change)¶
- [ ] D-1 [NEEDS-TRACE]
Am7990Lance.ClearInterrupt()on level-2 IACK (review B1). Hardware IACK doesn't touch the LANCE; INTR follows CSR0. Read whatClearInterrupt()does; if it clears flags/pin, model level 2 as continuousIsInterruptActiveinstead. - [ ] D-2 [NEEDS-TRACE] MERRSTAT/EAREN latch event (review B3). Should latch on MERR (parity), not on unmapped-address bus errors. Relevant to TPE 24/25 (currently failing anyway). Low priority.
- [ ] D-3 [NEEDS-TRACE] Protect table / WRIV(I7) / LANERROR(I5) unwired (review B4). TPE 26.
- [ ] D-4 [LIKELY] Confirm production firmware never writes 0xEF0140 (STC) so B-REV-1/2 are safe (it should now hit MERRSTAT read). Check a trace.
E. Cosmetic / low-risk (batch whenever)¶
- Octal-vs-decimal vector logging (
LogMFPVectorType/MapMFPVectorToSystem) - dead code, add/keep warning comment (review C1 / TRAP C). - Bank number hardcoded 16 for all thumbwheels - take from thumbwheel (review C2).
- CPU clock comment 10 MHz -> 12.5 MHz; revisit
CPU68K_CYCLES_PER_ND100_TICK(1:3.2 vs 1:4).
F. The critical validation question (do this FIRST, before C-1)¶
Establish the TPE ETHERNET-TWO baseline on the current committed build and write down the exact pass/fail of tests 1-11-12-20..28. Everything after is measured against it. If any of C-1..C-4 regresses tests 1-11, revert that single change and re-examine - do not stack changes.
Order of execution: F (baseline) -> B-REV-1/2/3 (revert STC) -> C-1 -> C-2 -> C-3 -> C-4 -> C-5 -> (D verifications) -> C-6. One at a time, both oracles each step.