#!/usr/bin/env bash
# bench-staxi-title.sh - Space Taxi title-screen logo cadence measurement
# (the PERF-AUDIT #3 acceptance test: the logo repaints via 103
# jlTilePasteMono calls, intended every 4th frame -- stRender.c
# titleAnimateLogo's `& 3u` divider mirroring the C64 original).
#
# Boots GS/OS under headless MAME with a WORK COPY of joey.2mg (must
# contain STAXI + its DATA tree; build with
#   JOEY_DISK_EXAMPLES="STAXI" scripts/make-iigs-disk.sh),
# launches STAXI via the standard Finder keystroke timeline, then
# samples 8 known logo tile cells from the SHR framebuffer EVERY frame.
# Each frame the sampled 256 bytes fold into a rolling hash; a hash
# change means the logo visibly changed on screen (the flip-book tile
# differs on every 4-frame step, so a healthy title changes every 4
# frames; a slow repaint stretches the observed period).
#
# Emits "STAXI-CHG frame=N sum=XXXXXX" per change, heartbeats, and a
# final verify-style summary. Post-process the change frames into
# periods with the analysis snippet in the acceptance report.
#
# Usage:   scripts/bench-staxi-title.sh [label]
#   MAME_ROMPATH        override ROM dir (default ~/.mame/roms)
#   STAXI_MAX_FRAMES    frame cap (default 15000)
#   STAXI_MAX_CHANGES   stop after this many logo changes (default 80)
set -euo pipefail

repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
: "${LLVM816_ROOT:?bench-staxi-title.sh: source toolchains/env.sh first}"
CADIUS="${CADIUS:-$LLVM816_ROOT/tools/cadius/cadius}"

sys_disk=$repo/toolchains/emulators/support/gsos-system.po
data_disk=$repo/build/iigs/bin/joey.2mg
rompath="${MAME_ROMPATH:-$HOME/.mame/roms}"
maxFrames="${STAXI_MAX_FRAMES:-15000}"
maxChanges="${STAXI_MAX_CHANGES:-80}"
label="${1:-run}"

for f in "$sys_disk" "$data_disk"; do
    [ -f "$f" ] || { echo "bench-staxi-title: missing $f" >&2; exit 2; }
done
if ! "$CADIUS" CATALOG "$data_disk" 2>/dev/null | grep -qE '^  STAXI +S16'; then
    echo "bench-staxi-title: STAXI not on joey.2mg (JOEY_DISK_EXAMPLES=\"STAXI\" scripts/make-iigs-disk.sh)" >&2
    exit 2
fi

work=$(mktemp -d -t joeylib-staxi.XXXXXX)
trap 'rm -rf "$work"' EXIT
cp "$sys_disk"  "$work/boot.po"
cp "$data_disk" "$work/joey.2mg"

cat > "$work/staxi.lua" <<LUA
local cpu = manager.machine.devices[":maincpu"]
local mem = cpu.spaces["program"]
local nat = manager.machine.natkeyboard
local frame = 0
local idx = 1

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 key_cmd = 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

-- 8 logo tile cells (bx,by) chosen from title.dat's 0x84 map: byte
-- offset in SHR = 0xE12000 + (by*8 + r)*160 + bx*4, 4 bytes per row.
-- Every repaint pastes a different flip tile into these cells, so
-- their content changes on every animation step.
local cells = { {6,1},{11,1},{24,1},{29,1},{12,7},{16,8},{12,9},{15,10} }
local function logoSum()
    local sum = 0
    for _, c in ipairs(cells) do
        local base = 0xE12000 + (c[2] * 8) * 160 + c[1] * 4
        for r = 0, 7 do
            local off = base + r * 160
            for b = 0, 3 do
                sum = (sum * 33 + mem:read_u8(off + b)) % 16777213
            end
        end
    end
    return sum
end

local steps = {
    {3000, function() nat:post("J") end},
    {3120, function() press(key_cmd) end},
    {3126, function() nat:post("o") end},
    {3180, function() release(key_cmd) end},
    {3540, function() nat:post("STAXI") end},
    {3660, function() press(key_cmd) end},
    {3666, function() nat:post("o") end},
    {3720, function() release(key_cmd) end},
}

local prevSum = -1
local nChanges = 0

local function summary(tag)
    local distinct = {}
    local nonzero = 0
    local checksum = 0
    for i = 0, 31999 do
        local b = mem:read_u8(0xE12000 + i)
        if b ~= 0 then nonzero = nonzero + 1 end
        distinct[b & 0x0F] = true
        distinct[(b >> 4) & 0x0F] = true
        checksum = (checksum + b) & 0xFFFFFF
    end
    local n = 0
    for _ in pairs(distinct) do n = n + 1 end
    io.write(string.format("STAXI-%s label=$label frame=%d changes=%d distinctNibbles=%d nonZeroBytes=%d checksum=%06X\n",
        tag, frame, nChanges, n, nonzero, checksum))
    io.flush()
end

emu.register_frame_done(function()
    frame = frame + 1
    while idx <= #steps and frame >= steps[idx][1] do
        steps[idx][2]()
        idx = idx + 1
    end
    if frame >= 3800 then
        local s = logoSum()
        if s ~= prevSum then
            io.write(string.format("STAXI-CHG frame=%d sum=%06X\n", frame, s))
            io.flush()
            prevSum = s
            nChanges = nChanges + 1
            if nChanges >= $maxChanges then
                summary("DONE")
                manager.machine:exit()
            end
        end
    end
    if frame % 1500 == 0 then
        io.write(string.format("STAXI-HEART frame=%d changes=%d\n", frame, nChanges))
        io.flush()
    end
    if frame >= $maxFrames then
        summary("TIMEOUT")
        manager.machine:exit()
    end
end)
LUA

echo "bench-staxi-title[$label]: running STAXI headless under MAME (cap $maxFrames frames, $maxChanges changes)..." >&2
cd "$work"
out=$(QT_QPA_PLATFORM=offscreen SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy \
    timeout "${STAXI_WALL_TIMEOUT:-900}" mame apple2gs \
        -rompath "$rompath" \
        -flop3 "$work/boot.po" -flop4 "$work/joey.2mg" \
        -video none -sound none -nothrottle \
        -autoboot_script "$work/staxi.lua" </dev/null 2>&1) || true

echo "$out" | grep -E '^STAXI-(CHG|HEART|DONE|TIMEOUT)' > "$repo/build/iigs/bin/staxi-title-$label.log" || true
tail -3 "$repo/build/iigs/bin/staxi-title-$label.log" >&2
lines=$(grep -c '^STAXI-CHG' "$repo/build/iigs/bin/staxi-title-$label.log" || true)
echo "bench-staxi-title[$label]: $lines change events -> build/iigs/bin/staxi-title-$label.log" >&2
