docs: enumerate the three remaining failing checks; record the transmit-start citation

Enumeration (measurement only): of the 18 flag-set sites in L3FA71BC0 and 4 in L3FA753D0,
exactly three fire -- L3FA71BC0 c6 (cmp 3FA73970 btst5 on struct[index].0x60; actual
0x0001/0x0009, bit5 clear) and L3FA753D0 c1/c0 (cmp 3FA760E0 btst1 / 3FA76050 btst4 on
the index4/index5 SRA snapshots; actual 0x05/0x07, FFULL and OVR clear).  All other
checks pass; cE is a summary flag, not a check.

Task 2 citation (for independent reading): SCN2681 p.7 "Data is transferred from the
holding register to transmit shift register when it is idle..." and p.22 "TxRDY sets at
the end of the 'start bit' time.  It is during the start bit that the data in the transmit
holding register is transferred...".  Neither states a bit-count latency; MAME measurably
inserts ~1 bit (RX sync = THRA write + 2605 cycles, bit = 2604).  Candidate deviation,
not written.

Full picture (established / ruled out / remaining discrepancy / open deviations) recorded
in DUART_REPORT.md.  Acceptance still fails; regression holds.
This commit is contained in:
SDD committed 2026-10-16 12:21:16 +03:00
1 parent 03e6a88b22
commit d7725faa1e
4 files changed
+170542

No files matched your search

