diff --git a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs index 439cd60c03..98da8619ba 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs @@ -45,6 +45,8 @@ namespace BizHawk.Emulation.Consoles.GB InputCallback = new LibGambatte.InputGetter(ControllerCallback); LibGambatte.gambatte_setinputgetter(GambatteState, InputCallback); + + InitMemoryDomains(); } public static readonly ControllerDefinition GbController = new ControllerDefinition @@ -251,16 +253,55 @@ namespace BizHawk.Emulation.Consoles.GB get { return GbOutputComm; } } - public IList MemoryDomains + + MemoryDomain CreateMemoryDomain(LibGambatte.MemoryAreas which) { - get { throw new NotImplementedException(); } + IntPtr data = IntPtr.Zero; + int length = 0; + + if (!LibGambatte.gambatte_getmemoryarea(GambatteState, which, ref data, ref length)) + throw new Exception("gambatte_getmemoryarea() failed!"); + + if (data == IntPtr.Zero || length <= 0) + throw new Exception("bad return from gambatte_getmemoryarea()"); + + Func peeker = delegate(int addr) + { + if (addr >= length || addr < 0) + throw new ArgumentOutOfRangeException(); + byte[] result = new byte[1]; + System.Runtime.InteropServices.Marshal.Copy(data + addr, result, 0, 1); + return result[0]; + }; + + Action poker = delegate(int addr, byte val) + { + if (addr >= length || addr < 0) + throw new ArgumentOutOfRangeException(); + byte[] source = new byte[1]; + source[0] = val; + System.Runtime.InteropServices.Marshal.Copy(source, 0, data + addr, 1); + }; + return new MemoryDomain(which.ToString(), length, Endian.Little, peeker, poker); } - public MemoryDomain MainMemory + void InitMemoryDomains() { - get { throw new NotImplementedException(); } + MemoryDomains = new MemoryDomain[4]; + + MemoryDomains[0] = CreateMemoryDomain(LibGambatte.MemoryAreas.rambank); + MemoryDomains[1] = CreateMemoryDomain(LibGambatte.MemoryAreas.rom); + MemoryDomains[2] = CreateMemoryDomain(LibGambatte.MemoryAreas.vram); + MemoryDomains[3] = CreateMemoryDomain(LibGambatte.MemoryAreas.wram); + + // what is this supposed to be, exactly? + MainMemory = MemoryDomains[1]; } + public IList MemoryDomains { get; private set; } + + public MemoryDomain MainMemory { get; private set; } + public void Dispose() { LibGambatte.gambatte_destroy(GambatteState); diff --git a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs index d184ed78f2..1112696397 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs @@ -268,5 +268,26 @@ namespace BizHawk.Emulation.Consoles.GB [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void gambatte_setgameshark(IntPtr core, string codes); + /// + /// memory areas that gambatte_getmemoryarea() can return + /// + public enum MemoryAreas : int + { + vram = 0, + rom = 1, + wram = 2, + rambank = 3, + } + + /// + /// get pointer to internal memory areas, for debugging purposes + /// + /// opaque state pointer + /// which memory area to access + /// pointer to the start of the area + /// valid length of the area, in bytes + /// success + [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern bool gambatte_getmemoryarea(IntPtr core, MemoryAreas which, ref IntPtr data, ref int length); } } diff --git a/BizHawk.MultiClient/output/libgambatte.dll b/BizHawk.MultiClient/output/libgambatte.dll index 08d529cca3..5712394eb3 100644 Binary files a/BizHawk.MultiClient/output/libgambatte.dll and b/BizHawk.MultiClient/output/libgambatte.dll differ diff --git a/libgambatte/include/gambatte.h b/libgambatte/include/gambatte.h index 00028d3afd..5ffbf24349 100644 --- a/libgambatte/include/gambatte.h +++ b/libgambatte/include/gambatte.h @@ -97,6 +97,9 @@ public: int saveSavedataLength(); void saveSavedata(char *dest); + // 0 = vram, 1 = rom, 2 = wram, 3 = rambank + bool getMemoryArea(int which, unsigned char **data, int *length); + /** Saves emulator state to the state slot selected with selectState(). * The data will be stored in the directory given by setSaveDir(). * diff --git a/libgambatte/src/cinterface.cpp b/libgambatte/src/cinterface.cpp index f808d35cf9..c106715861 100644 --- a/libgambatte/src/cinterface.cpp +++ b/libgambatte/src/cinterface.cpp @@ -187,3 +187,8 @@ __declspec(dllexport) void gambatte_setgameshark(void *core, const char *codes) g->setGameShark(std::string(codes)); } +__declspec(dllexport) int gambatte_getmemoryarea(void *core, int which, unsigned char **data, int *length) +{ + GB *g = (GB *) core; + return g->getMemoryArea(which, data, length); +} diff --git a/libgambatte/src/cinterface.h b/libgambatte/src/cinterface.h index ee2a39a301..0a7ebcffee 100644 --- a/libgambatte/src/cinterface.h +++ b/libgambatte/src/cinterface.h @@ -46,6 +46,8 @@ extern "C" __declspec(dllexport) void gambatte_setgamegenie(void *core, const char *codes); __declspec(dllexport) void gambatte_setgameshark(void *core, const char *codes); + + __declspec(dllexport) int gambatte_getmemoryarea(void *core, int which, unsigned char **data, int *length); } diff --git a/libgambatte/src/cpu.h b/libgambatte/src/cpu.h index a84fd723cb..87a26dbcd4 100644 --- a/libgambatte/src/cpu.h +++ b/libgambatte/src/cpu.h @@ -55,6 +55,8 @@ public: int saveSavedataLength() {return memory.saveSavedataLength(); } void saveSavedata(char *dest) { memory.saveSavedata(dest); } + bool getMemoryArea(int which, unsigned char **data, int *length) { return memory.getMemoryArea(which, data, length); } + void setVideoBuffer(uint_least32_t *const videoBuf, const int pitch) { memory.setVideoBuffer(videoBuf, pitch); } diff --git a/libgambatte/src/gambatte.cpp b/libgambatte/src/gambatte.cpp index a6deec0f80..1688f68128 100644 --- a/libgambatte/src/gambatte.cpp +++ b/libgambatte/src/gambatte.cpp @@ -142,6 +142,13 @@ int GB::saveSavedataLength() { return -1; } +bool GB::getMemoryArea(int which, unsigned char **data, int *length) { + if (p_->cpu.loaded()) + return p_->cpu.getMemoryArea(which, data, length); + else + return false; +} + void GB::setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned rgb32) { p_->cpu.setDmgPaletteColor(palNum, colorNum, rgb32); } diff --git a/libgambatte/src/mem/cartridge.cpp b/libgambatte/src/mem/cartridge.cpp index 0c4bf5c972..d463b38c00 100644 --- a/libgambatte/src/mem/cartridge.cpp +++ b/libgambatte/src/mem/cartridge.cpp @@ -694,6 +694,35 @@ void Cartridge::saveSavedata(char *dest) { } } +bool Cartridge::getMemoryArea(int which, unsigned char **data, int *length) +{ + if (!data || !length) + return false; + + switch (which) + { + case 0: + *data = memptrs.vramdata(); + *length = memptrs.vramdataend() - memptrs.vramdata(); + return true; + case 1: + *data = memptrs.romdata(); + *length = memptrs.romdataend() - memptrs.romdata(); + return true; + case 2: + *data = memptrs.wramdata(0); + *length = memptrs.wramdataend() - memptrs.wramdata(0); + return true; + case 3: + *data = memptrs.rambankdata(); + *length = memptrs.rambankdataend() - memptrs.rambankdata(); + return true; + default: + return false; + } + return false; +} + static int asHex(const char c) { return c >= 'A' ? c - 'A' + 0xA : c - '0'; } diff --git a/libgambatte/src/mem/cartridge.h b/libgambatte/src/mem/cartridge.h index ee036f6077..da78a47875 100644 --- a/libgambatte/src/mem/cartridge.h +++ b/libgambatte/src/mem/cartridge.h @@ -87,6 +87,9 @@ public: void saveSavedata(char *dest); const std::string saveBasePath() const; void setSaveDir(const std::string &dir); + + bool getMemoryArea(int which, unsigned char **data, int *length); + int loadROM(const char *romfiledata, unsigned romfilelength, bool forceDmg, bool multicartCompat); const char * romTitle() const { return reinterpret_cast(memptrs.romdata() + 0x134); } void setGameGenie(const std::string &codes); diff --git a/libgambatte/src/memory.h b/libgambatte/src/memory.h index 70d9fd6308..83b93aa1b0 100644 --- a/libgambatte/src/memory.h +++ b/libgambatte/src/memory.h @@ -83,6 +83,8 @@ public: void saveSavedata(char *dest) { cart.saveSavedata(dest); } const std::string saveBasePath() const { return cart.saveBasePath(); } + bool getMemoryArea(int which, unsigned char **data, int *length) { return cart.getMemoryArea(which, data, length); } + void setOsdElement(std::auto_ptr osdElement) { display.setOsdElement(osdElement); }