Put the container on the chip, and find the held bus costs 463 times the seam

ROADMAP P6c, FINDINGS 68. 78,125 B of a DLXP2's audio out of channel 3,
sample-exact, while the video channel fetches records off the same disc.

The two pieces 67.6 said were missing: the lump buffer (pg_afill/pg_afetch,
three slots and the minimum is unmeasured) and 67.2's remainder accumulator
(pg_apay). The capture prices what the accumulator avoided at 1.26 s of
lip-sync over the game, against 67.2's predicted 1.25.

The finding is the third piece, which nothing had named: the MSM6258 has no
starvation state, so the gap between a channel counting out and the next arm
is a held nibble pair driving the predictor. Stealing, the seam is 0.51 ms
over ten seconds because dma.i's new DM_HOOK services the chip from inside
the transfer wait -- 250,000 of 250,240 looks. Held, the 68000 is halted and
gets 369: every one of the ten lump boundaries has a seam, worst 72.8 ms,
2.31% of the audio. Identical bytes, different sound. 64.3 reaching the audio.

Two bugs, and no counter in the player could see either. Clearing DM_BARV does
not unchain a channel -- OCR bits 3-2 are what it obeys -- and the symptom is
POLL TIMEOUT on the lump and every record after it. And the refill ran one lump
ahead of its ring and overwrote the buffer the channel was reading: 11 of 11
armed, 11 fetched, no starve, and the sound wrong from 0.2 s in. Which is why
the gate is a WAV: verify_packed_audio.py walks the stream one delivered byte
at a time, because MAME's okim6258 resets the nibble select on every write and
a byte is two nibbles only 99.994% of the time.

check.sh ALL GREEN before (tmp/check_s36_start.log) and after
(tmp/check_s36_end.log), with the new stage.

