diff --git a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs index c9f685ede4..302a8c8d35 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs @@ -488,6 +488,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy LibGambatte.MemoryCallback readcb; LibGambatte.MemoryCallback writecb; + LibGambatte.MemoryCallback execcb; void RefreshMemoryCallbacks() { @@ -503,9 +504,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy writecb = delegate(uint addr) { mcs.CallWrite(addr); RefreshMemoryCallbacks(); }; else writecb = null; + if (mcs.HasExecutes) + execcb = delegate(uint addr) { mcs.CallExecute(addr); RefreshMemoryCallbacks(); }; + else + execcb = null; LibGambatte.gambatte_setreadcallback(GambatteState, readcb); LibGambatte.gambatte_setwritecallback(GambatteState, writecb); + LibGambatte.gambatte_setexeccallback(GambatteState, execcb); } diff --git a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs index caba667895..00db1c7687 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs @@ -146,7 +146,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy public delegate void MemoryCallback(uint address); /// - /// set a callback to occur immediately BEFORE EVERY cpu read + /// set a callback to occur immediately BEFORE EVERY cpu read, except for opcode first byte fetches /// /// opaque state pointer /// null to clear @@ -161,6 +161,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void gambatte_setwritecallback(IntPtr core, MemoryCallback callback); + /// + /// set a callback to occur immediately BEFORE EVERY cpu opcode (first byte) fetch + /// + /// opaque state pointer + /// null to clear + [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void gambatte_setexeccallback(IntPtr core, MemoryCallback callback); + /// /// type of the cpu trace callback /// diff --git a/libgambatte/include/gambatte.h b/libgambatte/include/gambatte.h index bd1f533fe7..542ce48291 100644 --- a/libgambatte/include/gambatte.h +++ b/libgambatte/include/gambatte.h @@ -88,6 +88,7 @@ public: void setReadCallback(void (*callback)(unsigned)); void setWriteCallback(void (*callback)(unsigned)); + void setExecCallback(void (*callback)(unsigned)); void setTraceCallback(void (*callback)(void *)); void setScanlineCallback(void (*callback)(), int sl); void setRTCCallback(std::time_t (*callback)()); diff --git a/libgambatte/src/cinterface.cpp b/libgambatte/src/cinterface.cpp index cbe7c855d8..d73e727450 100644 --- a/libgambatte/src/cinterface.cpp +++ b/libgambatte/src/cinterface.cpp @@ -83,6 +83,12 @@ __declspec(dllexport) void gambatte_setwritecallback(void *core, void (*callback g->setWriteCallback(callback); } +__declspec(dllexport) void gambatte_setexeccallback(void *core, void (*callback)(unsigned)) +{ + GB *g = (GB *) core; + g->setExecCallback(callback); +} + __declspec(dllexport) void gambatte_settracecallback(void *core, void (*callback)(void *)) { GB *g = (GB *) core; diff --git a/libgambatte/src/cinterface.h b/libgambatte/src/cinterface.h index 8a81d658e5..8389dc0c81 100644 --- a/libgambatte/src/cinterface.h +++ b/libgambatte/src/cinterface.h @@ -24,6 +24,8 @@ extern "C" __declspec(dllexport) void gambatte_setwritecallback(void *core, void (*callback)(unsigned)); + __declspec(dllexport) void gambatte_setexeccallback(void *core, void (*callback)(unsigned)); + __declspec(dllexport) void gambatte_settracecallback(void *core, void (*callback)(void *)); __declspec(dllexport) void gambatte_setscanlinecallback(void *core, void (*callback)(), int sl); diff --git a/libgambatte/src/cpu.cpp b/libgambatte/src/cpu.cpp index 1755228700..711319b7bb 100644 --- a/libgambatte/src/cpu.cpp +++ b/libgambatte/src/cpu.cpp @@ -131,7 +131,7 @@ void CPU::loadState(const SaveState &state) { #define READ(dest, addr) do { (dest) = memory.read(addr, cycleCounter); cycleCounter += 4; } while (0) // #define PC_READ(dest, addr) do { (dest) = memory.pc_read(addr, cycleCounter); cycleCounter += 4; } while (0) -#define PC_READ(dest) do { (dest) = memory.read(PC, cycleCounter); PC = (PC + 1) & 0xFFFF; cycleCounter += 4; } while (0) +#define PC_READ(dest) do { (dest) = memory.read_excb(PC, cycleCounter); PC = (PC + 1) & 0xFFFF; cycleCounter += 4; } while (0) #define FF_READ(dest, addr) do { (dest) = memory.ff_read(addr, cycleCounter); cycleCounter += 4; } while (0) #define WRITE(addr, data) do { memory.write(addr, data, cycleCounter); cycleCounter += 4; } while (0) diff --git a/libgambatte/src/cpu.h b/libgambatte/src/cpu.h index 2bd7ca2e2e..82ffe599c4 100644 --- a/libgambatte/src/cpu.h +++ b/libgambatte/src/cpu.h @@ -75,6 +75,10 @@ public: memory.setWriteCallback(callback); } + void setExecCallback(void (*callback)(unsigned)) { + memory.setExecCallback(callback); + } + void setTraceCallback(void (*callback)(void *)) { tracecallback = callback; } @@ -124,7 +128,7 @@ public: //unsigned char ExternalRead(unsigned short addr) { return memory.read(addr, cycleCounter_); } unsigned char ExternalRead(unsigned short addr) { return memory.peek(addr); } - void ExternalWrite(unsigned short addr, unsigned char val) { memory.write(addr, val, cycleCounter_); } + void ExternalWrite(unsigned short addr, unsigned char val) { memory.write_nocb(addr, val, cycleCounter_); } int LinkStatus(int which) { return memory.LinkStatus(which); } diff --git a/libgambatte/src/gambatte.cpp b/libgambatte/src/gambatte.cpp index bca5e65140..b855f4a62e 100644 --- a/libgambatte/src/gambatte.cpp +++ b/libgambatte/src/gambatte.cpp @@ -103,6 +103,10 @@ void GB::setWriteCallback(void (*callback)(unsigned)) { p_->cpu.setWriteCallback(callback); } +void GB::setExecCallback(void (*callback)(unsigned)) { + p_->cpu.setExecCallback(callback); +} + void GB::setTraceCallback(void (*callback)(void *)) { p_->cpu.setTraceCallback(callback); } diff --git a/libgambatte/src/memory.cpp b/libgambatte/src/memory.cpp index 4b0364c894..66b4c6c5a2 100644 --- a/libgambatte/src/memory.cpp +++ b/libgambatte/src/memory.cpp @@ -29,6 +29,7 @@ Memory::Memory(const Interrupter &interrupter_in) : getInput(0), readCallback(0), writeCallback(0), + execCallback(0), divLastUpdate(0), lastOamDmaUpdate(DISABLED_TIME), display(ioamhram, 0, VideoInterruptRequester(&intreq)), diff --git a/libgambatte/src/memory.h b/libgambatte/src/memory.h index 037eb524b8..e0ec5d210e 100644 --- a/libgambatte/src/memory.h +++ b/libgambatte/src/memory.h @@ -35,6 +35,7 @@ class Memory { void (*readCallback)(unsigned); void (*writeCallback)(unsigned); + void (*execCallback)(unsigned); InputGetter *getInput; unsigned long divLastUpdate; @@ -125,10 +126,23 @@ public: return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_read(P, cycleCounter); } + unsigned read_excb(const unsigned P, const unsigned long cycleCounter) { + if (execCallback) + execCallback(P); + return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_read(P, cycleCounter); + } + unsigned peek(const unsigned P) { return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_peek(P); } + void write_nocb(const unsigned P, const unsigned data, const unsigned long cycleCounter) { + if (cart.wmem(P >> 12)) { + cart.wmem(P >> 12)[P] = data; + } else + nontrivial_write(P, data, cycleCounter); + } + void write(const unsigned P, const unsigned data, const unsigned long cycleCounter) { if (cart.wmem(P >> 12)) { cart.wmem(P >> 12)[P] = data; @@ -161,6 +175,9 @@ public: void setWriteCallback(void (*callback)(unsigned)) { this->writeCallback = callback; } + void setExecCallback(void (*callback)(unsigned)) { + this->execCallback = callback; + } void setScanlineCallback(void (*callback)(), int sl) { display.setScanlineCallback(callback, sl); diff --git a/output/dll/libgambatte.dll b/output/dll/libgambatte.dll index 0e03875488..6f8eb165f7 100644 Binary files a/output/dll/libgambatte.dll and b/output/dll/libgambatte.dll differ