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.
This commit is contained in:
arti committed 2026-10-30 15:56:08 +02:00
1 parent 2ec9787435
commit 3cd03cdc19
5 files changed
+54 -8

No files matched your search

+46 -4
View File
@@ -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.
Binary file not shown.
Binary file not shown.
+4 -2
View File
@@ -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 */
+4 -2
View File
@@ -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 */