#!/usr/bin/env bash
# verify-x68000-input.sh - Headless typed-character acceptance gate for
# the X68000 port. Boots Human68k under the patched MAME with KEYS.X in
# AUTOEXEC.BAT, waits for the example's A5A5 sentinel to appear in
# GVRAM, types the RetroNet definition-of-done string on the emulated
# keyboard, and reads the verification scanline back out of GVRAM.
# KEYS encodes every character it received from jlInputGetChar as nibble
# pixel pairs, so the row must equal the typed ASCII exactly.
#
# GVRAM geometry (crtmod 13, 256-colour graphics plane): 16-bit word
# per pixel at $C00000, 512 words per row; the 320x200 stage is centred
# at origin (96, 156). Verification row = stage y 198 -> GVRAM y 354.
#
#   X68K_SCRATCH=<dir with x68mame/> bash scripts/verify-x68000-input.sh
set -uo pipefail

repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
SP="${X68K_SCRATCH:?set X68K_SCRATCH to a work dir containing x68mame/}"
MAME="$repo/toolchains/cache/mame-mame0264/x68k"
TEMPLATE="$SP/x68mame/HUMAN302.XDF"
WALL="${X68K_INPUT_WALL:-900}"

target="192.168.1.10:6510"

[ -x "$MAME" ] || { echo "verify-x68000-input: missing patched MAME at $MAME" >&2; exit 2; }
[ -f "$TEMPLATE" ] || { echo "verify-x68000-input: missing $TEMPLATE" >&2; exit 2; }
[ -f "$repo/build/x68000/bin/KEYS.X" ] || { echo "verify-x68000-input: build KEYS.X first (make -f make/x68000.mk)" >&2; exit 2; }

work=$(mktemp -d -t joey-x68input.XXXXXX)
trap 'rm -rf "$work"' EXIT

printf 'A:\\KEYS.X\r\n\x1a' > "$work/AUTOEXEC.BAT"
cp "$TEMPLATE" "$work/boot.xdf"
for f in USKCG.SYS BEEP.SYS KEY.SYS STARTUP.ENV; do
    python3 "$repo/tools/xdftool.py" delete "$work/boot.xdf" "$f" >/dev/null 2>&1
done
python3 "$repo/tools/xdftool.py" add "$work/boot.xdf" "$repo/build/x68000/bin/KEYS.X" KEYS.X >/dev/null || exit 1
python3 "$repo/tools/xdftool.py" add "$work/boot.xdf" "$work/AUTOEXEC.BAT" AUTOEXEC.BAT >/dev/null

cat > "$work/input.lua" <<LUA
local cpu = manager.machine.devices[":maincpu"]
local mem = cpu.spaces["program"]
local nat = manager.machine.natkeyboard
local frame = 0
local typedAt = 0
local done = false

-- Stage pixel (px, 198) -> GVRAM word at base + 2*px, value low byte.
local rowBase = 0xC00000 + ((156 + 198) * 512 + 96) * 2

local function pix(px)
    return mem:read_u8(rowBase + 2 * px + 1)
end

local function report()
    local bytes = {}
    for i = 0, 39 do
        bytes[#bytes + 1] = string.format("%02X", (pix(2 * i) << 4) | pix(2 * i + 1))
    end
    io.write(string.format("VERIFY-X68K-INPUT frame=%d typedAt=%d row=%s\n",
                           frame, typedAt, table.concat(bytes)))
    io.flush()
end

emu.register_frame_done(function()
    frame = frame + 1
    if done then return end
    if typedAt == 0 and frame > 600 and frame % 100 == 0 then
        -- KEYS is up once initialPaint stamped the A5A5 sentinel.
        if pix(0) == 0xA and pix(1) == 0x5 and pix(2) == 0xA and pix(3) == 0x5 then
            typedAt = frame + 60
        end
    end
    if typedAt ~= 0 and frame == typedAt then
        nat:post("$target")
    end
    if typedAt ~= 0 and frame >= typedAt + 3000 then
        done = true
        report()
        manager.machine:exit()
    end
    if frame > 30000 then
        done = true
        io.write("VERIFY-X68K-INPUT timeout: sentinel never appeared\n")
        io.flush()
        manager.machine:exit()
    end
end)
LUA

# Run from the work dir so MAME's cfg/ and nvram/ droppings land there
# instead of the caller's cwd.
cd "$work"
out=$(timeout -s KILL "$WALL" "$MAME" x68000 -bios ipl10 \
    -rompath "$SP/x68mame/roms" -flop1 "$work/boot.xdf" \
    -video none -sound none -nothrottle \
    -autoboot_script "$work/input.lua" </dev/null 2>&1) || true

line=$(echo "$out" | grep -E '^VERIFY-X68K-INPUT ' | tail -1)
echo "$line"
if [ -z "$line" ] || echo "$line" | grep -q timeout; then
    echo "verify-x68000-input: FAIL - KEYS never came up" >&2
    echo "$out" | tail -10 >&2
    exit 1
fi

row=$(echo "$line" | sed -E 's/.*row=([0-9A-Fa-f]+).*/\1/')
expect="A5A5"
expect+=$(printf '%02X' ${#target})
expect+="00"
expect+=$(printf '%s' "$target" | od -A n -t x1 | tr -d ' \n' | tr 'a-f' 'A-F')
got=${row:0:${#expect}}
if [ "$got" = "$expect" ]; then
    echo "verify-x68000-input: PASS (typed \"$target\", all ${#target} chars arrived via jlInputGetChar)"
else
    echo "verify-x68000-input: FAIL" >&2
    echo "  expected row prefix: $expect" >&2
    echo "  got:                 $got" >&2
    exit 1
fi
