diff --git a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs index e0b894e333..db24d2f677 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs @@ -128,13 +128,39 @@ namespace BizHawk.Emulation.Consoles.GB public byte[] ReadSaveRam { - get { return new byte[0]; } + get + { + int length = LibGambatte.gambatte_savesavedatalength(GambatteState); + + if (length > 0) + { + byte[] ret = new byte[length]; + LibGambatte.gambatte_savesavedata(GambatteState, ret); + return ret; + } + else + return new byte[0]; + } } + public void StoreSaveRam(byte[] data) + { + if (data.Length != LibGambatte.gambatte_savesavedatalength(GambatteState)) + throw new ArgumentException("Size of saveram data does not match expected!"); + LibGambatte.gambatte_loadsavedata(GambatteState, data); + } + + public bool SaveRamModified { - get; - set; + get + { + if (LibGambatte.gambatte_savesavedatalength(GambatteState) == 0) + return false; + else + return true; // need to wire more stuff into the core to actually know this + } + set { } } public void ResetFrameCounter() diff --git a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs index 8414b2a9bb..d184ed78f2 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs @@ -155,11 +155,28 @@ namespace BizHawk.Emulation.Consoles.GB public static extern bool gambatte_isloaded(IntPtr core); /// - /// Writes persistent cartridge data to disk. Done implicitly on ROM close. + /// Get persistant cart memory. /// /// opaque state pointer + /// byte buffer to write into. gambatte_savesavedatalength() bytes will be written [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void gambatte_savesavedata(IntPtr core); + public static extern void gambatte_savesavedata(IntPtr core, byte[] dest); + + /// + /// restore persistant cart memory. + /// + /// opaque state pointer + /// byte buffer to read from. gambatte_savesavedatalength() bytes will be read + [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void gambatte_loadsavedata(IntPtr core, byte[] data); + + /// + /// get the size of the persistant cart memory block. this value DEPENDS ON THE PARTICULAR CART LOADED + /// + /// opaque state pointer + /// length in bytes. 0 means no internal persistant cart memory + [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int gambatte_savesavedatalength(IntPtr core); /// /// Saves emulator state to the state to a byte array diff --git a/BizHawk.MultiClient/MainForm.cs b/BizHawk.MultiClient/MainForm.cs index 4cf252994f..5d437d898e 100644 --- a/BizHawk.MultiClient/MainForm.cs +++ b/BizHawk.MultiClient/MainForm.cs @@ -1560,7 +1560,10 @@ namespace BizHawk.MultiClient reader.Read(sram, 0, Global.Emulator.ReadSaveRam.Length); if (Global.Emulator is LibsnesCore) ((LibsnesCore)Global.Emulator).StoreSaveRam(sram); - else Array.Copy(sram, Global.Emulator.ReadSaveRam, Global.Emulator.ReadSaveRam.Length); + else if (Global.Emulator is Gameboy) + ((Gameboy)Global.Emulator).StoreSaveRam(sram); + else + Array.Copy(sram, Global.Emulator.ReadSaveRam, Global.Emulator.ReadSaveRam.Length); } catch { } } diff --git a/BizHawk.MultiClient/output/libgambatte.dll b/BizHawk.MultiClient/output/libgambatte.dll index ad71e22bad..08d529cca3 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 467b22d094..00028d3afd 100644 --- a/libgambatte/include/gambatte.h +++ b/libgambatte/include/gambatte.h @@ -92,8 +92,10 @@ public: /** Returns true if a ROM image is loaded. */ bool isLoaded() const; - /** Writes persistent cartridge data to disk. Done implicitly on ROM close. */ - void saveSavedata(); + /** Writes persistent cartridge data to disk. NOT Done implicitly on ROM close. */ + void loadSavedata(const char *data); + int saveSavedataLength(); + void saveSavedata(char *dest); /** 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 7995e03f0d..f808d35cf9 100644 --- a/libgambatte/src/cinterface.cpp +++ b/libgambatte/src/cinterface.cpp @@ -83,11 +83,31 @@ __declspec(dllexport) int gambatte_isloaded(void *core) return g->isLoaded(); } +/* __declspec(dllexport) void gambatte_savesavedata(void *core) { GB *g = (GB *) core; g->saveSavedata(); } +*/ + +__declspec(dllexport) void gambatte_savesavedata(void *core, char *dest) +{ + GB *g = (GB *) core; + g->saveSavedata(dest); +} + +__declspec(dllexport) void gambatte_loadsavedata(void *core, const char *data) +{ + GB *g = (GB *) core; + g->loadSavedata(data); +} + +__declspec(dllexport) int gambatte_savesavedatalength(void *core) +{ + GB *g = (GB *) core; + return g->saveSavedataLength(); +} /* __declspec(dllexport) int gambatte_savestate(void *core, const unsigned long *videobuf, int pitch) diff --git a/libgambatte/src/cinterface.h b/libgambatte/src/cinterface.h index 4fbbb44b95..ee2a39a301 100644 --- a/libgambatte/src/cinterface.h +++ b/libgambatte/src/cinterface.h @@ -24,7 +24,9 @@ extern "C" __declspec(dllexport) int gambatte_isloaded(void *core); - __declspec(dllexport) void gambatte_savesavedata(void *core); + __declspec(dllexport) void gambatte_savesavedata(void *core, char *dest); + __declspec(dllexport) void gambatte_loadsavedata(void *core, const char *data); + __declspec(dllexport) int gambatte_savesavedatalength(void *core); //__declspec(dllexport) int gambatte_savestate(void *core, const unsigned long *videobuf, int pitch); diff --git a/libgambatte/src/cpu.h b/libgambatte/src/cpu.h index 6b3208a209..a84fd723cb 100644 --- a/libgambatte/src/cpu.h +++ b/libgambatte/src/cpu.h @@ -51,8 +51,9 @@ public: void saveState(SaveState &state); void loadState(const SaveState &state); - void loadSavedata() { memory.loadSavedata(); } - void saveSavedata() { memory.saveSavedata(); } + void loadSavedata(const char *data) { memory.loadSavedata(data); } + int saveSavedataLength() {return memory.saveSavedataLength(); } + void saveSavedata(char *dest) { memory.saveSavedata(dest); } 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 b2fbfd1ae4..a6deec0f80 100644 --- a/libgambatte/src/gambatte.cpp +++ b/libgambatte/src/gambatte.cpp @@ -47,8 +47,8 @@ struct GB::Priv { GB::GB() : p_(new Priv) {} GB::~GB() { - if (p_->cpu.loaded()) - p_->cpu.saveSavedata(); + //if (p_->cpu.loaded()) + // p_->cpu.saveSavedata(); delete p_; } @@ -70,13 +70,24 @@ long GB::runFor(gambatte::uint_least32_t *const videoBuf, const int pitch, void GB::reset() { if (p_->cpu.loaded()) { - p_->cpu.saveSavedata(); + + int length = p_->cpu.saveSavedataLength(); + char *s; + if (length > 0) + { + s = (char *) std::malloc(length); + p_->cpu.saveSavedata(s); + } SaveState state; p_->cpu.setStatePtrs(state); setInitState(state, p_->cpu.isCgb(), p_->gbaCgbMode); p_->cpu.loadState(state); - p_->cpu.loadSavedata(); + if (length > 0) + { + p_->cpu.loadSavedata(s); + std::free(s); + } } } @@ -89,8 +100,8 @@ void GB::setSaveDir(const std::string &sdir) { } int GB::load(const char *romfiledata, unsigned romfilelength, const unsigned flags) { - if (p_->cpu.loaded()) - p_->cpu.saveSavedata(); + //if (p_->cpu.loaded()) + // p_->cpu.saveSavedata(); const int failed = p_->cpu.load(romfiledata, romfilelength, flags & FORCE_DMG, flags & MULTICART_COMPAT); @@ -99,7 +110,7 @@ int GB::load(const char *romfiledata, unsigned romfilelength, const unsigned fla p_->cpu.setStatePtrs(state); setInitState(state, p_->cpu.isCgb(), p_->gbaCgbMode = flags & GBA_CGB); p_->cpu.loadState(state); - p_->cpu.loadSavedata(); + //p_->cpu.loadSavedata(); p_->stateNo = 1; p_->cpu.setOsdElement(std::auto_ptr()); @@ -116,9 +127,19 @@ bool GB::isLoaded() const { return p_->cpu.loaded(); } -void GB::saveSavedata() { +void GB::saveSavedata(char *dest) { if (p_->cpu.loaded()) - p_->cpu.saveSavedata(); + p_->cpu.saveSavedata(dest); +} +void GB::loadSavedata(const char *data) { + if (p_->cpu.loaded()) + p_->cpu.loadSavedata(data); +} +int GB::saveSavedataLength() { + if (p_->cpu.loaded()) + return p_->cpu.saveSavedataLength(); + else + return -1; } void GB::setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned rgb32) { @@ -127,7 +148,7 @@ void GB::setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned rgb32) bool GB::loadState(std::istream &file) { if (p_->cpu.loaded()) { - p_->cpu.saveSavedata(); + // p_->cpu.saveSavedata(); SaveState state; p_->cpu.setStatePtrs(state); diff --git a/libgambatte/src/mem/cartridge.cpp b/libgambatte/src/mem/cartridge.cpp index 05252e28d2..0c4bf5c972 100644 --- a/libgambatte/src/mem/cartridge.cpp +++ b/libgambatte/src/mem/cartridge.cpp @@ -655,49 +655,42 @@ static bool hasBattery(const unsigned char headerByte0x147) { } } -void Cartridge::loadSavedata() { - const std::string &sbp = saveBasePath(); - +void Cartridge::loadSavedata(const char *data) { if (hasBattery(memptrs.romdata()[0x147])) { - std::ifstream file((sbp + ".sav").c_str(), std::ios::binary | std::ios::in); - - if (file.is_open()) { - file.read(reinterpret_cast(memptrs.rambankdata()), memptrs.rambankdataend() - memptrs.rambankdata()); - enforce8bit(memptrs.rambankdata(), memptrs.rambankdataend() - memptrs.rambankdata()); - } + int length = memptrs.rambankdataend() - memptrs.rambankdata(); + std::memcpy(memptrs.rambankdata(), data, length); + data += length; + enforce8bit(memptrs.rambankdata(), length); } if (hasRtc(memptrs.romdata()[0x147])) { - std::ifstream file((sbp + ".rtc").c_str(), std::ios::binary | std::ios::in); - - if (file.is_open()) { - unsigned long basetime = file.get() & 0xFF; - - basetime = basetime << 8 | (file.get() & 0xFF); - basetime = basetime << 8 | (file.get() & 0xFF); - basetime = basetime << 8 | (file.get() & 0xFF); - - rtc.setBaseTime(basetime); - } + unsigned long basetime; + std::memcpy(&basetime, data, 4); + rtc.setBaseTime(basetime); } } -void Cartridge::saveSavedata() { - const std::string &sbp = saveBasePath(); - +int Cartridge::saveSavedataLength() { + int ret = 0; if (hasBattery(memptrs.romdata()[0x147])) { - std::ofstream file((sbp + ".sav").c_str(), std::ios::binary | std::ios::out); - file.write(reinterpret_cast(memptrs.rambankdata()), memptrs.rambankdataend() - memptrs.rambankdata()); + ret = memptrs.rambankdataend() - memptrs.rambankdata(); + } + if (hasRtc(memptrs.romdata()[0x147])) { + ret += 4; + } + return ret; +} + +void Cartridge::saveSavedata(char *dest) { + if (hasBattery(memptrs.romdata()[0x147])) { + int length = memptrs.rambankdataend() - memptrs.rambankdata(); + std::memcpy(dest, memptrs.rambankdata(), length); + dest += length; } if (hasRtc(memptrs.romdata()[0x147])) { - std::ofstream file((sbp + ".rtc").c_str(), std::ios::binary | std::ios::out); const unsigned long basetime = rtc.getBaseTime(); - - file.put(basetime >> 24 & 0xFF); - file.put(basetime >> 16 & 0xFF); - file.put(basetime >> 8 & 0xFF); - file.put(basetime & 0xFF); + std::memcpy(dest, &basetime, 4); } } diff --git a/libgambatte/src/mem/cartridge.h b/libgambatte/src/mem/cartridge.h index b7a8a41b37..ee036f6077 100644 --- a/libgambatte/src/mem/cartridge.h +++ b/libgambatte/src/mem/cartridge.h @@ -82,8 +82,9 @@ public: void rtcWrite(unsigned data) { rtc.write(data); } unsigned char rtcRead() const { return *rtc.getActive(); } - void loadSavedata(); - void saveSavedata(); + void loadSavedata(const char *data); + int saveSavedataLength(); + void saveSavedata(char *dest); const std::string saveBasePath() const; void setSaveDir(const std::string &dir); int loadROM(const char *romfiledata, unsigned romfilelength, bool forceDmg, bool multicartCompat); diff --git a/libgambatte/src/memory.h b/libgambatte/src/memory.h index 00bcfdbc14..70d9fd6308 100644 --- a/libgambatte/src/memory.h +++ b/libgambatte/src/memory.h @@ -78,8 +78,9 @@ public: void setStatePtrs(SaveState &state); unsigned long saveState(SaveState &state, unsigned long cc); void loadState(const SaveState &state/*, unsigned long oldCc*/); - void loadSavedata() { cart.loadSavedata(); } - void saveSavedata() { cart.saveSavedata(); } + void loadSavedata(const char *data) { cart.loadSavedata(data); } + int saveSavedataLength() {return cart.saveSavedataLength(); } + void saveSavedata(char *dest) { cart.saveSavedata(dest); } const std::string saveBasePath() const { return cart.saveBasePath(); } void setOsdElement(std::auto_ptr osdElement) {