From 3cd03cdc19460c6681fd4dd92477ffed5f0a5c48 Mon Sep 17 00:00:00 2001 From: Arti Zirk Date: Fri, 30 Oct 2026 15:56:08 +0200 Subject: [PATCH] fix crash: 0x23CC50 is the RDP pointer, not a CSR0 shadow The restore wrote 0x0042 into 0x23CC50, overwriting the driver's RDP pointer (0x05800000); the next CSR access then targeted 0x0042 and the terminal died with an illegal opcode. The TX kick does move @0x23CC50,a3 / move *a3,a5 -- it reads the live CSR0 and ORs TDMD, there is no shadow cell. Report: section 10 corrected, section 62 added with the disassembly and the consequence. --- harness/mame/NETWORK_REPORT.md | 50 ++++++++++++++++++++-- harness/udpstream/build/lance.coff | Bin 6355 -> 6345 bytes harness/udpstream/build/lance_fixlen.coff | Bin 6357 -> 6347 bytes harness/udpstream/lance.c | 6 ++- harness/udpstream/lance_fixlen.c | 6 ++- 5 files changed, 54 insertions(+), 8 deletions(-) diff --git a/harness/mame/NETWORK_REPORT.md b/harness/mame/NETWORK_REPORT.md index eb28c78..758a8a4 100644 --- a/harness/mame/NETWORK_REPORT.md +++ b/harness/mame/NETWORK_REPORT.md @@ -249,10 +249,21 @@ a5 |= 0x0008 ; TDMD > real-silicon `CSR0 = 0x1BB` decode (`STRT`=1, `TDMD`=1, `TXON`=1) shows a poll > that never ran, which is a different problem entirely. -**The transmit demand is sent as `shadow | TDMD`, never as a bare `TDMD`.** The -write must preserve the shadow's read/write bits (in particular `INEA`), and it -matches the driver; our payload arms the descriptor at kick time and writes -`STRT|TDMD` in one word. +**The transmit demand is sent as `CSR0-read-back | TDMD`.** `0x23CC50` is **not** +a shadow cell — it holds the driver's **RDP pointer** (`0x05800000`), and the kick +reads CSR0 back through it: + +``` +3F9D5960 move @0x23CC50,a3,1 ; a3 = RDP pointer (0x05800000) +3F9D5990 move *a3,a5,0 ; a5 = *RDP = current CSR0 +3F9D59B0 or a3=8,a5 ; a5 |= TDMD +3F9D59D0 move @0x23CC30,a5,1 ; a5 = RDP pointer (second alias) +3F9D5A00 move *a13,*a5,0 ; *RDP = a5 +``` + +So the driver reads the *live* CSR0 and ORs `TDMD`, preserving whatever +read/write bits (notably `INEA`) are currently set. Section 10 called that cell a +"shadow" and section 62 records why that is wrong and what it broke. ## 11. The live driver paths (RX poll, TX completion) @@ -4225,3 +4236,34 @@ from the real unit (they are the ones that displayed correctly there). MAME's frame dump does **not** reproduce the panel — the OS repaints the screen continuously there, and the real unit's VRAM layout differs slightly — so the panel is verified on the machine, not from an emulator screenshot. + +## 62. Correction: `0x23CC50` is the RDP pointer, not a CSR0 shadow + +Section 10 (and the restore code written from it) treated cell `0x23CC50` as a +software shadow of CSR0 and wrote `0x0042` into it. That is wrong and it +**crashed the terminal with an illegal opcode** on the machine. + +The disassembly is unambiguous: + +``` +3F9D5960 move @0x23CC50,a3,1 ; a3 = value of the cell = 0x05800000 +3F9D5990 move *a3,a5,0 ; a5 = *(0x05800000) = *RDP = current CSR0 +3F9D59B0 or a3=8,a5 ; a5 |= TDMD +3F9D59D0 move @0x23CC30,a5,1 ; a5 = second RDP alias (also 0x05800000) +3F9D5A00 move *a13,*a5,0 ; *RDP = a5 +``` + +`0x23CC50` holds a **pointer** (`0x05800000`, matching the RAM dump in section 2), +and the driver reads the *live* CSR0 through it before OR-ing `TDMD`. There is no +shadow: the "preserved" bits are simply whatever the chip currently reports. + +Consequences, all now fixed: + +* writing `0x0042` into `0x23CC50` overwrites the RDP pointer, so the driver's + next CSR access targets address `0x0042` — the fault observed on the unit; +* the restore must write CSR0 through `RAP`/`RDP`, never through that cell; +* section 10's phrase "CSR0 = shadow | TDMD" should read "CSR0 = read-back | TDMD". + +The restore path in `harness/udpstream/lance.c` now re-programs the chip with +`0x7F41` (the firmware's own init value: `INIT | INEA | all status bits`), polls +`IDON`, writes `0x0042`, and leaves the driver's cells untouched. diff --git a/harness/udpstream/build/lance.coff b/harness/udpstream/build/lance.coff index 78ee53ad99cbcf36c2d62bad1d9493c8f7d31b30..68c2be2331c48c3f442d99ae08b94b9f4a5bb895 100644 GIT binary patch delta 475 zcmca?c+#+b0s{*J*S;rN8Db0!iVO@4G7QX&9E`^q4y*xkfM7u<1B1cB9!3U+9>xP} zdKmReQY%WpGB7a)h6`Xmf=~c5^->Z`5`i>G4+w)~L3SVm2L^_T^_(0qB@-u#PrfV0 zyK##GKV$ditNd%389O#N3kx!Co+rY^BxA6Uf#DFcb|gC{8;C1S+`uyVm6!sf!DMc6 zWu^mbfMOB#2Uhejg6w8uh%ZV_Oo<0NXeC@EB{e6pGM?eUGPp=?Vopwea{Pg%aFOEF zoYdr!_yeopB1xHfU~?A1MT+y2vr~a;fWZW@3*<@`AU@!+7$y{-R+O3wvVJvOBsnL) z7$|gL30x#6v$!NRFaE%CxJYqHVi7R74JP|bD64@23St3r=rV!5mkJN>$ulIZ0Uii* A@c;k- delta 466 zcmX?Uc-gRi0s{*}-`*!#MPdvLiVO@4G7QX&9E`^q1l9sMK(L^bfuUhx4f7#!V?#; zO?D9H*tkK3pK-$GtNd%38GAQ33kx!Go#Aw1=wS~yqs*{*iU=1IW5eY6Vv+pWi?RvKs<{9 diff --git a/harness/udpstream/build/lance_fixlen.coff b/harness/udpstream/build/lance_fixlen.coff index 231c3ac815f9bc3e166621762058c4476c4d07b4..1daaa6df6124ab1fdeaf972838706c469795e959 100644 GIT binary patch delta 452 zcmca=c-pXj0s{*J@4hElSz-(fiVO@4G7QX&9E`^qF027^fM7u<1B1iD9!3U+9>xo6 zdKmReQY%WpGB7a)h6`Xmf=~c5^->Z`5`i>G4+w)~L3SVm2L^_T^_(0qB@-u#Prfh4 zyK##WKV$di>-=k(89O$&3JWrBULeB7#ON@2wU{K+g*B6piMateyyD6bj?&~1akKgh zD|#3~mM}5I7o{eq!~<B-Sb!XiOknS&!UJ~lED37>9tCqb delta 459 zcmX?Yc-63e0s{-f#Jx|lO2il#6d4#8WEhwkIT(*KD69o?fM7u<1H*)cJ&X(tJ&X!# zdl>afQY%WpGB7a)h6`Xmf=~c5^->Z`5`i>G4+w)~L3SVm2L^_T^_(0qB@-u#Z(Od= z&p2W8b^f)?jJ=y%g#{V8&Tu+0^sonYbWm!a|3di#g!o( zrO966X7vgydl*4>F)_p!r6#7t10ApmE|QX(lUNzgps*Y+lAD;5lb;-~unaCzoSKuG zToSLa8ZMHQnFls!F