201 lines
7.9 KiB
Bash
Executable file
201 lines
7.9 KiB
Bash
Executable file
#!/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
|
|
# color.
|
|
#
|
|
# 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), color 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" <<LUA
|
|
local mem = manager.machine.devices[":maincpu"].spaces["program"]
|
|
local nat = manager.machine.natkeyboard
|
|
|
|
local FRAMES = $frames
|
|
local FIRST_LOOK = 3800 -- the Finder launch below is done by then
|
|
local SAMPLE_EVERY = 10 -- frames between lamp looks
|
|
local LAMP_STABLE = 3 -- looks in a row that must agree
|
|
local EXIT_SETTLE = 120 -- let the program settle before MAME writes the disk back
|
|
|
|
local LAMP_X, LAMP_Y, LAMP_W, LAMP_H = 128, 68, 64, 64
|
|
local PASS_COLOR, FAIL_COLOR, FILL_COLOR = 1, 2, 9
|
|
local MARGIN = 4 -- inside probes keep off the lamp's edge
|
|
local BESIDE = 8 -- outside probes sit this far off it
|
|
|
|
local frame = 0
|
|
local idx = 1
|
|
local seen = 0
|
|
local lamp = 0
|
|
local exitAt = 0
|
|
local done = false
|
|
|
|
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 keyCmd = 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 stagePixel(x, y)
|
|
local b = mem:read_u8(0xE12000 + y * 160 + (x >> 1))
|
|
if (x & 1) == 0 then return (b >> 4) & 0x0F else return b & 0x0F end
|
|
end
|
|
|
|
-- The lamp color when the whole lamp shows one verdict color 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
|