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) {