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.
This commit is contained in:
opencode.energia.arti.ee committed 2026-11-11 17:59:16 +00:00
1 parent eb896f7b8c
commit 7a2cef56ad
19 files changed
+183 -134

No files matched your search

-1
View File
@@ -73,7 +73,6 @@ tools/tms34010-sdk/1991-07 TIGA Promo Kit and Art Software/
# termtris build scratch (TI tools + 2ine libs)
apps/termtris/work/
apps/termtris/build/*.log
apps/termtris/build/*.log
apps/termtris/build/smoke.*
apps/termtris/build/fmt.*
apps/termtris/build/render.*
+10 -7
View File
@@ -40,7 +40,7 @@ Link map (relevant addresses are **bit** addresses, like everything the
TMS34010 sees):
```
.text 018A0000 .data 018A0000 .cinit 018B4730
.text 018A0000 .data 018A0000 .cinit 018B4B10
.bss 01A00000
ENTRY POINT SYMBOL: "_start" address: 018a0000
```
@@ -63,8 +63,9 @@ untouched. With that in place the smoke test receives a real
The frame is an 80×24 grid of 6×13 cells (the default GC font, baseline +10),
so the window is 480×312. The VT1200 raster is **one bit deep**, so the backend
follows the game's own monochrome convention (`ansi.c -m`): colour is dropped
and the bold bit (`0x80`) reverses a cell. The playfield is therefore black
renders like the game's monochrome mode (colour is dropped) and uses the bold
bit (`0x80`) as reverse video for emphasis — a choice of this backend, not the
upstream ANSI convention (which emits SGR bold and leaves the colours alone). The playfield is therefore black
spaces and the tetrominoes are the `[`/`]` tiles, exactly what a 1-bit terminal
can show.
@@ -123,8 +124,9 @@ panels DIAG: loops=323 events=12 focus=00400001 quit=0
quit DIAG: loops=277 events=10 focus=00400001 quit=1
```
`focus=00400001` is the termtris window, so the key events really were
delivered to it, and `quit=1` is the game's own global after `q`.
`focus=00400001` is the window this process created (it is the only one in the
run), so the key events were delivered to it, and `quit=1` is the game's own
global after `q`.
## Limits, stated plainly
@@ -136,8 +138,9 @@ delivered to it, and `quit=1` is the game's own global after `q`.
display server is still settling, `main()` retries up to 40 times with a
50 ms sleep before giving up. Observed as an intermittent early exit.
* **`q` ends the game loop but the window stays on screen.** `quit=1` is
observable in RAM; the created process does not tear down its X connection,
so the server keeps the window.
observable in RAM and `main()` returns; the frame captured about a second
later still shows the window, so the X connection is not torn down by process
exit in this OS. Treat that as an observation, not a designed behaviour.
* **The board is text.** Tetrominoes are `[`/`]` tiles, not filled blocks — the
only thing a 1-bit cell can show without a custom font.
-5
View File
@@ -103,11 +103,6 @@ compile_asm() {
run "$base.obj" ./gspa.exe "$base.ASM"
}
for base in $OBJS; do
case " $* " in
*" $base "*) ;; # handled below by extension scan
esac
done
# Compile every collected object exactly once, in the order given.
for arg in "$@"; do
Binary file not shown.
+107 -106
View File
@@ -1,7 +1,7 @@
*****************************************************
TMS340 COFF Linker Version 5.01
*****************************************************
Tue Nov 03 20:09:24 2026
Wed Nov 11 17:58:44 2026
OUTPUT FILE NAME: <MAIN.out>
ENTRY POINT SYMBOL: "_start" address: 018a0000
@@ -20,38 +20,38 @@ SECTION ALLOCATION MAP
output attributes/
section page origin length input sections
-------- ---- ---------- ---------- ----------------
.text 0 018a0000 00014940
.text 0 018a0000 00014b10
018a0000 00000150 ENTRY.obj (.text)
018a0150 00001c90 MAIN.obj (.text)
018a1de0 0000ce50 GAME.obj (.text)
018aec30 00000d20 SCOREDB.obj (.text)
018af950 00002a40 X11.obj (.text)
018b2390 00001640 COMPAT.obj (.text)
018b39d0 00000210 XGFIX.obj (.text)
018b3be0 00000450 rts.lib (.text)
018b4030 000001a0 rts.lib (.text)
018b41d0 00000230 rts.lib (.text)
018b4400 00000150 rts.lib (.text)
018b4550 00000120 rts.lib (.text)
018b4670 00000110 rts.lib (.text)
018b4780 000001c0 rts.lib (.text)
018a0150 00001e60 MAIN.obj (.text)
018a1fb0 0000ce50 GAME.obj (.text)
018aee00 00000d20 SCOREDB.obj (.text)
018afb20 00002a40 X11.obj (.text)
018b2560 00001640 COMPAT.obj (.text)
018b3ba0 00000210 XGFIX.obj (.text)
018b3db0 00000450 rts.lib (.text)
018b4200 000001a0 rts.lib (.text)
018b43a0 00000230 rts.lib (.text)
018b45d0 00000150 rts.lib (.text)
018b4720 00000120 rts.lib (.text)
018b4840 00000110 rts.lib (.text)
018b4950 000001c0 rts.lib (.text)
.cinit 0 018b4940 000012d0
018b4940 00000050 MAIN.obj (.cinit)
018b4990 00001190 GAME.obj (.cinit)
018b5b20 00000050 SCOREDB.obj (.cinit)
018b5b70 00000050 X11.obj (.cinit)
018b5bc0 00000050 rts.lib (.cinit)
.cinit 0 018b4b10 000012d0
018b4b10 00000050 MAIN.obj (.cinit)
018b4b60 00001190 GAME.obj (.cinit)
018b5cf0 00000050 SCOREDB.obj (.cinit)
018b5d40 00000050 X11.obj (.cinit)
018b5d90 00000050 rts.lib (.cinit)
.bss 0 01a00000 0001ec00 UNINITIALIZED
.bss 0 01a00000 0001ec20 UNINITIALIZED
01a00000 00008000 ENTRY.obj (.bss)
01a08000 00000400 MAIN.obj (.bss)
01a08400 00004a40 GAME.obj (.bss)
01a0ce40 00000b80 SCOREDB.obj (.bss)
01a0d9c0 0000f200 X11.obj (.bss)
01a1cbc0 00000020 COMPAT.obj (.bss)
01a1cbe0 00002000 XGFIX.obj (.bss)
01a1ebe0 00000020 rts.lib (.bss)
01a08000 00000420 MAIN.obj (.bss)
01a08420 00004a40 GAME.obj (.bss)
01a0ce60 00000b80 SCOREDB.obj (.bss)
01a0d9e0 0000f200 X11.obj (.bss)
01a1cbe0 00000020 COMPAT.obj (.bss)
01a1cc00 00002000 XGFIX.obj (.bss)
01a1ec00 00000020 rts.lib (.bss)
.data 0 018a0000 00000000 UNINITIALIZED
@@ -60,81 +60,82 @@ GLOBAL SYMBOLS
address name address name
-------- ---- -------- ----
01a00000 .bss 018a0000 .text
018a0000 .data 018a0000 .data
018a0000 .text 018a0000 edata
01a08a00 _blackpf 018a0000 _start
018a2f40 _cleanup_game 018a0150 _now_ms
01a08380 _dbg_events 018a03d0 _sleep_ms
01a083c0 _dbg_focus 018a0530 _vt_poll_event
01a083a0 _dbg_last 018a0ea0 _vt_handle_event
01a08360 _dbg_loops 018a1700 _wait_display
01a083e0 _dbg_rev 018a1740 _main
018b2390 _fflush 018a1de0 _init_game
018a84e0 _game_input 018a2f40 _cleanup_game
018a1de0 _init_game 018a3130 _update
018a1740 _main 018a84e0 _game_input
018b3be0 _memcpy 018aef90 _read_scores
018b3d80 _memmove 018af310 _save_score
018b4030 _memset 018af8a0 _print_scores
01a089a0 _monochrome 018af950 _vt_root_window
018a0150 _now_ms 018afa30 _vt_x11_init
01a089e0 _onlyascii 018b01e0 _x11_clearscr
018af8a0 _print_scores 018b03a0 _x11_reset
018b2400 _putchar 018b03e0 _x11_cursor
01a08940 _quit 018b0440 _x11_setcolor
018b41d0 _rand 018b0560 _x11_setcursor
018aef90 _read_scores 018b07b0 _x11_ibmchar
01a08a20 _rotstep 018b0c30 _term_putstr
018af310 _save_score 018b0dd0 _vt_x11_flush
01a08a80 _scr 018b2000 _vt_x11_term_init
018a03d0 _sleep_ms 018b2320 _term_init
018b2c10 _sprintf 018b2390 _fflush
018b4330 _srand 018b2400 _putchar
018a0000 _start 018b2c10 _sprintf
01a1cbc0 _stdout 018b39d0 _vt_install_xg
018b4400 _strcmp 018b3be0 _memcpy
018b4550 _strcpy 018b3d80 _memmove
018b4670 _strlen 018b4030 _memset
018b4780 _strncpy 018b41d0 _rand
01a1cae0 _term_clearscr 018b4330 _srand
01a1cb20 _term_cursor 018b4400 _strcmp
01a08a60 _term_height 018b4550 _strcpy
01a1cb60 _term_ibmchar 018b4670 _strlen
018b2320 _term_init 018b4780 _strncpy
018b0c30 _term_putstr 018b4940 cinit
01a1cac0 _term_reset 018b4940 etext
01a1cb40 _term_setcolor 01a00000 .bss
01a1cb00 _term_setcursor 01a08360 _dbg_loops
01a1cba0 _term_type 01a08380 _dbg_events
01a08a40 _term_width 01a083a0 _dbg_last
01a1cb80 _termenv 01a083c0 _dbg_focus
01a08960 _tick_interval 01a083e0 _dbg_rev
018a3130 _update 01a08940 _quit
01a08980 _use_bell 01a08960 _tick_interval
01a089c0 _use_gfxchar 01a08980 _use_bell
01a0ce40 _username 01a089a0 _monochrome
01a1ca40 _vt_dpy 01a089c0 _use_gfxchar
01a1ca80 _vt_gc 01a089e0 _onlyascii
018a0ea0 _vt_handle_event 01a08a00 _blackpf
018b39d0 _vt_install_xg 01a08a20 _rotstep
018a0530 _vt_poll_event 01a08a40 _term_width
018af950 _vt_root_window 01a08a60 _term_height
01a1ca60 _vt_win 01a08a80 _scr
018b0dd0 _vt_x11_flush 01a0ce40 _username
018afa30 _vt_x11_init 01a1ca40 _vt_dpy
01a1caa0 _vt_x11_progress 01a1ca60 _vt_win
018b2000 _vt_x11_term_init 01a1ca80 _vt_gc
018a1700 _wait_display 01a1caa0 _vt_x11_progress
018b01e0 _x11_clearscr 01a1cac0 _term_reset
018b03e0 _x11_cursor 01a1cae0 _term_clearscr
018b07b0 _x11_ibmchar 01a1cb00 _term_setcursor
018b03a0 _x11_reset 01a1cb20 _term_cursor
018b0440 _x11_setcolor 01a1cb40 _term_setcolor
018b0560 _x11_setcursor 01a1cb60 _term_ibmchar
018b4940 cinit 01a1cb80 _termenv
018a0000 edata 01a1cba0 _term_type
01a1ec00 end 01a1cbc0 _stdout
018b4940 etext 01a1ec00 end
01a00000 .bss 018a0000 .data
018a0000 .data 018a0000 .text
018a0000 .text 018a0000 _start
01a08a20 _blackpf 018a0000 edata
018a3110 _cleanup_game 018a0150 _now_ms
01a083a0 _dbg_events 018a03d0 _vt_rand_seed
01a083e0 _dbg_focus 018a0420 _sleep_ms
01a083c0 _dbg_last 018a0580 _vt_poll_event
01a08380 _dbg_loops 018a0ef0 _vt_handle_event
01a08400 _dbg_rev 018a18d0 _wait_display
018b2560 _fflush 018a1910 _main
018a86b0 _game_input 018a1fb0 _init_game
018a1fb0 _init_game 018a3110 _cleanup_game
018a1910 _main 018a3300 _update
018b3db0 _memcpy 018a86b0 _game_input
018b3f50 _memmove 018af160 _read_scores
018b4200 _memset 018af4e0 _save_score
01a089c0 _monochrome 018afa70 _print_scores
018a0150 _now_ms 018afb20 _vt_root_window
01a08a00 _onlyascii 018afc00 _vt_x11_init
018afa70 _print_scores 018b03b0 _x11_clearscr
018b25d0 _putchar 018b0570 _x11_reset
01a08960 _quit 018b05b0 _x11_cursor
018b43a0 _rand 018b0610 _x11_setcolor
018af160 _read_scores 018b0730 _x11_setcursor
01a08a40 _rotstep 018b0980 _x11_ibmchar
018af4e0 _save_score 018b0e00 _term_putstr
01a08aa0 _scr 018b0fa0 _vt_x11_flush
018a0420 _sleep_ms 018b21d0 _vt_x11_term_init
018b2de0 _sprintf 018b24f0 _term_init
018b4500 _srand 018b2560 _fflush
018a0000 _start 018b25d0 _putchar
01a1cbe0 _stdout 018b2de0 _sprintf
018b45d0 _strcmp 018b3ba0 _vt_install_xg
018b4720 _strcpy 018b3db0 _memcpy
018b4840 _strlen 018b3f50 _memmove
018b4950 _strncpy 018b4200 _memset
01a1cb00 _term_clearscr 018b43a0 _rand
01a1cb40 _term_cursor 018b4500 _srand
01a08a80 _term_height 018b45d0 _strcmp
01a1cb80 _term_ibmchar 018b4720 _strcpy
018b24f0 _term_init 018b4840 _strlen
018b0e00 _term_putstr 018b4950 _strncpy
01a1cae0 _term_reset 018b4b10 cinit
01a1cb60 _term_setcolor 018b4b10 etext
01a1cb20 _term_setcursor 01a00000 .bss
01a1cbc0 _term_type 01a08380 _dbg_loops
01a08a60 _term_width 01a083a0 _dbg_events
01a1cba0 _termenv 01a083c0 _dbg_last
01a08980 _tick_interval 01a083e0 _dbg_focus
018a3300 _update 01a08400 _dbg_rev
01a089a0 _use_bell 01a08960 _quit
01a089e0 _use_gfxchar 01a08980 _tick_interval
01a0ce60 _username 01a089a0 _use_bell
01a1ca60 _vt_dpy 01a089c0 _monochrome
01a1caa0 _vt_gc 01a089e0 _use_gfxchar
018a0ef0 _vt_handle_event 01a08a00 _onlyascii
018b3ba0 _vt_install_xg 01a08a20 _blackpf
018a0580 _vt_poll_event 01a08a40 _rotstep
018a03d0 _vt_rand_seed 01a08a60 _term_width
018afb20 _vt_root_window 01a08a80 _term_height
01a1ca80 _vt_win 01a08aa0 _scr
018b0fa0 _vt_x11_flush 01a0ce60 _username
018afc00 _vt_x11_init 01a1ca60 _vt_dpy
01a1cac0 _vt_x11_progress 01a1ca80 _vt_win
018b21d0 _vt_x11_term_init 01a1caa0 _vt_gc
018a18d0 _wait_display 01a1cac0 _vt_x11_progress
018b03b0 _x11_clearscr 01a1cae0 _term_reset
018b05b0 _x11_cursor 01a1cb00 _term_clearscr
018b0980 _x11_ibmchar 01a1cb20 _term_setcursor
018b0570 _x11_reset 01a1cb40 _term_cursor
018b0610 _x11_setcolor 01a1cb60 _term_setcolor
018b0730 _x11_setcursor 01a1cb80 _term_ibmchar
018b4b10 cinit 01a1cba0 _termenv
018a0000 edata 01a1cbc0 _term_type
01a1ec20 end 01a1cbe0 _stdout
018b4b10 etext 01a1ec20 end
[76 symbols]
[77 symbols]
Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

+1
View File
@@ -36,4 +36,5 @@ exec env VT1200_SKIP_LEVEL1=1 \
LOADER_BIN="$LOADER" LOADER_COFF="$COFF" LOADER_OUT="$DIR/build" \
"$M" vt1200 -rompath "$ROOT/harness/mame/roms" \
-skip_gameinfo -debug -debugger none \
-lightgun -lightgun_device mouse \
-autoboot_script "$DIR/tests/play.lua" -autoboot_delay 0
+2 -2
View File
@@ -25,7 +25,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "term.h"
#include "scoredb.h"
extern long now_ms(void);
extern unsigned vt_rand_seed(void);
int quit;
@@ -192,7 +192,7 @@ int init_game(void)
scores = read_scores(0, 10);
memset(&cur_score, 0, sizeof cur_score);
srand((unsigned)now_ms());
srand(vt_rand_seed());
pause = 0;
gameover = 0;
+19 -1
View File
@@ -18,6 +18,7 @@ static vt_u32 evbuf[24];
static long ms_base;
static int ms_last = -1;
static int focused;
static int vt_paused;
volatile vt_u32 dbg_loops, dbg_events, dbg_last, dbg_focus, dbg_rev;
long now_ms(void)
@@ -34,6 +35,16 @@ long now_ms(void)
return ms_base;
}
/*
* Seed for the game's PRNG. now_ms() returns 0 on its first call (it only
* latches the counter there), so seeding from it gives a constant; read the
* free-running 16-bit tick directly instead.
*/
unsigned vt_rand_seed(void)
{
return (unsigned)*(volatile unsigned short *)0x001E93C0UL;
}
void sleep_ms(int ms)
{
if(ms < 1) ms = 1;
@@ -105,8 +116,15 @@ void vt_handle_event(void)
game_input('`');
} else if(evbuf[0] == 9) { /* FocusIn */
focused = 1;
if(vt_paused) { /* resume only what we paused */
game_input('p');
vt_paused = 0;
}
} else if(evbuf[0] == 10) { /* FocusOut */
if(focused) game_input('p');
if(focused && !vt_paused) {
game_input('p'); /* 'p' toggles pause in game_input */
vt_paused = 1;
}
focused = 0;
}
}
+1 -1
View File
@@ -64,7 +64,7 @@ int vt_x11_init(void)
if(!vt_win)
return -1;
vt_x11_progress = 14;
VT_XSELECT(vt_dpy, vt_win, 0x22000FUL);
VT_XSELECT(vt_dpy, vt_win, 0x22800FUL); /* + ExposureMask */
vt_gc = VT_XGC(vt_dpy, vt_win, 0, 0);
if(!vt_gc)
return -1;
+1 -1
View File
@@ -12,7 +12,7 @@ LOG="$APP/build/fmt.log"
mkdir -p "$APP/build"
"$APP/build.sh" "$DIR/fmt.c" "$APP/src/vt1200/compat.c" >"$APP/build/fmt-build.log" 2>&1
FMT=$(awk '/_out/ {print $1; exit}' "$APP/build/fmt.map")
FMT=$(awk '{for(i=2;i<=NF;i++) if($i=="_out") print $(i-1)}' "$APP/build/fmt.map" | head -1)
VT1200_SKIP_LEVEL1=1 FMT_MARK="0x$FMT" \
LOADER_AT=2500 LOADER_END=2700 \
LOADER_BIN="$ROOT/dwt/loader/build/loader.bin" \
+3
View File
@@ -36,6 +36,7 @@ local key_zero = ports[":lk401:K10"].fields["0 )"]
local key_ret = ports[":lk401:K68"].fields["Return"]
local key_del = ports[":lk401:K67"].fields["Delete"]
local key_q = ports[":lk401:K13"].fields["Q"]
local key_p = ports[":lk401:K22"].fields["P"]
local tabx = ports[":tablet:TABLET_X"].fields["Tablet X"]
local taby = ports[":tablet:TABLET_Y"].fields["Tablet Y"]
local tabb = ports[":tablet:TABLET_BTN"].fields["P1 Button 1"]
@@ -154,6 +155,8 @@ local function key_step(frames, key)
if frames == 3250 then key_del:set_value(0) end
if frames == 3260 then key_q:set_value(1) end
if frames == 3270 then key_q:set_value(0) end
if frames == 3280 then key_p:set_value(1) end
if frames == 3290 then key_p:set_value(0) end
end
local function r32(a)
+2 -2
View File
@@ -8,7 +8,7 @@ M=${MAME:-/home/arti/code/k-space/mame0289/vt1200}
LOG="$APP/build/input.log"
mkdir -p "$APP/build"
"$APP/build.sh" "$DIR/input.c" "$APP/src/vt1200/main.c" "$APP/src/vt1200/x11.c" "$APP/src/vt1200/xgfix.c" >"$APP/build/input-build.log" 2>&1
MARK=$(awk '/_mark/ {print $1; exit}' "$APP/build/input.map")
MARK=$(awk '{for(i=2;i<=NF;i++) if($i=="_mark") print $(i-1)}' "$APP/build/input.map" | head -1)
VT1200_SKIP_LEVEL1=1 INPUT_MARK="0x$MARK" \
LOADER_AT=2500 LOADER_END=3400 \
LOADER_BIN="$ROOT/dwt/loader/build/loader.bin" \
@@ -20,7 +20,7 @@ LOADER_OUT="$APP/build" \
-autoboot_script "$DIR/input.lua" -autoboot_delay 0 \
>"$LOG" 2>&1 || true
grep 'INPUT:' "$LOG" | tail -3
grep -q 'INPUT: .*bytes=.*61 9B 41 9B 42 9B 44 9B 43 30 0A 7F 71' "$LOG" || {
grep -q 'INPUT: .*bytes=.*61 9B 41 9B 42 9B 44 9B 43 30 0A 7F 71 70' "$LOG" || {
echo "input.sh: mapped key sequence missing (see $LOG)" >&2
exit 1
}
+5
View File
@@ -25,6 +25,8 @@
local function hex(v, w) return string.format("%0" .. (w or 8) .. "X", v) end
local machine = manager.machine
local PTICK = tonumber(os.getenv("DIAG_TICK") or "0")
local PQUIT = tonumber(os.getenv("DIAG_QUIT") or "0")
local ports = machine.ioport.ports
local tabx = ports[":tablet:TABLET_X"].fields["Tablet X"]
local taby = ports[":tablet:TABLET_Y"].fields["Tablet Y"]
@@ -274,6 +276,9 @@ local function inspect()
r32(0x01890140), r32(0x01890160), hex(r32(0x01890100)),
hex(r32(0x01890110)), hex(r32(0x01890120)), hex(r32(0x01890130))))
end
if PTICK ~= 0 or PQUIT ~= 0 then
print(string.format("DIAG: tick=%d quit=%d", PTICK ~= 0 and r32(PTICK) or -1, PQUIT ~= 0 and r32(PQUIT) or -1))
end
print(string.format("LOADER: PC at inspection = %s", hex(cpu.state['PC'].value)))
end
+14 -2
View File
@@ -8,8 +8,13 @@ M=${MAME:-/home/arti/code/k-space/mame0289/vt1200}
EV="$APP/evidence"
LOG="$APP/build/play.log"
mkdir -p "$EV" "$APP/build"
OUTNAME=termtris "$APP/build.sh" "$APP/src/vt1200/main.c" "$APP/src/game.c" "$APP/src/vt1200/scoredb.c" \
"$APP/src/vt1200/x11.c" "$APP/src/vt1200/compat.c" "$APP/src/vt1200/xgfix.c" \
>"$APP/build/play-build.log" 2>&1
rm -f "$EV/loader_frame3300.png"
VT1200_SKIP_LEVEL1=1 LOADER_SNAP=1 \
TICK=$(awk '{for(i=2;i<=NF;i++) if($i=="_tick_interval") print $(i-1)}' "$APP/build/termtris.map" | head -1)
QUIT=$(awk '{for(i=2;i<=NF;i++) if($i=="_quit") print $(i-1)}' "$APP/build/termtris.map" | head -1)
VT1200_SKIP_LEVEL1=1 LOADER_SNAP=1 DIAG_TICK="0x$TICK" DIAG_QUIT="0x$QUIT" \
LOADER_AT=2500 LOADER_END=3300 \
LOADER_BIN="$ROOT/dwt/loader/build/loader.bin" \
LOADER_COFF="$APP/build/termtris.coff" \
@@ -19,7 +24,14 @@ LOADER_OUT="$EV" \
-debug -debugger none \
-autoboot_script "$DIR/play.lua" -autoboot_delay 0 \
>"$LOG" 2>&1 || true
grep -E 'PLAY:|LOADER: result|LOADER: snapshot' "$LOG" | tail -6
grep -E 'PLAY:|DIAG:|LOADER: result|LOADER: snapshot' "$LOG" | tail -6
grep -q 'LOADER: result status=0' "$LOG" || { echo "play.sh: the game did not start (see $LOG)" >&2; exit 1; }
DIAG=$(grep -a 'DIAG: tick=' "$LOG" | head -1)
[ -n "$DIAG" ] || { echo "play.sh: no DIAG line (see $LOG)" >&2; exit 1; }
TICKVAL=$(printf '%s' "$DIAG" | sed -n 's/.*tick=\([-0-9]*\).*/\1/p')
QUITVAL=$(printf '%s' "$DIAG" | sed -n 's/.*quit=\([-0-9]*\).*/\1/p')
[ "$TICKVAL" -gt 0 ] || { echo "play.sh: init_game never ran (tick=$TICKVAL)" >&2; exit 1; }
[ "$QUITVAL" = 0 ] || { echo "play.sh: game quit by itself" >&2; exit 1; }
[ -s "$EV/loader_frame3300.png" ] || { echo "play.sh: no snapshot (see $LOG)" >&2; exit 1; }
cp "$EV/loader_frame3300.png" "$EV/termtris_frame3300.png"
echo "play: $EV/termtris_frame3300.png"
+3
View File
@@ -7,6 +7,9 @@ ROOT=$(cd "$APP/../.." && pwd)
M=${MAME:-/home/arti/code/k-space/mame0289/vt1200}
EV="$APP/evidence"
mkdir -p "$EV" "$APP/build"
OUTNAME=termtris "$APP/build.sh" "$APP/src/vt1200/main.c" "$APP/src/game.c" "$APP/src/vt1200/scoredb.c" \
"$APP/src/vt1200/x11.c" "$APP/src/vt1200/compat.c" "$APP/src/vt1200/xgfix.c" \
>"$APP/build/play_keys-build.log" 2>&1
for mode in ${MODES:-move panels quit}; do
LOG="$APP/build/play_$mode.log"
rm -f "$EV/loader_frame3200.png"
+10 -2
View File
@@ -11,8 +11,8 @@ LOG="$APP/build/render.log"
mkdir -p "$EV" "$APP/build"
"$APP/build.sh" "$DIR/render.c" "$APP/src/vt1200/x11.c" "$APP/src/vt1200/xgfix.c" >"$APP/build/render-build.log" 2>&1
rm -f "$EV/loader_frame3400.png"
MARK=$(awk '/_mark/ {print $1; exit}' "$APP/build/render.map")
PROG=$(awk '/_vt_x11_progress/ {print $1; exit}' "$APP/build/render.map")
MARK=$(awk '{for(i=2;i<=NF;i++) if($i=="_mark") print $(i-1)}' "$APP/build/render.map" | head -1)
PROG=$(awk '{for(i=2;i<=NF;i++) if($i=="_vt_x11_progress") print $(i-1)}' "$APP/build/render.map" | head -1)
VT1200_SKIP_LEVEL1=1 LOADER_SNAP=1 RENDER_MARK="0x$MARK" X11_PROGRESS="0x$PROG" \
LOADER_AT=2500 LOADER_END=3400 \
LOADER_BIN="$ROOT/dwt/loader/build/loader.bin" \
@@ -24,6 +24,14 @@ LOADER_OUT="$EV" \
-autoboot_script "$DIR/render.lua" -autoboot_delay 0 \
>"$LOG" 2>&1 || true
grep -E 'LOADER: snapshot|LOADER: result' "$LOG" | tail -4
grep -q 'RENDER: magic=524E4452 .*flus=464C5553' "$LOG" || {
echo "render.sh: the renderer did not finish (see $LOG)" >&2
exit 1
}
grep -q 'RENDER: .*progress=00FFFFFF' "$LOG" || {
echo "render.sh: flush did not complete (see $LOG)" >&2
exit 1
}
[ -s "$EV/loader_frame3400.png" ] || { echo "render.sh: no snapshot (see $LOG)" >&2; exit 1; }
cp "$EV/loader_frame3400.png" "$EV/render_frame3400.png"
echo "render: $EV/render_frame3400.png"
+1 -1
View File
@@ -13,7 +13,7 @@ LOG="$APP/build/smoke.log"
mkdir -p "$APP/build"
"$APP/build.sh" "$DIR/smoke.c" "$APP/src/vt1200/xgfix.c" >"$APP/build/smoke-build.log" 2>&1
MARK=$(awk '/_mark/ {print $1; exit}' "$APP/build/smoke.map")
MARK=$(awk '{for(i=2;i<=NF;i++) if($i=="_mark") print $(i-1)}' "$APP/build/smoke.map" | head -1)
VT1200_SKIP_LEVEL1=1 SMOKE_MARK="0x$MARK" \
LOADER_AT=2500 LOADER_END=3400 \
LOADER_BIN="$ROOT/dwt/loader/build/loader.bin" \
+4 -3
View File
@@ -30,7 +30,7 @@ file as success and retries a missing one. Two quirks are handled there:
Result (map):
```
.text 018A0000 .cinit 018B4730 .bss 01A00000
.text 018A0000 .cinit 018B4B10 .bss 01A00000
ENTRY POINT SYMBOL: "_start" address: 018a0000
```
@@ -51,8 +51,9 @@ Smoke test evidence (`apps/termtris/tests/smoke.sh`):
## Rendering and the flush deadlock
80×24 cells of 6×13 px (the default GC font, baseline +10) → a 480×312 window.
The raster is 1 bit deep, so the backend follows the game's own monochrome
convention: colour is dropped and bold (`0x80`) reverses a cell. The playfield
The raster is 1 bit deep, so the backend drops colour (like the game's `-m`
monochrome mode) and treats the bold bit (`0x80`) as reverse video. That
reversal is this backend's choice; upstream `ansi.c -m` only emits SGR bold. The playfield
is black spaces; tetrominoes are the `[`/`]` tiles.
`vt_x11_flush()` repaints **whole rows** — one fill for the row background, one