diff --git a/core/cpuhook.h b/core/cpuhook.h new file mode 100644 index 0000000..b656077 --- /dev/null +++ b/core/cpuhook.h @@ -0,0 +1,80 @@ +/*************************************************************************************** + * Genesis Plus GX + * CPU hooking support + * + * Copyright DrMefistO (2018-2019) + + * Copyright feos (2019) + * + * Redistribution and use of this code or any derivative works are permitted + * provided that the following conditions are met: + * + * - Redistributions may not be sold, nor may they be used in a commercial + * product or activity. + * + * - Redistributions that are modified from the original source must include the + * complete source code, including the source code for all components used by a + * binary built from the modified sources. However, as a special exception, the + * source code distributed need not include anything that is normally distributed + * (in either source or binary form) with the major components (compiler, kernel, + * and so on) of the operating system on which the executable runs, unless that + * component itself accompanies the executable. + * + * - Redistributions must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************************/ + +#ifndef _CPUHOOK_H_ +#define _CPUHOOK_H_ + +typedef enum { + HOOK_ANY = (0 << 0), + + // M68K + HOOK_M68K_E = (1 << 0), + HOOK_M68K_R = (1 << 1), + HOOK_M68K_W = (1 << 2), + HOOK_M68K_RW = HOOK_M68K_R | HOOK_M68K_W, + + // VDP + HOOK_VRAM_R = (1 << 3), + HOOK_VRAM_W = (1 << 4), + HOOK_VRAM_RW = HOOK_VRAM_R | HOOK_VRAM_W, + + HOOK_CRAM_R = (1 << 5), + HOOK_CRAM_W = (1 << 6), + HOOK_CRAM_RW = HOOK_CRAM_R | HOOK_CRAM_W, + + HOOK_VSRAM_R = (1 << 7), + HOOK_VSRAM_W = (1 << 8), + HOOK_VSRAM_RW = HOOK_VSRAM_R | HOOK_VSRAM_W, + + // Z80 + HOOK_Z80_E = (1 << 9), + HOOK_Z80_R = (1 << 10), + HOOK_Z80_W = (1 << 11), + HOOK_Z80_RW = HOOK_Z80_R | HOOK_Z80_W, + + // REGS + HOOK_VDP_REG = (1 << 12), + HOOK_M68K_REG = (1 << 13), +} hook_type_t; + +void (*cpu_hook)(hook_type_t type, int width, unsigned int address, unsigned int value); +void set_cpu_hook(void(*hook)(hook_type_t type, int width, unsigned int address, unsigned int value)); + +#endif /* _CPUHOOK_H_ */ \ No newline at end of file diff --git a/core/m68k/m68k.h b/core/m68k/m68k.h index 0aed500..244e000 100644 --- a/core/m68k/m68k.h +++ b/core/m68k/m68k.h @@ -43,6 +43,7 @@ #include #include "macros.h" +#include "cpuhook.h" /* ======================================================================== */ /* ==================== ARCHITECTURE-DEPENDANT DEFINES ==================== */ diff --git a/core/m68k/m68kcpu.c b/core/m68k/m68kcpu.c index 37020bd..e4b48f2 100644 --- a/core/m68k/m68kcpu.c +++ b/core/m68k/m68kcpu.c @@ -72,6 +72,19 @@ static void default_set_fc_callback(unsigned int new_fc) #endif +/* CPU hook is called on read, write, and execute, if HOOK_CPU is defined in + * a makefile or an MSVC project. Use set_cpu_hook() to assign a callback + * that can process the data provided by cpu_hook(). + */ + +void (*cpu_hook)(hook_type_t type, int width, unsigned int address, unsigned int value) = NULL; + +void set_cpu_hook(void (*hook)(hook_type_t type, int width, unsigned int address, unsigned int value)) +{ + cpu_hook = hook; +} + + /* ======================================================================== */ /* ================================= API ================================== */ /* ======================================================================== */ @@ -289,6 +302,12 @@ void m68k_run(unsigned int cycles) /* Set the address space for reads */ m68ki_use_data_space() /* auto-disable (see m68kcpu.h) */ +#ifdef HOOK_CPU + /* Trigger execution hook */ + if (cpu_hook) + cpu_hook(HOOK_M68K_E, 0, REG_PC, 0); +#endif + /* Decode next instruction */ REG_IR = m68ki_read_imm_16(); diff --git a/core/m68k/m68kcpu.h b/core/m68k/m68kcpu.h index bd4f63f..13f0c0a 100644 --- a/core/m68k/m68kcpu.h +++ b/core/m68k/m68kcpu.h @@ -849,36 +849,60 @@ INLINE uint m68ki_read_imm_32(void) */ INLINE uint m68ki_read_8(uint address) { - cpu_memory_map *temp = &m68ki_cpu.memory_map[((address)>>16)&0xff];; + cpu_memory_map *temp = &m68ki_cpu.memory_map[((address)>>16)&0xff]; + uint val; m68ki_set_fc(FLAG_S | m68ki_get_address_space()) /* auto-disable (see m68kcpu.h) */ - if (temp->read8) return (*temp->read8)(ADDRESS_68K(address)); - else return READ_BYTE(temp->base, (address) & 0xffff); + if (temp->read8) val = (*temp->read8)(ADDRESS_68K(address)); + else val = READ_BYTE(temp->base, (address) & 0xffff); + +#ifdef HOOK_CPU + if (cpu_hook) + cpu_hook(HOOK_M68K_R, 1, address, val); +#endif + + return val; } INLINE uint m68ki_read_16(uint address) { cpu_memory_map *temp; + uint val; m68ki_set_fc(FLAG_S | m68ki_get_address_space()) /* auto-disable (see m68kcpu.h) */ m68ki_check_address_error(address, MODE_READ, FLAG_S | m68ki_get_address_space()) /* auto-disable (see m68kcpu.h) */ temp = &m68ki_cpu.memory_map[((address)>>16)&0xff]; - if (temp->read16) return (*temp->read16)(ADDRESS_68K(address)); - else return *(uint16 *)(temp->base + ((address) & 0xffff)); + if (temp->read16) val = (*temp->read16)(ADDRESS_68K(address)); + else val = *(uint16 *)(temp->base + ((address) & 0xffff)); + +#ifdef HOOK_CPU + if (cpu_hook) + cpu_hook(HOOK_M68K_R, 2, address, val); +#endif + + return val; } INLINE uint m68ki_read_32(uint address) { cpu_memory_map *temp; + uint val; m68ki_set_fc(FLAG_S | m68ki_get_address_space()) /* auto-disable (see m68kcpu.h) */ m68ki_check_address_error(address, MODE_READ, FLAG_S | m68ki_get_address_space()) /* auto-disable (see m68kcpu.h) */ temp = &m68ki_cpu.memory_map[((address)>>16)&0xff]; - if (temp->read16) return ((*temp->read16)(ADDRESS_68K(address)) << 16) | ((*temp->read16)(ADDRESS_68K(address + 2))); - else return m68k_read_immediate_32(address); + if (temp->read16) val = ((*temp->read16)(ADDRESS_68K(address)) << 16) | ((*temp->read16)(ADDRESS_68K(address + 2))); + else val = m68k_read_immediate_32(address); + +#ifdef HOOK_CPU + if (cpu_hook) + cpu_hook(HOOK_M68K_R, 4, address, val); +#endif + + return val; } INLINE void m68ki_write_8(uint address, uint value) @@ -887,6 +911,11 @@ INLINE void m68ki_write_8(uint address, uint value) m68ki_set_fc(FLAG_S | FUNCTION_CODE_USER_DATA) /* auto-disable (see m68kcpu.h) */ +#ifdef HOOK_CPU + if (cpu_hook) + cpu_hook(HOOK_M68K_W, 1, address, value); +#endif + temp = &m68ki_cpu.memory_map[((address)>>16)&0xff]; if (temp->write8) (*temp->write8)(ADDRESS_68K(address),value); else WRITE_BYTE(temp->base, (address) & 0xffff, value); @@ -899,6 +928,11 @@ INLINE void m68ki_write_16(uint address, uint value) m68ki_set_fc(FLAG_S | FUNCTION_CODE_USER_DATA) /* auto-disable (see m68kcpu.h) */ m68ki_check_address_error(address, MODE_WRITE, FLAG_S | FUNCTION_CODE_USER_DATA); /* auto-disable (see m68kcpu.h) */ +#ifdef HOOK_CPU + if (cpu_hook) + cpu_hook(HOOK_M68K_W, 2, address, value); +#endif + temp = &m68ki_cpu.memory_map[((address)>>16)&0xff]; if (temp->write16) (*temp->write16)(ADDRESS_68K(address),value); else *(uint16 *)(temp->base + ((address) & 0xffff)) = value; @@ -911,6 +945,11 @@ INLINE void m68ki_write_32(uint address, uint value) m68ki_set_fc(FLAG_S | FUNCTION_CODE_USER_DATA) /* auto-disable (see m68kcpu.h) */ m68ki_check_address_error(address, MODE_WRITE, FLAG_S | FUNCTION_CODE_USER_DATA) /* auto-disable (see m68kcpu.h) */ +#ifdef HOOK_CPU + if (cpu_hook) + cpu_hook(HOOK_M68K_W, 4, address, value); +#endif + temp = &m68ki_cpu.memory_map[((address)>>16)&0xff]; if (temp->write16) (*temp->write16)(ADDRESS_68K(address),value>>16); else *(uint16 *)(temp->base + ((address) & 0xffff)) = value >> 16; diff --git a/core/vdp_ctrl.c b/core/vdp_ctrl.c index 82b9f1e..cc40063 100644 --- a/core/vdp_ctrl.c +++ b/core/vdp_ctrl.c @@ -2167,6 +2167,11 @@ static void vdp_bus_w(unsigned int data) MARK_BG_DIRTY (index); } +#ifdef HOOK_CPU + if (cpu_hook) + cpu_hook(HOOK_VRAM_W, 2, addr, data); +#endif + #ifdef LOGVDP error("[%d(%d)][%d(%d)] VRAM 0x%x write -> 0x%x (%x)\n", v_counter, (v_counter + (m68k.cycles - mcycles_vdp)/MCYCLES_PER_LINE)%lines_per_frame, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC)); #endif @@ -2210,6 +2215,12 @@ static void vdp_bus_w(unsigned int data) remap_line(v_counter); } } + +#ifdef HOOK_CPU + if (cpu_hook) + cpu_hook(HOOK_CRAM_W, 2, addr, data); +#endif + #ifdef LOGVDP error("[%d(%d)][%d(%d)] CRAM 0x%x write -> 0x%x (%x)\n", v_counter, (v_counter + (m68k.cycles - mcycles_vdp)/MCYCLES_PER_LINE)%lines_per_frame, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC)); #endif @@ -2230,6 +2241,12 @@ static void vdp_bus_w(unsigned int data) render_line(v_counter); } } + +#ifdef HOOK_CPU + if (cpu_hook) + cpu_hook(HOOK_VSRAM_W, 2, addr, data); +#endif + #ifdef LOGVDP error("[%d(%d)][%d(%d)] VSRAM 0x%x write -> 0x%x (%x)\n", v_counter, (v_counter + (m68k.cycles - mcycles_vdp)/MCYCLES_PER_LINE)%lines_per_frame, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC)); #endif @@ -2434,6 +2451,11 @@ static unsigned int vdp_68k_data_r_m5(void) /* read two bytes from VRAM */ data = *(uint16 *)&vram[addr & 0xFFFE]; +#ifdef HOOK_CPU + if (cpu_hook) + cpu_hook(HOOK_VRAM_R, 2, addr, data); +#endif + #ifdef LOGVDP error("[%d(%d)][%d(%d)] VRAM 0x%x read -> 0x%x (%x)\n", v_counter, (v_counter + (m68k.cycles - mcycles_vdp)/MCYCLES_PER_LINE)%lines_per_frame, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC)); #endif @@ -2458,6 +2480,11 @@ static unsigned int vdp_68k_data_r_m5(void) /* Unused bits are set using data from next available FIFO entry */ data |= (fifo[fifo_idx] & ~0x7FF); +#ifdef HOOK_CPU + if (cpu_hook) + cpu_hook(HOOK_VSRAM_R, 2, addr, data); +#endif + #ifdef LOGVDP error("[%d(%d)][%d(%d)] VSRAM 0x%x read -> 0x%x (%x)\n", v_counter, (v_counter + (m68k.cycles - mcycles_vdp)/MCYCLES_PER_LINE)%lines_per_frame, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC)); #endif @@ -2475,6 +2502,11 @@ static unsigned int vdp_68k_data_r_m5(void) /* Unused bits are set using data from next available FIFO entry */ data |= (fifo[fifo_idx] & ~0xEEE); +#ifdef HOOK_CPU + if (cpu_hook) + cpu_hook(HOOK_CRAM_R, 2, addr, data); +#endif + #ifdef LOGVDP error("[%d(%d)][%d(%d)] CRAM 0x%x read -> 0x%x (%x)\n", v_counter, (v_counter + (m68k.cycles - mcycles_vdp)/MCYCLES_PER_LINE)%lines_per_frame, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC)); #endif @@ -2489,6 +2521,11 @@ static unsigned int vdp_68k_data_r_m5(void) /* Unused bits are set using data from next available FIFO entry */ data |= (fifo[fifo_idx] & ~0xFF); +#ifdef HOOK_CPU + if (cpu_hook) + cpu_hook(HOOK_VRAM_R, 2, addr, data); +#endif + #ifdef LOGVDP error("[%d(%d)][%d(%d)] 8-bit VRAM 0x%x read -> 0x%x (%x)\n", v_counter, (v_counter + (m68k.cycles - mcycles_vdp)/MCYCLES_PER_LINE)%lines_per_frame, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC)); #endif diff --git a/libretro/libretro_msvc/genesis_plus_gx_libretro.vcxproj b/libretro/libretro_msvc/genesis_plus_gx_libretro.vcxproj index 9f1b203..00b7e10 100644 --- a/libretro/libretro_msvc/genesis_plus_gx_libretro.vcxproj +++ b/libretro/libretro_msvc/genesis_plus_gx_libretro.vcxproj @@ -308,6 +308,7 @@ + diff --git a/libretro/libretro_msvc/genesis_plus_gx_libretro.vcxproj.filters b/libretro/libretro_msvc/genesis_plus_gx_libretro.vcxproj.filters index d4633c9..765739f 100644 --- a/libretro/libretro_msvc/genesis_plus_gx_libretro.vcxproj.filters +++ b/libretro/libretro_msvc/genesis_plus_gx_libretro.vcxproj.filters @@ -749,5 +749,8 @@ core + + core + \ No newline at end of file diff --git a/sdl/Makefile.sdl1 b/sdl/Makefile.sdl1 index 4a8699e..142878a 100644 --- a/sdl/Makefile.sdl1 +++ b/sdl/Makefile.sdl1 @@ -18,12 +18,13 @@ # -D15BPP_RENDERING - configure for 15-bit pixels (RGB555) # -D16BPP_RENDERING - configure for 16-bit pixels (RGB565) # -D32BPP_RENDERING - configure for 32-bit pixels (RGB888) -# -DUSE_LIBCHDR : enable CHD file support -# -DUSE_LIBTREMOR : enable OGG file support for CD emulation using provided TREMOR library -# -DUSE_LIBVORBIS : enable OGG file support for CD emulation using external VORBIS library +# -DUSE_LIBCHDR : enable CHD file support +# -DUSE_LIBTREMOR : enable OGG file support for CD emulation using provided TREMOR library +# -DUSE_LIBVORBIS : enable OGG file support for CD emulation using external VORBIS library # -DISABLE_MANY_OGG_OPEN_FILES : only have one OGG file opened at once to save RAM -# -DMAXROMSIZE: defines maximal size of ROM/SRAM buffer (also shared with CD hardware) */ -# -DHAVE_YM3438_CORE: enable (configurable) support for Nuked cycle-accurate YM3438 core */ +# -DMAXROMSIZE : defines maximal size of ROM/SRAM buffer (also shared with CD hardware) +# -DHAVE_YM3438_CORE : enable (configurable) support for Nuked cycle-accurate YM3438 core +# -DHOOK_CPU : enable CPU hooks NAME = gen_sdl diff --git a/sdl/Makefile.sdl2 b/sdl/Makefile.sdl2 index 03bbce4..2df1ac0 100644 --- a/sdl/Makefile.sdl2 +++ b/sdl/Makefile.sdl2 @@ -18,12 +18,13 @@ # -D15BPP_RENDERING - configure for 15-bit pixels (RGB555) # -D16BPP_RENDERING - configure for 16-bit pixels (RGB565) # -D32BPP_RENDERING - configure for 32-bit pixels (RGB888) -# -DUSE_LIBCHDR : enable CHD file support -# -DUSE_LIBTREMOR : enable OGG file support for CD emulation using provided TREMOR library -# -DUSE_LIBVORBIS : enable OGG file support for CD emulation using external VORBIS library +# -DUSE_LIBCHDR : enable CHD file support +# -DUSE_LIBTREMOR : enable OGG file support for CD emulation using provided TREMOR library +# -DUSE_LIBVORBIS : enable OGG file support for CD emulation using external VORBIS library # -DISABLE_MANY_OGG_OPEN_FILES : only have one OGG file opened at once to save RAM -# -DMAXROMSIZE: defines maximal size of ROM/SRAM buffer (also shared with CD hardware) */ -# -DHAVE_YM3438_CORE: enable (configurable) support for Nuked cycle-accurate YM3438 core */ +# -DMAXROMSIZE : defines maximal size of ROM/SRAM buffer (also shared with CD hardware) +# -DHAVE_YM3438_CORE : enable (configurable) support for Nuked cycle-accurate YM3438 core +# -DHOOK_CPU : enable CPU hooks NAME = gen_sdl2