Two sessions, unrecorded until now, committed together because their edits share files and cannot be split cleanly after the fact. Session 28 (FINDINGS 60): the container is DLX5 -- every record sector-aligned, 120/120 starting on a boundary where 3/120 did, +0.48% on the wire and zero clocks -- and the ring's release rounds to RECALN so no pad is stranded. Two encoder levers measured and refused: `--spans all` buys +0.19 dB for +67% of the wire, and joint span/lam selection emits byte-identical containers because `lam` never leaves its floor on any of 120 frames. Session 29 (FINDINGS 61): the packed full-frame blit is 27.3% of a 12 fps frame, a channel fills GVRAM in buffer mode off the disc with the CPU halted, and it walks the 1,024 B line stride itself through array chaining. At the 9 clk/B dual-address floor the codec is 110.4% of a frame and a decoder-free packed literal player is 55.2%, at +4.89 dB -- 2.75 dB past a ceiling the codec's scene-wide palette cannot cross. Encoder work is parked; the codec is kept and not built on. check.sh is ALL GREEN before and after, plus one new stage that gates the ORDER of the measured paint costs rather than their values. Claude-Session: https://claude.ai/code/session_01194oWYW8DQXK1SZ2DnChW6
118 lines
6.6 KiB
Bash
Executable File
118 lines
6.6 KiB
Bash
Executable File
#!/bin/bash
|
|
# One HD63450 data-phase run: does the DMAC drive the SCSI data phase, and does
|
|
# it HOLD THE BUS? (ROADMAP P4a, the last item before M2.)
|
|
#
|
|
# tools/bench/dma_run.sh [container.dlx]
|
|
#
|
|
# The apparatus is tools/bench/scsi_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, the same bytes the host-file ring rig reads.
|
|
#
|
|
# WHAT A GREEN RUN MEANS: the same 2,048 B came off the disc three ways -- PIO,
|
|
# the channel with the bus held, the channel stealing cycles -- all three
|
|
# byte-exact against the host's copy; and in the held configuration THE WHOLE
|
|
# TRANSFER HAPPENED BETWEEN TWO INSTRUCTIONS, which is what holding the bus
|
|
# means and is not a claim about $EA0015 (57.3).
|
|
#
|
|
# WHAT IT DOES NOT MEAN: anything about `W`. MAME's DMAC runs on wall-clock
|
|
# attotimes (42.5) and models a held bus by HALTING the CPU rather than by
|
|
# charging it cycles per operand. This settles which configuration works.
|
|
set -e
|
|
cd "$(dirname "$0")/../.."
|
|
DLX=${1:-tmp/rc_fr_singe_scsi_span.dlx}
|
|
|
|
bash tools/bench/mkvol.sh "$DLX"
|
|
|
|
tools/vasm/vasmm68k_mot -Fbin -o tmp/dmagate.bin src/player/dmagate.s > /dev/null
|
|
|
|
# What the player will program, decoded out of the same constants it programs.
|
|
python3 tools/analysis/27_dmac_config.py
|
|
|
|
# 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 && SDL_VIDEODRIVER=dummy stdbuf -oL timeout -k 5 300 \
|
|
mame x68000 -bios ipl10 -exp1 cz6bs1 \
|
|
-rompath "$HOME/mame/roms;./p4roms" -hard dlxdisk.chd \
|
|
-ramsize 2M -video soft -window -sound none -nothrottle -plugins \
|
|
-autoboot_script ../tools/bench/dma.lua \
|
|
-seconds_to_run 90 > dma_run.log 2>&1 )
|
|
grep -aq "^\[DMA\] done" tmp/dma_run.log || {
|
|
echo "FAIL: the DMA gate did not finish -- no completion marker."
|
|
tail -8 tmp/dma_run.log; exit 1; }
|
|
grep -a "^\[DMA\]" tmp/dma_run.log | sed 's/^\[DMA\] / /'
|
|
|
|
# THE ASSERTIONS. Printing a result and gating on it are different things.
|
|
fail() { echo "FAIL: $1"; exit 1; }
|
|
grep -aq "BYTES OK: 2048 B from LBA 1000 .*\[pio\]" tmp/dma_run.log || \
|
|
fail "the PIO reference read did not match -- nothing below is about the DMAC."
|
|
grep -aq "BYTES OK: 2048 B from LBA 1000 .*\[held\]" tmp/dma_run.log || \
|
|
fail "the bus-held DMA read did not deliver the disc's bytes."
|
|
grep -aq "BYTES OK: 2048 B from LBA 1000 .*\[steal\]" tmp/dma_run.log || \
|
|
fail "the cycle-stealing DMA read did not deliver the disc's bytes."
|
|
grep -aq "MTC one instruction after START: 0 of 2048 .*NEVER EXECUTED .*\[held\]" \
|
|
tmp/dma_run.log || \
|
|
fail "the bus was NOT held: the CPU executed while the channel ran, so this is
|
|
not the configuration ROADMAP P4a asks for. That MTC is the whole of the
|
|
evidence that does not come from watching \$EA0015 (57.3)."
|
|
grep -aq "CPU trips round the wait loop: 1 \[held\]" tmp/dma_run.log || \
|
|
fail "the held configuration's CPU went round its wait loop more than once --
|
|
it was running, so the bus was not held for the whole transfer."
|
|
# A NEGATIVE ASSERTION IS WRITTEN AS AN `if`, not as `grep ... && fail`: under
|
|
# `set -e` a failing grep in an AND-list takes the whole script's exit status
|
|
# with it, so the run would report the failure it was looking for as a pass.
|
|
SPIN=$(sed -n 's/.*CPU trips round the wait loop: \([0-9]*\) \[steal\].*/\1/p' \
|
|
tmp/dma_run.log)
|
|
[ -n "$SPIN" ] && [ "$SPIN" -ge 100 ] || \
|
|
fail "the cycle-stealing configuration did not leave the CPU running (spin
|
|
= ${SPIN:-none}) -- the two configurations are meant to DIFFER in exactly
|
|
that, and a contrast of one against one is not a contrast."
|
|
if grep -aq "MTC one instruction after START: 0 of 2048 .*\[steal\]" tmp/dma_run.log
|
|
then
|
|
fail "the cycle-stealing configuration also finished between two instructions,
|
|
so the comparison has no contrast in it and the discriminator is measuring
|
|
something other than bus ownership."
|
|
fi
|
|
grep -aq "COC .*CER=\$00 MTC=0 .*(+2048) \[held\]" tmp/dma_run.log || \
|
|
fail "the held channel did not report a clean completion of every byte."
|
|
grep -aq "COC .*CER=\$00 MTC=0 .*(+2048) \[steal\]" tmp/dma_run.log || \
|
|
fail "the stealing channel did not report a clean completion of every byte."
|
|
# ---- the GVRAM run and its control (47.6.2). A channel that writes GVRAM in
|
|
# buffer mode is the decoder-free packed player's entire per-frame path, and a
|
|
# run with no control is 58.3's vacuous "UNDERRUNS: 0/120" again -- the IPL
|
|
# leaves R20 = $0B16, bit 11 ALREADY SET, so the first cut of this test could
|
|
# not have failed.
|
|
grep -aq "BYTES OK: 2048 B from LBA 1000 .*\[gvram\]" tmp/dma_run.log || \
|
|
fail "the channel did not fill GVRAM in buffer mode -- a device->GVRAM
|
|
transfer is the whole of the decoder-free packed player's frame."
|
|
grep -aq "R20 during the run = \$0916 (bit 11 SET)" tmp/dma_run.log || \
|
|
fail "the GVRAM run did not run in buffer mode with a KNOWN R20."
|
|
grep -aq "R20 during the run = \$0116 (bit 11 CLEAR)" tmp/dma_run.log || \
|
|
fail "the negative control did not run with bit 11 clear."
|
|
if grep -aq "BYTES OK: 2048 B from LBA 1000 .*\[masked\]" tmp/dma_run.log
|
|
then
|
|
fail "the MASKED control delivered every byte, so the run above is not a
|
|
measurement of R20 bit 11 -- it is a measurement of nothing."
|
|
fi
|
|
grep -aq "EXACTLY THE MECHANISM" tmp/dma_run.log || \
|
|
fail "the masked control lost bytes at ODD offsets too, or lost none at all.
|
|
The claim is not a COUNT -- stale GVRAM matches the disc by coincidence
|
|
wherever the record is pad -- it is a PLACE: gvram_w's 256-colour arm
|
|
drops what the channel wrote to EVEN addresses and stores what it wrote
|
|
to odd ones. Damage anywhere else is a different mechanism."
|
|
|
|
grep -aq "BYTES OK: 2048 B from LBA 1000 .*\[chain\]" tmp/dma_run.log || \
|
|
fail "the array-chained run did not put the bytes at the row bases its array
|
|
named. A picture row is 256 B of a 1024 B line stride, so a frame is 192
|
|
destinations; if the channel cannot walk them the CPU has to restart it
|
|
per row and the decoder-free path costs a per-row front end."
|
|
grep -aq "THE CHANNEL WALKED THE ARRAY ITSELF" tmp/dma_run.log || \
|
|
fail "the chained run did not report walking its own array."
|
|
|
|
grep -aq "WINDOWED DMA READ REFUSED" tmp/dma_run.log || \
|
|
fail "a WINDOWED read through the channel was not refused. 117 of 120 records
|
|
start part way into a sector (58.3), and a channel cannot drop the bytes
|
|
in front of one -- so it would write the neighbouring records into the
|
|
ring, over data the decoder has not finished with, with no bounds check
|
|
to catch it (49.2)."
|
|
exit 0
|