docs: identify the writers of +0x3c0/+0x3d0 (the DUART ISR) and what L3FA71BC0 checks

Direct writer evidence (VT1200_STRUCTLOG): test +0x3c0 = ISR struct[idx4].0x3b0 and
+0x3d0 = the ISR index5 SRA snapshot (TxRDYA path, 3FA79690/3FA7A390); test
struct[i].0x60 = the ISR's received-status field (RxRDYA path 3FA79690).  So both
sub-tests' failures are the ISR's SRA snapshots and nothing else.

L3FA71BC0 (18 flag sites probed, exactly one fires): c6, cmp 3FA73970 btst5 on
struct[i].0x60, set when bit5 = SRA PARITY ERROR is set.  Observed 0x0001 (clean) in most
combinations and 0x0021 (RxRDY|parity error) in 3 -> its remaining failure is a parity
error in the received status, not a timing one.  c5 (framing error) does not fire.

L3FA753D0's failure is the index4/index5 snapshots lacking FFULL/OVR (receive-count lag).
One mechanism can produce both (a receive-side sub-bit mis-sampling/offset) but the parity
error should be checked directly before attributing.

Owner's L3FA753D0 reading verified with two corrections: their PCs are the loads (the
compares are 3FA76050/E0, 3FA761E0, 3FA76390); and the flag encoding is bit N = flag
+cN (proof: the +c6 store logs as val=0040 at the word a13(0xc0)), with the caveat that
the 32-bit return also spans a13+0xd0.
This commit is contained in:
SDD committed 2026-10-16 12:23:14 +03:00
1 parent d7725faa1e
commit 88d006730a
1 file changed
+69
+69
View File
@@ -896,3 +896,72 @@ status — minor, not biting; (4) `COUNTER_READY` set at the Start-Counter read
**Acceptance:** `HOST PORT - 15` still present. **Regression:** holds
(`PC=3FDCE400 samples=199`).
---
# WHO WRITES +0x3c0 / +0x3d0, AND WHAT L3FA71BC0 ACTUALLY CHECKS
Direct writer evidence from the transparent descriptor-area proxy
(`VT1200_STRUCTLOG`, `hp_struct.log`), not inference:
```
W 270C50 pc=3FA79E50 val=0004 / 0005 <- test +0x3c0 = ISR struct[idx4].0x3b0 (SRA snapshot)
W 270C60 pc=3FA7A3C0 val=0004 / 0007 <- test +0x3d0 = ISR index5 SRA snapshot
W 2708F0 pc=3FA796D0 val=0001 / 0021 <- test struct[i].0x60 = ISR struct[i].0x90 (SRA snapshot)
```
All three are written by the **DUART ISR `L3FA78D90`**, and only there:
* `3FA79E30`/`3FA7A3A0` are its **TxRDYA** path (`*a7(0x3b0) = window reg1`) — the
per-index SRA snapshot. So test `+0x3c0` = the snapshot at **index 4** and `+0x3d0` =
the snapshot at **index 5** (the test's descriptor is the ISR's descriptor **+0x30**, so
test `+0x3cN` == ISR `struct[idxN].0x3b0`). Bit 1 = FFULL, bit 4 = OVR.
* `3FA79690` is its **RxRDYA** path (`*a11(0x90) = window reg1`) — the received status for
each character. Test `struct[i].0x60` is exactly that field, which is why the `c6`
comparison sees `0x0001` / `0x0021`.
**So both sub-tests' failures are the ISR's *SRA snapshots*, and nothing else.**
## What `L3FA71BC0` checks (my own evidence)
Broken on all 18 of its flag-set sites (`hp_flags.lua`): **exactly one fires** — `c6`.
The comparison is `3FA73970 btst 5, a9` with `a9 = struct[i].0x60` (the ISR's received
status for character *i*), and `jreq` skips the set — so `c6` is set when **bit 5 is SET**.
SRA bit 5 is **PARITY ERROR**. Observed: `a9 = 0x0001` (no error) in most combinations,
and **`a9 = 0x0021` (= RxRDY | parity error) in 3 combinations**, which are the 3 times
`c6` fires.
So:
* `L3FA71BC0`'s remaining failure = a **PARITY ERROR in the received status**, in 3 of its
combinations (the parity-enabled `MR1` settings) — a *status* mismatch, not a timing one.
Its `c5` check (bit 6 = framing error) does **not** fire.
* `L3FA753D0`'s remaining failure = the ISR's index4/index5 snapshots lack **FFULL / OVR**
— a *receive-count* lag.
These are two different mismatches (one status, one count), both read from SRA by the ISR.
The single mechanism that could produce both is a receive-side mis-sampling/offset: a
sub-bit offset shifts character completion (-> FFULL/OVR missing) and can flip the parity
bit (-> parity error) while leaving the data bits correct (-> the RHRA compares still
pass). That keeps the measured ~1-bit write->receive offset (§ earlier) as the leading
candidate, but the parity error is a new, *testable* consequence of it and should be
checked directly before attributing.
## Owner's static reading of `L3FA753D0` — verified, with corrections
Correct on all substantive points (the four checks, the 144 = 4x3x3x4 nested sweep, the
CRA sequence, the per-check flags, and the index record at `+0xc4/c8/ca/cc` on failure).
Two corrections:
1. The PCs quoted are the **loads** (`3FA76030`, `3FA760C0`, `3FA76190`, `3FA76340`); the
actual comparisons are `3FA76050` (btst 4), `3FA760E0` (btst 1), `3FA761E0`
(andi 0xf0 / subk 16) and `3FA76390` (cmp).
2. Flag bit encoding confirmed: each flag is a **1-bit** field at bit address
`a13 + 0xc0 + N`, so the 32-bit return read gives **bit N = flag `+0xcN`**. Proof: the
`+0xc6` store shows up in the proxy as `W 001E30 pc=3FA739D0 val=0040` — bit 6 of the
word at `a13(0xc0)`.
*Caveat:* the 32-bit read also spans the word at `a13+0xd0` (bits 16-31). For
`L3FA71BC0` the return `0x00900040` has bits 20/23 set from *that* word, i.e. the return
carries adjacent frame data as well as flags — so "return == 0" is stricter than "all
checks pass" unless that word is zero. Worth confirming before treating `L3FA71BC0`'s
return as a pure flag word.