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 78ee53a..68c2be2 100644 Binary files a/harness/udpstream/build/lance.coff and b/harness/udpstream/build/lance.coff differ diff --git a/harness/udpstream/build/lance_fixlen.coff b/harness/udpstream/build/lance_fixlen.coff index 231c3ac..1daaa6d 100644 Binary files a/harness/udpstream/build/lance_fixlen.coff and b/harness/udpstream/build/lance_fixlen.coff differ diff --git a/harness/udpstream/lance.c b/harness/udpstream/lance.c index b2dd9e6..d8d97db 100644 --- a/harness/udpstream/lance.c +++ b/harness/udpstream/lance.c @@ -408,8 +408,10 @@ int main() break; } } - /* keep the driver's command shadow consistent with the chip */ - *(unsigned int *)0x23CC50 = 0x0042; + /* NOTE: do not write 0x23CC50 -- it is the driver's RDP pointer + * cell (0x05800000), not a CSR0 shadow. The TX kick reads CSR0 + * back through it and ORs TDMD; storing here corrupts the pointer + * and the next CSR access faults (illegal opcode). */ } cell(0x260, csr0res); /* CSR0 after the restore */ cell(0x280, osblk); /* init block we handed back */ diff --git a/harness/udpstream/lance_fixlen.c b/harness/udpstream/lance_fixlen.c index c8b8ec5..678533c 100644 --- a/harness/udpstream/lance_fixlen.c +++ b/harness/udpstream/lance_fixlen.c @@ -408,8 +408,10 @@ int main() break; } } - /* keep the driver's command shadow consistent with the chip */ - *(unsigned int *)0x23CC50 = 0x0042; + /* NOTE: do not write 0x23CC50 -- it is the driver's RDP pointer + * cell (0x05800000), not a CSR0 shadow. The TX kick reads CSR0 + * back through it and ORs TDMD; storing here corrupts the pointer + * and the next CSR access faults (illegal opcode). */ } cell(0x260, csr0res); /* CSR0 after the restore */ cell(0x280, osblk); /* init block we handed back */