Files
vt1200/apps/termtris/build.sh
T
opencode.energia.arti.ee 7a2cef56ad fix(termtris): review pass -- seed, focus/pause, expose, test assertions
- seed the game from the raw 0x1E93C0 counter (now_ms() returns 0 on its
  first call, so the old seed was always zero)
- track pause ourselves: FocusOut pauses once, FocusIn resumes only what we
  paused (game_input('p') is a toggle)
- select ExposureMask so the Expose redraw path actually fires
- play.sh/play_keys.sh rebuild the COFF (OUTNAME=termtris) and assert the
  run: status=0, tick>0, loops/events/quit per mode; render.sh asserts the
  renderer finished; map symbol lookup is column-order independent
- run.sh passes -lightgun -lightgun_device mouse so the pointer drives the
  tablet
- docs: link map addresses, monochrome/reverse wording, honest caption and
  limits text

Verified here: play.sh and input.sh pass. Still open: the MAME driver in the
tree is newer than the installed binary (Oct 30 build, VR150-era geometry),
so the acceptance suite must be re-run after a rebuild.
2026-11-11 17:59:16 +00:00

171 lines
4.9 KiB
Bash
Executable File

#!/bin/sh
# build.sh -- build a VT1200 COFF with TI TMS34010 r5.01 under 2ine.
#
# apps/termtris/build.sh SOURCE.c [SOURCE.c ...] [EXTRA.obj ...]
#
# The first .c is the main program; the output is build/<main>.coff. entry.asm
# and cinit.asm are always assembled and linked. The 2ine loader is outside the
# repo: point NINE at its build directory (default /home/arti/os2-work/2ine/build).
set -eu
DIR=$(cd "$(dirname "$0")" && pwd)
ROOT=$(cd "$DIR/../.." && pwd)
WORK="$DIR/work"
OUT="$DIR/build"
NINE="${NINE:-/home/arti/os2-work/2ine/build}"
LX="$NINE/lx_loader"
SDK="$ROOT/tools/tms34010-sdk/1990-11 TMS340 Family SDK"
Z1="$SDK/1990-11-19 TMS340 Family Code Generation Tools (1 of 2) r5.01 rev2564062-1641.zip"
Z2="$SDK/1990-11-19 TMS340 Family Code Generation Tools (2 of 2) r5.01 rev2564062-1641.zip"
if [ ! -x "$LX" ]; then
echo "build.sh: no 2ine lx_loader at $LX (set NINE=...)" >&2
exit 1
fi
if [ ! -f "$Z1" ] || [ ! -f "$Z2" ]; then
echo "build.sh: r5.01 SDK zips not found under $SDK" >&2
exit 1
fi
mkdir -p "$WORK" "$OUT"
if [ ! -x "$WORK/gspac.exe" ]; then
unzip -oq "$Z1" -d "$WORK"
unzip -oq "$Z2" -d "$WORK"
fi
for so in "$NINE"/lib*.so; do
[ -e "$so" ] && ln -sf "$so" "$WORK/"
done
cp "$DIR/src/vt1200/"*.h "$WORK/" 2>/dev/null || true
cp "$DIR/src/"*.h "$WORK/" 2>/dev/null || true
cp "$DIR/src/vt1200/entry.asm" "$DIR/src/vt1200/cinit.asm" "$DIR/src/vt1200/cinitz.asm" "$WORK/"
# Collect objects. C sources are copied under their uppercase basename because
# the OS/2 tools are case-sensitive on this host.
OBJS=""
MAIN=""
for arg in "$@"; do
case "$arg" in
*.c)
base=$(basename "$arg" .c | tr 'a-z' 'A-Z')
[ -n "$MAIN" ] || MAIN="$base"
cp "$arg" "$WORK/$base.C"
OBJS="$OBJS $base"
;;
*.obj)
cp "$arg" "$WORK/"
OBJS="$OBJS $(basename "$arg")"
;;
*.asm)
base=$(basename "$arg" .asm | tr 'a-z' 'A-Z')
cp "$arg" "$WORK/$base.ASM"
OBJS="$OBJS $base"
;;
*)
echo "build.sh: unsupported input: $arg" >&2
exit 1
;;
esac
done
if [ -z "$MAIN" ]; then
echo "build.sh: give at least one .c source" >&2
exit 1
fi
# The 2ine-hosted tools frequently crash during teardown after doing their work
# (exit 139 / 134). Treat an output file as success, and retry a missing one.
run() {
_out=$1
shift
i=0
while [ "$i" -lt 5 ]; do
( cd "$WORK" && "$LX" "$@" ) >/dev/null 2>&1 || true
if [ -f "$WORK/$_out" ]; then
return 0
fi
i=$((i + 1))
done
echo "build.sh: stage failed to produce $WORK/$_out: $*" >&2
return 1
}
compile_c() {
base=$1
rm -f "$WORK/$base.IF" "$WORK/$base.OPT" "$WORK/$base.ASM" "$WORK/$base.obj"
run "$base.IF" ./gspac.exe -k -i. "$base.C" "$base.IF"
run "$base.OPT" ./gspopt.exe -k -O2 "$base.IF" "$base.OPT"
run "$base.ASM" ./gspcg.exe -m "$base.OPT" "$base.ASM" "$base.TMP"
run "$base.obj" ./gspa.exe "$base.ASM"
}
compile_asm() {
base=$1
rm -f "$WORK/$base.obj"
run "$base.obj" ./gspa.exe "$base.ASM"
}
# Compile every collected object exactly once, in the order given.
for arg in "$@"; do
case "$arg" in
*.c) compile_c "$(basename "$arg" .c | tr 'a-z' 'A-Z')" ;;
*.asm) compile_asm "$(basename "$arg" .asm | tr 'a-z' 'A-Z')" ;;
esac
done
compile_asm ENTRY
compile_asm CINIT
compile_asm CINITZ
OUTNAME=${OUTNAME:-$(printf '%s' "$MAIN" | tr 'A-Z' 'a-z')}
CMD="$WORK/$MAIN.CMD"
{
printf '%s\n' '-a'
printf '%s\n' "-o $MAIN.out"
printf '%s\n' "-m $MAIN.map"
printf '%s\n' '-e _start'
printf '%s\n' 'CINIT.obj'
printf '%s\n' 'ENTRY.obj'
for arg in "$@"; do
case "$arg" in
*.c) printf '%s\n' "$(basename "$arg" .c | tr 'a-z' 'A-Z').obj" ;;
*.asm) printf '%s\n' "$(basename "$arg" .asm | tr 'a-z' 'A-Z').obj" ;;
*.obj) printf '%s\n' "$(basename "$arg")" ;;
esac
done
printf '%s\n' '-l rts.lib'
printf '%s\n' 'MEMORY'
printf '%s\n' '{'
printf '%s\n' ' prog: origin = 018A0000h, length = 20000h'
printf '%s\n' ' ram: origin = 01A00000h, length = 40000h'
printf '%s\n' '}'
printf '%s\n' 'SECTIONS'
printf '%s\n' '{'
printf '%s\n' ' .text: {} > prog'
printf '%s\n' ' .data: {} > prog'
printf '%s\n' ' .cinit: {} > prog'
printf '%s\n' ' .bss: {} > ram'
printf '%s\n' '}'
} > "$CMD"
sed -i 's/$/\r/' "$CMD"
rm -f "$WORK/$MAIN.out" "$WORK/$MAIN.map"
run "$MAIN.out" ./gsplnk.exe "$MAIN.CMD"
if [ ! -f "$WORK/$MAIN.map" ]; then
echo "build.sh: no link map" >&2
exit 1
fi
# An empty .cinit makes the linker's `cinit` symbol point at .text; the entry's
# cinit walker would then treat an instruction as a record count. Relink with
# a one-word terminator when the map says the section is empty.
CSIZE=$(awk '$1 == ".cinit" {print $4; exit}' "$WORK/$MAIN.map")
if [ "$CSIZE" = "00000000" ]; then
sed -i 's/CINIT\.obj/CINITZ.obj/' "$CMD"
rm -f "$WORK/$MAIN.out" "$WORK/$MAIN.map"
run "$MAIN.out" ./gsplnk.exe "$MAIN.CMD"
fi
cp "$WORK/$MAIN.out" "$OUT/$OUTNAME.coff"
sed 's/\r$//' "$WORK/$MAIN.map" > "$OUT/$OUTNAME.map"
echo "build.sh: $OUT/$OUTNAME.coff ($(wc -c < "$OUT/$OUTNAME.coff") bytes)"
sed -n '1,40p' "$OUT/$OUTNAME.map"