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
159 lines
8.6 KiB
Bash
Executable File
159 lines
8.6 KiB
Bash
Executable File
#!/bin/bash
|
|
# THE PACKED PLAYER, END TO END, OFF A REAL VOLUME. ROADMAP K3.
|
|
#
|
|
# tools/bench/packed_run.sh [container.dlxp]
|
|
#
|
|
# Four runs of src/player/packed.s, and each answers a different question. They
|
|
# are separate runs because the questions interfere: the write window has to be
|
|
# OPEN for the whole transfer and buffer mode blanks the graphics layer, so at
|
|
# the container's own 12 fps there is no instant at which a complete frame is
|
|
# displayable and the pixel gate has nothing to sample. Pacing slower opens a
|
|
# display interval without changing one byte of the transfer. Reporting the
|
|
# rate off the gate run instead would have been the flattering shortcut, and it
|
|
# reports the PACE rather than the disc -- the first cut of packed.lua did
|
|
# exactly that and printed 297 KB/s off a 6 fps run.
|
|
#
|
|
# 1. GATE, stealing, paced at half rate: 120 records, 120 snapshots, every one
|
|
# compared. A packed frame is a LITERAL, so unlike the codec's gate the last
|
|
# frame audits nothing and all 120 have to be checked (verify_packed.py).
|
|
# 2. RATE, stealing, FREE-RUNNING: the loop is transfer-bound, so the mean
|
|
# inter-frame IS the emulated transport's time for a record.
|
|
# 3. RATE, held, FREE-RUNNING: the same, with the bus held.
|
|
# 4. CLOCK, held, paced at the container's fps: what holding the bus does to a
|
|
# frame clock built on counting V-DISP interrupts.
|
|
#
|
|
# DLX_PK_GATE_ONLY=1 runs 1 alone. That is what tools/bench/check.sh takes: the
|
|
# green light's job is to catch a regression in the PLAYER, and runs 2-4 measure
|
|
# the apparatus rather than gate it -- three more MAME jobs for numbers that
|
|
# cannot change unless MAME does.
|
|
#
|
|
# THE APPARATUS is tools/bench/dma_run.sh's -- `x68000 -exp1 cz6bs1` and a
|
|
# zero-filled scsiexrom.bin on a private rompath -- and the volume is
|
|
# tools/bench/mkvol.sh's, which for a DLXP container is the container itself.
|
|
#
|
|
# WHAT NO RUN HERE MEASURES: `W`, and any rate a real medium would deliver.
|
|
# MAME's device models carry no transfer timing (docs/BENCHMARK.md, 42.5). What
|
|
# is measured is the SHAPE -- one channel start, 193 destinations, 120 times,
|
|
# on a clock the machine keeps itself, with every frame pixel-exact.
|
|
set -e
|
|
cd "$(dirname "$0")/../.."
|
|
DLXP=${1:-tmp/packed_singe.dlxp}
|
|
NFR=${DLX_PK_NFR:-120}
|
|
GATE_FPS=${DLX_PK_GATE_FPS:-6}
|
|
|
|
bash tools/bench/mkvol.sh "$DLXP"
|
|
python3 tools/bench/prep_packed.py "$DLXP"
|
|
# WHICH ORDER THIS CONTAINER USES, read out of the container rather than
|
|
# assumed. FINDINGS 62.5/63.4 priced palette-first and palette-last at -12.8 dB
|
|
# for one paint apiece and could not choose between them, so the format records
|
|
# it (dlxp.py flags bit 1) and BOTH have to pass this gate. The chain assertion
|
|
# below is the only place the difference is visible from outside the machine,
|
|
# and hard-coding either order there would turn "K3 ran both" into "K3 ran one
|
|
# and the other could not have failed".
|
|
PALLAST=$(sed -n 's/.*palette_last = \([01]\),.*/\1/p' tmp/packed_meta.lua)
|
|
if [ "$PALLAST" = "1" ]; then
|
|
CHAIN0='chain\[0\] = MAR \$C08000 MTC 256'
|
|
ORDER="palette LAST -- the 193rd entry"
|
|
else
|
|
CHAIN0='chain\[0\] = MAR \$E82000 MTC 512 ; chain\[1\] = MAR \$C08000 MTC 256'
|
|
ORDER="palette FIRST -- entry 0, then 192 rows"
|
|
fi
|
|
echo " container order: $ORDER"
|
|
tools/vasm/vasmm68k_mot -Fbin -o tmp/packed.bin src/player/packed.s > /dev/null
|
|
|
|
# One run. $1 names the log, the rest are environment.
|
|
run() {
|
|
local tag=$1; shift
|
|
rm -rf "tmp/snap_packed_$tag"; mkdir -p "tmp/snap_packed_$tag"
|
|
# stdbuf -oL: without it a long MAME run is unobservable until it exits, and a
|
|
# run that is merely finishing looks exactly like one that is wedged (34.1).
|
|
( cd tmp && env SDL_VIDEODRIVER=dummy "$@" stdbuf -oL timeout -k 5 900 \
|
|
mame x68000 -bios ipl10 -exp1 cz6bs1 \
|
|
-rompath "$HOME/mame/roms;./p4roms" -hard dlxpdisk.chd \
|
|
-ramsize 2M -video soft -window -sound none -nothrottle -plugins \
|
|
-autoboot_script ../tools/bench/packed.lua \
|
|
-snapshot_directory "./snap_packed_$tag" -snapview native \
|
|
-seconds_to_run "$SECS" > "packed_$tag.log" 2>&1 )
|
|
grep -aq "^\[PK\] done" "tmp/packed_$tag.log" || {
|
|
echo "FAIL: the $tag run did not finish -- no completion marker."
|
|
tail -12 "tmp/packed_$tag.log"; exit 1; }
|
|
grep -a "^\[PK\]" "tmp/packed_$tag.log" | sed 's/^\[PK\] / /'
|
|
}
|
|
fail() { echo "FAIL: $1"; exit 1; }
|
|
|
|
echo "--- 1. THE GATE: $NFR records, paced at $GATE_FPS fps, channel stealing ---"
|
|
SECS=$(( NFR / GATE_FPS + 25 ))
|
|
run gate DLX_PK_HELD=0 DLX_PK_PACE=1 DLX_PK_FPS=$GATE_FPS DLX_PK_NFR=$NFR
|
|
cp tmp/packed_snaps.csv tmp/packed_snaps_gate.csv
|
|
|
|
# THE ASSERTIONS. Printing a result and gating on it are different things.
|
|
grep -aq "^\[PK\] FLAG=\$FF" tmp/packed_gate.log || \
|
|
fail "the player did not reach the end of the scene. FLAG=\$E1 is a CRTC mode
|
|
the frame clock cannot divide, \$E2 is a transport failure -- and the
|
|
TRANSPORT FAILED line above names which."
|
|
grep -aq "array: the 68000 built 193 entries (the container wants 193)" \
|
|
tmp/packed_gate.log || \
|
|
fail "the 68000 built a chain of the wrong length. One entry short delivers a
|
|
picture with its last row missing, which looks like a decode bug and is a
|
|
layout bug; the container's geometry and the player's arithmetic are two
|
|
independent statements of one number and they have to agree."
|
|
grep -aq "$CHAIN0" tmp/packed_gate.log || \
|
|
fail "the chain does not have the shape this container asks for ($ORDER).
|
|
The crossing from the palette registers into GVRAM IS the packed frame
|
|
(FINDINGS 62) -- a palette entry and 192 row entries, one start, the CPU
|
|
halted throughout -- and an array built the other way round from the
|
|
record feeding it does not fail: it paints 192 rows of picture into the
|
|
palette registers and 512 B of palette across the top of the screen."
|
|
grep -aq "late frames (tick already past at the gate): 0$" tmp/packed_gate.log || \
|
|
fail "a frame missed its slot in the GATE run, which is paced at half rate on
|
|
purpose. That is not a rate result -- it means the transfer did not fit in
|
|
a slot twice as long as the container's, and the pixel comparison below is
|
|
then sampling frames the player was still overwriting."
|
|
|
|
grep -aq "0 frames NOT SAMPLED" tmp/packed_gate.log || \
|
|
fail "the gate run could not sample every frame: the write window reopened
|
|
before the snapshot on at least one. At half the container's rate the
|
|
transfer must fit inside the display interval with room to spare, and if
|
|
it does not the comparison below is checking frames the player was still
|
|
overwriting."
|
|
|
|
python3 tools/bench/verify_packed.py "$DLXP" --snap tmp/snap_packed_gate \
|
|
--map tmp/packed_snaps_gate.csv --min-frames "$NFR"
|
|
|
|
if [ "${DLX_PK_GATE_ONLY:-0}" = "1" ]; then exit 0; fi
|
|
|
|
echo
|
|
echo "--- 2/3. THE RATE: free-running, both channel configurations ---"
|
|
SECS=$(( NFR / 8 + 25 ))
|
|
run free_steal DLX_PK_HELD=0 DLX_PK_PACE=0 DLX_PK_NFR=$NFR
|
|
run free_held DLX_PK_HELD=1 DLX_PK_PACE=0 DLX_PK_NFR=$NFR
|
|
for t in free_steal free_held; do
|
|
grep -aq "FREE-RUNNING, so the mean IS the transport" "tmp/packed_$t.log" || \
|
|
fail "the $t run did not report a transport time, so there is no rate here
|
|
to read -- and a rate read off a PACED run is the pace."
|
|
done
|
|
|
|
echo
|
|
echo "--- 4. THE CLOCK: held, paced at the container's own rate ---"
|
|
SECS=$(( NFR / 12 + 25 ))
|
|
run held_paced DLX_PK_HELD=1 DLX_PK_PACE=1 DLX_PK_NFR=$NFR
|
|
# THE FINDING THIS RUN EXISTS FOR, asserted rather than admired. A held channel
|
|
# halts the 68000, and the frame clock is an INTERRUPT off V-DISP whose pending
|
|
# bit is ONE BIT -- so every edge that falls inside a transfer spanning two of
|
|
# them is an edge the machine can never count. If this ever comes back at zero,
|
|
# either the transfer got short enough to fit between two rasters or the held
|
|
# configuration stopped halting the CPU, and both change what the run means.
|
|
LOST=$(sed -n 's/.*-> \([0-9]*\) edges LOST.*/\1/p' tmp/packed_held_paced.log | head -1)
|
|
[ -n "$LOST" ] && [ "$LOST" -gt 0 ] || \
|
|
fail "the held run lost no V-DISP edges (${LOST:-none}). Either the bus is no
|
|
longer being held for the transfer, or the transfer now fits between two
|
|
rasters -- and the comparison with the stealing run below is then a
|
|
comparison of two configurations that do the same thing."
|
|
LOSTS=$(sed -n 's/.*-> \([0-9]*\) edges LOST.*/\1/p' tmp/packed_gate.log | head -1)
|
|
echo
|
|
echo " V-DISP edges lost: $LOST held at 12 fps, $LOSTS stealing at $GATE_FPS fps."
|
|
echo " A player keeps a clock, reads a stick and feeds ADPCM. Which of the two"
|
|
echo " configurations can do any of that is a DESIGN question, and it is the"
|
|
echo " one this run answers; neither figure is W."
|
|
exit 0
|