A map-time Expose arrives before the game has a current piece, and the game's full-redraw path then draws a bogus piece over the top row: visible as a blanked well border with stray X tiles (the previous commit's screenshots showed it). The window is never obscured in this session, so drop the mask, drop the Expose branch, and note the reason in HANDOFF.md. Refreshed with verify.sh: move 354/18, panels 346/12, quit 300/10, all with focus=00400001; evidence re-captured and clean.
7.0 KiB
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.
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:
- Re-run
apps/termtris/verify.sh --skip-mameand note the newDIAG: loops=... events=... quit=...values. - 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. - Update the numbers in
VT1200.md("Acceptance values") and inharness/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.binin 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 61 9B 41 9B 42 9B 44 9B 43 30 0A 7F 71 70
(a/up/down/left/right/0/Return/Delete/q/p)
play PASS DIAG: tick=887 quit=0
play_keys PASS move DIAG: loops=354 events=18 focus=00400001 quit=0
panels DIAG: loops=346 events=12 focus=00400001 quit=0
quit DIAG: loops=300 events=10 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 |
blanked well border with stray X tiles at the top |
ExposureMask + map-time Expose runs the game's full redraw before it has a piece |
do not select ExposureMask (current code); if repainting on expose is ever needed, guard full_redraw against cur_piece < 0 |
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.