+78
View File
@@ -818,3 +818,81 @@ Not banked; recorded as the open item.
* Console: `HOST PORT - 15` — **still present**; no next gate.
* Regression: `PC=3FDCE400 samples=199` — **holds**.
---
# ENUMERATION — the exact remaining failing checks (measurement only)
Broken on every flag-set site in both sub-tests (`hp_flags.lua`) and on the three
comparisons (`hp_vals.lua`), current tree (edit 1 reverted, edit 2 kept). Of the 18
flag-set sites in `L3FA71BC0` and 4 in `L3FA753D0`, **exactly three fire**; every other
check in both sub-tests passes:
| sub-test | flag | comparison PC | quantity / expected | actual |
|---|---|---|---|---|
| `L3FA71BC0` | `c6` | `3FA73970` `btst 5,a9` | bit5 of `struct[index].0x60` = 1 | `0x0001`, `0x0009` -> bit5 = 0 (3 passes; `0x0021` passes) |
| `L3FA753D0` | `c1` | `3FA760E0` `btst 1,a11` | bit1 (FFULL) of `struct+0x3c0` (index4 SRA snapshot) = 1 | `0x05` -> FFULL = 0 |
| `L3FA753D0` | `c0` | `3FA76050` `btst 4,a11` | bit4 (OVR) of `struct+0x3d0` (index5 SRA snapshot) = 1 | `0x07` -> OVR = 0 |
Note: `cE` (`3FA75060`) also fires once but it is a *summary* (it copies `*a13(0x40)` when
any earlier flag is set), not an independent check. So `L3FA71BC0` has **one** failing
condition and `L3FA753D0` has **two** — the two status-snapshot checks. The *direct*
SRA/RHRA reads in `L3FA753D0` pass (flags `c2`/`c3` do not fire).
Delta at the two snapshot checks: at index4 the FIFO holds 1-2 (needs 3 for FFULL) and at
index5 it holds 3 (needs 4 for OVR) — i.e. the receive count is one to two bytes behind
the transmit count at the comparison instants.
# TASK 2 — the transmit-start citation (for independent reading)
Question: *when does the fitted part begin transmitting after a character is loaded into
the THR of an idle transmitter?* The two sentences that bear on it
(`reference/duart-datasheet/SCN2681-transputer.txt`):
* p.7, "Transmitter Operation":
> "Data is transferred from the holding register to transmit shift register **when it is
> idle** or has completed transmission of the previous character. The TxRDY conditions
> are then asserted again which means one full character time of buffering is provided."
* p.22, "Transmitter Disable Note":
> "**TxRDY sets at the end of the 'start bit' time. It is during the start bit that the
> data in the transmit holding register is transferred to the transmit shift register.**"
Reading: "when it is idle" implies **no** waiting for a character boundary for an idle
transmitter (the transfer is immediate), and p.22 places the transfer *inside* the start
bit — so the start bit must already be running when the transfer happens, i.e. the first
bit begins at (or within a fraction of a bit of) the write. **Neither sentence states a
bit-count latency.** MAME measurably inserts ~1 bit: measured `RX sync = THRA write +
2605` cycles with a 2604-cycle bit (`hp_duart_cfg2.log` / `hp_irq_cfg2.log`). So the
candidate deviation is "MAME delays the first transmitted bit by ~1 bit", justified by
p.7's "when it is idle" — but that sentence does not by itself pin the number, so this
needs the independent read before it is written, exactly like the last two.
# FULL PICTURE (bound reached — stopping here)
**Established.**
* The quantity to zero is `L3FA6E4B0`'s return (all five descriptor fields = 0); verified
at the call site and at the handler (`0x400`).
* The IRQ wiring is required and correct (THRA 0 -> 20 writes/run); the direct SRA/RHRA
checks pass; the overrun-latch edit (edit 2) is confirmed and clears the `RXCHECK` flags
it targets.
* The exact three failing checks and their comparison PCs (table above).
**Ruled out.** external responder; FIFO depth (faithful); loopback-clock deviation as the
*cause* (phase-only, received bytes correct); the counter/COUNTER_READY (not in IMR, not
handled); INT1-vs-INT2 and the OP interrupt outputs (`L3FA78D90` ignores its mask arg;
OPCR/OPR cleared); character frame width (`MR1A=0x10` -> 5 bits matches the `0x1F` mask);
CSRA rate mismatch (TX == RX == 2400).
**Remaining discrepancy.** A ~0.5-1 bit transmit-start latency (above), which at the
snapshot boundaries shows up as a 1-2 byte receive lag. Measured numbers: THRA writes at
`t, t+0.3, t+1.0, t+2.0, t+3.0` char; RX completion at `write + 1.07 char`; snapshots at
the write instants.
**Open MAME deviations.** (1) transmit-start latency ~1 bit — *candidate, citation not
crisp, not written*; (2) loopback receive clock, SCN2681 p.12 item 2 — *real, not the
cause, not written*; (3) `write_CR` bit1 clears `RxRDY` where the datasheet preserves FIFO
status — minor, not biting; (4) `COUNTER_READY` set at the Start-Counter read — not biting;
(5) the pre-existing `tms34010` REFCNT local edit.
**Acceptance:** `HOST PORT - 15` still present. **Regression:** holds
(`PC=3FDCE400 samples=199`).
+23
View File
@@ -0,0 +1,23 @@
-- hp_flags.lua -- which check in each sub-test fails: break on every flag-set site.
local machine = manager.machine
local cpu = machine.devices[':maincpu']
local dbg = machine.debugger
if not dbg then print("ERROR: no debugger"); machine:exit(); return end
local function bp(addr, msg)
dbg:command('bpset ' .. addr .. ',,{ printf "FLAG ' .. msg .. '\\n" ; g }')
end
-- L3FA71BC0 flag-set sites (dis34 addresses)
bp("3fa73490","BC0/c0"); bp("3fa73520","BC0/c1"); bp("3fa735a0","BC0/c2"); bp("3fa73630","BC0/c3")
bp("3fa73830","BC0/c4"); bp("3fa738f0","BC0/c5"); bp("3fa739b0","BC0/c6"); bp("3fa73a70","BC0/c7")
bp("3fa73cb0","BC0/c8a"); bp("3fa73ee0","BC0/c9a"); bp("3fa74110","BC0/c9b"); bp("3fa743b0","BC0/c8b")
bp("3fa745c0","BC0/c9c"); bp("3fa74850","BC0/cA"); bp("3fa74a40","BC0/cB"); bp("3fa74f70","BC0/cC")
bp("3fa75000","BC0/cD"); bp("3fa75060","BC0/cE")
-- L3FA753D0 flag-set sites
bp("3fa76090","RX/c0"); bp("3fa76120","RX/c1"); bp("3fa76220","RX/c3"); bp("3fa763d0","RX/c2")
local n = 0
emu.register_frame_done(function()
n = n + 1
if n >= tonumber(os.getenv("HP_FRAMES") or "700") then print("done "..n); machine:exit() end
end, "vt1200-hp-flags")
dbg.visible_cpu = cpu
dbg.execution_state = 'run'
+170420
View File
File diff suppressed because it is too large. Load diff
+21
View File
@@ -0,0 +1,21 @@
-- hp_vals.lua -- actual values at the three failing comparisons.
local machine = manager.machine
local cpu = machine.devices[':maincpu']
local dbg = machine.debugger
if not dbg then print("ERROR: no debugger"); machine:exit(); return end
local function bp(addr, msg)
dbg:command('bpset ' .. addr .. ',,{ printf "' .. msg ..
' a7=%08X a9=%08X a11=%08X\\n", a7, a9, a11 ; g }')
end
-- L3FA71BC0: c6 -> btst 5 on struct[index].0x60 (set site 3FA739B0)
bp("3fa73970", "BC0/c6-cmp(btst5)")
-- L3FA753D0: c0 -> btst 4 on *a7(0x3d0); c1 -> btst 1 on *a7(0x3c0)
bp("3fa76050", "RX/c0-cmp(btst4)")
bp("3fa760e0", "RX/c1-cmp(btst1)")
local n = 0
emu.register_frame_done(function()
n = n + 1
if n >= tonumber(os.getenv("HP_FRAMES") or "700") then print("done "..n); machine:exit() end
end, "vt1200-hp-vals")
dbg.visible_cpu = cpu
dbg.execution_state = 'run'