From 116356a9756cdd84661372764b28f350c9a795a7 Mon Sep 17 00:00:00 2001 From: Arti Zirk Date: Sun, 1 Nov 2026 10:16:12 +0200 Subject: [PATCH] feat(badapple): full 30s stream and MAME exactness --- bad-apple/data/manifest.json | 31 +++++++++++++++++++++++++++++ bad-apple/player/fill.asm | 5 +++++ bad-apple/player/main.c | 10 ++++++++++ bad-apple/player/movie.c | 33 +++++++++++++++++++------------ bad-apple/player/movie.h | 16 +++++---------- bad-apple/tools/load_mame.lua | 37 ++++++++++++++++++++++++++--------- bad-apple/tools/run_mame.sh | 3 ++- 7 files changed, 102 insertions(+), 33 deletions(-) create mode 100644 bad-apple/data/manifest.json diff --git a/bad-apple/data/manifest.json b/bad-apple/data/manifest.json new file mode 100644 index 0000000..f04d837 --- /dev/null +++ b/bad-apple/data/manifest.json @@ -0,0 +1,31 @@ +{ + "cost_us": { + "max": 37991, + "mean": 7472.0695503699535, + "p50": 7948, + "p95": 12011 + }, + "data_bytes": 2401942, + "dirty_tiles": { + "max": 320, + "mean": 44.899829254410925, + "p50": 47, + "p95": 72 + }, + "display_hz": 72, + "dropped": 43, + "frame_count": 1757, + "height": 512, + "rects": { + "max": 1175, + "mean": 393.14968696642, + "p50": 409, + "p95": 670 + }, + "scale": 2, + "source_fps": 60, + "source_frames": 1800, + "tile": 32, + "video": "/tmp/opencode/badapple-real/hd60.mp4", + "width": 640 +} \ No newline at end of file diff --git a/bad-apple/player/fill.asm b/bad-apple/player/fill.asm index c9fc5c7..d037393 100644 --- a/bad-apple/player/fill.asm +++ b/bad-apple/player/fill.asm @@ -39,6 +39,11 @@ _fill_run_: move *sp+, b2, 1 rets + .globl _vid_dint_ +_vid_dint_: + dint + rets + .globl _fill_init_ _fill_init_: setf 32, 0, 1 diff --git a/bad-apple/player/main.c b/bad-apple/player/main.c index 0dea369..52983d3 100644 --- a/bad-apple/player/main.c +++ b/bad-apple/player/main.c @@ -11,9 +11,12 @@ #define CTRL_PACE (MARK + 0x28 * 8) #define CTRL_MOVIE (MARK + 0x2C * 8) #define CTRL_MOVIELEN (MARK + 0x30 * 8) +#define CTRL_WAIT (MARK + 0x34 * 8) +#define CTRL_READY (MARK + 0x38 * 8) extern void fill_run_(); extern void fill_init_(); +extern void vid_dint_(); unsigned int fill_daddr; unsigned int fill_dydx; @@ -77,6 +80,7 @@ int main() unsigned int movie_len; int rc; + vid_dint_(); fill_init_(); /* Display interrupt at line 1: our only timebase. Interrupts stay off; @@ -95,6 +99,12 @@ int main() movie_len = MOVIE_MAX; } + if (*(unsigned int *)CTRL_WAIT != 0) { + *(unsigned int *)(MARK + 0x10 * 8) = 0x10; /* takeover, waiting for data */ + while (*(unsigned int *)CTRL_READY == 0) { + } + } + rc = movie_open((unsigned char *)movie_base, movie_len, &header); if (rc != 0) { *(unsigned int *)MARK = 0xBAD00001; diff --git a/bad-apple/player/movie.c b/bad-apple/player/movie.c index 5348fd7..c4a67d6 100644 --- a/bad-apple/player/movie.c +++ b/bad-apple/player/movie.c @@ -1,26 +1,30 @@ /* movie.c -- pure decoder for the BAPL tile-delta movie format. * - * C89-compatible: the 1987 TMS34010 compiler has no stdint.h and no mixed - * declarations. The host test compiles this same file with gcc -std=c99. + * K&R C: the 1987 TMS34010 compiler has no const, no ANSI prototypes and no + * stdint.h. The host test compiles this same file with gcc -std=c99. */ #include "movie.h" #define HEADER_SIZE 36 #define INDEX_ENTRY_SIZE 6 -static unsigned int rd16(const unsigned char *p) +static unsigned int rd16(p) +unsigned char *p; { return (unsigned int)p[0] | ((unsigned int)p[1] << 8); } -static unsigned long rd32(const unsigned char *p) +static unsigned long rd32(p) +unsigned char *p; { return (unsigned long)p[0] | ((unsigned long)p[1] << 8) | ((unsigned long)p[2] << 16) | ((unsigned long)p[3] << 24); } -int movie_open(const unsigned char *data, unsigned long len, - struct movie_header *header) +int movie_open(data, len, header) +unsigned char *data; +unsigned long len; +struct movie_header *header; { unsigned int version; @@ -57,10 +61,13 @@ int movie_open(const unsigned char *data, unsigned long len, return 0; } -int movie_decode_frame(const unsigned char *data, unsigned long len, - unsigned int frame, - const struct movie_header *header, - movie_fill_fn fill, void *ctx) +int movie_decode_frame(data, len, frame, header, fill, ctx) +unsigned char *data; +unsigned long len; +unsigned int frame; +struct movie_header *header; +movie_fill_fn fill; +void *ctx; { unsigned long index_off; unsigned long off; @@ -142,7 +149,9 @@ int movie_decode_frame(const unsigned char *data, unsigned long len, return 0; } -unsigned int movie_checksum(const unsigned char *data, unsigned long len) +unsigned int movie_checksum(data, len) +unsigned char *data; +unsigned long len; { unsigned long sum = 0; unsigned long i; @@ -151,7 +160,7 @@ unsigned int movie_checksum(const unsigned char *data, unsigned long len) return 0; } for (i = 0; i < len; i++) { - sum = (sum + data[i]) & 0xFFFFFFFFUL; + sum = (sum + data[i]) & 0xFFFFFFFF; } return (unsigned int)sum; } diff --git a/bad-apple/player/movie.h b/bad-apple/player/movie.h index ef694c5..abf514b 100644 --- a/bad-apple/player/movie.h +++ b/bad-apple/player/movie.h @@ -1,6 +1,7 @@ #ifndef BADAPPLE_MOVIE_H #define BADAPPLE_MOVIE_H +/* K&R declarations: the 1987 TI compiler has no ANSI prototypes. */ struct movie_header { unsigned int width; unsigned int height; @@ -15,17 +16,10 @@ struct movie_header { unsigned int display_hz; }; -typedef void (*movie_fill_fn)(int x, int y, int w, int h, int color, - void *ctx); +typedef void (*movie_fill_fn)(); -int movie_open(const unsigned char *data, unsigned long len, - struct movie_header *header); - -int movie_decode_frame(const unsigned char *data, unsigned long len, - unsigned int frame, - const struct movie_header *header, - movie_fill_fn fill, void *ctx); - -unsigned int movie_checksum(const unsigned char *data, unsigned long len); +int movie_open(); +int movie_decode_frame(); +unsigned int movie_checksum(); #endif diff --git a/bad-apple/tools/load_mame.lua b/bad-apple/tools/load_mame.lua index 679d297..ab60e73 100644 --- a/bad-apple/tools/load_mame.lua +++ b/bad-apple/tools/load_mame.lua @@ -36,6 +36,7 @@ local STOP_AT = tonumber(os.getenv("BA_END") or "2600") local START = tonumber(os.getenv("BA_START") or "0") local COUNT = tonumber(os.getenv("BA_COUNT") or "0") local PACE = tonumber(os.getenv("BA_PACE") or "0") +local WAIT = tonumber(os.getenv("BA_WAIT") or "0") local MOVIE_PATH = os.getenv("BA_MOVIE") or "bad-apple/data/test_movie.bin" local PAYLOAD_PATH = os.getenv("BA_PAYLOAD") or "bad-apple/player/build/player.bin" local ENV_PATH = os.getenv("BA_ENV") or "bad-apple/player/build/player.env" @@ -113,6 +114,7 @@ end local loaded = false local entered = false local done = false +local movie_sent = false local frames = 0 local function load_and_enter() @@ -128,17 +130,20 @@ local function load_and_enter() prog:write_u32(MARK + 0x28 * 8, PACE) prog:write_u32(MARK + 0x2C * 8, MOVIE) prog:write_u32(MARK + 0x30 * 8, #movie) - -- Arm the entry breakpoint before the large movie write; the write blocks - -- emulation, so it cannot fire until the movie is in place. + prog:write_u32(MARK + 0x34 * 8, WAIT) + prog:write_u32(MARK + 0x38 * 8, 0) dbg:command("bpset " .. hex(ENTRY_PC) .. ",,{ pc = " .. hex(entry) .. " ; g }") - write_bytes(movie, MOVIE) - ok, bad = verify(movie, MOVIE) - if not ok then - print("BA ERROR: movie readback mismatch at byte " .. bad) - machine:exit() - return + if WAIT == 0 then + write_bytes(movie, MOVIE) + ok, bad = verify(movie, MOVIE) + if not ok then + print("BA ERROR: movie readback mismatch at byte " .. bad) + machine:exit() + return + end end - print(string.format("BA: loaded; start=%d count=%d pace=%d", START, COUNT, PACE)) + print(string.format("BA: loaded; start=%d count=%d pace=%d wait=%d", + START, COUNT, PACE, WAIT)) end emu.register_frame_done(function() @@ -147,6 +152,20 @@ emu.register_frame_done(function() loaded = true load_and_enter() end + if loaded and WAIT == 1 and not movie_sent + and prog:read_u16(MARK + 0x10 * 8) == 0x10 then + movie_sent = true + print("BA: takeover seen; sending movie to low RAM") + write_bytes(movie, MOVIE) + local ok, bad = verify(movie, MOVIE) + if not ok then + print("BA ERROR: movie readback mismatch at byte " .. bad) + machine:exit() + return + end + prog:write_u32(MARK + 0x38 * 8, 1) + print("BA: movie ready") + end if loaded and not entered then local status = prog:read_u16(MARK + 0x10 * 8) if status == 1 or status == 2 then diff --git a/bad-apple/tools/run_mame.sh b/bad-apple/tools/run_mame.sh index a35a4de..8e9a842 100755 --- a/bad-apple/tools/run_mame.sh +++ b/bad-apple/tools/run_mame.sh @@ -18,6 +18,7 @@ BA_COUNT=${BA_COUNT:-0} BA_AT=${BA_AT:-2500} BA_END=${BA_END:-3000} BA_MOVIE_BASE=${BA_MOVIE_BASE:-0x01D00000} +BA_WAIT=${BA_WAIT:-0} if [ "$MODE" = "play" ]; then BA_PACE=${BA_PACE:-1} @@ -27,7 +28,7 @@ cd "$ROOT" VT1200_SKIP_LEVEL1=1 \ BA_MOVIE="$BA_MOVIE" BA_PACE="$BA_PACE" BA_START="$BA_START" \ BA_COUNT="$BA_COUNT" BA_AT="$BA_AT" BA_END="$BA_END" \ -BA_MOVIE_BASE="$BA_MOVIE_BASE" \ +BA_MOVIE_BASE="$BA_MOVIE_BASE" BA_WAIT="$BA_WAIT" \ "$M" vt1200 -rompath harness/mame/roms -video none -sound none -nothrottle \ -skip_gameinfo -debug -debugger none \ -autoboot_script "$ROOT/bad-apple/tools/load_mame.lua" -autoboot_delay 0