65816-llvm-mos/scripts/snapDemo.sh
2026-05-25 21:00:32 -05:00

114 lines
4.7 KiB
Bash
Executable file

#!/usr/bin/env bash
# snapDemo.sh - boot a demo OMF in MAME and capture multiple SHR
# snapshots while it runs. Useful for verifying that a demo's window
# is actually drawn (vs the headless test which only checks the $99
# end-marker at $00:0070).
#
# Usage: bash scripts/snapDemo.sh <demo-name> [snap-frame-list]
# Default snap frames: 4800,5000,5200,5500,6000,6500.
# Optional env: SYSDISK=path/to/sys602.po (or other ProDOS .po).
#
# Snapshots land in a TMPDIR-rooted snapdir; the path is echoed at
# the end. The work disk image and Finder navigation script are
# cleaned up via trap.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
[ $# -ge 1 ] || { echo "usage: $0 <demo-name> [frames]" >&2; exit 2; }
BASE="$1"
FRAMES="${2:-4800,5000,5200,5500,6000,6500}"
CADIUS="${CADIUS:-$PROJECT_ROOT/tools/cadius/cadius}"
SYSDISK="${SYSDISK:-$PROJECT_ROOT/tools/gsos/sys602.po}"
OMF="$PROJECT_ROOT/demos/${BASE}.omf"
[ -x "$CADIUS" ] || { echo "cadius not found: $CADIUS" >&2; exit 2; }
[ -f "$SYSDISK" ] || { echo "sysdisk not found: $SYSDISK" >&2; exit 2; }
[ -f "$OMF" ] || { echo "OMF not found: $OMF (run demos/build.sh $BASE first)" >&2; exit 2; }
command -v mame >/dev/null || { echo "mame not in PATH" >&2; exit 2; }
WORK=$(mktemp -d -t snapDemo.XXXXXX)
SNAPDIR=$(mktemp -d -t snapDemoOut.XXXXXX)
trap 'rm -rf "$WORK"' EXIT
cp "$SYSDISK" "$WORK/disk.po"
"$CADIUS" CREATEVOLUME "$WORK/data.po" DATA 800KB >/dev/null
cp "$OMF" "$WORK/HELLO#B30000"
"$CADIUS" ADDFILE "$WORK/data.po" /DATA "$WORK/HELLO#B30000" >/dev/null
# Build lua steps[] entries for each requested snap frame.
SNAP_STEPS=""
for f in ${FRAMES//,/ }; do
SNAP_STEPS="${SNAP_STEPS} {${f}, function() manager.machine.video:snapshot(); print(string.format(\"SNAP-FRAME=${f}\")) end},
"
done
cat > "$WORK/launch.lua" <<LUA
local cpu = manager.machine.devices[":maincpu"]
local mem = cpu.spaces["program"]
local nat = manager.machine.natkeyboard
local frame = 0; local idx = 1
local function gf(p,n) local pp = manager.machine.ioport.ports[p]; return pp and pp.fields[n] end
local kcmd = gf(":macadb:KEY3", "Command / Open Apple")
local function press(f) if f then f:set_value(1) end end
local function release(f) if f then f:set_value(0) end end
-- ADB mouse input ports (set when PARK_MOUSE is enabled to scroll the
-- IIgs cursor out of the snapshot region — otherwise the Finder-left
-- cursor sits on the menu bar and the inverted-XOR cursor shape leaves
-- a visible dark square in the captured screen).
local mx = gf(":macadb:MOUSE1", "Mouse X")
local my = gf(":macadb:MOUSE2", "Mouse Y")
local park_active = ${PARK_MOUSE:-0}
local park_frame_start = 5500 -- after the Cmd-O that launches the demo
local park_frame_end = 5900 -- stop nudging once well off screen
local steps = {
{3300, function() nat:post("D") end},
{3540, function() press(kcmd) end},
{3546, function() nat:post("o") end},
{3600, function() release(kcmd) end},
{4200, function() nat:post("H") end},
{4500, function() press(kcmd) end},
{4506, function() nat:post("o") end},
{4560, function() release(kcmd) end},
${SNAP_STEPS}
{8500, function()
local count = 0
for o = 0, 31999 do
if mem:read_u8(0xE12000 + o) ~= 0 then count = count + 1 end
end
print(string.format("SHR-NONZERO=%d", count))
print(string.format("MAME-READ 0x70=%02x", mem:read_u8(0x70)))
print(string.format("MAME-READ 0x71=%02x", mem:read_u8(0x71)))
print(string.format("MAME-READ 0x72=%02x", mem:read_u8(0x72)))
print(string.format("MAME-READ 0x73=%02x", mem:read_u8(0x73)))
manager.machine:exit()
end},
}
emu.register_frame_done(function()
frame = frame + 1
-- Park the cursor at the right edge of the screen when PARK_MOUSE=1.
-- ADB mouse takes deltas, so push X for a window of frames and the
-- cursor scrolls right until the IIgs cursor manager clamps it at
-- the screen edge. Don't push Y — that moves the cursor INTO the
-- demo's content area (most demos sit in the upper screen, so a
-- downward-parked cursor lands ON visible content).
if park_active == 1 and mx and my and
frame >= park_frame_start and frame <= park_frame_end then
mx:set_value(100); my:set_value(0)
end
while idx <= #steps and frame >= steps[idx][1] do
steps[idx][2](); idx = idx + 1
end
end)
LUA
timeout 200 mame apple2gs -rompath "$PROJECT_ROOT/tools/mame/roms" \
-window -nothrottle -sound none \
-snapshot_directory "$SNAPDIR" \
-seconds_to_run 180 -flop3 "$WORK/disk.po" -flop4 "$WORK/data.po" \
-autoboot_script "$WORK/launch.lua" </dev/null 2>&1 | \
grep -E "MAME-READ|SHR-|SNAP-" || true
echo "snaps in: $SNAPDIR"
find "$SNAPDIR" -name '*.png' | sort