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
+126
View File
@@ -6949,3 +6949,129 @@ correct because Sharp wrote it.
DLXP2 would be built from, and no byte of one has been written.
- **What audio does to a scene change.** The slack table is here, but 51.3's
refill climb with a second consumer through a real branch point is not.
---
## 66. The chip is asked, and it disagrees with the encoder on all four axes — the largest of them is not the one we were worried about (session 34)
**ROADMAP P6a.** `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 drives the transport; the thing measured is
**MAME 0.277's `okim6258` device model**, end to end through the machine's real
DMA path. It settles the **rig** — an emulated audio test encoded against the
wrong model is 25 dB of nothing — and it does **not** settle the silicon. What a
real MSM6258V does is still a hardware/datasheet item.
### 66.0 A MAME source tree IS reachable from this machine, and 64.4 is struck
FINDINGS 64.4 and `tools/encoder/adpcm.py`'s header both record "no MAME source
tree is on this machine". There is no tree on disk, but the machine has network
and `raw.githubusercontent.com/mamedev/mame/mame0277/...` fetches. That is how
this session designed its experiment rather than swept blindly, and it is worth
recording because two sessions reasoned about MAME's device model as an
unopenable box when it was one `curl` away.
**It does not replace the measurement and did not become one.** The installed
binary is Ubuntu's 0.277 and the tag is upstream's; whether the two are the same
bytes is not something a fetch can say. Everything below is read out of a
capture from the binary that is actually here.
### 66.1 The transport is the IPL ROM's own, and it works first time
`src/player/adpcm.i` programs HD63450 **channel 3** with the bytes
`tools/analysis/21_iplrom_dmac.py` decodes out of the IPL ROM at `$FF0C2E` and
`$FF9A82`: `DCR = $80` (dual address, 8-bit port, cycle steal without hold),
`SCR = $04`, `MFC = DFC = $05`, `CPR = $01`, `DAR = $E92003`, `OCR = $32`
(memory→device, byte, **external request**), `CCR = $80`, then command `$02` to
`$E92001`. 839 bytes moved in **0.1074 s = 7,811.4 B/s** against the format's own
7,812.5, `CSR = $E0`, `CER = $00`, `MTC = 0`. **This is P6b's transport, not
scaffolding.**
**Two things session 33 could not have guessed and did not have to.** 65.5 fed
the chip from Lua, got silence, swept control 0..3 × port C 0..15 and stopped.
Both reasons are ordinary:
* **The PPI's port C is an INPUT until it is told otherwise.** ADPCM pan and the
sample-rate divider are port C bits; an i8255 out of reset has every port an
input, so writes to `$E9A005` move a latch nothing is reading. Control word
`$92` first, and only then does `$08` mean *pan both, ÷512*.
* **`$01` is COMMAND_STOP.** `$02` is PLAY. The sweep that "covered" 0..3 wrote
`$01` in the probe that swept port C, so the chip was never playing in it.
### 66.2 THE HEADLINE: four axes were wrong, and the expensive one is the NIBBLE ORDER
The probe is 1,678 nibbles — 16 zero nibbles of prologue, a trigger, an encoded
sine, then loud bursts — and `verify_adpcm_chip.py` searches **sixteen candidate
decoder models** (nibble feed × delta formula × clamp × initial accumulator)
crossed with three capture decimations and a prologue length. **Exactly one
reproduces the capture, over 1,678 consecutive samples, sample-exact**, and each
axis carries a negative control: flip it alone and the closest surviving
alternative disagrees on 826, 1,504, 156 and 1,522 samples respectively.
| axis | `adpcm.py` default | **the chip** | cost of getting it 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 *(on this window)* |
| accumulator at PLAY | 0 | **2** | 0.45 dB |
| **all four at once** | | | **10.38 dB** against 21.97 |
**65.2 named the wrong axis as the risk.** It priced the delta formula at 25 dB
and left nibble order recorded as "HIGH FIRST, **measured**". That measurement
was real and it was **against ffmpeg**, i.e. about the Dialogic VOX *file*
convention — not about what a chip does with a byte written to its data
register. The two are different questions with different answers, and the one
this port needs is the second. `verify_adpcm.py` keeps ffmpeg's parameters
deliberately: a reference check whose reference has been adjusted to agree is
not a check. `adpcm.CHIP` carries the measured set, and anything that encodes
**for the machine** passes it explicitly.
### 66.3 The clamp is 10-bit, it costs nothing here, and that is the finding that will bite
The MSM6258's D/A is 10-bit and the model clamps the **accumulator** there, so it
is inside the recursion rather than an output scaling. On the Singe window it is
free — encode for 12 bits or for 10 and the answer is **21.99 dB either way,
with zero samples on the clamp** — for one reason only: that window peaks at
**435 of 511**, i.e. **1.4 dB of headroom**, and it is a 13.4 dBFS passage.
A 10-bit accumulator is **12.1 dB smaller** than the 12-bit word the encoder was
clamping to. **65.1's "the level is not a lever" survives downward and is now
wrong upward**: normalising still buys nothing, and a passage a few dB louder
than this one does not fit. **Nothing in this project has measured the loudest
passage on the disc**, so the audio level is an open choice, not a settled one.
### 66.4 A rig fact that cost this session most of its time, and is worth the space
The 8 MHz ADPCM master clock is **CT1 in the YM2151's port register `$1B`**, in a
different device from the divider. MAME delivers that write to the ADPCM chip on
the **sound system's own schedule**, not at the instant of the store — so a
transfer started in the same breath as the setup plays its first ~17 ms at the
previous clock. The symptom is specific and misleading: the capture's first
~130 samples arrive in **exact identical pairs**, the rest do not, and **no model
fits a stream that changed rate part way through** — which reads exactly like a
broken probe. `adpcmgate.s` spins ~100 ms after `ad_setup` and says why. A
player sets its clock once at boot and never meets this.
**The general lesson is the one this tree keeps relearning**: a run that fails to
match is not evidence about the thing being measured until the apparatus has
been shown to be steady. Three quarters of the diagnosis here was spent
disproving hypotheses about the *chip* for a symptom that was about the *clock
write*.
### 66.5 What is still open, stated so it is not read as closed
* **The silicon.** Every value in 66.2 is MAME's. A real MSM6258V may differ on
any of the four, and the two published references already disagree on one.
This is a datasheet or a board, and it is cheap on a board: play a known
nibble stream and record the line out.
* **Nothing has played as audio.** The capture is a measurement instrument, not
a listening test, and no ADPCM has reached a speaker on real hardware.
* **The encoder is still greedy** (65 risk list, unchanged): exhaustive
per-sample search, no lookahead. 21.99 dB is this format's floor here.
* **P6b is now unblocked and its bytes are decided**: DLXP2 must be encoded with
`adpcm.CHIP`, and 65.3's cadence arithmetic (F=11, A=14, wire 582.0 → 589.6
KB/s) is untouched by any of this — it is a byte count, and none of the four
axes changes how many bytes a second the format needs.