Claude-Session: https://claude.ai/code/session_01194oWYW8DQXK1SZ2DnChW6
This commit is contained in:
prosolis
2026-08-25 13:11:37 -07:00
parent e3778f62b0
commit 191f2b47bb
13 changed files with 1413 additions and 20 deletions
+125
View File
@@ -1,3 +1,128 @@
# Status & next-session handoff — end of session 36 (2026-08-25)
## Session 36: the container is played, and holding the bus costs the audio
**Green light first and last: `./tools/bench/check.sh` was ALL GREEN before any
of this (`tmp/check_s36_start.log`) and ALL GREEN after
(`tmp/check_s36_end.log`)** — the same stages, plus one new one.
**FINDINGS 68. ROADMAP P6c is DONE.** `src/player/packed.s` (the audio path),
`src/player/dma.i` (`DM_HOOK`), `src/player/scsi.i`, `tools/encoder/adpcm.py`
(`decode_state`), `tools/bench/verify_packed_audio.py`,
`tools/bench/prep_packed.py`, `tools/bench/packed.lua`,
`tools/bench/packed_run.sh`, `tools/bench/check.sh`.
**NAME THE LAYER.** 68000 code fetched an interleaved DLXP2 off a real MB89352
volume, ran the video path against it, and fed the lumps to the **MSM6258 as
MAME models it** through the IPL ROM's own channel 3. The instrument is MAME's
`-wavwrite`. **No board ran.** What is new is that a byte of this container has
now been *heard* on some layer — 67.6 recorded that none had.
**1. IT PLAYS.** All **78,125 B** of the container's audio reached the chip, in
order, and every sample is exact against `adpcm.py` run with the four axes out
of the container's own header — **156,257 samples**, worst residual 1 count on
`signal = sample/8`. 11 of 11 lumps armed and fetched, 0 starves.
**2. THE HEADLINE, AND IT IS 64.3 ARRIVING ON THE AUDIO SIDE.** The chip has no
FIFO and **no starvation state**: when its channel counts out it goes on
decoding the byte its data register still holds. So the gap between a count-out
and the next arm is a **held nibble pair driving the predictor**, and it is in
the capture. Same container, same player, one bit of DCR:
| | stealing | held |
|---|---:|---:|
| service calls | 250,240 | 369 |
| boundaries with a seam | 4 of 10 | **10 of 10** |
| worst seam | 0.13 ms | **72.83 ms** |
| total replayed | 0.51 ms (0.005%) | **236.42 ms (2.31%)** |
| bytes wrong | 0 | 0 |
**The bytes are identical and the sound is not.** 673x fewer looks at the
channel, 463x the seam. And the reason stealing wins is `DM_HOOK`: **250,000 of
the 250,240 service calls came from inside dma.i's transfer wait**, which is the
only time a 68000 driving this video path has. Once a frame is a 90 ms seam by
construction, in either configuration.
**3. THE DRIFT IS MEASURED NOW.** `pg_apay` is 67.2's accumulator in a player,
and the capture prices what it avoided over the 10 lumps that carry a whole
group: 71,614 B against 71,680 B of lump space, **0.092%, 8.45 ms over 9.17 s ->
1.26 s over the game's 22.8 min. 67.2 predicted 1.25.** The accumulator ends at
1/24, where the arithmetic says.
**4. TWO BUGS, AND NEITHER IS VISIBLE FROM INSIDE THE PLAYER.** Clearing
`DM_BARV` does not unchain a channel — the register the channel obeys is OCR
bits 3-2 — and the symptom is POLL TIMEOUT on the lump *and every record after
it*, which reads like a disc problem. And the refill ran one lump too far ahead
and **overwrote the buffer channel 3 was reading**: 11 of 11 armed, 11 fetched,
78,125 B, no starve, and the sound wrong from 0.2 s in. That is 67.4's failure
mode on the audio side and it is why the gate is a WAV.
**5. THE RIG FACT THAT SHAPES THE GATE.** MAME's `okim6258::data_w` resets the
nibble select, and the DMA (7,812.5 B/s) and the stream (15,625 Hz) are
independent clocks — so a delivered byte is *usually* two nibbles and sometimes
one or three. Measured: **78,120 of 78,125 (99.994%)** were exactly two. So the
gate walks the stream **one delivered byte at a time**, and every stretched byte
in both runs was the last byte of a lump.
**RISKS IN THIS SESSION'S RESULT:**
- **Two slots was not tried.** Three lump slots and a prefill of two is what
ran; the minimum depth is unmeasured, so the RAM figure is an upper bound.
- **The seam milliseconds are the apparatus's**, set by how long the emulated
transport takes a record. The held/stealing RATIO is the finding.
- **Nothing has been listened to.** The capture is an instrument, not a listen.
- **The level is still open downward** (66.3) and the loudest passage on the
disc is still unmeasured. Unchanged since session 34.
- **The silicon is untouched.** All four axes are still MAME's.
## HANDOFF — start here
**THE TREE IS ALL GREEN**, session 36's stage included.
### The work, in the order it should be done
**1. THE AUDIO LEVEL, which 66.3 reopened and two sessions have now deferred.**
The 10-bit clamp is 12.1 dB below where the encoder was clamping and it is
INSIDE the recursion, so a scene that clips does not merely distort, it drives
the predictor. **Measure the loudest passage on the disc before choosing a
level.** This is the oldest open item in P6 and it needs no new machinery.
**2. THE REFILL CLIMB WITH A SECOND CONSUMER, through a real branch point**
(51.3, 55.4). The last quarter of P6 that is not P6c. The slack table is in
`32_audio_wire.py`; nothing has been run. Session 36 gives it the thing it was
missing — a player that actually holds two streams at once — so this is now a
matter of pointing it at a scene change rather than of building anything.
**3. THE BUFFERING DEPTH, which is cheap now.** `PG_ANBUF` is 3 and `PG_APRE` is
a mailbox. Two slots is one constant and one run, and it is 7,168 B of a
machine that has 99,328 B of record buffer to find elsewhere.
### What is still BLOCKED, so it is not picked up by mistake
**K4 — the packed player that is on screen — is conditional on B2**, a board
question. **E7, E4 and C1** are parked (61.8), and **P4a's wiring** is parked
with the ring K3 deleted.
**The hardware list is unchanged and is the user's**: B1 (sustained AND the
data-phase BURST rate, 64.2 — acceptance is **589.6 KB/s**), B2 (blanking), B3
(`#EXREQ`), B4 (a byte write to a palette register), and session 34's fifth:
play a known nibble stream on a real MSM6258V and record the line out. **Session
36 adds nothing to that list and strengthens the case for the fifth**: every
decoder axis the player now depends on is still MAME's.
### Reproducing this session
./tools/bench/check.sh # ALL GREEN
bash tools/bench/packed_run.sh tmp/packed_singe.dlxp
# run 5 is the audio gate, run 6 the held contrast
python3 tools/bench/verify_packed_audio.py tmp/packed_singe.dlxp \
tmp/packed_aud.wav tmp/packed_aud.json
**WHAT IS NEXT.** The level, and then the refill climb with the second consumer
that now exists.
---
# Status & next-session handoff — end of session 35 (2026-08-25)
## Session 35: the packed container gets sound, and the padding is drift