94 lines
3.4 KiB
Bash
94 lines
3.4 KiB
Bash
# Part of JoeyLib, Copyright (c) 2026 Scott Duensing, under the MIT License.
|
|
# See LICENSE.md for license information.
|
|
# SPDX-License-Identifier: MIT
|
|
#
|
|
# Shared by the PSP gates (scripts/bench-psp.sh, scripts/verify-psp-*.sh) and
|
|
# joey-run: run a PSP program (make psp: bin/NAME/EBOOT.PBP and its DATA)
|
|
# under PPSSPPHeadless, the installer's patched headless PPSSPP (ppsspp
|
|
# component, installer/patches/ppsspp). Source after joeyEnv.sh.
|
|
#
|
|
# PPSSPPHeadless keeps its memory stick in $HOME/.ppsspp, so it always runs
|
|
# with HOME pointing at a work folder: the program folder goes on that
|
|
# memory stick where a PSP keeps it, PSP/GAME/NAME, and runs from there
|
|
# (ms0:/PSP/GAME/NAME is its current directory, as on a PSP). Every run
|
|
# checks every memory access as a PSP does (--strict-mem, on the IR JIT,
|
|
# the core that checks alignment): an unaligned or wild access stops the
|
|
# program, and pspStrictCheck reports it.
|
|
#
|
|
# pspNeed exit 2 unless PPSSPPHeadless is installed
|
|
# pspStage WORK DIR copy the program folder DIR onto WORK's
|
|
# memory stick; prints the folder's path there
|
|
# pspRun WORK FOLDER SECS ARGS start the program in FOLDER (pspStage's) in
|
|
# the background for at most SECS seconds of
|
|
# real time, with PPSSPPHeadless's ARGS too;
|
|
# its output goes to WORK/ppsspp.log; sets
|
|
# PSP_PID
|
|
# pspWait wait for the run to end by itself
|
|
# pspStrictCheck WORK DIR 0 unless the run of the program folder DIR
|
|
# stopped at a bad memory access; then prints
|
|
# where, and the line psp-addr2line finds for
|
|
# it in the program's ELF (make/psp.mk keeps
|
|
# bin/NAME's in elf/NAME.elf)
|
|
# pspStop stop the run
|
|
|
|
PSP_PID=""
|
|
# Real seconds a run is given beyond SECS before it is killed outright.
|
|
PSP_KILL_GRACE=30
|
|
|
|
|
|
pspNeed() {
|
|
joeyNeed PPSSPP_HEADLESS emulator:psp
|
|
}
|
|
|
|
|
|
pspStage() {
|
|
local folder
|
|
folder="$1/.ppsspp/PSP/GAME/$(basename "$2")"
|
|
mkdir -p "$folder"
|
|
cp -r "$2/." "$folder/"
|
|
printf '%s\n' "$folder"
|
|
}
|
|
|
|
|
|
pspRun() {
|
|
local work="$1"
|
|
local folder="$2"
|
|
local seconds="$3"
|
|
shift 3
|
|
HOME="$work" timeout -s KILL "$((seconds + PSP_KILL_GRACE))" "$PPSSPP_HEADLESS" "$folder/EBOOT.PBP" --strict-mem --jit-ir --timeout="$seconds" "$@" > "$work/ppsspp.log" 2>&1 &
|
|
PSP_PID=$!
|
|
}
|
|
|
|
|
|
pspWait() {
|
|
wait "$PSP_PID" 2> /dev/null || true
|
|
PSP_PID=""
|
|
}
|
|
|
|
|
|
pspStrictCheck() {
|
|
local line
|
|
local pc
|
|
local elf
|
|
line="$(grep -m1 '^STRICT-MEM: ' "$1/ppsspp.log" 2> /dev/null)" || return 0
|
|
echo "$(basename "$0"): the program stopped at a bad memory access, as a PSP would:" >&2
|
|
sed -n '/^STRICT-MEM: /,/^$/p' "$1/ppsspp.log" >&2
|
|
pc="$(sed -n 's/.*, pc \([0-9a-f]*\)$/\1/p' <<< "$line")"
|
|
elf="$(dirname "$(dirname "$2")")/elf/$(basename "$2").elf"
|
|
if [ -n "$pc" ] && [ -f "$elf" ] && [ -n "${PSPDEV:-}" ]; then
|
|
echo " pc $pc: $("$PSPDEV/bin/psp-addr2line" -f -e "$elf" "0x$pc" | tr '\n' ' ')" >&2
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
|
|
pspStop() {
|
|
local child
|
|
if [ -n "$PSP_PID" ]; then
|
|
if child="$(joeyChild "$PSP_PID")"; then
|
|
joeyStop "$child"
|
|
fi
|
|
joeyStop "$PSP_PID"
|
|
fi
|
|
PSP_PID=""
|
|
}
|