Move the loader onto the 68000, and find 5,920 bytes nobody counted
src/player/load.i expands both codebooks to word-per-pixel form and packs the palette to GGGGGRRRRRBBBBBI out of the RAW container header, byte-exact against tools/bench/dlxload.py on both CPU cores. The palette half is gated on words read back out of the palette registers at $E82000, so "the words reached the hardware" is part of what passes. ROADMAP P1 is done; P2's encoder half (a reserved black entry, 23.4) is not, and is a re-encode rather than an edit. A scene change costs 18.96 ms of 68000 time, 22.8% of one 12 fps frame; boot costs 24.70 ms. The scratch tables describe the CRTC, not the scene, so pal_tables is a separate entry point built once at boot -- 5.29 ms off every scene change. The one that moves something: the scene header is 5,920 B that no rate table in this tree included, because it belongs to no frame record. In FINDINGS 51.3's currency it is divided by the surplus pipe - wire, so it is hypersensitive: 138 ms of extra refill climb at 488 KB/s and 1.099 s at 451.4 KB/s, for the same bytes. tools/analysis/22_scene_load.py prices it across explicit rates. Recorded as open: the two CPU cores agree to <3% on every stage but the table build, where they differ by 16.4%. px68k's C68K charges a flat 50 clocks for MULU/MULS (c68kmacro.h:1869) where the 68000 charges 38+2n, which explains 4,608 of the 8,703 clock gap. 4,095 clocks are unexplained. Nothing else in src/player/ multiplies, so no figure in FINDINGS 24-52 is affected. decode.s and stream.s are untouched; decode.bin is still 1,296 B at the same MD5. check.sh gains a stage that gates byte-exactness on both cores and deliberately does not gate the cycle counts -- MAME's clock is 1/55.46 s and a wall timing would make the green light host-sensitive. Claude-Session: https://claude.ai/code/session_01194oWYW8DQXK1SZ2DnChW6
This commit is contained in:
@@ -1,3 +1,93 @@
|
||||
# Status & next-session handoff — end of session 21 (2026-08-24)
|
||||
|
||||
## Session 21: the loader moves onto the 68000, and a scene change gets a price
|
||||
|
||||
**Green light first and last: `./tools/bench/check.sh` was ALL GREEN before any
|
||||
of this and ALL GREEN after**, 120/120 on both cores, no `TRUNCATED`, plus a new
|
||||
load-time stage.
|
||||
|
||||
**ROADMAP P1 is DONE and P2 is half done. FINDINGS 53.** Session 20's handoff
|
||||
named P4 as the item that decides the project, and P4 is **blocked in this
|
||||
tree** — re-checked, not assumed: there is still no `scsiexrom.bin` anywhere on
|
||||
this machine (`~/mame/roms/x68000.zip` holds six files, four IPLs, a cgrom and
|
||||
an sram), MAME's `x68000` has no MB89352 path, and `hd63450.cpp` decodes no
|
||||
DTYP. **Nothing here can measure W.** P1+P2 was the M2 item that could be built
|
||||
here, and it is the one that touches an already-measured number: it lands at a
|
||||
scene change, where FINDINGS 51.3's refill climb is.
|
||||
|
||||
**1. The transforms are on the 68000 and they are byte-exact.** `src/player/
|
||||
load.i` expands both codebooks to word-per-pixel form and packs the palette to
|
||||
`GGGGGRRRRRBBBBBI` with the shared LSB chosen per entry, out of the RAW
|
||||
container header. Gated **byte-for-byte against `tools/bench/dlxload.py`**,
|
||||
which stays the reference — what changed is where the transforms run, not what
|
||||
they produce. The palette half is read back **out of the palette registers at
|
||||
`$E82000`**, so "the words reached the hardware" is part of what passes. Both
|
||||
CPU cores emit the same 10,752 B. 53.1.
|
||||
|
||||
**2. A scene change costs 18.96 ms of 68000 time, 22.8% of one 12 fps frame.**
|
||||
Boot costs 24.70 ms. Split: codebooks 92,609 clocks, palette entries 97,019,
|
||||
scratch tables 52,919. Cross-checked on px68k's C68K, which agrees to 1.4% on
|
||||
the scene-change figure. 53.2.
|
||||
|
||||
**3. The scratch tables describe the machine, not the scene.** They are the
|
||||
CRTC's 6-to-8-bit rendering, its square, and the per-channel error difference —
|
||||
so `pal_tables` is a separate entry point, built once at boot. **5.29 ms off
|
||||
every scene change**, 22% of what a naive port of `dlxload.py` would have cost
|
||||
per scene. 53.3.
|
||||
|
||||
**4. THE ONE THAT MOVES SOMETHING: the scene header is 5,920 bytes nothing has
|
||||
ever counted.** Palette + CB1 + CB4, and it must arrive before frame 0 can be
|
||||
decoded. It is not part of any frame record, so no rate table in this tree
|
||||
includes it. `tools/analysis/22_scene_load.py` prices it across explicit rates.
|
||||
The whole fixed cost of a scene change is about **a third of one frame slot** —
|
||||
but its cost in FINDINGS 51.3's currency, accumulated slack, is divided by the
|
||||
surplus `pipe - wire` and so is hypersensitive: **138 ms of extra climb at 488
|
||||
KB/s, and 1.099 s at 451.4 KB/s**, for the same 5,920 bytes. 53.5.
|
||||
|
||||
**5. An instrument disagreement worth carrying forward.** The two CPU cores
|
||||
agree to <3% on every stage except the table build, where they differ by 16.4%
|
||||
— and that is the only code in this tree that multiplies. **px68k's C68K charges
|
||||
a flat 50 clocks for `MULU`/`MULS`** regardless of operand (`c68kmacro.h:1869`),
|
||||
where the 68000 charges 38+2n. That explains 4,608 of the 8,703 clock gap;
|
||||
**4,095 clocks are not explained and are recorded as open.** Nothing in
|
||||
`src/player/` outside these three instructions multiplies (checked), so no
|
||||
figure in FINDINGS 24-52 is affected — but the second opinion this tree leans on
|
||||
over-charges multiplies, and a future measurement containing one must not be
|
||||
taken from it uncorrected. 53.4.
|
||||
|
||||
**6. Shipping pre-expanded codebooks was considered and refused.** It would
|
||||
trade 9.26 ms of 68000 time for 5,120 more bytes in every scene header — 10.5 ms
|
||||
of pipe at 488 KB/s, and bytes that lengthen the climb. Close to a wash in
|
||||
milliseconds, not a wash in kind: the CPU is idle during a seek and the pipe is
|
||||
what this project is short of. **Derived, not measured.** 53.6.
|
||||
|
||||
**New in the tree:** `src/player/load.i` (the transforms) and
|
||||
`src/player/loadgate.s` (its front-end, 488 B); `tools/bench/prep_load.py`,
|
||||
`load.lua`, `verify_load.py`, `load_run.sh` (the rig, both cores);
|
||||
`tools/analysis/22_scene_load.py` (the pricing). `tools/bench/c68k/harness.c`
|
||||
gains a `--loadraw` mode, which also makes its flag-watch address a variable
|
||||
rather than a constant. `check.sh` gains a stage that gates byte-exactness on
|
||||
both cores, and deliberately does **not** gate the cycle counts — MAME's clock
|
||||
is 1/55.46 s and a wall timing would make the green light host-sensitive, the
|
||||
same reason `blit.s` and `span.sh` are not in it.
|
||||
|
||||
**`decode.s` and `stream.s` are unchanged.** Nothing in the per-frame path was
|
||||
touched; `decode.bin` is still 1,296 B at the same MD5.
|
||||
|
||||
**Still open in P2:** the encoder does not reserve a black entry (23.4), so the
|
||||
letterbox still gets the palette's closest thing to black (index 255 here). That
|
||||
half is encoder-side, it changes the container, and it moves every constant
|
||||
fitted to the gate container — a re-encode plus a re-measurement, not an edit.
|
||||
|
||||
**Next:** P3 (a real frame clock from the MFP or VBL) and P5 (per-record index,
|
||||
prefill policy, the accumulated-slack rule in the player rather than the rig)
|
||||
are both buildable here. G1 (import the scene graph) is the one that would let
|
||||
this tree ask a question it currently cannot: what is the worst gap between
|
||||
consecutive decision points, and does the refill climb survive it. P4 still
|
||||
decides the project and still cannot be measured here.
|
||||
|
||||
---
|
||||
|
||||
# Status & next-session handoff — end of session 20 (2026-08-24)
|
||||
|
||||
## Session 20: the DMAC configuration was in the IPL ROM the whole time
|
||||
|
||||
Reference in New Issue
Block a user