forked from opencode.energia.arti.ee/vt1200
chore(termtris): handoff script and notes for the next machine
apps/termtris/verify.sh runs the whole acceptance: ROM md5 guard, 2ine check, MAME build (--skip-mame to reuse one), the six tests, the acceptance summary and the evidence list, all logged under build/. HANDOFF.md states what is done, what is still open (the docs' figures and screenshots predate the VR319 default because the installed MAME binary is the 30 Oct build), the expected outputs, and the failure modes already diagnosed. Refresh the acceptance numbers from the verify run: 348/19, 338/13, 292/11.
This commit is contained in:
1 parent
be5b323f5d
commit
a12fb47d5f
9 files changed
+249
-8
No files matched your search
@@ -0,0 +1,133 @@
|
||||
# Handoff — termtris running inside the VT1200
|
||||
|
||||
Everything here is on branch **`termtris`** of
|
||||
`https://git.wut.ee/opencode.energia.arti.ee/vt1200.git` (remote `origin`).
|
||||
The branch was developed in a worktree at
|
||||
`/home/arti/.local/share/opencode/worktree/26e92e/termtris`; any checkout of the
|
||||
branch is equivalent.
|
||||
|
||||
```sh
|
||||
git fetch origin termtris
|
||||
git checkout -b termtris origin/termtris
|
||||
apps/termtris/verify.sh
|
||||
```
|
||||
|
||||
`verify.sh` is the whole acceptance run: ROM checksum, toolchain check, MAME
|
||||
build (skip with `--skip-mame`), the six tests, the acceptance summary and the
|
||||
evidence list. It exits non-zero on the first failure and keeps every test log
|
||||
under `apps/termtris/build/verify_<name>.log`. `RUNTIME` is roughly 12 minutes
|
||||
once MAME is built; the MAME build itself is the long part.
|
||||
|
||||
## What is done
|
||||
|
||||
The upstream game (John Tsiombikas' `termtris`, commit `7c5435d`) builds as a
|
||||
native TMS34010 program with the 1990 TI r5.01 C toolchain under 2ine, loads
|
||||
into VT1200 RAM through `dwt/loader`, opens a 480×312 window on the terminal's
|
||||
own X server through the ROM Xlib, and reads real X11 key events. It is the
|
||||
actual game: board, score/level/lines panels, piece preview, help and
|
||||
high-score panels, moving/rotating/dropping pieces, and `q` to quit.
|
||||
|
||||
| task | state | commit |
|
||||
|---|---|---|
|
||||
| vendor + toolchain + XG smoke test | done, `smoke.sh` PASS | `a861268` |
|
||||
| `sprintf`/stdio compat | done, `fmt.sh` PASS | `a804181` |
|
||||
| cell-grid X11 backend | done, `render.sh` PASS | `264b53a` |
|
||||
| key map, clock, main loop | done, `input.sh` PASS | `c1945cf` |
|
||||
| game integration, scores, COFF | done, `play.sh`/`play_keys.sh` PASS | `41d3cec` |
|
||||
| docs + harness report | done | `3e2ddde` |
|
||||
| review pass (seed, focus, expose, assertions) | done | `7a2cef5` |
|
||||
| handoff script + this note | done | (this commit) |
|
||||
|
||||
`VT1200.md` is the port documentation; `harness/mame/TERMTRIS_REPORT.md` is the
|
||||
harness-side report; the design and plan are in
|
||||
`docs/superpowers/specs/2026-11-03-termtris-vt1200-design.md` and
|
||||
`docs/superpowers/plans/2026-11-03-termtris-vt1200.md`.
|
||||
|
||||
## What is *not* done yet — read this first
|
||||
|
||||
All screenshots and the acceptance numbers in the docs were produced with an
|
||||
**older MAME binary** (`/home/arti/code/k-space/mame0289/vt1200d`, 30 Oct) that
|
||||
predates the driver's VR319 default. That binary has no `VT1200_MONITOR`, and
|
||||
its frames are 1024×864, i.e. the old VR150 geometry. The driver in this tree
|
||||
defaults to **VR319** (1280×1024 active, 1696×1063 raster), which changes the
|
||||
frame cadence and therefore the frame at which the loader and the tests act.
|
||||
|
||||
So on the new box, after `harness/mame/build.sh`:
|
||||
|
||||
1. Re-run `apps/termtris/verify.sh --skip-mame` and note the new
|
||||
`DIAG: loops=... events=... quit=...` values.
|
||||
2. Re-capture the screenshots (the test scripts write them into
|
||||
`apps/termtris/evidence/`) and look at them: the board must still be a
|
||||
bordered well with `[`/`]` tetrominoes, the score/level/lines boxes on the
|
||||
right, and the preview box. The window is positioned at (80,80) inside a
|
||||
larger raster, so the PNGs get bigger but the window content is unchanged.
|
||||
3. Update the numbers in `VT1200.md` ("Acceptance values") and in
|
||||
`harness/mame/TERMTRIS_REPORT.md`, and say plainly that the earlier figures
|
||||
were VR150.
|
||||
|
||||
If the behaviour itself changes at VR319 (pieces not visible, no events), that
|
||||
is a real finding, not a formatting detail — the loader acts at frame 2500 and
|
||||
the keys at 3100–3290, which may need re-timing if the new raster shifts the
|
||||
frame budget.
|
||||
|
||||
## Prerequisites on the new box
|
||||
|
||||
* a MAME 0.289 checkout (`MAME_SRC`, default `/home/arti/code/k-space/mame0289`);
|
||||
* the 2ine build with `lx_loader` (`NINE=`, default
|
||||
`/home/arti/os2-work/2ine/build`);
|
||||
* the r5.01 SDK zips, already in the repo under
|
||||
`tools/tms34010-sdk/1990-11 TMS340 Family SDK/`;
|
||||
* `vt1200_v22.bin` in the repo root (the harness ROM dir symlinks to it).
|
||||
|
||||
`verify.sh` checks the ROM and the 2ine loader before doing anything, and
|
||||
`harness/mame/build.sh` re-registers the driver in `mame.lst` and builds the
|
||||
single-driver `vt1200` subtarget.
|
||||
|
||||
## Expected results
|
||||
|
||||
Last run here (older MAME, VR150 geometry):
|
||||
|
||||
```
|
||||
smoke PASS type=2 keycode=194 lookup_n=1 ch=61 ks=0061
|
||||
fmt PASS six formats exact
|
||||
render PASS flus=464C5553 progress=00FFFFFF
|
||||
input PASS bytes 60 61 9B 41 9B 42 9B 44 9B 43 30 0A 7F 71 70
|
||||
(60 is the Expose redraw, then a/up/down/left/right/0/Return/Delete/q/p)
|
||||
play PASS DIAG: tick=887 quit=0
|
||||
play_keys PASS move DIAG: loops=348 events=19 focus=00400001 quit=0
|
||||
panels DIAG: loops=338 events=13 focus=00400001 quit=0
|
||||
quit DIAG: loops=292 events=11 focus=00400001 quit=1
|
||||
```
|
||||
|
||||
`focus=00400001` is the window the process created; `quit=1` is the game's own
|
||||
global after `q` — that is the proof the key reached the game and not just the
|
||||
window.
|
||||
|
||||
## Known failure modes (all seen, all diagnosed)
|
||||
|
||||
| symptom | cause | handling |
|
||||
|---|---|---|
|
||||
| build stage "fails" with exit 139 but produced its file | 2ine-hosted TI tools crash during teardown | `build.sh` retries only when the output is missing; `gspac` needs `-i.` |
|
||||
| linker points `cinit` into `.text` | empty `.cinit` section | `build.sh` relinks with the one-word `CINITZ.obj` terminator |
|
||||
| `XNextEvent` never returns an event, keycode zero | child's per-process Xlib context is NULL | `src/vt1200/xgfix.c` writes a zeroed 1 KiB block before `XOpenDisplay` (RAM only) |
|
||||
| the game exits immediately at startup, sometimes | `XOpenDisplay`/window creation while the display server settles | `main()` retries 40 × 50 ms, then returns 1 |
|
||||
| window paints once, then hangs; a debug marker stops mid-flush | per-cell flushing overflowed the X socket / `XSync` per row deadlocked the client | flush repaints whole rows (fill + one 80-char string + inverse spans + one `XFlush`) |
|
||||
| playfield is a white block with invisible pieces | the 1-bit raster cannot show colour | backend drops colour and uses bold (`0x80`) as reverse; pieces are `[`/`]` glyphs |
|
||||
|
||||
## Layout
|
||||
|
||||
```
|
||||
apps/termtris/
|
||||
├── build.sh TI r5.01 -> COFF (OUTNAME=termtris for the game)
|
||||
├── run.sh interactive MAME session (lightgun/tablet input)
|
||||
├── verify.sh one-command acceptance (see above)
|
||||
├── VT1200.md port documentation
|
||||
├── src/game.c upstream game; only srand(vt_rand_seed()) differs
|
||||
├── src/vt1200/ main.c x11.c xgfix.c compat.c xlib.h scoredb.c *.asm
|
||||
├── tests/ smoke fmt render input play play_keys (+ .lua drivers)
|
||||
├── evidence/ screenshots
|
||||
└── build/termtris.coff the built image (tracked for convenience)
|
||||
```
|
||||
|
||||
The tests build from source every run (`play.sh`/`play_keys.sh` rebuild
|
||||
`termtris.coff`), so an edit cannot silently pass by using a stale binary.
|
||||
@@ -89,7 +89,7 @@ level 0).
|
||||
Keys arrive as X11 `KeyPress` events and go through `XLookupString`; letters are
|
||||
lower-cased and handed to `game_input()`. Arrows are sent as the game's own CSI
|
||||
codes (`0x9b` + `A`/`B`/`C`/`D`), which `game_input` translates back to
|
||||
`w`/`s`/`d`/`a`. `0x7F` is Backspace/Delete. `Expose` triggers a full redraw and
|
||||
`w`/`s`/`d`/`a`. `0x7F` is Backspace/Delete. `Expose` (selected with `0x22800F`) triggers a full redraw and
|
||||
`FocusOut` (only after a `FocusIn`) pauses the game.
|
||||
|
||||
## Running it in MAME
|
||||
@@ -105,6 +105,7 @@ harness/mame/build.sh # rebuild the vt1200 subtarget (JOBS=4 on small h
|
||||
Then:
|
||||
|
||||
```sh
|
||||
apps/termtris/verify.sh # build MAME + run every test (see HANDOFF.md)
|
||||
apps/termtris/tests/play.sh # load, click, snapshot
|
||||
apps/termtris/tests/play_keys.sh # move / panels / quit acceptance runs
|
||||
apps/termtris/run.sh # same run, interactive session
|
||||
@@ -129,9 +130,9 @@ which copies the sections to their linked addresses and calls
|
||||
Acceptance values from the last full run (`play_keys.sh`):
|
||||
|
||||
```
|
||||
move DIAG: loops=333 events=18 focus=00400001 quit=0
|
||||
panels DIAG: loops=323 events=12 focus=00400001 quit=0
|
||||
quit DIAG: loops=277 events=10 focus=00400001 quit=1
|
||||
move DIAG: loops=348 events=19 focus=00400001 quit=0
|
||||
panels DIAG: loops=338 events=13 focus=00400001 quit=0
|
||||
quit DIAG: loops=292 events=11 focus=00400001 quit=1
|
||||
```
|
||||
|
||||
`focus=00400001` is the window this process created (it is the only one in the
|
||||
|
||||
Binary file not shown.
@@ -1,7 +1,7 @@
|
||||
*****************************************************
|
||||
TMS340 COFF Linker Version 5.01
|
||||
*****************************************************
|
||||
Wed Nov 11 17:58:44 2026
|
||||
Thu Nov 12 05:12:58 2026
|
||||
|
||||
OUTPUT FILE NAME: <MAIN.out>
|
||||
ENTRY POINT SYMBOL: "_start" address: 018a0000
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Executable
+107
@@ -0,0 +1,107 @@
|
||||
#!/bin/sh
|
||||
# verify.sh -- one-command acceptance for the VT1200 termtris port.
|
||||
#
|
||||
# apps/termtris/verify.sh # build MAME, then run every test
|
||||
# apps/termtris/verify.sh --skip-mame # use the emulator already installed
|
||||
#
|
||||
# Exits non-zero on the first failed check. Each test's full output is kept in
|
||||
# apps/termtris/build/verify_<name>.log.
|
||||
set -eu
|
||||
|
||||
DIR=$(cd "$(dirname "$0")" && pwd)
|
||||
ROOT=$(cd "$DIR/../.." && pwd)
|
||||
M=${MAME:-/home/arti/code/k-space/mame0289/vt1200}
|
||||
ROM_MD5=b46a3e442ccb86134d2356bd70d22fd2
|
||||
|
||||
skip_mame=0
|
||||
for arg in "$@"; do
|
||||
case $arg in
|
||||
--skip-mame) skip_mame=1 ;;
|
||||
-h|--help)
|
||||
sed -n '2,8p' "$0" | sed 's/^# \{0,1\}//'
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "verify.sh: unknown argument: $arg" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
mkdir -p "$DIR/build"
|
||||
|
||||
echo "== ROM checksum"
|
||||
got=$(md5sum "$ROOT/vt1200_v22.bin" | cut -d' ' -f1)
|
||||
if [ "$got" != "$ROM_MD5" ]; then
|
||||
echo "FAIL: vt1200_v22.bin md5 is $got, expected $ROM_MD5" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "ok: $got"
|
||||
|
||||
echo "== 2ine toolchain"
|
||||
LX="${NINE:-/home/arti/os2-work/2ine/build}/lx_loader"
|
||||
if [ ! -x "$LX" ]; then
|
||||
echo "FAIL: no 2ine lx_loader at $LX (set NINE=/path/to/2ine/build)" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "ok: $LX"
|
||||
|
||||
echo "== emulator"
|
||||
if [ "$skip_mame" -eq 0 ]; then
|
||||
JOBS=${JOBS:-8} "$ROOT/harness/mame/build.sh"
|
||||
fi
|
||||
if [ ! -x "$M" ]; then
|
||||
echo "FAIL: no vt1200 binary at $M (set MAME=... or drop --skip-mame)" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "ok: $M"
|
||||
|
||||
export MAME="$M"
|
||||
fail=0
|
||||
|
||||
run() {
|
||||
name=$1
|
||||
shift
|
||||
printf '== %-9s ' "$name"
|
||||
if "$@" >"$DIR/build/verify_$name.log" 2>&1; then
|
||||
echo "PASS"
|
||||
else
|
||||
echo "FAIL (apps/termtris/build/verify_$name.log)"
|
||||
tail -20 "$DIR/build/verify_$name.log" | sed 's/^/ /'
|
||||
fail=1
|
||||
fi
|
||||
}
|
||||
|
||||
run smoke "$DIR/tests/smoke.sh"
|
||||
run fmt "$DIR/tests/fmt.sh"
|
||||
run render "$DIR/tests/render.sh"
|
||||
run input "$DIR/tests/input.sh"
|
||||
run play "$DIR/tests/play.sh"
|
||||
run play_keys "$DIR/tests/play_keys.sh"
|
||||
|
||||
echo
|
||||
echo "== play acceptance"
|
||||
if [ -f "$DIR/build/play_move.log" ]; then
|
||||
for mode in move panels quit; do
|
||||
grep -a -h 'DIAG: loops' "$DIR/build/play_$mode.log" 2>/dev/null |
|
||||
head -1 | sed "s/^/ $mode /"
|
||||
done
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "== evidence"
|
||||
ls -1 "$DIR"/evidence/*.png 2>/dev/null | sed 's/^/ /'
|
||||
|
||||
echo
|
||||
echo "== ROM checksum (after the suite)"
|
||||
got=$(md5sum "$ROOT/vt1200_v22.bin" | cut -d' ' -f1)
|
||||
[ "$got" = "$ROM_MD5" ] || { echo "FAIL: ROM changed during the run" >&2; exit 1; }
|
||||
echo "ok: $got"
|
||||
|
||||
if [ "$fail" -ne 0 ]; then
|
||||
echo
|
||||
echo "verify: FAILED" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo
|
||||
echo "verify: PASS"
|
||||
@@ -94,9 +94,9 @@ The run is `VT1200_SKIP_LEVEL1=1 LOADER_AT=2500` with the loader payload at bit
|
||||
Last full acceptance run:
|
||||
|
||||
```
|
||||
move DIAG: loops=333 events=18 focus=00400001 quit=0
|
||||
panels DIAG: loops=323 events=12 focus=00400001 quit=0
|
||||
quit DIAG: loops=277 events=10 focus=00400001 quit=1
|
||||
move DIAG: loops=348 events=19 focus=00400001 quit=0
|
||||
panels DIAG: loops=338 events=13 focus=00400001 quit=0
|
||||
quit DIAG: loops=292 events=11 focus=00400001 quit=1
|
||||
```
|
||||
|
||||
`focus=00400001` is the termtris window, and `quit=1` is the game's global after
|
||||
|
||||
Reference in new issue
Block a user