ROADMAP P5. The loader moved in session 21 and the frame clock in 22; the ring producer was the last policy living outside the machine. src/player/ring.i does `aligned` placement, the descriptor ring, a prefill, 51.2's slack rule and a seek, and the host keeps only the transport. It needed a container change. `aligned` asks whether the next record fits before the end of the ring -- a length asked BEFORE the record is fetched -- and every reader in this tree answered that by walking the frame stream, which is exactly what a player streaming off a disc cannot do. DLX4 carries nframes u16 record lengths in the scene header. Frame payloads are byte-identical to the DLX3 encode, so no fitted constant moves; the scene header goes 5,920 to 6,164 B. The producer reproduces the host's tiling exactly: 18 wraps, 14.7 KB mean hole, pixel-exact, a third independent implementation of the same policy. What it exposed is bigger than the item. A channel only moves bytes while it has a request and only the CPU can issue one, so the disc stands still between records by an amount the PLAYER sets, not the medium -- and no host-filled run could see it. At 488 KB/s in a 256 KB ring a one-deep request queue gives away 6.8% of the pipe and underruns 59 of 120 frames; two-deep gives away 3.4% and underruns none. The container's whole surplus over the wire is 8.7%, so the player's own loop was spending most of the slack a branch point saves up. Prefill is the weaker lever: six records of it still leaves 24 underruns. Three silent bugs are recorded in FINDINGS 55.7 -- all produced wrong pixels or a desync rather than a fault -- plus a rig one: MAME renders a screen line by line, so snapshotting the frame the decoder finished in captures a tear that reads exactly like a decoder bug. check.sh gains the machine-owned ring and a seek with the decode after it. decode.bin is unchanged at 1,296 B and a host-filled run executes none of the new code, so every FINDINGS 49/51 figure stands. ALL GREEN before and after. Claude-Session: https://claude.ai/code/session_01194oWYW8DQXK1SZ2DnChW6
60 lines
2.6 KiB
Python
60 lines
2.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Lay out the LOAD-TIME test: raw container header in, expected results out.
|
|
|
|
python3 tools/bench/prep_load.py <in.dlx> [--out tmp/load]
|
|
|
|
src/player/load.i does on the 68000 what tools/bench/dlxload.py has been doing
|
|
host-side since session 1: expand the two codebooks to word-per-pixel form and
|
|
pack the 24-bit palette into GGGGGRRRRRBBBBBI with the shared LSB chosen per
|
|
entry (ROADMAP P1 and P2). This writes both halves of that comparison.
|
|
|
|
<out>_data.bin the container's HEADER REGION, byte for byte as it comes
|
|
off the disc: magic, geometry, the three section offsets,
|
|
the 768-byte palette, CB1 and CB4. Nothing is pre-chewed --
|
|
that is the entire point. It ends where the frame stream
|
|
begins, so it is also exactly what a player would have to
|
|
read before it could draw anything.
|
|
<out>_expect.bin what dlxload.py says the 68000 must produce: expanded CB1,
|
|
expanded CB4, then 256 big-endian palette words.
|
|
<out>_meta.lua sizes, k1/k4, and the expected darkest-entry index.
|
|
|
|
The expectation is generated by the SAME module the two decode rigs load
|
|
through, so this cannot pass by agreeing with a second copy of the maths.
|
|
"""
|
|
import sys, argparse
|
|
sys.path.insert(0, "tools/encoder")
|
|
sys.path.insert(0, "tools/bench")
|
|
from dlx import DLX
|
|
import dlxload as DL
|
|
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("container")
|
|
ap.add_argument("--out", default="tmp/load")
|
|
a = ap.parse_args()
|
|
|
|
d = DLX(a.container)
|
|
if d.version < 3:
|
|
sys.exit(f"{a.container} is DLX{d.version}: load.i wants DLX3 or DLX4")
|
|
if d.idx_bytes != 1:
|
|
sys.exit("2-byte codebook indices: load.i expands one source byte per pixel")
|
|
|
|
off_frm = int.from_bytes(d.raw[28:32], "big")
|
|
raw = d.raw[:off_frm]
|
|
|
|
cb1, cb4 = DL.expand_codebooks(d)
|
|
palb, dark, _ = DL.pack_palette(d)
|
|
|
|
open(a.out + "_data.bin", "wb").write(raw)
|
|
open(a.out + "_expect.bin", "wb").write(cb1.tobytes() + cb4.tobytes() + palb.tobytes())
|
|
|
|
with open(a.out + "_meta.lua", "w") as fh:
|
|
fh.write("-- generated by tools/bench/prep_load.py -- do not edit\nreturn {\n")
|
|
fh.write(f" k1={d.k1}, k4={d.k4}, dark={dark},\n")
|
|
fh.write(f" raw_len={len(raw)}, cb1_len={cb1.nbytes}, cb4_len={cb4.nbytes},\n")
|
|
fh.write(f" pal_len={palb.nbytes},\n}}\n")
|
|
|
|
print(f"{a.container}: k1={d.k1} k4={d.k4}, header region {len(raw)} B "
|
|
f"(pal 768 + cb1 {d.k1*16} + cb4 {d.k4*4} + 32)")
|
|
print(f" the 68000 must produce {cb1.nbytes} + {cb4.nbytes} B of expanded "
|
|
f"codebook and {palb.nbytes} B of palette, darkest entry {dark}")
|