#!/usr/bin/env bash # runInMameCycles.sh — measure emulated CPU time between START / DONE # markers via MAME's emu.time(). # # Usage: runInMameCycles.sh # 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" <= 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=$(timeout 60 mame apple2gs \ -rompath "$PROJECT_ROOT/tools/mame/roms" \ -plugins -autoboot_script "$LUA_PATH" \ -window -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