joeylib2/scripts/verify-x68000-tilebank.sh
2026-10-13 14:01:46 -05:00

174 lines
6.8 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-x68000-tilebank.sh - Tile-bank gate for the X68000: proves that
# assetbake's x68000 encoder (plane-major, like the Amiga's, under its own
# target byte) writes exactly the layout the X68000's native tile paste
# (src/m68k/planarTile.h via src/x68000/x68kTile.h) reads, and that the
# X68000 build refuses a bank baked for any other target.
#
# Boots Human68k headless under MAME with TILEBANK.X (examples/tilebank) and
# the DATA/tilebank make/x68000.mk staged from the host gate's fixture on a
# data disk in drive B. 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, logs one TILEBANK line and shows its verdict lamp. The Lua
# below waits for the lamp in text VRAM, then presses a key so the program
# exits -- Human68k only finalises joeylog.txt's directory entry when the
# program's stdio closes it -- and stops MAME. The line, extracted from the
# data disk, 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.
#
# Text-plane geometry (see verify-x68000-input.sh): four 1bpp planes 0x20000
# apart at 0xE00000, 128 bytes per row, leftmost pixel in bit 7, the 320x200
# stage centred at (96, 156). The lamp is examples/tilebank's: 64x64 at stage
# (128, 68), colour 1 for PASS and 2 for FAIL, with FILL_COLOR (9) either side
# of it on its rows.
#
# Usage: scripts/verify-x68000-tilebank.sh
# Env: TILEBANK_DATA_DIR stage this DATA/tilebank instead (negative controls)
# Requires: MAME, the X68000 firmware and CG ROM, a host cc;
# build/x68000/bin/TILEBANK.X and its DATA/tilebank (make x68000).
set -uo pipefail
repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
source "$repo/scripts/lib/joeyEnv.sh"
source "$repo/scripts/lib/tileBankGate.sh"
joeyNeed MAME mame
joeyNeed X68K_DIR x68kFirmware
joeyNeedFile "$X68K_DIR/roms/x68000/cgrom.dat" x68kCgrom
source "$repo/scripts/lib/x68kDisk.sh"
joeyNeedFile "$X68K_SYSTEM_DISK" x68kFirmware
binDir=$repo/build/x68000/bin
dataDir=$(tileBankData "$binDir")
wall=600 # hard cap on MAME, whatever happens to this script
frames=20000 # emulated frames before the Lua gives up on the lamp
tileBankNeedBuild "$binDir/TILEBANK.X" "$dataDir" "make x68000"
tileBankReference
work=$(mktemp -d -t joeylib-x68-tilebank.XXXXXX)
trap 'rm -rf "$work"' EXIT
# The boot disk carries only Human68k and AUTOEXEC; the program, its DATA and
# its log live on the data disk in B:, which AUTOEXEC makes current.
x68kBootDisk "$work/boot.xdf" 'B:' 'B:\TILEBANK.X' || exit 1
x68kDataDisk "$work/data.xdf" || exit 1
x68kXdf add "$work/data.xdf" "$binDir/TILEBANK.X" TILEBANK.X > /dev/null || exit 1
x68kAddTree "$work/data.xdf" "$dataDir" DATA/TILEBANK || exit 1
cat > "$work/tilebank.lua" <<LUA
local mem = manager.machine.devices[":maincpu"].spaces["program"]
local nat = manager.machine.natkeyboard
local FRAMES = $frames
local SAMPLE_EVERY = 10 -- frames between lamp looks
local LAMP_STABLE = 3 -- looks in a row that must agree
local KEY_EVERY = 60 -- frames between key presses once the lamp shows
local EXIT_SETTLE = 900 -- keypress -> jlShutdown -> stdio closes the log
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 seen = 0
local lamp = 0
local exitAt = 0
local done = false
local function stagePixel(px, py)
local x = 96 + px
local byteOff = (156 + py) * 128 + (x >> 3)
local bit = 0x80 >> (x & 7)
local v = 0
for plane = 0, 3 do
if (mem:read_u8(0xE00000 + plane * 0x20000 + byteOff) & bit) ~= 0 then
v = v | (1 << plane)
end
end
return v
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
emu.register_frame_done(function()
frame = frame + 1
if done then return end
if exitAt == 0 then
if 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-X68K lamp=%s f%d\n", (lamp == PASS_COLOR) and "PASS" or "FAIL", frame))
io.flush()
exitAt = frame + EXIT_SETTLE
end
end
else
if frame % KEY_EVERY == 0 then nat:post(" ") end
if frame >= exitAt then
done = true
manager.machine:exit()
end
end
if frame > FRAMES then
done = true
io.write("TILEBANK-X68K 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" && timeout -s KILL "$wall" "$MAME" x68000 -bios ipl10 \
-rompath "$X68K_DIR/roms" -flop1 "$work/boot.xdf" -flop2 "$work/data.xdf" \
-video none -sound none -nothrottle \
-autoboot_script "$work/tilebank.lua" < /dev/null 2>&1 | grep '^TILEBANK-X68K')
echo "${out:-TILEBANK-X68K: 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
if ! x68kXdf extract "$work/data.xdf" joeylog.txt "$work/joeylog.txt" > /dev/null 2>&1; then
echo "verify-x68000-tilebank: FAIL - no joeylog.txt on the data disk (the program never logged, or never exited)" >&2
exit 1
fi
tileBankJudge "$work/joeylog.txt" || exit 1
if [ "$lampOk" -eq 0 ]; then
echo "verify-x68000-tilebank: FAIL - the on-screen lamp did not show PASS" >&2
exit 1
fi