diff --git a/BizHawk.Client.EmuHawk/tools/PCE/PCECDL.cs b/BizHawk.Client.EmuHawk/tools/PCE/PCECDL.cs index 991c6e1950..dc69b2c02a 100644 --- a/BizHawk.Client.EmuHawk/tools/PCE/PCECDL.cs +++ b/BizHawk.Client.EmuHawk/tools/PCE/PCECDL.cs @@ -6,6 +6,8 @@ using System.Windows.Forms; using BizHawk.Emulation.Common; using BizHawk.Emulation.Common.IEmulatorExtensions; + +using BizHawk.Emulation.Cores.Nintendo.Gameboy; using BizHawk.Emulation.Cores.Components.H6280; using BizHawk.Emulation.Cores.PCEngine; @@ -17,7 +19,7 @@ namespace BizHawk.Client.EmuHawk public partial class PCECDL : Form, IToolFormAutoConfig { [RequiredService] - private PCEngine _emu { get; set; } + public IEmulator _emu { get; private set; } private CodeDataLog _cdl; private RecentFiles _recent_fld = new RecentFiles(); @@ -59,9 +61,18 @@ namespace BizHawk.Client.EmuHawk public void Restart() { - LoggingActiveCheckbox.Checked = _emu.Cpu.CDLLoggingActive; - _cdl = _emu.Cpu.CDL; - _emu.InitCDLMappings(); + if (_emu.SystemId == "PCE") + { + var pce = _emu as PCEngine; + LoggingActiveCheckbox.Checked = pce.Cpu.CDLLoggingActive; + _cdl = pce.Cpu.CDL; + pce.InitCDLMappings(); + } + else if(_emu.SystemId == "GB") + { + var gambatte = _emu as Gameboy; + _cdl = gambatte.CDL; + } UpdateDisplay(); } @@ -116,17 +127,32 @@ namespace BizHawk.Client.EmuHawk using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read)) { var newCDL = CodeDataLog.Load(fs); - if (!newCDL.CheckConsistency(_emu.Cpu.Mappings)) + + //this check may be inadequate in the future + if(newCDL.SubType != _emu.SystemId) + throw new InvalidDataException("File is a CDL file of the wrong target core (like, a different game console)!"); + + _cdl = newCDL; + if (_emu.SystemId == "PCE") { - MessageBox.Show(this, "CDL file does not match emulator's current memory map!"); + var pce = _emu as PCEngine; + var cdl_pce = newCDL as CodeDataLog_PCE; + if (!cdl_pce.CheckConsistency(pce.Cpu.Mappings)) + { + MessageBox.Show(this, "CDL file does not match emulator's current memory map!"); + return; + } + pce.Cpu.CDL = _cdl; } - else + else if (_emu.SystemId == "GB") { - _cdl = newCDL; - _emu.Cpu.CDL = _cdl; - UpdateDisplay(); + var gambatte = _emu as Gameboy; + var cdl_gb = newCDL as CodeDataLog_GB; + gambatte.CDL = cdl_gb; } } + + UpdateDisplay(); } #region Events @@ -154,8 +180,21 @@ namespace BizHawk.Client.EmuHawk var result = MessageBox.Show(this, "OK to create new CDL?", "Query", MessageBoxButtons.YesNo); if (result == DialogResult.Yes) { - _cdl = CodeDataLog.Create(_emu.Cpu.Mappings); - _emu.Cpu.CDL = _cdl; + if (_emu.SystemId == "PCE") + { + var pce = _emu as PCEngine; + _cdl = CodeDataLog_PCE.Create(pce.Cpu.Mappings); + pce.Cpu.CDL = _cdl; + } + else if (_emu.SystemId == "GB") + { + var gambatte = _emu as Gameboy; + var memd = gambatte.AsMemoryDomains(); + var cdl_gb = CodeDataLog_GB.Create(memd); + gambatte.CDL = cdl_gb; + _cdl = cdl_gb; + } + UpdateDisplay(); } } @@ -173,22 +212,7 @@ namespace BizHawk.Client.EmuHawk if (file != null) { - using (var fs = new FileStream(file.FullName, FileMode.Open, FileAccess.Read)) - { - var newCDL = CodeDataLog.Load(fs); - if (!newCDL.CheckConsistency(_emu.Cpu.Mappings)) - { - MessageBox.Show(this, "CDL file does not match emulator's current memory map!"); - } - else - { - _cdl = newCDL; - _emu.Cpu.CDL = _cdl; - UpdateDisplay(); - _recent.Add(file.FullName); - _currentFileName = file.FullName; - } - } + LoadFile(file.FullName); } } } @@ -314,7 +338,14 @@ namespace BizHawk.Client.EmuHawk LoggingActiveCheckbox.Checked = false; } - _emu.Cpu.CDLLoggingActive = LoggingActiveCheckbox.Checked; + if (_emu.SystemId == "PCE") + { + //set a special flag on the CPU to indicate CDL is running, maybe it's faster, who knows + var pce = _emu as PCEngine; + pce.Cpu.CDLLoggingActive = LoggingActiveCheckbox.Checked; + } + + _cdl.Active = LoggingActiveCheckbox.Checked; } private void PCECDL_DragEnter(object sender, DragEventArgs e) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs index 5389945b1c..e2993af865 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs @@ -173,6 +173,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy TimeCallback = new LibGambatte.RTCCallback(GetCurrentTime); LibGambatte.gambatte_setrtccallback(GambatteState, TimeCallback); + //seems to have near negligable speed impact. lets always use it, for now. + //someone who cares can make it controllable + CDCallback = new LibGambatte.CDCallback(CDCallbackProc); + LibGambatte.gambatte_setcdcallback(GambatteState, CDCallback); + NewSaveCoreSetBuff(); } catch @@ -182,6 +187,24 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy } } + public CodeDataLog_GB CDL; + LibGambatte.CDCallback CDCallback; + void CDCallbackProc(int addr, LibGambatte.CDLog_AddrType addrtype, LibGambatte.CDLog_Flags flags) + { + if (CDL == null) return; + if (!CDL.Active) return; + string key; + switch (addrtype) + { + case LibGambatte.CDLog_AddrType.ROM: key = "ROM"; break; + case LibGambatte.CDLog_AddrType.HRAM: key = "HRAM"; break; + case LibGambatte.CDLog_AddrType.WRAM: key = "WRAM"; break; + case LibGambatte.CDLog_AddrType.CartRAM: key = "CartRAM"; break; + default: throw new InvalidOperationException("Juniper lightbulb proxy"); + } + CDL[key][addr] |= (byte)flags; + } + public IEmulatorServiceProvider ServiceProvider { get; private set; } #region ALL SAVESTATEABLE STATE GOES HERE diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibGambatte.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibGambatte.cs index 6d17f87db7..cdd3b43e27 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibGambatte.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibGambatte.cs @@ -34,6 +34,19 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy MULTICART_COMPAT = 4 } + public enum CDLog_AddrType : int + { + ROM, HRAM, WRAM, CartRAM + } + + [Flags] + public enum CDLog_Flags : int + { + ExecFirst = 1, + ExecOperand = 2, + Data = 4 + } + /// <summary> /// Load ROM image. /// </summary> @@ -161,6 +174,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void MemoryCallback(uint address); + /// <summary> + /// type of the CDLogger callback + /// </summary> + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void CDCallback(int addr, CDLog_AddrType addrtype, CDLog_Flags flags); + /// <summary> /// set a callback to occur immediately BEFORE EVERY cpu read, except for opcode first byte fetches /// </summary> @@ -185,6 +204,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void gambatte_setexeccallback(IntPtr core, MemoryCallback callback); + /// <summary> + /// set a callback whicih enables CD Logger feedback + /// </summary> + [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void gambatte_setcdcallback(IntPtr core, CDCallback callback); + /// <summary> /// type of the cpu trace callback /// </summary> diff --git a/libgambatte/include/gambatte.h b/libgambatte/include/gambatte.h index 990d3f9a64..f36121ca23 100644 --- a/libgambatte/include/gambatte.h +++ b/libgambatte/include/gambatte.h @@ -28,6 +28,21 @@ namespace gambatte { enum { BG_PALETTE = 0, SP1_PALETTE = 1, SP2_PALETTE = 2 }; +typedef void (*CDCallback)(int32_t addr, int32_t addrtype, int32_t flags); + +enum eCDLog_AddrType +{ + eCDLog_AddrType_ROM, eCDLog_AddrType_HRAM, eCDLog_AddrType_WRAM, eCDLog_AddrType_CartRAM, + eCDLog_AddrType_None +}; + +enum eCDLog_Flags +{ + eCDLog_Flags_ExecFirst = 1, + eCDLog_Flags_ExecOperand = 2, + eCDLog_Flags_Data = 4, +}; + class GB { public: GB(); @@ -88,6 +103,7 @@ public: void setReadCallback(void (*callback)(unsigned)); void setWriteCallback(void (*callback)(unsigned)); void setExecCallback(void (*callback)(unsigned)); + void setCDCallback(CDCallback); void setTraceCallback(void (*callback)(void *)); void setScanlineCallback(void (*callback)(), int sl); void setRTCCallback(std::uint32_t (*callback)()); diff --git a/libgambatte/src/cinterface.cpp b/libgambatte/src/cinterface.cpp index e9c52041bc..77eaf09f01 100644 --- a/libgambatte/src/cinterface.cpp +++ b/libgambatte/src/cinterface.cpp @@ -83,6 +83,12 @@ GBEXPORT void gambatte_setexeccallback(GB *g, void (*callback)(unsigned)) g->setExecCallback(callback); } +GBEXPORT void gambatte_setcdcallback(GB *g, CDCallback cdc) +{ + g->setCDCallback(cdc); +} + + GBEXPORT void gambatte_settracecallback(GB *g, void (*callback)(void *)) { g->setTraceCallback(callback); diff --git a/libgambatte/src/cpu.cpp b/libgambatte/src/cpu.cpp index e1674bebb1..3f6619eb78 100644 --- a/libgambatte/src/cpu.cpp +++ b/libgambatte/src/cpu.cpp @@ -112,7 +112,8 @@ 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_excb(PC, cycleCounter); PC = (PC + 1) & 0xFFFF; cycleCounter += 4; } while (0) +#define PC_READ(dest) do { (dest) = memory.read_excb(PC, cycleCounter, false); PC = (PC + 1) & 0xFFFF; cycleCounter += 4; } while (0) +#define PC_READ_FIRST(dest) do { (dest) = memory.read_excb(PC, cycleCounter, true); 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) @@ -518,13 +519,13 @@ void CPU::process(const unsigned long cycles) { result[9] = H; result[10] = L; result[11] = skip; - PC_READ(opcode); + PC_READ_FIRST(opcode); result[12] = opcode; result[13] = memory.debugGetLY(); tracecallback((void *)result); } else { - PC_READ(opcode); + PC_READ_FIRST(opcode); } if (skip) { diff --git a/libgambatte/src/cpu.h b/libgambatte/src/cpu.h index a55fb07ca6..09c966ccbb 100644 --- a/libgambatte/src/cpu.h +++ b/libgambatte/src/cpu.h @@ -79,6 +79,10 @@ public: memory.setExecCallback(callback); } + void setCDCallback(CDCallback cdc) { + memory.setCDCallback(cdc); + } + void setTraceCallback(void (*callback)(void *)) { tracecallback = callback; } diff --git a/libgambatte/src/gambatte.cpp b/libgambatte/src/gambatte.cpp index 1c7dcc1f62..7f20278da2 100644 --- a/libgambatte/src/gambatte.cpp +++ b/libgambatte/src/gambatte.cpp @@ -114,6 +114,10 @@ void GB::setExecCallback(void (*callback)(unsigned)) { p_->cpu.setExecCallback(callback); } +void GB::setCDCallback(CDCallback cdc) { + p_->cpu.setCDCallback(cdc); +} + void GB::setTraceCallback(void (*callback)(void *)) { p_->cpu.setTraceCallback(callback); } diff --git a/libgambatte/src/mem/cartridge.h b/libgambatte/src/mem/cartridge.h index f6ea99bfa9..4038593d23 100644 --- a/libgambatte/src/mem/cartridge.h +++ b/libgambatte/src/mem/cartridge.h @@ -29,12 +29,26 @@ namespace gambatte { + //DOOM +//enum eAddressMappingType +//{ +// eAddressMappingType_ROM, +// eAddressMappingType_RAM +//}; +// +//struct AddressMapping +//{ +// int32_t address; +// eAddressMappingType type; +//}; + class Mbc { public: virtual ~Mbc() {} virtual void romWrite(unsigned P, unsigned data) = 0; virtual void loadState(const SaveState::Mem &ss) = 0; virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned address, unsigned rombank) const = 0; + //virtual void mapAddress(AddressMapping* mapping, unsigned address) const = 0; //DOOM template<bool isReader>void SyncState(NewState *ns) { diff --git a/libgambatte/src/memory.cpp b/libgambatte/src/memory.cpp index f1881eccb2..4bae856679 100644 --- a/libgambatte/src/memory.cpp +++ b/libgambatte/src/memory.cpp @@ -28,6 +28,7 @@ Memory::Memory(const Interrupter &interrupter_in) : readCallback(0), writeCallback(0), execCallback(0), + cdCallback(0), getInput(0), divLastUpdate(0), lastOamDmaUpdate(DISABLED_TIME), diff --git a/libgambatte/src/memory.h b/libgambatte/src/memory.h index 8ffd355c31..b6a4bafd24 100644 --- a/libgambatte/src/memory.h +++ b/libgambatte/src/memory.h @@ -25,6 +25,7 @@ #include "interrupter.h" #include "tima.h" #include "newstate.h" +#include "gambatte.h" namespace gambatte { class InputGetter; @@ -37,6 +38,7 @@ class Memory { void (*readCallback)(unsigned); void (*writeCallback)(unsigned); void (*execCallback)(unsigned); + CDCallback cdCallback; unsigned (*getInput)(); unsigned long divLastUpdate; @@ -117,15 +119,78 @@ public: return P < 0xFF80 ? nontrivial_ff_read(P, cycleCounter) : ioamhram[P - 0xFE00]; } + struct CDMapResult + { + eCDLog_AddrType type; + unsigned addr; + }; + + CDMapResult CDMap(const unsigned P) const + { + if(P<0x4000) + { + CDMapResult ret = { eCDLog_AddrType_ROM, P }; + return ret; + } + else if(P<0x8000) + { + unsigned bank = cart.rmem(P>>12) - cart.rmem(0); + unsigned addr = P+bank; + CDMapResult ret = { eCDLog_AddrType_ROM, addr }; + return ret; + } + else if(P<0xA000) {} + else if(P<0xC000) + { + if(cart.wsrambankptr()) + { + //not bankable + unsigned addr = P&0x1FFF; + CDMapResult ret = { eCDLog_AddrType_CartRAM, addr }; + return ret; + } + } + else if(P<0xE000) + { + unsigned bank = cart.wramdata(P >> 12 & 1) - cart.wramdata(0); + unsigned addr = (P&0xFFF)+bank; + CDMapResult ret = { eCDLog_AddrType_WRAM, addr }; + return ret; + } + else if(P<0xFF80) {} + else + { + ////this is just for debugging, really, it's pretty useless + //CDMapResult ret = { eCDLog_AddrType_HRAM, (P-0xFF80) }; + //return ret; + } + + CDMapResult ret = { eCDLog_AddrType_None }; + return ret; + } + + unsigned read(const unsigned P, const unsigned long cycleCounter) { if (readCallback) readCallback(P); + if(cdCallback) + { + CDMapResult map = CDMap(P); + if(map.type != eCDLog_AddrType_None) + cdCallback(map.addr,map.type,eCDLog_Flags_Data); + } return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_read(P, cycleCounter); } - unsigned read_excb(const unsigned P, const unsigned long cycleCounter) { + unsigned read_excb(const unsigned P, const unsigned long cycleCounter, bool first) { if (execCallback) execCallback(P); + if(cdCallback) + { + CDMapResult map = CDMap(P); + if(map.type != eCDLog_AddrType_None) + cdCallback(map.addr,map.type,first?eCDLog_Flags_ExecFirst : eCDLog_Flags_ExecOperand); + } return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_read(P, cycleCounter); } @@ -147,6 +212,12 @@ public: nontrivial_write(P, data, cycleCounter); if (writeCallback) writeCallback(P); + if(cdCallback) + { + CDMapResult map = CDMap(P); + if(map.type != eCDLog_AddrType_None) + cdCallback(map.addr,map.type,eCDLog_Flags_Data); + } } void ff_write(const unsigned P, const unsigned data, const unsigned long cycleCounter) { @@ -154,6 +225,12 @@ public: ioamhram[P - 0xFE00] = data; } else nontrivial_ff_write(P, data, cycleCounter); + if(cdCallback) + { + CDMapResult map = CDMap(P); + if(map.type != eCDLog_AddrType_None) + cdCallback(map.addr,map.type,eCDLog_Flags_Data); + } } unsigned long event(unsigned long cycleCounter); @@ -174,6 +251,9 @@ public: void setExecCallback(void (*callback)(unsigned)) { this->execCallback = callback; } + void setCDCallback(CDCallback cdc) { + this->cdCallback = cdc; + } void setScanlineCallback(void (*callback)(), int sl) { display.setScanlineCallback(callback, sl); diff --git a/output/dll/libgambatte.dll b/output/dll/libgambatte.dll index 381b65d829..bb85ac5da6 100644 Binary files a/output/dll/libgambatte.dll and b/output/dll/libgambatte.dll differ