mirror of
https://git.k-space.ee/arti/vt1200.git
synced 2026-10-30 12:03:54 +02:00
Runtime region-writes (on-disk ROM untouched) applied after the level-0 ROM
checksum:
three known failing checks: 3FA73980 CA04->C004, 3FA76060 CB04->C004,
3FA760F0 CB04->C004 (skip the c6/c0/c1 flag stores)
VT1200_L1PATCH_EXTRA adds the second-round checks 3FA761F0 / 3FA763A0
(the retry loop reaches c3/c2 once c0/c1 stop short-circuiting)
VT1200_L1PATCH_VERDICT optionally forces L3FA6E4B0's return (3FA71B60
4D28 move a9,a8 -> 5708 clr a8)
With the five branch patches the HOST PORT test's caller returns 0 and no
'HOST PORT - 15' is printed, but level 1 does not complete: the CPU stays in
the DUART ISR chain (INT1 0x0F60 -> 3FA92F40 -> L3FA78D90 -> 3FA78xxx-3FA7Bxxx)
for >19000 frames with no error. l1p_pie_frame1500.png is a frame dump of the
self-test circle/pie -- the renderer draws curves, fills and blits correctly.
95 lines
4.0 KiB
Lua
95 lines
4.0 KiB
Lua
-- l1patch.lua -- runtime ROM patch for the level-1 HOST PORT test, plus a
|
|
-- console capture, so level 1 can run past it and report the rest of the tests.
|
|
--
|
|
-- Mechanism: manager.machine.memory.regions[':maincpu']:write_u16() writes into
|
|
-- the host-side region buffer (bypasses the read-only CPU mapping). The
|
|
-- on-disk ROM is never touched. Applied after the level-0 ROM checksum.
|
|
--
|
|
-- VT1200_L1PATCH=1 enable the patch
|
|
-- VT1200_L1PATCH_AT=<n> frame to apply at (default 50)
|
|
-- VT1200_L1PATCH_EXTRA=1 also patch the two extra L3FA753D0 checks
|
|
-- VT1200_L1PATCH_VERDICT=1 also force L3FA6E4B0's return to 0
|
|
-- VT1200_L1PATCH_MAX=<n> exit frame (default 3000)
|
|
|
|
local machine = manager.machine
|
|
local cpu = machine.devices[':maincpu']
|
|
local dbg = machine.debugger
|
|
local mem = machine.memory
|
|
if not dbg then print("ERROR: no debugger"); machine:exit(); return end
|
|
|
|
local ROM_BIT_BASE = 0x3F200000
|
|
local region = mem.regions[':maincpu']
|
|
local function bitoff(a) return (a - ROM_BIT_BASE) >> 3 end
|
|
|
|
local enabled = (os.getenv("VT1200_L1PATCH") ~= nil)
|
|
local at = tonumber(os.getenv("VT1200_L1PATCH_AT") or "50")
|
|
local maxframes = tonumber(os.getenv("VT1200_L1PATCH_MAX") or "3000")
|
|
|
|
-- c0/c1 (and c6) are the report's three known failing checks; c2/c3 are the
|
|
-- second-round checks the retry loop reaches once c0/c1 stop short-circuiting.
|
|
local patches = {
|
|
{ 0x3FA73980, 0xCA04, 0xC004, "L3FA71BC0 flag c6 (SRA parity) -> skip store" },
|
|
{ 0x3FA76060, 0xCB04, 0xC004, "L3FA753D0 flag c0 (OVR) -> skip store" },
|
|
{ 0x3FA760F0, 0xCB04, 0xC004, "L3FA753D0 flag c1 (FFULL) -> skip store" },
|
|
}
|
|
if os.getenv("VT1200_L1PATCH_EXTRA") then
|
|
patches[#patches + 1] = { 0x3FA761F0, 0xCA04, 0xC004, "L3FA753D0 flag c3 (direct SRA read) -> skip store" }
|
|
patches[#patches + 1] = { 0x3FA763A0, 0xCA04, 0xC004, "L3FA753D0 flag c2 (framing) -> skip store" }
|
|
end
|
|
if os.getenv("VT1200_L1PATCH_VERDICT") then
|
|
patches[#patches + 1] = { 0x3FA71B60, 0x4D28, 0x5708, "L3FA6E4B0 verdict: move a9,a8 -> clr a8 (force return 0)" }
|
|
end
|
|
|
|
local function apply_patches()
|
|
if not region then print("L1PATCH ERROR: no region"); return end
|
|
print(string.format("L1PATCH applying %d patches", #patches))
|
|
for _, p in ipairs(patches) do
|
|
local off = bitoff(p[1])
|
|
local before = region:read_u16(off)
|
|
if before ~= p[2] then
|
|
print(string.format("L1PATCH ERROR %08X: expected %04X found %04X", p[1], p[2], before))
|
|
else
|
|
region:write_u16(off, p[3])
|
|
print(string.format("L1PATCH %08X off=%#010x %04X -> %04X (cpu reads %04X) %s",
|
|
p[1], off, p[2], p[3], cpu.spaces['program']:read_u16(p[1]), p[4]))
|
|
end
|
|
end
|
|
end
|
|
|
|
-- console printer: a9 = message pointer (resolved offline)
|
|
dbg:command('bpset 3fde00c0,,{ printf "PRINT pc=%08X a9=%08X a11=%08X\\n", pc, a9, a11 ; g }')
|
|
-- host-port caller return (level-1 generic tester verdict)
|
|
dbg:command('bpset 3fa84fe0,,{ printf "HOSTPORT-RET a8=%08X\\n", a8 ; g }')
|
|
|
|
if enabled and at == 0 then apply_patches() end
|
|
local pc = cpu.state['PC']
|
|
local n = 0
|
|
local hist, first, last = {}, {}, 0
|
|
emu.register_frame_done(function()
|
|
n = n + 1
|
|
if enabled and n == at then apply_patches() end
|
|
if os.getenv("VT1200_L1PATCH_TRACE") and n == tonumber(os.getenv("VT1200_L1PATCH_TRACE_AT") or "1") then
|
|
dbg:command('trace ' .. os.getenv("VT1200_L1PATCH_TRACE"))
|
|
end
|
|
if os.getenv("VT1200_L1PATCH_TRACE") and n == (tonumber(os.getenv("VT1200_L1PATCH_TRACE_AT") or "1") + 1) then
|
|
dbg:command('trace off')
|
|
end
|
|
local v = pc.value
|
|
hist[v] = (hist[v] or 0) + 1
|
|
if not first[v] then first[v] = n end
|
|
last = v
|
|
if n >= maxframes then
|
|
print(string.format("--- frames=%d last PC=%08X ---", n, last))
|
|
local list = {}
|
|
for k, c in pairs(hist) do list[#list + 1] = { k, c } end
|
|
table.sort(list, function(a, b) return a[2] > b[2] end)
|
|
for i = 1, math.min(12, #list) do
|
|
print(string.format(" PC=%08X samples=%d first_frame=%d", list[i][1], list[i][2], first[list[i][1]]))
|
|
end
|
|
machine:exit()
|
|
end
|
|
end, "vt1200-l1patch")
|
|
|
|
dbg.visible_cpu = cpu
|
|
dbg.execution_state = 'run'
|