diff --git a/.gitignore b/.gitignore index 7bc69e1..c7909c8 100644 --- a/.gitignore +++ b/.gitignore @@ -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.* diff --git a/apps/termtris/VT1200.md b/apps/termtris/VT1200.md index 0add46b..8d418e9 100644 --- a/apps/termtris/VT1200.md +++ b/apps/termtris/VT1200.md @@ -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. diff --git a/apps/termtris/build.sh b/apps/termtris/build.sh index 39c3b06..6b0c33e 100755 --- a/apps/termtris/build.sh +++ b/apps/termtris/build.sh @@ -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 diff --git a/apps/termtris/build/termtris.coff b/apps/termtris/build/termtris.coff index 6c515d9..cf4275a 100644 Binary files a/apps/termtris/build/termtris.coff and b/apps/termtris/build/termtris.coff differ diff --git a/apps/termtris/build/termtris.map b/apps/termtris/build/termtris.map index f8a9ea8..78e98d3 100644 --- a/apps/termtris/build/termtris.map +++ b/apps/termtris/build/termtris.map @@ -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: 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] diff --git a/apps/termtris/evidence/termtris_frame3300.png b/apps/termtris/evidence/termtris_frame3300.png index 47128cb..54cbf26 100644 Binary files a/apps/termtris/evidence/termtris_frame3300.png and b/apps/termtris/evidence/termtris_frame3300.png differ diff --git a/apps/termtris/run.sh b/apps/termtris/run.sh index bc80057..495d30d 100755 --- a/apps/termtris/run.sh +++ b/apps/termtris/run.sh @@ -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 diff --git a/apps/termtris/src/game.c b/apps/termtris/src/game.c index 4eb2cb6..6e7fe04 100644 --- a/apps/termtris/src/game.c +++ b/apps/termtris/src/game.c @@ -25,7 +25,7 @@ along with this program. If not, see . #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; diff --git a/apps/termtris/src/vt1200/main.c b/apps/termtris/src/vt1200/main.c index 650b978..f4500eb 100644 --- a/apps/termtris/src/vt1200/main.c +++ b/apps/termtris/src/vt1200/main.c @@ -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; } } diff --git a/apps/termtris/src/vt1200/x11.c b/apps/termtris/src/vt1200/x11.c index 9d89af5..54139f2 100644 --- a/apps/termtris/src/vt1200/x11.c +++ b/apps/termtris/src/vt1200/x11.c @@ -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; diff --git a/apps/termtris/tests/fmt.sh b/apps/termtris/tests/fmt.sh index acb354b..19ff689 100755 --- a/apps/termtris/tests/fmt.sh +++ b/apps/termtris/tests/fmt.sh @@ -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" \ diff --git a/apps/termtris/tests/input.lua b/apps/termtris/tests/input.lua index ca3c703..fd89e54 100644 --- a/apps/termtris/tests/input.lua +++ b/apps/termtris/tests/input.lua @@ -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) diff --git a/apps/termtris/tests/input.sh b/apps/termtris/tests/input.sh index 6453f57..c4dd04d 100755 --- a/apps/termtris/tests/input.sh +++ b/apps/termtris/tests/input.sh @@ -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 } diff --git a/apps/termtris/tests/play.lua b/apps/termtris/tests/play.lua index 5f35daf..9e91d32 100644 --- a/apps/termtris/tests/play.lua +++ b/apps/termtris/tests/play.lua @@ -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 diff --git a/apps/termtris/tests/play.sh b/apps/termtris/tests/play.sh index 56f88fb..7afc6d9 100755 --- a/apps/termtris/tests/play.sh +++ b/apps/termtris/tests/play.sh @@ -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" diff --git a/apps/termtris/tests/play_keys.sh b/apps/termtris/tests/play_keys.sh index e39565e..a7a1fc0 100755 --- a/apps/termtris/tests/play_keys.sh +++ b/apps/termtris/tests/play_keys.sh @@ -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" diff --git a/apps/termtris/tests/render.sh b/apps/termtris/tests/render.sh index a088feb..74cb5c8 100755 --- a/apps/termtris/tests/render.sh +++ b/apps/termtris/tests/render.sh @@ -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" diff --git a/apps/termtris/tests/smoke.sh b/apps/termtris/tests/smoke.sh index a35d03d..af7044e 100755 --- a/apps/termtris/tests/smoke.sh +++ b/apps/termtris/tests/smoke.sh @@ -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" \ diff --git a/harness/mame/TERMTRIS_REPORT.md b/harness/mame/TERMTRIS_REPORT.md index 5d3f80a..aaa78d2 100644 --- a/harness/mame/TERMTRIS_REPORT.md +++ b/harness/mame/TERMTRIS_REPORT.md @@ -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