BizHawk icon indicating copy to clipboard operation
BizHawk copied to clipboard

[GBA] `event.on_bus_exec` is apparently fired *after* instruction is executed, not before

Open v1993 opened this issue 8 months ago • 7 comments

Summary

Here's a fragment of a (THUMB) GBA game code I'm hooking into:

Screenshot_20231011_163740

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

v1993 avatar Oct 11 '23 13:10 v1993

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

CasualPokePlayer avatar Oct 11 '23 22:10 CasualPokePlayer

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

v1993 avatar Oct 12 '23 09:10 v1993

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.

CasualPokePlayer avatar Oct 12 '23 09:10 CasualPokePlayer

To me it looks like that instruction currently being executed would be PC - 2 opcodes, no? Emulated prefetch pipeline is 2 instructions long.

v1993 avatar Oct 12 '23 09:10 v1993

See also #3700 if you're basing your addresses off the trace logger.

RetroEdit avatar Oct 14 '23 23:10 RetroEdit

@RetroEdit Nice to note, but in my case addresses come from Ghidra.

v1993 avatar Oct 14 '23 23:10 v1993

Exec callback and tracelogger are done at the same point with the same logic, so it's probably related.

CasualPokePlayer avatar Oct 14 '23 23:10 CasualPokePlayer