127 lines
4.8 KiB
Bash
Executable file
127 lines
4.8 KiB
Bash
Executable file
#!/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" <<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 field(port, name)
|
|
local p = manager.machine.ioport.ports[port]
|
|
if p == nil then return nil end
|
|
return p.fields[name]
|
|
end
|
|
local key_cmd = field(":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
|
|
|
|
local function report()
|
|
-- SHR pixels: \$E1/2000 .. \$E1/9CFF = 32000 bytes, 2 pixels/byte (4bpp).
|
|
local base = 0xE12000
|
|
local count = 32000
|
|
local seen = {}
|
|
local distinct = 0
|
|
local nonzero = 0
|
|
local sum = 0
|
|
for i = 0, count - 1 do
|
|
local b = mem:read_u8(base + i)
|
|
if b ~= 0 then nonzero = nonzero + 1 end
|
|
sum = (sum + b) & 0xFFFFFF
|
|
local hi = (b >> 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" </dev/null 2>&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
|