functioning saveram support for gambatte
This commit is contained in:
parent
efbe114e76
commit
4e35cb566f
|
@ -128,13 +128,39 @@ namespace BizHawk.Emulation.Consoles.GB
|
||||||
|
|
||||||
public byte[] ReadSaveRam
|
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
|
public bool SaveRamModified
|
||||||
{
|
{
|
||||||
get;
|
get
|
||||||
set;
|
{
|
||||||
|
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()
|
public void ResetFrameCounter()
|
||||||
|
|
|
@ -155,11 +155,28 @@ namespace BizHawk.Emulation.Consoles.GB
|
||||||
public static extern bool gambatte_isloaded(IntPtr core);
|
public static extern bool gambatte_isloaded(IntPtr core);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Writes persistent cartridge data to disk. Done implicitly on ROM close.
|
/// Get persistant cart memory.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="core">opaque state pointer</param>
|
/// <param name="core">opaque state pointer</param>
|
||||||
|
/// <param name="dest">byte buffer to write into. gambatte_savesavedatalength() bytes will be written</param>
|
||||||
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||||
public static extern void gambatte_savesavedata(IntPtr core);
|
public static extern void gambatte_savesavedata(IntPtr core, byte[] dest);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// restore persistant cart memory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="core">opaque state pointer</param>
|
||||||
|
/// <param name="data">byte buffer to read from. gambatte_savesavedatalength() bytes will be read</param>
|
||||||
|
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void gambatte_loadsavedata(IntPtr core, byte[] data);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// get the size of the persistant cart memory block. this value DEPENDS ON THE PARTICULAR CART LOADED
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="core">opaque state pointer</param>
|
||||||
|
/// <returns>length in bytes. 0 means no internal persistant cart memory</returns>
|
||||||
|
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int gambatte_savesavedatalength(IntPtr core);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Saves emulator state to the state to a byte array
|
/// Saves emulator state to the state to a byte array
|
||||||
|
|
|
@ -1560,7 +1560,10 @@ namespace BizHawk.MultiClient
|
||||||
reader.Read(sram, 0, Global.Emulator.ReadSaveRam.Length);
|
reader.Read(sram, 0, Global.Emulator.ReadSaveRam.Length);
|
||||||
if (Global.Emulator is LibsnesCore)
|
if (Global.Emulator is LibsnesCore)
|
||||||
((LibsnesCore)Global.Emulator).StoreSaveRam(sram);
|
((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 { }
|
catch { }
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
|
@ -92,8 +92,10 @@ public:
|
||||||
/** Returns true if a ROM image is loaded. */
|
/** Returns true if a ROM image is loaded. */
|
||||||
bool isLoaded() const;
|
bool isLoaded() const;
|
||||||
|
|
||||||
/** Writes persistent cartridge data to disk. Done implicitly on ROM close. */
|
/** Writes persistent cartridge data to disk. NOT Done implicitly on ROM close. */
|
||||||
void saveSavedata();
|
void loadSavedata(const char *data);
|
||||||
|
int saveSavedataLength();
|
||||||
|
void saveSavedata(char *dest);
|
||||||
|
|
||||||
/** Saves emulator state to the state slot selected with selectState().
|
/** Saves emulator state to the state slot selected with selectState().
|
||||||
* The data will be stored in the directory given by setSaveDir().
|
* The data will be stored in the directory given by setSaveDir().
|
||||||
|
|
|
@ -83,11 +83,31 @@ __declspec(dllexport) int gambatte_isloaded(void *core)
|
||||||
return g->isLoaded();
|
return g->isLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
__declspec(dllexport) void gambatte_savesavedata(void *core)
|
__declspec(dllexport) void gambatte_savesavedata(void *core)
|
||||||
{
|
{
|
||||||
GB *g = (GB *) core;
|
GB *g = (GB *) core;
|
||||||
g->saveSavedata();
|
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)
|
__declspec(dllexport) int gambatte_savestate(void *core, const unsigned long *videobuf, int pitch)
|
||||||
|
|
|
@ -24,7 +24,9 @@ extern "C"
|
||||||
|
|
||||||
__declspec(dllexport) int gambatte_isloaded(void *core);
|
__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);
|
//__declspec(dllexport) int gambatte_savestate(void *core, const unsigned long *videobuf, int pitch);
|
||||||
|
|
||||||
|
|
|
@ -51,8 +51,9 @@ public:
|
||||||
void saveState(SaveState &state);
|
void saveState(SaveState &state);
|
||||||
void loadState(const SaveState &state);
|
void loadState(const SaveState &state);
|
||||||
|
|
||||||
void loadSavedata() { memory.loadSavedata(); }
|
void loadSavedata(const char *data) { memory.loadSavedata(data); }
|
||||||
void saveSavedata() { memory.saveSavedata(); }
|
int saveSavedataLength() {return memory.saveSavedataLength(); }
|
||||||
|
void saveSavedata(char *dest) { memory.saveSavedata(dest); }
|
||||||
|
|
||||||
void setVideoBuffer(uint_least32_t *const videoBuf, const int pitch) {
|
void setVideoBuffer(uint_least32_t *const videoBuf, const int pitch) {
|
||||||
memory.setVideoBuffer(videoBuf, pitch);
|
memory.setVideoBuffer(videoBuf, pitch);
|
||||||
|
|
|
@ -47,8 +47,8 @@ struct GB::Priv {
|
||||||
GB::GB() : p_(new Priv) {}
|
GB::GB() : p_(new Priv) {}
|
||||||
|
|
||||||
GB::~GB() {
|
GB::~GB() {
|
||||||
if (p_->cpu.loaded())
|
//if (p_->cpu.loaded())
|
||||||
p_->cpu.saveSavedata();
|
// p_->cpu.saveSavedata();
|
||||||
|
|
||||||
delete p_;
|
delete p_;
|
||||||
}
|
}
|
||||||
|
@ -70,13 +70,24 @@ long GB::runFor(gambatte::uint_least32_t *const videoBuf, const int pitch,
|
||||||
|
|
||||||
void GB::reset() {
|
void GB::reset() {
|
||||||
if (p_->cpu.loaded()) {
|
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;
|
SaveState state;
|
||||||
p_->cpu.setStatePtrs(state);
|
p_->cpu.setStatePtrs(state);
|
||||||
setInitState(state, p_->cpu.isCgb(), p_->gbaCgbMode);
|
setInitState(state, p_->cpu.isCgb(), p_->gbaCgbMode);
|
||||||
p_->cpu.loadState(state);
|
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) {
|
int GB::load(const char *romfiledata, unsigned romfilelength, const unsigned flags) {
|
||||||
if (p_->cpu.loaded())
|
//if (p_->cpu.loaded())
|
||||||
p_->cpu.saveSavedata();
|
// p_->cpu.saveSavedata();
|
||||||
|
|
||||||
const int failed = p_->cpu.load(romfiledata, romfilelength, flags & FORCE_DMG, flags & MULTICART_COMPAT);
|
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);
|
p_->cpu.setStatePtrs(state);
|
||||||
setInitState(state, p_->cpu.isCgb(), p_->gbaCgbMode = flags & GBA_CGB);
|
setInitState(state, p_->cpu.isCgb(), p_->gbaCgbMode = flags & GBA_CGB);
|
||||||
p_->cpu.loadState(state);
|
p_->cpu.loadState(state);
|
||||||
p_->cpu.loadSavedata();
|
//p_->cpu.loadSavedata();
|
||||||
|
|
||||||
p_->stateNo = 1;
|
p_->stateNo = 1;
|
||||||
p_->cpu.setOsdElement(std::auto_ptr<OsdElement>());
|
p_->cpu.setOsdElement(std::auto_ptr<OsdElement>());
|
||||||
|
@ -116,9 +127,19 @@ bool GB::isLoaded() const {
|
||||||
return p_->cpu.loaded();
|
return p_->cpu.loaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GB::saveSavedata() {
|
void GB::saveSavedata(char *dest) {
|
||||||
if (p_->cpu.loaded())
|
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) {
|
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) {
|
bool GB::loadState(std::istream &file) {
|
||||||
if (p_->cpu.loaded()) {
|
if (p_->cpu.loaded()) {
|
||||||
p_->cpu.saveSavedata();
|
// p_->cpu.saveSavedata();
|
||||||
|
|
||||||
SaveState state;
|
SaveState state;
|
||||||
p_->cpu.setStatePtrs(state);
|
p_->cpu.setStatePtrs(state);
|
||||||
|
|
|
@ -655,49 +655,42 @@ static bool hasBattery(const unsigned char headerByte0x147) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::loadSavedata() {
|
void Cartridge::loadSavedata(const char *data) {
|
||||||
const std::string &sbp = saveBasePath();
|
|
||||||
|
|
||||||
if (hasBattery(memptrs.romdata()[0x147])) {
|
if (hasBattery(memptrs.romdata()[0x147])) {
|
||||||
std::ifstream file((sbp + ".sav").c_str(), std::ios::binary | std::ios::in);
|
int length = memptrs.rambankdataend() - memptrs.rambankdata();
|
||||||
|
std::memcpy(memptrs.rambankdata(), data, length);
|
||||||
if (file.is_open()) {
|
data += length;
|
||||||
file.read(reinterpret_cast<char*>(memptrs.rambankdata()), memptrs.rambankdataend() - memptrs.rambankdata());
|
enforce8bit(memptrs.rambankdata(), length);
|
||||||
enforce8bit(memptrs.rambankdata(), memptrs.rambankdataend() - memptrs.rambankdata());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasRtc(memptrs.romdata()[0x147])) {
|
if (hasRtc(memptrs.romdata()[0x147])) {
|
||||||
std::ifstream file((sbp + ".rtc").c_str(), std::ios::binary | std::ios::in);
|
unsigned long basetime;
|
||||||
|
std::memcpy(&basetime, data, 4);
|
||||||
if (file.is_open()) {
|
rtc.setBaseTime(basetime);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::saveSavedata() {
|
int Cartridge::saveSavedataLength() {
|
||||||
const std::string &sbp = saveBasePath();
|
int ret = 0;
|
||||||
|
|
||||||
if (hasBattery(memptrs.romdata()[0x147])) {
|
if (hasBattery(memptrs.romdata()[0x147])) {
|
||||||
std::ofstream file((sbp + ".sav").c_str(), std::ios::binary | std::ios::out);
|
ret = memptrs.rambankdataend() - memptrs.rambankdata();
|
||||||
file.write(reinterpret_cast<const char*>(memptrs.rambankdata()), 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])) {
|
if (hasRtc(memptrs.romdata()[0x147])) {
|
||||||
std::ofstream file((sbp + ".rtc").c_str(), std::ios::binary | std::ios::out);
|
|
||||||
const unsigned long basetime = rtc.getBaseTime();
|
const unsigned long basetime = rtc.getBaseTime();
|
||||||
|
std::memcpy(dest, &basetime, 4);
|
||||||
file.put(basetime >> 24 & 0xFF);
|
|
||||||
file.put(basetime >> 16 & 0xFF);
|
|
||||||
file.put(basetime >> 8 & 0xFF);
|
|
||||||
file.put(basetime & 0xFF);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,8 +82,9 @@ public:
|
||||||
void rtcWrite(unsigned data) { rtc.write(data); }
|
void rtcWrite(unsigned data) { rtc.write(data); }
|
||||||
unsigned char rtcRead() const { return *rtc.getActive(); }
|
unsigned char rtcRead() const { return *rtc.getActive(); }
|
||||||
|
|
||||||
void loadSavedata();
|
void loadSavedata(const char *data);
|
||||||
void saveSavedata();
|
int saveSavedataLength();
|
||||||
|
void saveSavedata(char *dest);
|
||||||
const std::string saveBasePath() const;
|
const std::string saveBasePath() const;
|
||||||
void setSaveDir(const std::string &dir);
|
void setSaveDir(const std::string &dir);
|
||||||
int loadROM(const char *romfiledata, unsigned romfilelength, bool forceDmg, bool multicartCompat);
|
int loadROM(const char *romfiledata, unsigned romfilelength, bool forceDmg, bool multicartCompat);
|
||||||
|
|
|
@ -78,8 +78,9 @@ public:
|
||||||
void setStatePtrs(SaveState &state);
|
void setStatePtrs(SaveState &state);
|
||||||
unsigned long saveState(SaveState &state, unsigned long cc);
|
unsigned long saveState(SaveState &state, unsigned long cc);
|
||||||
void loadState(const SaveState &state/*, unsigned long oldCc*/);
|
void loadState(const SaveState &state/*, unsigned long oldCc*/);
|
||||||
void loadSavedata() { cart.loadSavedata(); }
|
void loadSavedata(const char *data) { cart.loadSavedata(data); }
|
||||||
void saveSavedata() { cart.saveSavedata(); }
|
int saveSavedataLength() {return cart.saveSavedataLength(); }
|
||||||
|
void saveSavedata(char *dest) { cart.saveSavedata(dest); }
|
||||||
const std::string saveBasePath() const { return cart.saveBasePath(); }
|
const std::string saveBasePath() const { return cart.saveBasePath(); }
|
||||||
|
|
||||||
void setOsdElement(std::auto_ptr<OsdElement> osdElement) {
|
void setOsdElement(std::auto_ptr<OsdElement> osdElement) {
|
||||||
|
|
Loading…
Reference in New Issue