diff --git a/Assets/dll/bsnes.wbx.gz b/Assets/dll/bsnes.wbx.gz index 159417d9e6..202b17a0ce 100644 Binary files a/Assets/dll/bsnes.wbx.gz and b/Assets/dll/bsnes.wbx.gz differ diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesApi.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesApi.cs index c329420ed1..0c7aadd329 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesApi.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesApi.cs @@ -21,6 +21,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES public abstract void snes_set_layer_enables(ref BsnesApi.LayerEnables layerEnables); [BizImport(CallingConvention.Cdecl)] public abstract void snes_set_trace_enabled(bool enabled); + [BizImport(CallingConvention.Cdecl)] + public abstract void snes_set_hooks_enabled(bool readHookEnabled, bool writeHookEnabled, bool executeHookEnabled); [BizImport(CallingConvention.Cdecl)] public abstract BsnesApi.SNES_REGION snes_get_region(); @@ -150,6 +152,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES public delegate void snes_audio_sample_t(short left, short right); public delegate string snes_path_request_t(int slot, string hint, bool required); public delegate void snes_trace_t(string disassembly, string register_info); + public delegate void snes_read_hook_t(uint address); + public delegate void snes_write_hook_t(uint address, byte value); + public delegate void snes_exec_hook_t(uint address); [StructLayout(LayoutKind.Sequential)] public struct CpuRegisters @@ -193,7 +198,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES public snes_video_frame_t videoFrameCb; public snes_audio_sample_t audioSampleCb; public snes_path_request_t pathRequestCb; - public snes_trace_t snesTraceCb; + public snes_trace_t traceCb; + public snes_read_hook_t readHookCb; + public snes_write_hook_t writeHookCb; + public snes_exec_hook_t execHookCb; private static List FieldsInOrder; diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesCore.IEmulator.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesCore.IEmulator.cs index bebcba4ab1..29a65a8734 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesCore.IEmulator.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesCore.IEmulator.cs @@ -48,6 +48,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES }; // TODO: I really don't think stuff like this should be set every single frame (only on change) Api.core.snes_set_layer_enables(ref enables); + Api.core.snes_set_hooks_enabled(MemoryCallbacks.HasReads, MemoryCallbacks.HasWrites, MemoryCallbacks.HasExecutes); Api.core.snes_set_trace_enabled(_tracer.IsEnabled()); Api.core.snes_set_video_enabled(render); Api.core.snes_set_audio_enabled(renderSound); diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesCore.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesCore.cs index fe2490585d..139fc86b60 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesCore.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesCore.cs @@ -59,7 +59,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES videoFrameCb = snes_video_refresh, audioSampleCb = snes_audio_sample, pathRequestCb = snes_path_request, - snesTraceCb = snes_trace + traceCb = snes_trace, + readHookCb = ReadHook, + writeHookCb = WriteHook, + execHookCb = ExecHook }; Api = new BsnesApi(CoreComm.CoreFileProvider.DllPath(), CoreComm, callbacks.AllDelegatesInMemoryOrder()); @@ -383,5 +386,29 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES private void snes_trace(string disassembly, string registerInfo) => _tracer.Put(new(disassembly: disassembly, registerInfo: registerInfo)); + + private void ReadHook(uint addr) + { + if (MemoryCallbacks.HasReads) + { + MemoryCallbacks.CallMemoryCallbacks(addr, 0, (uint) MemoryCallbackFlags.AccessRead, "System Bus"); + } + } + + private void WriteHook(uint addr, byte value) + { + if (MemoryCallbacks.HasWrites) + { + MemoryCallbacks.CallMemoryCallbacks(addr, value, (uint) MemoryCallbackFlags.AccessWrite, "System Bus"); + } + } + + private void ExecHook(uint addr) + { + if (MemoryCallbacks.HasExecutes) + { + MemoryCallbacks.CallMemoryCallbacks(addr, 0, (uint) MemoryCallbackFlags.AccessExecute, "System Bus"); + } + } } } diff --git a/waterbox/bsnescore/bsnes/emulator/platform.hpp b/waterbox/bsnescore/bsnes/emulator/platform.hpp index 0cde99a938..5be9bc46f6 100644 --- a/waterbox/bsnescore/bsnes/emulator/platform.hpp +++ b/waterbox/bsnescore/bsnes/emulator/platform.hpp @@ -26,7 +26,13 @@ struct Platform { virtual auto getBackdropColor() -> uint16 { return 0; } bool traceEnabled = false; + bool readHookEnabled = false; + bool writeHookEnabled = false; + bool executeHookEnabled = false; virtual auto cpuTrace(vector) -> void {} + virtual auto readHook(uint address) -> void {} + virtual auto writeHook(uint address, uint8 value) -> void {} + virtual auto execHook(uint address) -> void {} }; extern Platform* platform; diff --git a/waterbox/bsnescore/bsnes/sfc/cpu/cpu.cpp b/waterbox/bsnescore/bsnes/sfc/cpu/cpu.cpp index bce90f544c..6822a65f4a 100644 --- a/waterbox/bsnescore/bsnes/sfc/cpu/cpu.cpp +++ b/waterbox/bsnescore/bsnes/sfc/cpu/cpu.cpp @@ -36,6 +36,8 @@ auto CPU::main() -> void { if(r.wai) return instructionWait(); if(r.stp) return instructionStop(); if(!status.interruptPending) { + if (__builtin_expect(platform->executeHookEnabled, 0)) + platform->execHook(cpu.r.pc.d); if (platform->traceEnabled) { vector disassembly = disassemble(); disassembly[1].append(" V:", hex(cpu.vcounter(), 3), " H:", hex(cpu.hdot(), 3)); diff --git a/waterbox/bsnescore/bsnes/sfc/cpu/memory.cpp b/waterbox/bsnescore/bsnes/sfc/cpu/memory.cpp index c63de17a44..ecc3d0f690 100644 --- a/waterbox/bsnescore/bsnes/sfc/cpu/memory.cpp +++ b/waterbox/bsnescore/bsnes/sfc/cpu/memory.cpp @@ -7,6 +7,9 @@ auto CPU::idle() -> void { } auto CPU::read(uint address) -> uint8 { + if (__builtin_expect(platform->readHookEnabled, 0)) + platform->readHook(address); + if(address & 0x408000) { if(address & 0x800000 && io.fastROM) { status.clockCount = 6; @@ -46,6 +49,9 @@ auto CPU::read(uint address) -> uint8 { } auto CPU::write(uint address, uint8 data) -> void { + if (__builtin_expect(platform->writeHookEnabled, 0)) + platform->writeHook(address, data); + aluEdge(); if(address & 0x408000) { diff --git a/waterbox/bsnescore/bsnes/target-bsnescore/bsnescore.cpp b/waterbox/bsnescore/bsnes/target-bsnescore/bsnescore.cpp index 95cc6c01a3..a88ad95eee 100644 --- a/waterbox/bsnescore/bsnes/target-bsnescore/bsnescore.cpp +++ b/waterbox/bsnescore/bsnes/target-bsnescore/bsnescore.cpp @@ -267,6 +267,13 @@ EXPORT void snes_set_trace_enabled(bool enabled) platform->traceEnabled = enabled; } +EXPORT void snes_set_hooks_enabled(bool read_hook_enabled, bool write_hook_enabled, bool execute_hook_enabled) +{ + platform->readHookEnabled = read_hook_enabled; + platform->writeHookEnabled = write_hook_enabled; + platform->executeHookEnabled = execute_hook_enabled; +} + EXPORT int snes_get_region(void) { return Region::PAL(); diff --git a/waterbox/bsnescore/bsnes/target-bsnescore/callbacks.h b/waterbox/bsnescore/bsnes/target-bsnescore/callbacks.h index c2f9e84719..3c3b092625 100644 --- a/waterbox/bsnescore/bsnes/target-bsnescore/callbacks.h +++ b/waterbox/bsnescore/bsnes/target-bsnescore/callbacks.h @@ -10,6 +10,9 @@ typedef void (*snes_video_frame_t)(const uint16_t* data, int width, int height, typedef void (*snes_audio_sample_t)(int16_t left, int16_t right); typedef char* (*snes_path_request_t)(int slot, const char* hint, int required); typedef void (*snes_trace_t)(const char* disassembly, const char* register_info); +typedef void (*snes_read_hook_t)(uint32_t address); +typedef void (*snes_write_hook_t)(uint32_t address, uint8_t value); +typedef void (*snes_exec_hook_t)(uint32_t address); struct SnesCallbacks { snes_input_poll_t snes_input_poll; @@ -19,6 +22,9 @@ struct SnesCallbacks { snes_audio_sample_t snes_audio_sample; snes_path_request_t snes_path_request; snes_trace_t snes_trace; + snes_read_hook_t snes_read_hook; + snes_write_hook_t snes_write_hook; + snes_exec_hook_t snes_exec_hook; }; extern SnesCallbacks snesCallbacks; diff --git a/waterbox/bsnescore/bsnes/target-bsnescore/program.cpp b/waterbox/bsnescore/bsnes/target-bsnescore/program.cpp index 8d12cb529a..e82e41cc71 100644 --- a/waterbox/bsnescore/bsnes/target-bsnescore/program.cpp +++ b/waterbox/bsnescore/bsnes/target-bsnescore/program.cpp @@ -23,6 +23,9 @@ struct Program : Emulator::Platform auto notify(string text) -> void override; auto getBackdropColor() -> uint16 override; auto cpuTrace(vector) -> void override; + auto readHook(uint address) -> void override; + auto writeHook(uint address, uint8 value) -> void override; + auto execHook(uint address) -> void override; auto load() -> void; auto loadFile(string location) -> vector; @@ -455,6 +458,21 @@ auto Program::cpuTrace(vector parts) -> void snesCallbacks.snes_trace(parts[0], parts[1]); } +auto Program::readHook(uint address) -> void +{ + snesCallbacks.snes_read_hook(address); +} + +auto Program::writeHook(uint address, uint8 value) -> void +{ + snesCallbacks.snes_write_hook(address, value); +} + +auto Program::execHook(uint address) -> void +{ + snesCallbacks.snes_exec_hook(address); +} + auto Program::getBackdropColor() -> uint16 { return backdropColor;