Ask the chip which decoder it is, and find four wrong axes where one was expected

ROADMAP P6a, on the machine. 68000 code programs HD63450 channel 3 with the
IPL ROM's own ADPCM bytes -- dual address, 8-bit port, cycle steal, external
request -- and feeds the MSM6258 a designed 1,678-nibble stream at the chip's
own pace: 839 B in 0.1074 s = 7,811.4 B/s against the format's 7,812.5, CER=$00.
That transport is P6b's, not scaffolding.

Sixteen candidate decoder models, three capture decimations and a searched
prologue are fitted to MAME's capture. Exactly one reproduces it sample-exact
over all 1,678 samples, and every axis carries a negative control: flip it
alone and the closest survivor disagrees on 826, 1,504, 156 and 1,522 samples.

The chip runs 'terms', takes the LOW nibble of a byte first, clamps the
accumulator at 10 bits and starts it at -2. tools/encoder/adpcm.py defaulted to
the opposite of all four, and 65.2 named the wrong axis as the risk: the delta
formula is worth -2.88 dB and the NIBBLE ORDER is worth -25.74 dB. 65.1's "high
first, measured" was a measurement of ffmpeg, i.e. of the VOX file convention,
which is a different question from what a chip does with a byte in its data
register.

The 10-bit clamp is free on the Singe window and only because that window peaks
at 435 of 511 -- 1.4 dB of headroom on a -13.4 dBFS passage, 12.1 dB below where
the encoder was clamping, and inside the recursion. So the audio level is an
open choice again, downward, and the loudest passage on the disc is unmeasured.

Session 33's silence had two ordinary causes: the PPI's port C is an input until
control word $92 says otherwise, and $01 is COMMAND_STOP. And a rig fact worth
the space: the 8 MHz ADPCM clock is CT1 in the YM2151's $1B, delivered on the
sound system's schedule rather than at the store, so a transfer started in the
same breath as the setup plays its first ~17 ms at the old clock and no model
fits a stream that changed rate part way through.

Name the layer: this is MAME 0.277's okim6258 device model measured end to end
through the machine's real transport. It settles the rig and not the silicon.
Also struck: 64.4's "no MAME source tree is on this machine" -- there is none on
disk, but the machine has network and the upstream tag fetches.

check.sh ALL GREEN before (tmp/check_s34_start.log) and after
(tmp/check_s34_end.log), with one new stage.

