#!/usr/bin/env bash # verify-iigs.sh - Headless, deterministic visual-verification gate for the # IIgs port. Boots GS/OS under MAME, drives the Finder to launch one example # off the JOEYLIB data disk, then reads the Super Hi-Res framebuffer directly # out of emulated memory ($E1/2000..$E1/9CFF) and reports how many distinct # 4-bit pixel values were drawn plus a checksum. A blank/Finder screen yields # a tiny distinct count; a real rendered demo (pixels, lines, circles, flood # fills) lights up many of the 16 colors. # # Why memory reads instead of PNG snapshots: MAME's video:snapshot() needs a # real render target, which a headless `-video none` run does not have. Reading # the SHR bytes the asm actually wrote is render-target-independent and exact. # # Usage: scripts/verify-iigs.sh [example] [minDistinct] # example lowercase name (default: draw). Must be on joey.2mg (run # `make iigs-disk` first). The volume is JOEYLIB. # minDistinct PASS threshold for distinct nibble values (default: 4). # # Requires: toolchains/env.sh sourced; build/iigs/bin/joey.2mg built. set -euo pipefail repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) example=${1:-draw} minDistinct=${2:-4} NAME=${example^^} sys_disk=$repo/toolchains/emulators/support/gsos-system.po data_disk=$repo/build/iigs/bin/joey.2mg rompath="${MAME_ROMPATH:-$HOME/.mame/roms}" readFrame="${MAME_READ_FRAME:-9000}" for f in "$sys_disk" "$data_disk"; do [ -f "$f" ] || { echo "verify-iigs: missing $f (run 'make iigs-disk')" >&2; exit 2; } done work=$(mktemp -d -t joeylib-verify.XXXXXX) trap 'rm -rf "$work"' EXIT cp "$sys_disk" "$work/boot.po" cp "$data_disk" "$work/joey.2mg" # Finder keystroke timeline (frame counts calibrated against gsos-system.po): # select JOEYLIB volume (J), Cmd-O to open it, type the program name, Cmd-O to # launch. Then at readFrame, sum the SHR framebuffer and report. No -debug: we # drive input with natkeyboard and read memory via the program space directly, # and exit cleanly from Lua (so MAME never lingers). cat > "$work/verify.lua" <> 4) & 0x0F local lo = b & 0x0F if not seen[hi] then seen[hi] = true; distinct = distinct + 1 end if not seen[lo] then seen[lo] = true; distinct = distinct + 1 end end local scb0 = mem:read_u8(0xE19D00) io.write(string.format("VERIFY-IIGS name=$NAME frame=%d distinctNibbles=%d nonZeroBytes=%d checksum=%06X scb0=%02X\n", frame, distinct, nonzero, sum, scb0)) io.flush() end local steps = { {3000, function() nat:post("J") end}, {3120, function() press(key_cmd) end}, {3126, function() nat:post("o") end}, {3180, function() release(key_cmd) end}, {3540, function() nat:post("$NAME") end}, {3660, function() press(key_cmd) end}, {3666, function() nat:post("o") end}, {3720, function() release(key_cmd) end}, {$readFrame, function() report(); manager.machine:exit() end}, } emu.register_frame_done(function() frame = frame + 1 while idx <= #steps and frame >= steps[idx][1] do steps[idx][2]() idx = idx + 1 end end) LUA cd "$work" out=$(QT_QPA_PLATFORM=offscreen SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy \ timeout 300 mame apple2gs \ -rompath "$rompath" \ -flop3 "$work/boot.po" -flop4 "$work/joey.2mg" \ -video none -sound none -nothrottle \ -autoboot_script "$work/verify.lua" &1) || true line=$(echo "$out" | grep -E '^VERIFY-IIGS ' | tail -1) echo "$line" if [ -z "$line" ]; then echo "verify-iigs: FAIL - no framebuffer report (boot/launch failed)" >&2 echo "$out" | tail -15 >&2 exit 1 fi distinct=$(echo "$line" | sed -E 's/.*distinctNibbles=([0-9]+).*/\1/') if [ "$distinct" -ge "$minDistinct" ]; then echo "verify-iigs: PASS ($NAME rendered, distinctNibbles=$distinct >= $minDistinct)" else echo "verify-iigs: FAIL ($NAME distinctNibbles=$distinct < $minDistinct - screen looks blank)" >&2 exit 1 fi