Files
Dragon-s-Lair-X68k/tools/bench/prep_packed.py
T
prosolis 6f698ca226 Put the player on a real volume, and find the write window is the frame
ROADMAP K3. src/player/packed.s (2,898 B) brings up its own display, builds
its own 193-entry DMA chain, keeps its own frame clock off V-DISP and fetches
every record itself with READ(10) off a CZ-6BS1. The rig writes no picture
byte, no palette entry and no CRTC register.

120 of 120 frames pixel-exact, every one compared, in both palette orders --
the gate had to grow to do it, because a packed frame is a LITERAL and the
codec's recursion was what made one comparison audit 120.

And the write window turns out to be the frame. A packed write requires R20
bit 11, buffer mode blanks the layer, and a DMAC-direct player holds the
window open for the whole data phase, so

    dark fraction of a slot = record bytes / (DATA-PHASE rate x slot)

which is 1.0 at the container's own 582.0 KB/s: every frame delivered, on
time, pixel-exact, and none of them displayed. The rate in that expression is
the BURST rate, a third hardware number B1 has no test for. It reverses 61.5's
ranking -- a packed player that DMAs to RAM and paints with the measured 27.3%
blit is on screen 72.7% of every slot at any rate, and the two are equal only
at 2,131 KB/s = 3.7x the wire.

And a held channel costs the frame clock half its ticks without the clock
being able to tell: 487 of 1,038 V-DISP edges lost, zero late frames reported,
the player believing 12 fps while the screen ran at 6.37.

FINDINGS 64. ROADMAP K4 opened and fenced behind B2.
check.sh ALL GREEN before and after.

Claude-Session: https://claude.ai/code/session_01194oWYW8DQXK1SZ2DnChW6
2026-08-25 09:10:48 -07:00

58 lines
2.7 KiB
Python

#!/usr/bin/env python3
"""Everything tools/bench/packed.lua needs to know about a DLXP container.
python3 tools/bench/prep_packed.py <in.dlxp> -> tmp/packed_meta.lua
THERE IS NO BLOB TO PREPARE, and that is the whole difference from
`prep_stream.py`. The codec's rig has to hand the machine expanded codebooks, a
packed palette and a record index, because a DLX record cannot be found or drawn
without them; `prep_dlx.py` and `prep_stream.py` exist for that and FINDINGS
49.7.5 records what it cost to have two copies of one of those transforms. A
packed container carries no such thing: record `i` is at sector 1 + i*97 by
geometry and its bytes are already in the order GVRAM wants them (dlxp.py). So
this file emits METADATA ONLY -- six numbers the rig would otherwise have to
hard-code, every one of them read out of the container's own header.
The volume is the container itself; tools/bench/mkvol.sh copies it.
"""
import os, sys
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
"..", "encoder"))
from dlxp import DLXP, SECTOR
if len(sys.argv) != 2:
sys.exit(__doc__)
d = DLXP(sys.argv[1])
# The record's sector count, and the array chain's entry count, DERIVED here and
# asserted by the 68000 (PG_ARRN). Two independent statements of one geometry
# is the only way a container and a player can be caught disagreeing about it --
# a chain one entry short delivers a picture with its last row missing, which
# looks like a decode bug and is a layout bug.
recs = d.rec_bytes // SECTOR
rows = d.H
entries = rows + (1 if d.has_palette else 0)
out = "tmp/packed_meta.lua"
with open(out, "w") as fh:
fh.write("-- generated by tools/bench/prep_packed.py; do not edit\n")
fh.write("return {\n")
for k, v in [("W", d.W), ("H", d.H), ("fps", d.fps), ("nframes", d.nframes),
("rec_bytes", d.rec_bytes), ("rec_sectors", recs),
("pal_bytes", d.pal_bytes), ("pic_bytes", d.pic_bytes),
("lba0", d.off_frm // SECTOR),
("palette_last", int(d.palette_last)),
("has_palette", int(d.has_palette)),
("entries", entries)]:
fh.write(f" {k} = {v},\n")
fh.write("}\n")
print(f"{sys.argv[1]}: DLXP1 {d.W}x{d.H} {d.fps}fps {d.nframes} frames")
print(f" record {d.rec_bytes:,} B = {recs} sectors, palette "
f"{'LAST' if d.palette_last else 'FIRST'}, {d.pal_bytes} B")
print(f" record i is at LBA {d.off_frm // SECTOR} + i*{recs} -- ARITHMETIC. "
f"There is no index in this container and none can be needed.")
print(f" the chain the 68000 must build: {entries} entries "
f"({rows} rows{' + 1 palette' if d.has_palette else ''})")
print(f" wire {d.kbps():.1f} KB/s, FIXED by geometry -> {out}")