Claude-Session: https://claude.ai/code/session_01194oWYW8DQXK1SZ2DnChW6
This commit is contained in:
prosolis
2026-08-25 09:50:03 -07:00
parent f925a1dd9a
commit 6dd3fb3597
15 changed files with 1240 additions and 22 deletions
+119 -1
View File
@@ -1,4 +1,122 @@
# Status & next-session handoff — end of session 33 (2026-08-25)
# Status & next-session handoff — end of session 34 (2026-08-25)
## Session 34: the chip is asked, and the encoder was wrong on four axes
**Green light first and last: `./tools/bench/check.sh` was ALL GREEN before any
of this (`tmp/check_s34_start.log`) and ALL GREEN after
(`tmp/check_s34_end.log`)** — the same stages, plus one new one.
**FINDINGS 66. ROADMAP P6a is DONE.** `src/player/adpcm.i`,
`src/player/adpcmgate.s`, `tools/bench/prep_adpcm.py`, `tools/bench/adpcm.lua`,
`tools/bench/adpcm_run.sh`, `tools/bench/verify_adpcm_chip.py`,
`tools/analysis/33_adpcm_model.py`.
**NAME THE LAYER.** 68000 code drove the transport; the thing measured is
**MAME 0.277's `okim6258` device model**, end to end through the machine's own
DMA path. No board ran. It settles the RIG and not the silicon.
**0. A MAME SOURCE TREE IS REACHABLE AND 64.4 IS STRUCK.** There is no tree on
disk, but this machine has network and the upstream tag fetches. Two sessions
reasoned about MAME's device model as an unopenable box when it was one `curl`
away. It designed the experiment; it did not become the result.
**1. THE TRANSPORT IS THE IPL ROM'S OWN AND IT WORKED FIRST TIME.** HD63450
channel 3, `DCR=$80 SCR=$04 MFC=DFC=$05 CPR=$01 DAR=$E92003 OCR=$32 CCR=$80`,
then `$02` to `$E92001` — every byte decoded out of the ROM by
`21_iplrom_dmac.py`. **839 B in 0.1074 s = 7,811.4 B/s** against the format's
7,812.5, `CSR=$E0 CER=$00 MTC=0`. **This is P6b's transport arriving early.**
Session 33's silence (65.5) had two ordinary causes and neither was a register
semantic worth guessing at: **the PPI's port C is an INPUT until control word
`$92` says otherwise**, so the pan/divider writes went to a latch nothing read;
and **`$01` is COMMAND_STOP**, which is what the port-C sweep wrote every time.
**2. THE HEADLINE, AND IT IS NOT THE AXIS 65 WAS WORRIED ABOUT.** Sixteen
candidate models, three capture decimations, a searched prologue: **exactly one
reproduces the capture over 1,678 consecutive samples, sample-exact**, and every
axis has a negative control.
| axis | `adpcm.py` default | the chip | wrong ALONE |
|---|---|---|---:|
| nibble order | high first | **LOW first** | **25.74 dB** |
| delta formula | `shift` | **`terms`** | 2.88 dB |
| clamp | 12-bit | **10-bit** | 0.00 dB (this window) |
| accumulator at PLAY | 0 | **2** | 0.45 dB |
| all four | | | **10.38 dB** against 21.97 |
**65.1's "nibble order: HIGH FIRST, measured" was true and was about ffmpeg**
the Dialogic VOX *file* convention — not about what a chip does with a byte in
its data register. `verify_adpcm.py` keeps ffmpeg's parameters on purpose; the
measured set is `adpcm.CHIP` and callers that encode FOR the machine pass it.
**3. THE 10-BIT CLAMP IS FREE HERE AND ONLY BY LUCK.** Encode for 12 bits or for
10 and the Singe window is **21.99 dB either way, zero samples on the clamp**
because it peaks at **435 of 511**, **1.4 dB of headroom**, on a 13.4 dBFS
passage. The clamp is **12.1 dB below** where the encoder was clamping and it is
INSIDE the recursion. **65.1's "the level is not a lever" survives downward and
is now wrong upward**, and **the loudest passage on the disc is unmeasured**.
**4. THE RIG FACT THAT COST THIS SESSION MOST OF ITS TIME.** The 8 MHz ADPCM
clock is CT1 in the YM2151's `$1B`, in a different device from the divider, and
MAME delivers it on the sound system's schedule rather than at the store. A
transfer started in the same breath as the setup plays its first ~17 ms at the
old clock; the capture's first ~130 samples come out in **exact identical
pairs** and no model fits a stream that changed rate part way through — which
reads exactly like a broken probe. `adpcmgate.s` settles ~100 ms and says why.
**RISKS IN THIS SESSION'S RESULT:**
- **The silicon is untouched.** All four values are MAME's. A real MSM6258V may
differ on any of them, and the two published references already disagree on
one. Cheap on a board: play a known nibble stream, record the line out.
- **Nothing has played as audio.** The capture is an instrument, not a listen.
- **The encoder is still greedy** — no lookahead, unchanged from 65.
- **The 10-bit clamp is a ceiling nobody has measured the disc against.**
## HANDOFF — start here
**THE TREE IS ALL GREEN**, session 34's stage included.
### The work, in the order it should be done
**1. P6b — DLXP2, a container with sound in it.** Unblocked, and its bytes are
now decided: encode with **`adpcm.CHIP`** (`terms`, low nibble first, 10-bit,
init 2), not with the defaults. 65.3 is all the arithmetic and none of it
moved — cadence **F=11, A=14**, `LBA(i) = LBA0 + i*97 + floor(i/11)*14`,
14,336 B held, wire **582.0 → 589.6 KB/s** — because a byte count does not care
which decoder reads the bytes.
**2. THE AUDIO LEVEL, which 66.3 reopened.** The encoder now has 12.1 dB less
room than it thought. Measure the loudest passage on the disc before choosing a
level; a scene that clips inside the recursion does not merely distort, it
drives the predictor.
**3. WHAT IS LEFT OF P6 AFTER THAT** is the fourth quarter: 51.3's refill climb
with a second consumer through a real branch point. The slack table is in
`32_audio_wire.py`; nothing has been run.
### 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), B2 (blanking — the five-minute half), B3
(`#EXREQ`), B4 (a byte write to a palette register). **Session 34 adds a fifth
that is cheaper than any of them**: play a known nibble stream on a real
MSM6258V and record the line out, which settles 66.2's four axes on silicon.
### Reproducing this session
./tools/bench/check.sh # ALL GREEN
./tools/bench/adpcm_run.sh # the chip gate on its own
python3 tools/analysis/33_adpcm_model.py tmp/au_singe.raw
**WHAT IS NEXT.** P6b: a container with sound in it, encoded for the chip that
was just measured.
---
## Session 33: audio gets an encoder, and the packed container's best property gets a bill