#!/usr/bin/env bash # Part of JoeyLib, Copyright (c) 2026 Scott Duensing, under the MIT License. # See LICENSE.md for license information. # SPDX-License-Identifier: MIT # # verify-iigs-tilebank.sh - Tile-bank gate for the Apple IIgs: proves that # assetbake's iigs encoder (chunky 4bpp, high nibble = left pixel) writes # exactly the layout the IIgs tile paste reads, and that the IIgs build # refuses a bank baked for any other target. # # Builds a one-example JOEYLIB disk (TILEBANK, examples/tilebank, with the # DATA/tilebank make/iigs.mk staged from the host gate's fixture), boots GS/OS # under headless MAME and launches TILEBANK from the Finder (verify-iigs- # save.sh's keystroke timeline). The program loads its own bake through # jlTileBankLoadToSurface and through jlTileBankLoad + jlTilePaste, checks # every pixel of both against the PNG, hashes both, tries every other # target's bake, writes one TILEBANK line to JOEYLOG.TXT (jlLogFlush: one # open/write/close) and only then shows its verdict lamp. The Lua below waits # for the lamp in the Super Hi-Res framebuffer and stops MAME; the line, # extracted from the work disk with cadius, must say PASS with both hashes # equal to the host gate's (scripts/check-tilebank.sh, run here for the # value) and every other target refused, and the lamp must be the PASS # colour. # # SHR geometry: 160 bytes per row at $E12000, high nibble = left pixel; the # stage is the whole 320x200 screen. The lamp is examples/tilebank's: 64x64 # at (128, 68), colour 1 for PASS and 2 for FAIL, with FILL_COLOR (9) either # side of it on its rows. # # Usage: scripts/verify-iigs-tilebank.sh # (make -f make/iigs.mk iigs-verify-tilebank builds what it needs first) # Env: TILEBANK_DATA_DIR stage this DATA/tilebank instead (negative controls) # Requires: ./install.sh install iigs; MAME with the apple2gs ROM and the GS/OS # system disk; a host cc; build/iigs/bin/TILEBANK and its # DATA/tilebank (staged in build/iigs/data/TILEBANK/DATA). set -uo pipefail repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) source "$repo/scripts/lib/joeyEnv.sh" source "$repo/scripts/lib/tileBankGate.sh" joeyNeed LLVM816_ROOT toolchain:iigs joeyNeed CADIUS cadius joeyNeed MAME mame joeyNeed IIGS_ROMPATH iigsFirmware joeyNeed GSOS_SYSTEM_DISK iigsFirmware binDir=$repo/build/iigs/bin dataDir=$(tileBankData "$repo/build/iigs/data/TILEBANK") wall=900 # hard cap on MAME, whatever happens to this script frames=24000 # emulated frames before the Lua gives up on the lamp tileBankNeedBuild "$binDir/TILEBANK" "$dataDir" "make -f make/iigs.mk iigs-verify-tilebank" tileBankReference work=$(mktemp -d -t joeylib-iigs-tilebank.XXXXXX) trap 'rm -rf "$work"' EXIT # make-iigs-disk.sh packs BINDIR's TILEBANK and its DATA, staged in # BINDIR/../data/TILEBANK/DATA, so a scratch BINDIR carries whichever # DATA/tilebank this run stages. mkdir -p "$work/bin" "$work/data/TILEBANK/DATA" "$work/log" cp "$binDir/TILEBANK" "$work/bin/" cp -r "$dataDir" "$work/data/TILEBANK/DATA/tilebank" BINDIR="$work/bin" JOEY_DISK_EXAMPLES="TILEBANK" "$repo/scripts/make-iigs-disk.sh" "$work/joey.2mg" > /dev/null || exit 1 if ! "$CADIUS" CATALOG "$work/joey.2mg" 2> /dev/null | grep -qE '^ +OWN\.TBK +BIN'; then echo "verify-iigs-tilebank: FAIL - the disk has no DATA/TILEBANK/OWN.TBK" >&2 exit 1 fi cp "$GSOS_SYSTEM_DISK" "$work/boot.po" cat > "$work/tilebank.lua" <> 1)) if (x & 1) == 0 then return (b >> 4) & 0x0F else return b & 0x0F end end -- The lamp colour when the whole lamp shows one verdict colour with -- FILL_COLOR on its rows either side, else 0. local function lampColor() local left = LAMP_X + MARGIN local right = LAMP_X + LAMP_W - 1 - MARGIN local top = LAMP_Y + MARGIN local bottom = LAMP_Y + LAMP_H - 1 - MARGIN local midY = LAMP_Y + LAMP_H // 2 local c = stagePixel(left, top) if c ~= PASS_COLOR and c ~= FAIL_COLOR then return 0 end for _, p in ipairs({ {right, top}, {left, bottom}, {right, bottom}, {LAMP_X + LAMP_W // 2, midY} }) do if stagePixel(p[1], p[2]) ~= c then return 0 end end if stagePixel(LAMP_X - BESIDE, midY) ~= FILL_COLOR or stagePixel(LAMP_X + LAMP_W - 1 + BESIDE, midY) ~= FILL_COLOR then return 0 end return c end -- Select the JOEYLIB volume, open it, select TILEBANK, open it. local steps = { {3000, function() nat:post("J") end}, {3120, function() press(keyCmd) end}, {3126, function() nat:post("o") end}, {3180, function() release(keyCmd) end}, {3540, function() nat:post("TILEBANK") end}, {3660, function() press(keyCmd) end}, {3666, function() nat:post("o") end}, {3720, function() release(keyCmd) end}, } emu.register_frame_done(function() frame = frame + 1 if done then return end while idx <= #steps and frame >= steps[idx][1] do steps[idx][2]() idx = idx + 1 end if exitAt == 0 then if frame >= FIRST_LOOK and frame % SAMPLE_EVERY == 0 then local c = lampColor() if c ~= 0 and c == lamp then seen = seen + 1 else seen = (c ~= 0) and 1 or 0 end lamp = c if seen >= LAMP_STABLE then io.write(string.format("TILEBANK-IIGS lamp=%s f%d\n", (lamp == PASS_COLOR) and "PASS" or "FAIL", frame)) io.flush() exitAt = frame + EXIT_SETTLE end end elseif frame >= exitAt then done = true manager.machine:exit() end if frame > FRAMES then done = true io.write("TILEBANK-IIGS no-lamp f"..frame.."\n") io.flush() manager.machine:exit() end end) LUA # From the work dir, so MAME's cfg/ and nvram/ never persist between runs. out=$(cd "$work" && QT_QPA_PLATFORM=offscreen SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy \ timeout -s KILL "$wall" "$MAME" apple2gs \ -rompath "$IIGS_ROMPATH" \ -flop3 "$work/boot.po" -flop4 "$work/joey.2mg" \ -video none -sound none -nothrottle \ -autoboot_script "$work/tilebank.lua" < /dev/null 2>&1 | grep '^TILEBANK-IIGS') echo "${out:-TILEBANK-IIGS: no report from the Lua (MAME died, or hit the ${wall}s cap)}" lampOk=1 if ! grep -q 'lamp=PASS' <<< "$out"; then lampOk=0 fi # cadius names the extracted file with its ProDOS type appended. "$CADIUS" EXTRACTFILE "$work/joey.2mg" "/JOEYLIB/JOEYLOG.TXT" "$work/log/" > /dev/null 2>&1 log=$(find "$work/log" -maxdepth 1 -iname 'joeylog.txt*' -print -quit) if [ -z "$log" ]; then echo "verify-iigs-tilebank: FAIL - no JOEYLOG.TXT on the work disk (the program never flushed its log)" >&2 exit 1 fi tileBankJudge "$log" || exit 1 if [ "$lampOk" -eq 0 ]; then echo "verify-iigs-tilebank: FAIL - the on-screen lamp did not show PASS" >&2 exit 1 fi