Files
vt1200/bad-apple/tools/load_mame.lua
T

213 lines
6.4 KiB
Lua

-- load_mame.lua -- debugger entry for the Bad Apple payload.
--
-- Loads the payload at bit 0x018C0000 and the movie at bit 0x00080000, then
-- enters the payload at the OS idle loop. This is the development path; the
-- real delivery path is tools/load.sh (rdebug + LANCE).
--
-- Env:
-- BA_MODE=one|play (one is the only mode implemented here)
-- BA_MOVIE movie file (default bad-apple/data/test_movie.bin)
-- BA_PAYLOAD raw payload (default bad-apple/player/build/player.bin)
-- BA_ENV player.env with ENTRY_PTR (default .../player.env)
-- BA_AT load frame (default 2500)
-- BA_END inspection/exit frame (default 2600)
local function hex(v, w)
return string.format("%0" .. (w or 8) .. "X", v)
end
local machine = manager.machine
local cpu = machine.devices[':maincpu']
local dbg = machine.debugger
local prog = cpu.spaces['program']
if not dbg then
print("BA ERROR: debugger not enabled; pass -debug")
machine:exit()
return
end
local ORIGIN = 0x018C0000
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 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"
local function read_all(path)
local f, err = io.open(path, "rb")
if not f then
print("BA ERROR: cannot open " .. path .. ": " .. tostring(err))
machine:exit()
return nil
end
local data = f:read("*a")
f:close()
return data
end
local function entry_from_env()
local explicit = os.getenv("BA_ENTRY")
if explicit then
return tonumber(explicit)
end
local f = io.open(ENV_PATH, "r")
if not f then
return ORIGIN
end
for line in f:lines() do
local value = line:match("ENTRY_PTR=0x(%x+)")
if value then
f:close()
return tonumber(value, 16)
end
end
f:close()
return ORIGIN
end
local payload = read_all(PAYLOAD_PATH)
local movie = read_all(MOVIE_PATH)
if not payload or not movie then
return
end
local entry = entry_from_env()
do
local f = io.open(ENV_PATH, "r")
if f then
for line in f:lines() do
local value = line:match("MARK_PTR=0x(%x+)")
if value then
MARK = tonumber(value, 16)
end
end
f:close()
end
end
print(string.format("BA: payload %d bytes, movie %d bytes, entry %s mark %s",
#payload, #movie, hex(entry), hex(MARK)))
local function write_bytes(data, base)
local i
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
local function verify(data, base)
local i
for i = 0, #data - 1 do
if prog:read_u8(base + i * 8) ~= data:byte(i + 1) then
return false, i
end
end
return true, 0
end
local loaded = false
local entered = false
local done = false
local movie_sent = false
local frames = 0
local function load_and_enter()
write_bytes(payload, ORIGIN)
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 + 0x1C * 8, 0x42414450)
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)
prog:write_u32(MARK + 0x34 * 8, WAIT)
prog:write_u32(MARK + 0x38 * 8, 0)
prog:write_u32(MARK + 0x3C * 8, 0) -- debugger path, never network
dbg:command("bpset " .. hex(ENTRY_PC) .. ",,{ pc = " .. hex(entry) .. " ; g }")
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 wait=%d",
START, COUNT, PACE, WAIT))
end
emu.register_frame_done(function()
frames = frames + 1
if frames == AT and not loaded then
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
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 + 10 then
local err = prog:read_u32(MARK)
if err >= 0xBAD00000 then
print(string.format("BA ERROR: marker %s at frame %d",
hex(err), frames))
machine:exit()
end
end
if frames >= STOP_AT then
print(string.format("BA: end at frame %d (loaded=%s done=%s) status=%04X frame=%d magic=%08X",
frames, tostring(loaded), tostring(done),
prog:read_u16(MARK + 0x10 * 8), prog:read_u16(MARK),
prog:read_u32(MARK + 0x1C * 8)))
machine:exit()
end
end, "vt1200-badapple-loader")
dbg.visible_cpu = cpu
dbg.execution_state = 'run'