Add the fnptr C callback test (direct symbol, volatile local pointer and global pointer), its GSPA entry and marker script, and scripts/tests/m4/ fnptr.sh. The gate compiles at the default -O2 pipeline, requires all four markers to be 42 in MAME, and checks the linked assembly: _apply calls through an A register (CALL, never CALLA) after the argument push, while _fnptr_test keeps the direct CALLA and materialises inc with MOVI. It also pins the GSPA 0x0920 encoding and requires dis34 to decode the call as 'call aN'.
44 lines
1.3 KiB
Lua
44 lines
1.3 KiB
Lua
-- fnptr-check.lua -- M4 function-pointer/indirect-call markers.
|
|
--
|
|
-- M4_LOADER_LUA path to vendor/vt1200/dwt/loader/loader.lua
|
|
-- LOADER_END loader inspection/exit frame
|
|
--
|
|
-- Markers (0x20 bits apart):
|
|
-- 018A8000 apply(inc, 41) == 42
|
|
-- 018A8020 apply(vf, 41) == 42 (volatile local function pointer)
|
|
-- 018A8040 apply(g_fn, 43) == 42 (global function pointer = dec)
|
|
-- 018A8060 fnptr_test() == 42 (return value, stored by the entry)
|
|
|
|
dofile(os.getenv("M4_LOADER_LUA"))
|
|
|
|
local ENDF = tonumber(os.getenv("LOADER_END") or "2700")
|
|
|
|
local frames = 0
|
|
local checked = false
|
|
|
|
emu.register_frame_done(function()
|
|
frames = frames + 1
|
|
if frames == ENDF - 1 and not checked then
|
|
checked = true
|
|
local prog = manager.machine.devices[':maincpu'].spaces['program']
|
|
local m = {}
|
|
for i = 0, 3 do
|
|
m[i] = prog:read_u32(0x018A8000 + i * 0x20)
|
|
end
|
|
print(string.format("M4: fnptr=%d fnptr_volatile=%d fnptr_global=%d fnptr_ret=%d",
|
|
m[0], m[1], m[2], m[3]))
|
|
local want = {42, 42, 42, 42}
|
|
local ok = true
|
|
for i = 0, 3 do
|
|
if m[i] ~= want[i + 1] then
|
|
ok = false
|
|
end
|
|
end
|
|
if ok then
|
|
print("M4 MAME: PASS")
|
|
else
|
|
print("M4 MAME: FAIL (want fnptr=42 fnptr_volatile=42 fnptr_global=42 fnptr_ret=42)")
|
|
end
|
|
end
|
|
end, "fnptr-check")
|