forked from arti/vt1200
265 lines
12 KiB
Bash
Executable File
265 lines
12 KiB
Bash
Executable File
#!/bin/sh
|
|
# run-vidstream.sh -- build the streaming payload and run its MAME check.
|
|
#
|
|
# harness/mame/run-vidstream.sh # build, then mode alloc
|
|
# BENCH=0 harness/mame/run-vidstream.sh # use the existing .bin
|
|
# VT1200_MODE=rx harness/mame/run-vidstream.sh # alloc + the receive path
|
|
# VT1200_MODE=draw harness/mame/run-vidstream.sh # alloc + rx + the blit
|
|
# VT1200_MODE=stream harness/mame/run-vidstream.sh # the status back-channel
|
|
# VT1200_MODE=ring harness/mame/run-vidstream.sh # the RX ring's structure
|
|
# VT1200_MODE=dict harness/mame/run-vidstream.sh # dictionary upload + kinds
|
|
# VT1200_MODE=tiles harness/mame/run-vidstream.sh # the 32x32 tile blit
|
|
# VT1200_MODE=delta harness/mame/run-vidstream.sh # deltas and keyframes
|
|
# VT1200_MODE=replay harness/mame/run-vidstream.sh # the make_tiles.py clip
|
|
# STREAM_POOL_BYTES=0x7FFF000 harness/mame/run-vidstream.sh # force fallback
|
|
#
|
|
# Mode rx delivers one valid frame and one corrupted frame through the payload's
|
|
# own LANCE RX ring and asserts RX_OK == 1 && RX_BAD == 1 (see vidstream.lua and
|
|
# the task-7 report).
|
|
#
|
|
# Mode draw delivers one 128-row strip frame (stretch 8 = 1024 screen rows),
|
|
# lets the payload blit it, and dumps the screen and the delivered frame; this
|
|
# script then runs harness/mame/vidstream_check.py, which compares every screen
|
|
# row against its source row. The pixel verdict is the checker's, not the Lua's.
|
|
#
|
|
# Mode stream plays the sender: 200 strip frames, then RX_EOF so the terminal
|
|
# reports the final count. The payload takes the LANCE over for receive and
|
|
# transmit and builds a KIND_STATUS frame every 64 accepted frames; the Lua
|
|
# reads those frames back from the payload's own transmit buffer and this
|
|
# script runs harness/mame/vidstream_status_check.py, which decodes them with
|
|
# the host sender's wire format. There is no network in this run: the emulated
|
|
# LANCE has no interface (ruling R11), so the evidence is the buffer's bytes
|
|
# plus the completed descriptor, and the wire path needs the unit.
|
|
#
|
|
# Mode ring asserts the transport's structure: 16 descriptors armed with OWN set
|
|
# for slot A, a completed frame moving them to slot B, a header claiming more
|
|
# than SLOT_BYTES rejected without a blit (RX_BAD moves, RX_OK does not, the
|
|
# screen does not change), and a datagram the chip flags bad (RMD3 = 0, so it
|
|
# carries no bytes) counted in RX_FCS_DROP with its frame abandoned. The verdict
|
|
# is in the Lua; the evidence is $LOGDIR/ring-status.txt.
|
|
#
|
|
# Mode dict asserts the dictionary assembler and the kind dispatch: a TILES_FULL
|
|
# frame before the dictionary is rejected without painting, a 32 KB upload in 23
|
|
# KIND_DICT_CHUNK frames (with a duplicate offset and an overrunning tail chunk
|
|
# refused) makes DICT_READY 1 and DICT_BYTES 32,768, and the stored bytes are
|
|
# compared with what was sent. The verdict is in the Lua; the evidence is
|
|
# $LOGDIR/dict-status.txt.
|
|
#
|
|
# Mode tiles asserts the 32x32 tile blit: a 32 KB dictionary of row-varying
|
|
# entries is uploaded and read back, then one TILES_FULL frame (1,280 indices,
|
|
# a different dictionary entry at every corner) is delivered and painted. The
|
|
# Lua's verdict is the dispatch and the record; the PIXEL verdict is
|
|
# harness/mame/tile_check.py, which renders the screen the indices and the
|
|
# dictionary require and compares it with the VRAM dump. A wrong SPTCH in
|
|
# vram_tile.asm is the negative control: the frame is accepted and the pixels
|
|
# are wrong, which only the checker can see.
|
|
#
|
|
# Mode delta asserts the changed-tile list: a TILES_FULL keyframe is painted,
|
|
# then a one-tile TILES_DELTA must change exactly that 32x32 block and nothing
|
|
# else, with RX_OK/TILES_DROP/RX_LAST_LEN saying so. Two negative controls
|
|
# follow -- a delta naming a position off the 1,280-tile grid, and one whose
|
|
# count disagrees with its length -- and each must be refused (TILES_DROP, no
|
|
# RX_OK) with ZERO bytes of the screen changed; a good delta after them proves
|
|
# the refusal left no latch behind. The Lua holds the before/after dumps in
|
|
# memory and compares them itself: the assertion is a relation between two
|
|
# screens, not a rendering to re-derive, and it is why the first negative
|
|
# control's valid first entry matters (a decoder that painted as it decoded
|
|
# would have painted it). A last delta changes all 1,280 tiles (3,842 payload
|
|
# bytes: three datagrams), which is the only case where the count, the position
|
|
# list and the value list straddle a fragment boundary; every tile is compared
|
|
# with its new entry. Evidence: $LOGDIR/vram-delta-*.bin and delta-status.txt.
|
|
#
|
|
# Mode replay is Task 6's end-to-end check: it plays the cache make_tiles.py
|
|
# wrote (dictionary.bin + stream.bin) through the payload's own RX ring, one
|
|
# VS frame per clip frame, and dumps the 160 active bytes of every screen row
|
|
# after each one. This script then runs tile_check.py --replay, which decodes
|
|
# stream.bin with its own code, renders every frame through the dictionary and
|
|
# compares it with the dump. The pixels are the checker's verdict; the Lua's is
|
|
# the transport record (every frame accepted, none dropped, dictionary intact).
|
|
# The clip is synthetic: no Bad Apple source exists on this machine, and the
|
|
# script says so rather than implying otherwise.
|
|
#
|
|
# The run uses VT1200_SKIP_LEVEL1=1: the payload's heap is only initialised in
|
|
# the OS phase. In the diagnostics menu the free counter (0x1E8BA0) and the
|
|
# free-list head (0x1E8AC0) both read 0, so the malloc success path cannot be
|
|
# tested there. The skip is a documented divergence (harness/mame/README.md).
|
|
#
|
|
# Exit status: 0 only if vidstream.lua printed "VID: RESULT PASS" and, in draw
|
|
# or stream mode, the checker for that mode passed too.
|
|
set -eu
|
|
|
|
HERE=$(cd "$(dirname "$0")" && pwd)
|
|
ROOT=$(cd "$HERE/../.." && pwd)
|
|
MAME=${MAME:-/home/arti/code/k-space/mame0289/vt1200}
|
|
BENCH=${BENCH:-1}
|
|
MODE=${VT1200_MODE:-alloc}
|
|
LOGDIR=${LOGDIR:-/tmp/opencode}
|
|
LOG="$LOGDIR/vidstream-mame.log"
|
|
|
|
if [ ! -x "$MAME" ]; then
|
|
echo "run-vidstream.sh: no MAME binary at $MAME (set MAME=...)" >&2
|
|
exit 1
|
|
fi
|
|
if [ "$BENCH" != "0" ]; then
|
|
STREAM_POOL_BYTES=${STREAM_POOL_BYTES:-249856} \
|
|
"$ROOT/harness/udpstream/build-stream.sh"
|
|
fi
|
|
if [ ! -f "$ROOT/harness/udpstream/build/vidstream.bin" ]; then
|
|
echo "run-vidstream.sh: no build/vidstream.bin (run without BENCH=0)" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# POOL_BYTES / STATIC_PTR come from the image that was just built, so the check
|
|
# compares against the linked fallback address rather than a guess.
|
|
POOL_BYTES=249856
|
|
STATIC_PTR=0
|
|
ENTRY_PTR=0x018C0000
|
|
ENVFILE="$ROOT/harness/udpstream/build/vidstream.env"
|
|
if [ -f "$ENVFILE" ]; then
|
|
# shellcheck disable=SC1090
|
|
. "$ENVFILE"
|
|
fi
|
|
|
|
mkdir -p "$LOGDIR"
|
|
# Ruling R15: draw-mode evidence must come from THIS run. The Lua removes its
|
|
# own dump files at startup; removing them here as well means a run that dies
|
|
# before the script starts (or before it dumps) leaves no previous screen
|
|
# behind for vidstream_check.py to bless.
|
|
if [ "$MODE" = "draw" ]; then
|
|
rm -f "$LOGDIR/vram-draw.bin" "$LOGDIR/frame-draw.bin" \
|
|
"$LOGDIR/draw-status.txt"
|
|
fi
|
|
if [ "$MODE" = "stream" ]; then
|
|
rm -f "$LOGDIR/stream-status.bin" "$LOGDIR/stream-status.txt"
|
|
fi
|
|
if [ "$MODE" = "ring" ]; then
|
|
rm -f "$LOGDIR/ring-status.txt"
|
|
fi
|
|
if [ "$MODE" = "dict" ]; then
|
|
rm -f "$LOGDIR/dict-status.txt"
|
|
fi
|
|
if [ "$MODE" = "tiles" ]; then
|
|
rm -f "$LOGDIR/vram-tiles.bin" "$LOGDIR/dict-tiles.bin" \
|
|
"$LOGDIR/indices-tiles.bin" "$LOGDIR/tiles-status.txt"
|
|
fi
|
|
if [ "$MODE" = "delta" ]; then
|
|
rm -f "$LOGDIR/vram-delta-before.bin" "$LOGDIR/vram-delta-after.bin" \
|
|
"$LOGDIR/vram-delta-reject.bin" "$LOGDIR/vram-delta-recover.bin" \
|
|
"$LOGDIR/vram-delta-large.bin" "$LOGDIR/dict-delta.bin" \
|
|
"$LOGDIR/indices-delta.bin" "$LOGDIR/delta-status.txt"
|
|
fi
|
|
if [ "$MODE" = "replay" ]; then
|
|
# One dump per clip frame: the count comes from the stream, so a glob is
|
|
# the only way to be sure no previous run's frame survives (ruling R15).
|
|
rm -f "$LOGDIR"/vram-replay-*.bin "$LOGDIR/replay-status.txt" \
|
|
"$LOGDIR/dictionary.bin" "$LOGDIR/stream.bin" \
|
|
"$LOGDIR/tiles-manifest.json"
|
|
fi
|
|
# Absolute: the Lua runs with MAME's cwd, so a relative default only resolves
|
|
# when the caller happens to be at the repo root.
|
|
VID_PAYLOAD="$ROOT/harness/udpstream/build/vidstream.bin"
|
|
VID_TILE_DIR=${VID_TILE_DIR:-$ROOT/harness/udpstream/tiles}
|
|
if [ "$MODE" = "replay" ]; then
|
|
# The run's directory must be checkable on its own: the checker renders
|
|
# from these exact bytes, and a stale copy would be evidence of another
|
|
# stream (ruling R15).
|
|
cp "$VID_TILE_DIR/dictionary.bin" "$VID_TILE_DIR/stream.bin" "$LOGDIR/"
|
|
if [ -f "$VID_TILE_DIR/manifest.json" ]; then
|
|
cp "$VID_TILE_DIR/manifest.json" "$LOGDIR/tiles-manifest.json"
|
|
fi
|
|
fi
|
|
set +e
|
|
VT1200_SKIP_LEVEL1=1 \
|
|
VT1200_MODE="$MODE" \
|
|
VID_PAYLOAD="$VID_PAYLOAD" \
|
|
VID_DUMP_DIR="$LOGDIR" \
|
|
VID_POOL_BYTES="$POOL_BYTES" \
|
|
VID_STATIC_PTR="$STATIC_PTR" \
|
|
VID_ENTRY_PTR="$ENTRY_PTR" \
|
|
VID_TILE_DIR="$VID_TILE_DIR" \
|
|
"$MAME" vt1200 -rompath "$HERE/roms" -video none -sound none -nothrottle \
|
|
-skip_gameinfo -debug -debugger none \
|
|
-seconds_to_run "${VID_SECONDS:-120}" \
|
|
-autoboot_script "$HERE/vidstream.lua" -autoboot_delay 0 \
|
|
> "$LOG" 2>&1
|
|
STATUS=$?
|
|
set -e
|
|
|
|
grep '^VID:' "$LOG" || true
|
|
|
|
if [ "$STATUS" -ne 0 ]; then
|
|
echo "run-vidstream.sh: MAME exited $STATUS; log $LOG" >&2
|
|
tail -20 "$LOG" >&2
|
|
exit "$STATUS"
|
|
fi
|
|
if ! grep -q '^VID: RESULT PASS' "$LOG"; then
|
|
echo "run-vidstream.sh: check failed (log $LOG)" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# The pixel comparison is a separate, independent reading of the geometry
|
|
# (vidstream_check.py); a transport pass with the wrong picture is a failure.
|
|
if [ "$MODE" = "draw" ]; then
|
|
set +e
|
|
python3 "$HERE/vidstream_check.py" \
|
|
--vram "$LOGDIR/vram-draw.bin" \
|
|
--frame "$LOGDIR/frame-draw.bin" \
|
|
--status "$LOGDIR/draw-status.txt"
|
|
STATUS=$?
|
|
set -e
|
|
if [ "$STATUS" -ne 0 ]; then
|
|
echo "run-vidstream.sh: pixel check failed (log $LOG)" >&2
|
|
exit "$STATUS"
|
|
fi
|
|
fi
|
|
|
|
# The status frames are decoded by the host side's wire format, so the payload's
|
|
# encoder and frame.py cannot drift apart without failing here.
|
|
if [ "$MODE" = "stream" ]; then
|
|
set +e
|
|
python3 "$HERE/vidstream_status_check.py" \
|
|
--bin "$LOGDIR/stream-status.bin" \
|
|
--status "$LOGDIR/stream-status.txt" \
|
|
--frames "${VID_STREAM_FRAMES:-200}"
|
|
STATUS=$?
|
|
set -e
|
|
if [ "$STATUS" -ne 0 ]; then
|
|
echo "run-vidstream.sh: status check failed (log $LOG)" >&2
|
|
exit "$STATUS"
|
|
fi
|
|
fi
|
|
|
|
# The tile picture is a separate, independent reading of the geometry
|
|
# (tile_check.py renders the indices through the dictionary); a dispatch pass
|
|
# with the wrong picture is a failure. This is the check the SPTCH negative
|
|
# control is run against.
|
|
if [ "$MODE" = "tiles" ]; then
|
|
set +e
|
|
python3 "$HERE/tile_check.py" \
|
|
--vram "$LOGDIR/vram-tiles.bin" \
|
|
--dict "$LOGDIR/dict-tiles.bin" \
|
|
--indices "$LOGDIR/indices-tiles.bin" \
|
|
--status "$LOGDIR/tiles-status.txt"
|
|
STATUS=$?
|
|
set -e
|
|
if [ "$STATUS" -ne 0 ]; then
|
|
echo "run-vidstream.sh: tile check failed (log $LOG)" >&2
|
|
exit "$STATUS"
|
|
fi
|
|
fi
|
|
|
|
# The replay's picture is checked the same way: tile_check.py --replay reads
|
|
# the stream itself and renders every frame. A dispatch pass with a wrong
|
|
# picture is a failure, and so is a run whose dumps do not match the stream.
|
|
if [ "$MODE" = "replay" ]; then
|
|
set +e
|
|
python3 "$HERE/tile_check.py" --replay "$LOGDIR"
|
|
STATUS=$?
|
|
set -e
|
|
if [ "$STATUS" -ne 0 ]; then
|
|
echo "run-vidstream.sh: replay check failed (log $LOG)" >&2
|
|
exit "$STATUS"
|
|
fi
|
|
fi
|
|
exit 0
|