From 88d006730a38fe8d12522be2b40ce566dd700ec1 Mon Sep 17 00:00:00 2001 From: SDD Date: Fri, 16 Oct 2026 12:23:14 +0300 Subject: [PATCH] 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. --- harness/mame/DUART_REPORT.md | 69 ++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/harness/mame/DUART_REPORT.md b/harness/mame/DUART_REPORT.md index 23a2a63..379a320 100644 --- a/harness/mame/DUART_REPORT.md +++ b/harness/mame/DUART_REPORT.md @@ -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.