diff --git a/BizHawk.Client.EmuHawk/MainForm.Designer.cs b/BizHawk.Client.EmuHawk/MainForm.Designer.cs index f6659d7bdd..05871bd1c9 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Designer.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Designer.cs @@ -406,6 +406,7 @@ this.ShowMenuContextMenuSeparator = new System.Windows.Forms.ToolStripSeparator(); this.ShowMenuContextMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.timerMouseIdle = new System.Windows.Forms.Timer(this.components); + this.toolStripMenuItem18 = new System.Windows.Forms.ToolStripMenuItem(); this.MainformMenu.SuspendLayout(); this.MainStatusBar.SuspendLayout(); this.MainFormContextMenu.SuspendLayout(); @@ -2816,6 +2817,7 @@ this.GenesisSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.vDPViewerToolStripMenuItem, this.GenesisGameGenieECDC, + this.toolStripMenuItem18, this.toolStripSeparator26, this.GenesisSettingsToolStripMenuItem}); this.GenesisSubMenu.Name = "GenesisSubMenu"; @@ -3586,6 +3588,13 @@ this.timerMouseIdle.Interval = 2000; this.timerMouseIdle.Tick += new System.EventHandler(this.timerMouseIdle_Tick); // + // toolStripMenuItem18 + // + this.toolStripMenuItem18.Name = "toolStripMenuItem18"; + this.toolStripMenuItem18.Size = new System.Drawing.Size(217, 22); + this.toolStripMenuItem18.Text = "Code-Data Logger"; + this.toolStripMenuItem18.Click += new System.EventHandler(this.CodeDataLoggerMenuItem_Click); + // // MainForm // this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; @@ -4003,6 +4012,7 @@ private System.Windows.Forms.ToolStripMenuItem C64SubMenu; private System.Windows.Forms.ToolStripMenuItem C64SettingsMenuItem; private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem16; + private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem18; } } diff --git a/BizHawk.Client.EmuHawk/tools/CDL.cs b/BizHawk.Client.EmuHawk/tools/CDL.cs index 41759c0972..08d798cb8f 100644 --- a/BizHawk.Client.EmuHawk/tools/CDL.cs +++ b/BizHawk.Client.EmuHawk/tools/CDL.cs @@ -10,6 +10,8 @@ using BizHawk.Emulation.Common.IEmulatorExtensions; using BizHawk.Emulation.Cores.Nintendo.Gameboy; using BizHawk.Emulation.Cores.Components.H6280; using BizHawk.Emulation.Cores.PCEngine; +using BizHawk.Emulation.Cores.Consoles.Sega; +using BizHawk.Emulation.Cores.Consoles.Sega.gpgx; using BizHawk.Client.Common; using BizHawk.Client.EmuHawk.ToolExtensions; @@ -79,6 +81,15 @@ namespace BizHawk.Client.EmuHawk else LoggingActiveCheckbox.Checked = _cdl.Active; } + else if (_emu is GPGX) + { + var gpgx = _emu as GPGX; + _cdl = gpgx.CDL; + if (_cdl == null) + LoggingActiveCheckbox.Checked = false; + else + LoggingActiveCheckbox.Checked = _cdl.Active; + } UpdateDisplay(); } @@ -162,6 +173,18 @@ namespace BizHawk.Client.EmuHawk } gambatte.CDL = cdl_gb; } + else if (_emu is GPGX) + { + var gpgx = _emu as GPGX; + var cdl_gb = newCDL as CodeDataLog_GEN; + var memd = gpgx.AsMemoryDomains(); + if (!cdl_gb.CheckConsistency(memd)) + { + MessageBox.Show(this, "CDL file does not match emulator's current memory map!"); + return; + } + gpgx.CDL = cdl_gb; + } } UpdateDisplay(); @@ -206,6 +229,14 @@ namespace BizHawk.Client.EmuHawk gambatte.CDL = cdl_gb; _cdl = cdl_gb; } + else if (_emu is GPGX) + { + var gpgx = _emu as GPGX; + var memd = gpgx.AsMemoryDomains(); + var cdl_gen = CodeDataLog_GEN.Create(memd); + gpgx.CDL = cdl_gen; + _cdl = cdl_gen; + } UpdateDisplay(); } diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index 3f0794343d..0e3960b0b4 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -758,6 +758,7 @@ + diff --git a/BizHawk.Emulation.Cores/CDL.cs b/BizHawk.Emulation.Cores/CDL.cs index 9bc4818de6..080c369313 100644 --- a/BizHawk.Emulation.Cores/CDL.cs +++ b/BizHawk.Emulation.Cores/CDL.cs @@ -8,6 +8,7 @@ using BizHawk.Emulation.Common; //needed for being a factory using BizHawk.Emulation.Cores.Nintendo.Gameboy; using BizHawk.Emulation.Cores.Components.H6280; +using BizHawk.Emulation.Cores.Consoles.Sega; namespace BizHawk.Emulation.Cores.Components.H6280 { @@ -83,6 +84,8 @@ namespace BizHawk.Emulation.Cores.Components.H6280 return new CodeDataLog_PCE().Load(br); else if(FileSubType == "GB") return new CodeDataLog_GB().Load(br); + else if (FileSubType == "GEN") + return new CodeDataLog_GEN().Load(br); else return null; } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/CodeDataLog_GB.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/CodeDataLog_GB.cs index 0b5c18f54d..2ed8f180bc 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/CodeDataLog_GB.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/CodeDataLog_GB.cs @@ -1,8 +1,6 @@ using BizHawk.Emulation.Common; using BizHawk.Emulation.Cores.Components.H6280; -//TODO - refactor into different files - namespace BizHawk.Emulation.Cores.Nintendo.Gameboy { public class CodeDataLog_GB : CodeDataLog @@ -30,6 +28,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy { if (memdomains["ROM"].Size != this["ROM"].Length) return false; if (memdomains["WRAM"].Size != this["WRAM"].Length) return false; + if (memdomains.Has("CartRAM") != this.ContainsKey("CartRAM")) return false; if(memdomains.Has("CartRAM")) if (memdomains["CartRAM"].Size != this["CartRAM"].Length) return false; diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/CodeDataLog_GEN.cs b/BizHawk.Emulation.Cores/Consoles/Sega/CodeDataLog_GEN.cs new file mode 100644 index 0000000000..fa75cca4f3 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Sega/CodeDataLog_GEN.cs @@ -0,0 +1,38 @@ +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Cores.Components.H6280; + +namespace BizHawk.Emulation.Cores.Consoles.Sega +{ + public class CodeDataLog_GEN : CodeDataLog + { + public static CodeDataLog_GEN Create(IMemoryDomains memdomains) + { + var t = new CodeDataLog_GEN(); + + t["MD CART"] = new byte[memdomains["MD CART"].Size]; + t["68K RAM"] = new byte[memdomains["68K RAM"].Size]; + t["Z80 RAM"] = new byte[memdomains["Z80 RAM"].Size]; + + if(memdomains.Has("SRAM")) + t["SRAM"] = new byte[memdomains["SRAM"].Size]; + + return t; + } + + public override string SubType { get { return "GEN"; } } + public override int SubVer { get { return 0; } } + + //todo - this could be base classed + public bool CheckConsistency(IMemoryDomains memdomains) + { + if (memdomains["MD CART"].Size != this["MD CART"].Length) return false; + if (memdomains["68K RAM"].Size != this["68K RAM"].Length) return false; + if (memdomains["Z80 RAM"].Size != this["Z80 RAM"].Length) return false; + if (memdomains.Has("SRAM") != this.ContainsKey("SRAM")) return false; + if (memdomains.Has("SRAM")) + if (memdomains["SRAM"].Size != this["SRAM"].Length) + return false; + return true; + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/GPGX.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/GPGX.cs index 80094e61fb..0b5ba1b01b 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/GPGX.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/GPGX.cs @@ -170,6 +170,10 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx PutSettings((GPGXSettings)Settings ?? new GPGXSettings()); + //TODO - this hits performance, we need to make it controllable + CDCallback = new LibGPGX.CDCallback(CDCallbackProc); + LibGPGX.gpgx_set_cd_callback(CDCallback); + InitMemCallbacks(); KillMemCallbacks(); } @@ -180,6 +184,23 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx } } + public CodeDataLog_GEN CDL; + void CDCallbackProc(int addr, LibGPGX.CDLog_AddrType addrtype, LibGPGX.CDLog_Flags flags) + { + if (CDL == null) return; + if (!CDL.Active) return; + string key; + switch (addrtype) + { + case LibGPGX.CDLog_AddrType.MDCART: key = "MD CART"; break; + case LibGPGX.CDLog_AddrType.RAM68k: key = "68K RAM"; break; + case LibGPGX.CDLog_AddrType.RAMZ80: key = "Z80 RAM"; break; + case LibGPGX.CDLog_AddrType.SRAM: key = "SRAM"; break; + default: throw new InvalidOperationException("Lagrangian earwax incident"); + } + CDL[key][addr] |= (byte)flags; + } + public IEmulatorServiceProvider ServiceProvider { get; private set; } public bool DriveLightEnabled { get; private set;} @@ -671,6 +692,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx LibGPGX.mem_cb ExecCallback; LibGPGX.mem_cb ReadCallback; LibGPGX.mem_cb WriteCallback; + LibGPGX.CDCallback CDCallback; void InitMemCallbacks() { diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/LibGPGX.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/LibGPGX.cs index 9aa4980695..0399d95383 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/LibGPGX.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/LibGPGX.cs @@ -109,6 +109,24 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx DEVICE_ACTIVATOR = 0x0a,// Activator }; + + public enum CDLog_AddrType + { + MDCART, RAM68k, RAMZ80, SRAM, + }; + + [Flags] + public enum CDLog_Flags + { + Exec68k = 0x01, + Data68k = 0x04, + ExecZ80First = 0x08, + ExecZ80Operand = 0x10, + DataZ80 = 0x20, + DMASource = 0x40, + }; + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void input_cb(); @@ -118,9 +136,17 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void mem_cb(uint addr); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void CDCallback(int addr, CDLog_AddrType addrtype, CDLog_Flags flags); + [DllImport("libgenplusgx.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void gpgx_set_mem_callback(mem_cb read, mem_cb write, mem_cb exec); + [DllImport("libgenplusgx.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void gpgx_set_cd_callback(CDCallback cd); + + + /// /// not every flag is valid for every device! /// diff --git a/genplus-gx/cinterface/callbacks.h b/genplus-gx/cinterface/callbacks.h index c5df5a5c08..c99b625004 100644 --- a/genplus-gx/cinterface/callbacks.h +++ b/genplus-gx/cinterface/callbacks.h @@ -1,8 +1,28 @@ #ifndef CALLBACKS_H #define CALLBACKS_H +#include "types.h" + +typedef void (*CDCallback)(int32 addr, int32 addrtype, int32 flags); + extern void (*biz_execcb)(unsigned addr); extern void (*biz_readcb)(unsigned addr); extern void (*biz_writecb)(unsigned addr); +extern CDCallback biz_cdcallback; + +enum eCDLog_AddrType +{ + eCDLog_AddrType_MDCART, eCDLog_AddrType_RAM68k, eCDLog_AddrType_RAMZ80, eCDLog_AddrType_SRAM, +}; + +enum eCDLog_Flags +{ + eCDLog_Flags_Exec68k = 0x01, + eCDLog_Flags_Data68k = 0x04, + eCDLog_Flags_ExecZ80First = 0x08, + eCDLog_Flags_ExecZ80Operand = 0x10, + eCDLog_Flags_DataZ80 = 0x20, + eCDLog_Flags_DMASource = 0x40 +}; #endif diff --git a/genplus-gx/cinterface/cinterface.c b/genplus-gx/cinterface/cinterface.c index 9b57cf8d6c..4b2f238570 100644 --- a/genplus-gx/cinterface/cinterface.c +++ b/genplus-gx/cinterface/cinterface.c @@ -56,6 +56,7 @@ extern void zap(void); void (*biz_execcb)(unsigned addr) = NULL; void (*biz_readcb)(unsigned addr) = NULL; void (*biz_writecb)(unsigned addr) = NULL; +CDCallback biz_cdcallback = NULL; static void update_viewport(void) { @@ -545,6 +546,11 @@ GPGX_EX void gpgx_set_mem_callback(void (*read)(unsigned), void (*write)(unsigne biz_execcb = exec; } +GPGX_EX void gpgx_set_cd_callback(CDCallback cdcallback) +{ + biz_cdcallback = cdcallback; +} + GPGX_EX void gpgx_set_draw_mask(int mask) { cinterface_render_bga = !!(mask & 1); diff --git a/genplus-gx/core/m68k/m68kcpu.c b/genplus-gx/core/m68k/m68kcpu.c index e783102122..9ecb1033fa 100644 --- a/genplus-gx/core/m68k/m68kcpu.c +++ b/genplus-gx/core/m68k/m68kcpu.c @@ -20,6 +20,7 @@ extern int vdp_68k_irq_ack(int int_level); #include "m68kconf.h" #include "m68kcpu.h" #include "m68kops.h" +#include "shared.h" /* ======================================================================== */ /* ================================= DATA ================================= */ @@ -255,6 +256,53 @@ void m68k_set_irq_delay(unsigned int int_level) m68ki_check_interrupts(); /* Level triggered (IRQ) */ } + +extern uint8 work_ram[0x10000]; /* 68K RAM */ + +void CDLog68k(uint addr, uint flags) +{ + addr &= 0x00FFFFFF; + + //check for sram region first + if(sram.on) + { + if(addr >= sram.start && addr <= sram.end) + { + biz_cdcallback(addr - sram.start, eCDLog_AddrType_SRAM, flags); + return; + } + } + + if(addr < 0x400000) + { + uint block64k_rom; + + //apply memory map to process rom address + unsigned char* block64k = m68ki_cpu.memory_map[((addr)>>16)&0xff].base; + + //outside the ROM range. complex mapping logic/accessories; not sure how to handle any of this + if(block64k < cart.rom || block64k >= cart.rom + cart.romsize) + return; + + block64k_rom = block64k - cart.rom; + addr = ((addr) & 0xffff) + block64k_rom; + + //outside the ROM range somehow + if(addr >= cart.romsize) + return; + + biz_cdcallback(addr, eCDLog_AddrType_MDCART, flags); + return; + } + + if(addr > 0xFF0000) + { + //no memory map needed + biz_cdcallback(addr & 0xFFFF, eCDLog_AddrType_RAM68k, flags); + return; + } +} + void m68k_run(unsigned int cycles) { /* Make sure CPU is not already ahead */ @@ -294,6 +342,13 @@ void m68k_run(unsigned int cycles) if (biz_execcb) biz_execcb(REG_PC); + if(biz_cdcallback) + { + CDLog68k(REG_PC,eCDLog_Flags_Exec68k); + CDLog68k(REG_PC+1,eCDLog_Flags_Exec68k); + } + + /* Decode next instruction */ REG_IR = m68ki_read_imm_16(); diff --git a/genplus-gx/core/m68k/m68kcpu.h b/genplus-gx/core/m68k/m68kcpu.h index efd465c8bb..732016e480 100644 --- a/genplus-gx/core/m68k/m68kcpu.h +++ b/genplus-gx/core/m68k/m68kcpu.h @@ -16,6 +16,7 @@ #include "m68k.h" #include "../cinterface/callbacks.h" +void CDLog68k(uint addr, uint flags); /* ======================================================================== */ /* ============================ GENERAL DEFINES =========================== */ @@ -871,6 +872,9 @@ INLINE uint m68ki_read_8_fc(uint address, uint fc) if (biz_readcb) biz_readcb(address); + if(biz_cdcallback) + CDLog68k(address,eCDLog_Flags_Data68k); + m68ki_set_fc(fc) /* auto-disable (see m68kcpu.h) */ if (temp->read8) return (*temp->read8)(ADDRESS_68K(address)); @@ -883,6 +887,12 @@ INLINE uint m68ki_read_16_fc(uint address, uint fc) if (biz_readcb) biz_readcb(address); + if(biz_cdcallback) + { + CDLog68k(address,eCDLog_Flags_Data68k); + CDLog68k(address+1,eCDLog_Flags_Data68k); + } + m68ki_set_fc(fc) /* auto-disable (see m68kcpu.h) */ m68ki_check_address_error(address, MODE_READ, fc) /* auto-disable (see m68kcpu.h) */ @@ -897,6 +907,14 @@ INLINE uint m68ki_read_32_fc(uint address, uint fc) if (biz_readcb) biz_readcb(address); + if(biz_cdcallback) + { + CDLog68k(address,eCDLog_Flags_Data68k); + CDLog68k(address+1,eCDLog_Flags_Data68k); + CDLog68k(address+2,eCDLog_Flags_Data68k); + CDLog68k(address+3,eCDLog_Flags_Data68k); + } + m68ki_set_fc(fc) /* auto-disable (see m68kcpu.h) */ m68ki_check_address_error(address, MODE_READ, fc) /* auto-disable (see m68kcpu.h) */ diff --git a/genplus-gx/core/types.h b/genplus-gx/core/types.h index e1e9aa2c3e..3c3b78e77b 100644 --- a/genplus-gx/core/types.h +++ b/genplus-gx/core/types.h @@ -1,3 +1,6 @@ +#ifndef _TYPES_H +#define _TYPES_H + #undef uint8 #undef uint16 #undef uint32 @@ -27,3 +30,5 @@ typedef union } byte; } reg16_t; + +#endif \ No newline at end of file diff --git a/genplus-gx/core/vdp_ctrl.c b/genplus-gx/core/vdp_ctrl.c index e1506be117..5d1943bbb4 100644 --- a/genplus-gx/core/vdp_ctrl.c +++ b/genplus-gx/core/vdp_ctrl.c @@ -41,6 +41,7 @@ #include "shared.h" #include "hvc.h" +#include "../cinterface/callbacks.h" /* Mark a pattern as modified */ #define MARK_BG_DIRTY(addr) \ @@ -3021,6 +3022,8 @@ static void vdp_z80_data_w_sg(unsigned int data) /* DMA operations (Mega Drive VDP only) */ /*--------------------------------------------------------------------------*/ +void CDLog68k(uint addr, uint flags); + /* DMA from 68K bus: $000000-$7FFFFF (external area) */ static void vdp_dma_68k_ext(unsigned int length) { @@ -3040,6 +3043,16 @@ static void vdp_dma_68k_ext(unsigned int length) { data = *(uint16 *)(m68k.memory_map[source>>16].base + (source & 0xFFFF)); } + + if(biz_cdcallback) + { + //if((code & 0x0F) == 0x01) //VRAM target //lets handle everything here + { + CDLog68k(source,eCDLog_Flags_DMASource); + CDLog68k(source+1,eCDLog_Flags_DMASource); + } + } + /* Increment source address */ source += 2; diff --git a/genplus-gx/core/z80/z80.c b/genplus-gx/core/z80/z80.c index 7a1754df46..1ed07fbe80 100644 --- a/genplus-gx/core/z80/z80.c +++ b/genplus-gx/core/z80/z80.c @@ -126,6 +126,8 @@ #include "shared.h" #include "z80.h" +#include "../cinterface/callbacks.h" + /* execute main opcodes inside a big switch statement */ #define BIG_SWITCH 1 @@ -632,6 +634,35 @@ INLINE void WM16( UINT32 addr, PAIR *r ) WM((addr+1)&0xffff,r->b.h); } +void CDLog68k(uint addr, uint flags); + +void CDLogZ80(uint addr, uint flags) +{ + //in case we wrap around while reading a u16 from FFFF... + addr &= 0xFFFF; + + if(addr < 0x4000) + { + addr &= 0x1FFFF; + biz_cdcallback(addr, eCDLog_AddrType_RAMZ80, flags); + return; + } + + if(addr >= 0x8000) + { + addr = zbank | (addr & 0x7FFF); + if (zbank_memory_map[addr >> 16].write) + { + //special memory maps are hard to support here. + return; + } + + //punt to 68k mapper + CDLog68k(addr, flags); + return; + } +} + /*************************************************************** * ROP() is identical to RM() except it is used for * reading opcodes. In case of system with memory mapped I/O, @@ -641,6 +672,10 @@ INLINE UINT8 ROP(void) { unsigned pc = PCD; PC++; + + if(biz_cdcallback) + CDLogZ80(PC,eCDLog_Flags_ExecZ80First); + return cpu_readop(pc); } @@ -654,6 +689,10 @@ INLINE UINT8 ARG(void) { unsigned pc = PCD; PC++; + + if(biz_cdcallback) + CDLogZ80(pc,eCDLog_Flags_ExecZ80Operand); + return cpu_readop_arg(pc); } @@ -661,6 +700,13 @@ INLINE UINT32 ARG16(void) { unsigned pc = PCD; PC += 2; + + if(biz_cdcallback) + { + CDLogZ80(pc,eCDLog_Flags_ExecZ80Operand); + CDLogZ80(pc+1,eCDLog_Flags_ExecZ80Operand); + } + return cpu_readop_arg(pc) | (cpu_readop_arg((pc+1)&0xffff) << 8); } diff --git a/output/dll/libgenplusgx.dll b/output/dll/libgenplusgx.dll index 3ea31799cb..8658c60e37 100644 Binary files a/output/dll/libgenplusgx.dll and b/output/dll/libgenplusgx.dll differ