#!/usr/bin/env bash # runViaFinder.sh — boot real GS/OS 6.0.2 in MAME, drive Finder via # Lua keyboard automation to launch a user OMF, sample memory at # specific frames to verify the program executed. # # Usage: runViaFinder.sh [--data /DATA/NAME=local_file]... # --check =... # The OMF file is injected as /DATA/HELLO on a separate 800K data # disk; Lua drives Finder to open the Data volume and launch HELLO. # Each --data option also injects an arbitrary file (raw bytes) onto # the same disk under the given path — used for stdio smoke tests # that need a known file present at runtime. # # Memory checks happen at frame 5400 (~90s emulated, well after the # launch path completes) and exit 0 / 1 depending on whether each # requested address holds the requested value. # # Requires: # - tools/gsos/sys602.po (GS/OS 6.0.2 boot disk) # - /tmp/cadius/cadius (forked-file-aware ProDOS tool) # - mame apple2gs in PATH set -euo pipefail OMF="$1" shift [ -f "$OMF" ] || { echo "missing: $OMF" >&2; exit 2; } # Collect optional --data injections before --check. DATA_INJECTS=() while [ $# -gt 0 ] && [ "$1" = "--data" ]; do [ $# -ge 2 ] || { echo "usage: $0 [--data /DATA/NAME=path]... --check =..." >&2; exit 2; } DATA_INJECTS+=("$2") shift 2 done [ "${1:-}" = "--check" ] || { echo "usage: $0 [--data /DATA/NAME=path]... --check =..." >&2; exit 2; } shift PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" CADIUS=${CADIUS:-$PROJECT_ROOT/tools/cadius/cadius} SYSDISK=${SYSDISK:-$PROJECT_ROOT/tools/gsos/sys602.po} [ -x "$CADIUS" ] || { echo "cadius not found at $CADIUS" >&2; exit 2; } [ -f "$SYSDISK" ] || { echo "sysdisk not found at $SYSDISK" >&2; exit 2; } WORK=$(mktemp -d -t finderlaunch.XXXXXX) trap 'rm -rf "$WORK"' EXIT cp "$SYSDISK" "$WORK/disk.po" # Create a separate 800K data disk and put HELLO on it. Keeps the # boot disk untouched (and avoids the "20K free" limit on sys602.po # that fails for OMFs > ~15K). "$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 # Inject extra data files. Path syntax: /DATA/NAME=local_file. # Each gets type=$06 (BIN, generic data) so GS/OS treats it as a # plain file readable via gsosOpen. for inj in "${DATA_INJECTS[@]}"; do targetPath="${inj%=*}" srcPath="${inj#*=}" [ -f "$srcPath" ] || { echo "missing data injection source: $srcPath" >&2; exit 2; } # cadius ADDFILE uses the basename of the source as the on-disk name, # with #TTAAAAAA suffix selecting type+aux. Strip the leading # /VOL/ from targetPath to get the in-volume name. inVolName="${targetPath##*/}" cp "$srcPath" "$WORK/${inVolName}#060000" "$CADIUS" ADDFILE "$WORK/data.po" /DATA "$WORK/${inVolName}#060000" >/dev/null done LUA_CHECKS="" EXPECTS=() for pair in "$@"; do [ "$pair" = "--check" ] && continue addr="${pair%=*}"; val="${pair#*=}" EXPECTS+=("$pair") LUA_CHECKS="$LUA_CHECKS print(string.format('MAME-READ %s=%02x', '$addr', mem:read_u8($addr)))"$'\n' done cat > "$WORK/finder.lua" <= steps[idx][1] do steps[idx][2]() idx = idx + 1 end end) LUA OUT=$(timeout 150 mame apple2gs -rompath "$PROJECT_ROOT/tools/mame/roms" \ -window -nothrottle -sound none \ -seconds_to_run 130 -flop3 "$WORK/disk.po" -flop4 "$WORK/data.po" \ -autoboot_script "$WORK/finder.lua" &1) # Verify each expected value. fail=0 for pair in "${EXPECTS[@]}"; do addr="${pair%=*}"; want="${pair#*=}" line=$(echo "$OUT" | grep "MAME-READ $addr=" | tail -1) got=$(echo "$line" | sed -E 's/.*=([0-9a-f]+).*/\1/') # Compare numerically (handles case differences and 0x prefix variants). gotN=$(printf '%d' "0x$got" 2>/dev/null || echo -1) wantN=$(printf '%d' "$want" 2>/dev/null || echo -2) if [ "$gotN" = "$wantN" ]; then echo " $addr = 0x$got (want $want) ✓" else echo " $addr = 0x$got (want $want) ✗" fail=1 fi done exit $fail