#!/usr/bin/env bash
# runInMameCycles.sh — measure emulated CPU time between START / DONE
# markers via MAME's emu.time().
#
# Usage: runInMameCycles.sh <binary> <iters>
#   binary: 65816 image to load at $00:1000
#   iters:  number of bench iterations the binary ran (used to
#           normalize delta to per-iteration cycles)
#
# The binary MUST:
#   1. Switch DBR to bank 2 (so the marker writes are observable
#      at $025000 / $025002 — bank 0 there is also fine but harder
#      to find atomically).
#   2. Write 0xA1A1 to $025000 *immediately before* the bench loop.
#   3. Write 0xA2A2 to $025002 *immediately after* the bench loop.
#   4. while(1){} after the DONE marker.
#
# Output (stdout):
#   MAME-CYCLES iters=N delta_us=... cyc_per_call=... start_us=... done_us=...
# Exit 0 on success, 1 on time-out / missing markers.
#
# IIgs CPU clock rate.  MAME's apple2gs starts in IIgs slow mode
# (1.023 MHz, IIe-compatible) until the IIgs ROM enables fast mode
# via $C036.  We're booting our binary directly without going through
# the ROM, so we stay in slow mode unless the binary itself writes
# $80 to $C036.  For the cycle harness we calibrate against slow
# mode (1023000 Hz) — both clang and Calypsi binaries run under
# the same emulator state, so the ratio is what matters.  If you
# want fast-mode numbers, have the bench wrapper enable it.

set -euo pipefail
source "$(dirname "$0")/common.sh"

BIN="$1"
ITERS="${2:-100}"
SECS=10
CLOCK_HZ=1023000

[ -f "$BIN" ] || die "binary not found: $BIN"

LUA_PATH=$(mktemp --suffix=.lua)
trap 'rm -f "$LUA_PATH"' EXIT

cat > "$LUA_PATH" <<EOF
local frame = 0
local loaded = false
local start_t = nil
local done_t = nil

emu.register_frame_done(function()
    frame = frame + 1
    local cpu = manager.machine.devices[":maincpu"]
    local mem = cpu.spaces["program"]

    if frame == 30 and not loaded then
        local f = io.open("$BIN", "rb")
        if not f then print("BIN-MISSING"); manager.machine:exit(); return end
        local data = f:read("*all"); f:close()
        for i = 1, #data do
            local addr = 0x001000 + i - 1
            if not (addr >= 0x00C000 and addr < 0x00D000) then
                mem:write_u8(addr, data:byte(i))
            end
        end
        loaded = true
        cpu.state["PC"].value = 0x1000
        cpu.state["PB"].value = 0x00
        cpu.state["DB"].value = 0x00
        cpu.state["D"].value  = 0x00
        cpu.state["P"].value  = 0x34
        cpu.state["E"].value  = 0
        cpu.state["S"].value  = 0x01FF
        print("MAME-LOADED bytes=" .. #data)
        return
    end

    if not loaded then return end

    -- Poll markers on every frame after load.  Capture emu.time()
    -- the first frame each marker appears.
    if not start_t and mem:read_u16(0x025000) == 0xa1a1 then
        start_t = emu.time()
        print(string.format("MAME-MARK START frame=%d t=%.9f", frame, start_t))
    end
    if start_t and not done_t and mem:read_u16(0x025002) == 0xa2a2 then
        done_t = emu.time()
        print(string.format("MAME-MARK DONE  frame=%d t=%.9f", frame, done_t))
        local delta = done_t - start_t
        local delta_us = delta * 1e6
        local cyc = delta * $CLOCK_HZ
        local per_call = cyc / $ITERS
        print(string.format("MAME-CYCLES iters=$ITERS delta_us=%.3f total_cyc=%.0f cyc_per_call=%.2f",
              delta_us, cyc, per_call))
        manager.machine:exit()
    end
end)
EOF

OUT=$(SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy timeout 60 mame apple2gs \
    -rompath "$PROJECT_ROOT/tools/mame/roms" \
    -plugins -autoboot_script "$LUA_PATH" \
    -video none -sound none -nothrottle -seconds_to_run "$SECS" 2>&1 | grep "^MAME-")

echo "$OUT"
if echo "$OUT" | grep -q "MAME-CYCLES"; then
    exit 0
fi
warn "no MAME-CYCLES output — markers not observed within $SECS sec"
exit 1
