65816-llvm-mos/scripts/runMultiSeg.sh
Scott Duensing f542f4fa01 Checkpoint
2026-05-03 21:31:53 -05:00

127 lines
3.9 KiB
Bash
Executable file

#!/usr/bin/env bash
# runMultiSeg.sh — run a multi-segment program in MAME via a
# mini in-Lua loader. Reads the link816 manifest, loads each
# segment's image at its base address, sets PC to segment 1's
# entry, lets the program run, then reads check-address values.
#
# Usage: runMultiSeg.sh <manifest.json> [check args like runInMame.sh]
set -euo pipefail
source "$(dirname "$0")/common.sh"
MANIFEST="$1"
shift
SECS=3
# Build address list as Lua table entries, mirroring runInMame.sh.
LUA_CHECKS=""
EXPECT_LIST=()
ADDR_LIST=()
if [ "$1" = "--check" ]; then
shift
for pair in "$@"; do
ADDR="${pair%=*}"
EXP="${pair#*=}"
ADDR_LIST+=("$ADDR")
EXPECT_LIST+=("$EXP")
LUA_CHECKS="$LUA_CHECKS print(string.format('MAME-READ addr=0x%06x val=0x%04x', $ADDR, mem:read_u16($ADDR)))"$'\n'
done
else
ADDR="$1"
EXP="$2"
ADDR_LIST+=("$ADDR")
EXPECT_LIST+=("$EXP")
LUA_CHECKS="print(string.format('MAME-READ addr=0x%06x val=0x%04x', $ADDR, mem:read_u16($ADDR)))"
fi
[ -f "$MANIFEST" ] || die "manifest not found: $MANIFEST"
# Parse manifest with python (every machine has it). Emit a Lua
# table of (image_path, base, entry_offset_from_seg1).
PARSED=$(python3 - <<EOF
import json, os, sys
m = json.load(open("$MANIFEST"))
for s in m["segments"]:
base = int(s["base"], 16)
entry = int(s.get("entry_offset", "0x0"), 16) if s["num"] == 1 else 0
sz = s["size"]
print(f'{s["image"]}|{base}|{entry}|{sz}')
EOF
)
[ -n "$PARSED" ] || die "manifest parse failed"
LUA_PATH=$(mktemp --suffix=.lua)
trap 'rm -f "$LUA_PATH"' EXIT
# Build the per-segment load lua.
LOAD_LUA=""
ENTRY_BASE=0
ENTRY_OFF=0
while IFS='|' read -r img base entry sz; do
LOAD_LUA="$LOAD_LUA
do
local f = io.open('$img', 'rb')
if not f then print('SEG-MISSING $img'); manager.machine:exit(); return end
local data = f:read('*all'); f:close()
for i = 1, #data do
local addr = $base + i - 1
if not (addr >= 0x00C000 and addr < 0x00D000) then
mem:write_u8(addr, data:byte(i))
end
end
print('SEG-LOADED base=0x' .. string.format('%06x', $base) .. ' bytes=' .. #data)
end
"
if [ "$entry" != "0" ] || [ "$ENTRY_BASE" = "0" ]; then
ENTRY_BASE="$base"
ENTRY_OFF="$entry"
fi
done <<< "$PARSED"
cat > "$LUA_PATH" <<EOF
local frame = 0
local loaded = false
emu.register_frame_done(function()
frame = frame + 1
if frame == 30 and not loaded then
local cpu = manager.machine.devices[":maincpu"]
local mem = cpu.spaces["program"]
$LOAD_LUA
loaded = true
cpu.state["PC"].value = $ENTRY_BASE + $ENTRY_OFF
cpu.state["PB"].value = ($ENTRY_BASE >> 16) & 0xff
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-READY pc=0x' .. string.format('%06x', $ENTRY_BASE + $ENTRY_OFF))
end
if frame == 60 then
local cpu = manager.machine.devices[":maincpu"]
local mem = cpu.spaces["program"]
$LUA_CHECKS
manager.machine:exit()
end
end)
EOF
OUT=$(timeout 30 mame apple2gs \
-rompath "$PROJECT_ROOT/tools/mame/roms" \
-plugins -autoboot_script "$LUA_PATH" \
-window -sound none -nothrottle -seconds_to_run "$SECS" 2>&1 | grep -E "^(MAME-|SEG-)")
echo "$OUT"
mapfile -t GOT_LIST < <(printf '%s\n' "$OUT" | grep -oE 'val=0x[0-9a-f]+' | sed 's/val=0x//')
ok=1
for i in "${!EXPECT_LIST[@]}"; do
if [ "${GOT_LIST[$i]:-}" != "${EXPECT_LIST[$i]}" ]; then
warn "MAME mismatch at ${ADDR_LIST[$i]}: got 0x${GOT_LIST[$i]:-MISSING} expected 0x${EXPECT_LIST[$i]}"
ok=0
fi
done
if [ $ok -eq 1 ]; then
log "MAME (multi-seg) OK: ${#EXPECT_LIST[@]} reads matched"
exit 0
fi
exit 1