BizHawk
BizHawk copied to clipboard
[GBA] `event.on_bus_exec` is apparently fired *after* instruction is executed, not before
Summary
Here's a fragment of a (THUMB) GBA game code I'm hooking into:
event.on_bus_exec
documentation states that its callback
Fires immediately before the given address is executed by the core.
However!
event.on_bus_exec(function()
emu.setregister('R6', 0x1)
end,
0x80045b2)
Does not force game to take the branch at all times. Changing address to 0x80045b0
makes code work as intended.
Repro
Use the above script with Metroid Fusion (USA). The code in question is responsible for skipping starting sound playback under certain conditions and successful modification disables playback entirely.
Host env.
- BizHawk 2.9.1; Manjaro; Nvidia
I think this might actually be rather be some prefetch funny business? i.e. the PC is always behind/ahead (depending on your perspective) than what is actually being executed. See https://github.com/TASEmulators/mgba/blob/645282a395aac6d7bbd6f80124517bebbe108e57/include/mgba/internal/arm/isa-inlines.h#L126 and https://github.com/TASEmulators/mgba/blob/645282a395aac6d7bbd6f80124517bebbe108e57/src/arm/arm.c#L200-L226
That code seems to be designed to counter-act prefetch, though? R15 (PC) is always kept two instructions ahead of current instruction while _ARMPCAddress
subtracts two instructions to compensate for this.
FWIW:
event.on_bus_exec(function(addr)
print(('0x%x'):format(addr)) -- 0x80045b0
print(('0x%x'):format(emu.getregister 'R15')) -- 0x80045b4
emu.setregister('R6', 0x1)
end,
0x80045b0) -- Currently working address, one instruction before expected
The result of _ARMPCAddress is what's actually compared for the address you pass onto on_bus_exec. Although the instruction actually executed is going to be minus one opcode compared to the raw PC, and plus one opcode compared to the value returned by _ARMPCAddress.
To me it looks like that instruction currently being executed would be PC - 2 opcodes, no? Emulated prefetch pipeline is 2 instructions long.
See also #3700 if you're basing your addresses off the trace logger.
@RetroEdit Nice to note, but in my case addresses come from Ghidra.
Exec callback and tracelogger are done at the same point with the same logic, so it's probably related.