forked from arti/vt1200
feat(badapple): playback loop and vblank pacing
This commit is contained in:
1 parent
dbfc7b60c5
commit
150a6d86c0
4 files changed
+140
-22
No files matched your search
@@ -1,5 +1,6 @@
|
||||
data/*
|
||||
!data/manifest.json
|
||||
data5/
|
||||
preview/
|
||||
player/build/
|
||||
player/work/
|
||||
|
||||
+69
-9
@@ -6,6 +6,11 @@
|
||||
#define VRAM_BASE 0x04000000
|
||||
#define ROW_BITS 2048
|
||||
#define MARK 0x01810000
|
||||
#define CTRL_START (MARK + 0x20 * 8)
|
||||
#define CTRL_COUNT (MARK + 0x24 * 8)
|
||||
#define CTRL_PACE (MARK + 0x28 * 8)
|
||||
#define CTRL_MOVIE (MARK + 0x2C * 8)
|
||||
#define CTRL_MOVIELEN (MARK + 0x30 * 8)
|
||||
|
||||
extern void fill_run_();
|
||||
extern void fill_init_();
|
||||
@@ -42,33 +47,88 @@ void *ctx;
|
||||
fill_rect(x, y, w, h, color);
|
||||
}
|
||||
|
||||
/* Poll the display interrupt pending bit. Interrupts are disabled; this is
|
||||
* a status bit, not an ISR. A missing DPYINT only costs a bounded spin. */
|
||||
static void wait_vsync()
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned short pending;
|
||||
|
||||
/* Clear a stale DI, then wait for the next one. DPYINT is programmed to
|
||||
* line 1 once at startup, so DI appears at the top of every frame. */
|
||||
*(unsigned short *)0xC0000120 = 0;
|
||||
for (i = 0; i < 200000; i++) {
|
||||
pending = *(unsigned short *)0xC0000120;
|
||||
if (pending & 0x0400) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
struct movie_header header;
|
||||
unsigned int frame;
|
||||
unsigned int last;
|
||||
unsigned int start;
|
||||
unsigned int count;
|
||||
unsigned int pace;
|
||||
unsigned int movie_base;
|
||||
unsigned int movie_len;
|
||||
int rc;
|
||||
|
||||
fill_init_();
|
||||
|
||||
/* Display interrupt at line 1: our only timebase. Interrupts stay off;
|
||||
* wait_vsync() polls the pending bit. */
|
||||
*(unsigned short *)0xC00000A0 = 1;
|
||||
|
||||
/* Start from white; the OS left its own screen behind. */
|
||||
fill_rect(0, 0, 1280, 1024, 0);
|
||||
|
||||
rc = movie_open((unsigned char *)MOVIE_BASE, MOVIE_MAX, &header);
|
||||
movie_base = *(unsigned int *)CTRL_MOVIE;
|
||||
movie_len = *(unsigned int *)CTRL_MOVIELEN;
|
||||
if (movie_base == 0) {
|
||||
movie_base = MOVIE_BASE;
|
||||
}
|
||||
if (movie_len == 0) {
|
||||
movie_len = MOVIE_MAX;
|
||||
}
|
||||
|
||||
rc = movie_open((unsigned char *)movie_base, movie_len, &header);
|
||||
if (rc != 0) {
|
||||
*(unsigned int *)MARK = 0xBAD00001;
|
||||
for (;;) {
|
||||
}
|
||||
}
|
||||
|
||||
rc = movie_decode_frame((unsigned char *)MOVIE_BASE, MOVIE_MAX, 0,
|
||||
&header, paint, 0);
|
||||
if (rc != 0) {
|
||||
*(unsigned int *)MARK = 0xBAD00002;
|
||||
for (;;) {
|
||||
}
|
||||
start = *(unsigned int *)CTRL_START;
|
||||
count = *(unsigned int *)CTRL_COUNT;
|
||||
pace = *(unsigned int *)CTRL_PACE;
|
||||
last = header.frame_count;
|
||||
if (last != 0) {
|
||||
last = last - 1;
|
||||
}
|
||||
if (count != 0 && start + count - 1 < last) {
|
||||
last = start + count - 1;
|
||||
}
|
||||
|
||||
*(unsigned int *)MARK = 0; /* FRAME */
|
||||
*(unsigned int *)(MARK + 0x10 * 8) = 1; /* STATUS: painted */
|
||||
for (frame = 0; frame <= last; frame++) {
|
||||
if (pace != 0 && frame >= start) {
|
||||
wait_vsync();
|
||||
}
|
||||
rc = movie_decode_frame((unsigned char *)movie_base, movie_len, frame,
|
||||
&header, paint, 0);
|
||||
if (rc != 0) {
|
||||
*(unsigned int *)MARK = 0xBAD00002;
|
||||
*(unsigned int *)(MARK + 0x14 * 8) = frame;
|
||||
for (;;) {
|
||||
}
|
||||
}
|
||||
*(unsigned int *)MARK = frame;
|
||||
}
|
||||
|
||||
*(unsigned int *)(MARK + 0x10 * 8) = (count != 0) ? 2 : 1;
|
||||
for (;;) {
|
||||
}
|
||||
}
|
||||
@@ -28,11 +28,14 @@ if not dbg then
|
||||
end
|
||||
|
||||
local ORIGIN = 0x018C0000
|
||||
local MOVIE = 0x00080000
|
||||
local MOVIE = tonumber(os.getenv("BA_MOVIE_BASE") or "0x01D00000")
|
||||
local MARK = 0x01810000
|
||||
local ENTRY_PC = 0x3F579970
|
||||
local AT = tonumber(os.getenv("BA_AT") or "2500")
|
||||
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 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"
|
||||
@@ -80,8 +83,20 @@ print(string.format("BA: payload %d bytes, movie %d bytes, entry %s",
|
||||
|
||||
local function write_bytes(data, base)
|
||||
local i
|
||||
for i = 0, #data - 1 do
|
||||
local n = #data
|
||||
i = 0
|
||||
while i + 4 <= n do
|
||||
local b0 = data:byte(i + 1)
|
||||
local b1 = data:byte(i + 2)
|
||||
local b2 = data:byte(i + 3)
|
||||
local b3 = data:byte(i + 4)
|
||||
local word = b0 | (b1 << 8) | (b2 << 16) | (b3 << 24)
|
||||
prog:write_u32(base + i * 8, word)
|
||||
i = i + 4
|
||||
end
|
||||
while i < n do
|
||||
prog:write_u8(base + i * 8, data:byte(i + 1))
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
@@ -102,21 +117,28 @@ local frames = 0
|
||||
|
||||
local function load_and_enter()
|
||||
write_bytes(payload, ORIGIN)
|
||||
write_bytes(movie, MOVIE)
|
||||
local ok, bad = verify(payload, ORIGIN)
|
||||
if not ok then
|
||||
print("BA ERROR: payload readback mismatch at byte " .. bad)
|
||||
machine:exit()
|
||||
return
|
||||
end
|
||||
prog:write_u32(MARK + 0x20 * 8, START)
|
||||
prog:write_u32(MARK + 0x24 * 8, COUNT)
|
||||
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.
|
||||
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
|
||||
end
|
||||
print("BA: loaded; breakpoint at " .. hex(ENTRY_PC))
|
||||
dbg:command("bpset " .. hex(ENTRY_PC) .. ",,{ pc = " .. hex(entry) .. " ; g }")
|
||||
print(string.format("BA: loaded; start=%d count=%d pace=%d", START, COUNT, PACE))
|
||||
end
|
||||
|
||||
emu.register_frame_done(function()
|
||||
@@ -125,16 +147,18 @@ emu.register_frame_done(function()
|
||||
loaded = true
|
||||
load_and_enter()
|
||||
end
|
||||
if loaded and not entered and prog:read_u16(MARK) == 0x0000
|
||||
and prog:read_u16(MARK + 0x10 * 8) == 0x0001 then
|
||||
entered = true
|
||||
done = true
|
||||
print(string.format("BA: STATUS=painted at frame %d; FRAME=%d",
|
||||
frames, prog:read_u16(MARK)))
|
||||
if loaded and not entered then
|
||||
local status = prog:read_u16(MARK + 0x10 * 8)
|
||||
if status == 1 or status == 2 then
|
||||
entered = true
|
||||
done = true
|
||||
print(string.format("BA: STATUS=%d at frame %d; FRAME=%d",
|
||||
status, frames, prog:read_u16(MARK)))
|
||||
end
|
||||
end
|
||||
if loaded and not done and frames > AT + 30 then
|
||||
if loaded and not done and frames > AT + 10 then
|
||||
local err = prog:read_u32(MARK)
|
||||
if err ~= 0 then
|
||||
if err >= 0xBAD00000 then
|
||||
print(string.format("BA ERROR: marker %s at frame %d",
|
||||
hex(err), frames))
|
||||
machine:exit()
|
||||
|
||||
Executable
+33
@@ -0,0 +1,33 @@
|
||||
#!/bin/sh
|
||||
# Run the payload in MAME with the debugger loader.
|
||||
#
|
||||
# tools/run_mame.sh one # one frame, no pacing
|
||||
# tools/run_mame.sh play # full movie, paced
|
||||
# BA_MOVIE=data5/movie.bin BA_START=180 BA_COUNT=1 tools/run_mame.sh play
|
||||
set -eu
|
||||
|
||||
HERE=$(cd "$(dirname "$0")" && pwd)
|
||||
ROOT=$(cd "$HERE/../.." && pwd)
|
||||
M=${M:-/home/arti/code/k-space/mame0289/vt1200}
|
||||
|
||||
MODE=${1:-one}
|
||||
BA_MOVIE=${BA_MOVIE:-$ROOT/bad-apple/data/test_movie.bin}
|
||||
BA_PACE=${BA_PACE:-0}
|
||||
BA_START=${BA_START:-0}
|
||||
BA_COUNT=${BA_COUNT:-0}
|
||||
BA_AT=${BA_AT:-2500}
|
||||
BA_END=${BA_END:-3000}
|
||||
BA_MOVIE_BASE=${BA_MOVIE_BASE:-0x01D00000}
|
||||
|
||||
if [ "$MODE" = "play" ]; then
|
||||
BA_PACE=${BA_PACE:-1}
|
||||
fi
|
||||
|
||||
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" \
|
||||
"$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
|
||||
Reference in new issue
Block a user