diff --git a/BizHawk.Emulation/Consoles/Nintendo/GBA/LibMeteor.cs b/BizHawk.Emulation/Consoles/Nintendo/GBA/LibMeteor.cs index 2080b0f72d..5919b0b8f5 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/GBA/LibMeteor.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/GBA/LibMeteor.cs @@ -55,7 +55,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.GBA /// length of data in bytes [DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void libmeteor_loadrom(byte[] data, uint datalen); - + /// /// load a bios image /// @@ -85,16 +85,16 @@ namespace BizHawk.Emulation.Consoles.Nintendo.GBA [Flags] public enum Buttons : ushort { - BTN_A = 0x001, - BTN_B = 0x002, + BTN_A = 0x001, + BTN_B = 0x002, BTN_SELECT = 0x004, - BTN_START = 0x008, - BTN_RIGHT = 0x010, - BTN_LEFT = 0x020, - BTN_UP = 0x040, - BTN_DOWN = 0x080, - BTN_R = 0x100, - BTN_L = 0x200 + BTN_START = 0x008, + BTN_RIGHT = 0x010, + BTN_LEFT = 0x020, + BTN_UP = 0x040, + BTN_DOWN = 0x080, + BTN_R = 0x100, + BTN_L = 0x200 } /// @@ -146,5 +146,43 @@ namespace BizHawk.Emulation.Consoles.Nintendo.GBA /// null to clear [DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void libmeteor_settracecallback(TraceCallback callback); + + /// + /// load saveram from a byte buffer + /// + /// + /// + /// success + [DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern bool libmeteor_loadsaveram(byte[] data, uint size); + + /// + /// save saveram to a byte buffer + /// + /// buffer generated by core. coyp from, but do not modify + /// length of buffer + /// success + [DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern bool libmeteor_savesaveram(ref IntPtr data, ref uint size); + + /// + /// destroy a buffer previously returned by libmeteor_savesaveram() to avoid leakage + /// + /// + [DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void libmeteor_savesaveram_destroy(IntPtr data); + + /// + /// return true if there is saveram installed on currently loaded cart + /// + /// + [DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern bool libmeteor_hassaveram(); + + /// + /// resets the current cart's saveram + /// + [DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void libmeteor_clearsaveram(); } } diff --git a/BizHawk.Emulation/Consoles/Nintendo/GBA/Meteor.cs b/BizHawk.Emulation/Consoles/Nintendo/GBA/Meteor.cs index dc4b56fe7c..a04ee143b4 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/GBA/Meteor.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/GBA/Meteor.cs @@ -64,18 +64,31 @@ namespace BizHawk.Emulation.Consoles.Nintendo.GBA public byte[] ReadSaveRam() { - return new byte[0]; + if (!LibMeteor.libmeteor_hassaveram()) + return null; + IntPtr data = IntPtr.Zero; + uint size = 0; + if (!LibMeteor.libmeteor_savesaveram(ref data, ref size)) + throw new Exception("libmeteor_savesaveram() returned false!"); + byte[] ret = new byte[size]; + Marshal.Copy(data, ret, 0, (int)size); + LibMeteor.libmeteor_savesaveram_destroy(data); + return ret; } public void StoreSaveRam(byte[] data) { + if (!LibMeteor.libmeteor_loadsaveram(data, (uint)data.Length)) + throw new Exception("libmeteor_loadsaveram() returned false!"); } public void ClearSaveRam() { + LibMeteor.libmeteor_clearsaveram(); } - public bool SaveRamModified { get { return false; } set { } } + public bool SaveRamModified + { get { return LibMeteor.libmeteor_hassaveram(); } set { } } #endregion diff --git a/BizHawk.MultiClient/MainForm.cs b/BizHawk.MultiClient/MainForm.cs index e3ef6d3d29..3b3ed74f63 100644 --- a/BizHawk.MultiClient/MainForm.cs +++ b/BizHawk.MultiClient/MainForm.cs @@ -2041,20 +2041,18 @@ namespace BizHawk.MultiClient //zero says: this is sort of sketchy... but this is no time for rearchitecting try { - /* - var sram = new byte[Global.Emulator.ReadSaveRam.Length]; - using (var reader = new BinaryReader(new FileStream(PathManager.SaveRamPath(Global.Game), FileMode.Open, FileAccess.Read))) - reader.Read(sram, 0, Global.Emulator.ReadSaveRam.Length); - if (Global.Emulator is LibsnesCore) - ((LibsnesCore)Global.Emulator).StoreSaveRam(sram); - else if (Global.Emulator is Gameboy) - ((Gameboy)Global.Emulator).StoreSaveRam(sram); + byte[] sram; + // GBA core might not know how big the saveram ought to be, so just send it the whole file + if (Global.Emulator is GBA) + { + sram = File.ReadAllBytes(PathManager.SaveRamPath(Global.Game)); + } else - Array.Copy(sram, Global.Emulator.ReadSaveRam, Global.Emulator.ReadSaveRam.Length); - */ - var sram = new byte[Global.Emulator.ReadSaveRam().Length]; - using (var reader = new BinaryReader(new FileStream(PathManager.SaveRamPath(Global.Game), FileMode.Open, FileAccess.Read))) + { + sram = new byte[Global.Emulator.ReadSaveRam().Length]; + using (var reader = new BinaryReader(new FileStream(PathManager.SaveRamPath(Global.Game), FileMode.Open, FileAccess.Read))) reader.Read(sram, 0, sram.Length); + } Global.Emulator.StoreSaveRam(sram); } catch (IOException) { } diff --git a/BizHawk.MultiClient/output/dll/libmeteor.dll b/BizHawk.MultiClient/output/dll/libmeteor.dll index dcf3915798..3e03b60010 100644 Binary files a/BizHawk.MultiClient/output/dll/libmeteor.dll and b/BizHawk.MultiClient/output/dll/libmeteor.dll differ diff --git a/libmeteor/Makefile b/libmeteor/Makefile index a66f82a441..2029f11b3d 100644 --- a/libmeteor/Makefile +++ b/libmeteor/Makefile @@ -30,8 +30,9 @@ else CXXFLAGS += -DNO_MEMMEM endif +#__LIBRETRO__ enables a slightly different saveram mechanism that doesn't seem to serve any useful purpose? #CXXFLAGS += -Wall -pedantic -I. -I../ameteor/include -pipe -D__LIBRETRO__ -Wno-parentheses -fno-exceptions -fno-rtti -CXXFLAGS += -Wall -pedantic -I. -Iinclude -pipe -D__LIBRETRO__ -DX86_ASM -Wno-parentheses -fno-exceptions -fno-rtti +CXXFLAGS += -Wall -pedantic -I. -Iinclude -pipe -DX86_ASM -Wno-parentheses -fno-exceptions -fno-rtti ifeq ($(DEBUG), 1) CFLAGS += -O0 -g diff --git a/libmeteor/cinterface.cpp b/libmeteor/cinterface.cpp index 36ec943370..98f5f79144 100644 --- a/libmeteor/cinterface.cpp +++ b/libmeteor/cinterface.cpp @@ -120,8 +120,6 @@ EXPORT void libmeteor_init() static bool first = true; if (first) { - // TODO: saveram stuff - //AMeteor::_memory.LoadCartInferred(); AMeteor::_lcd.GetScreen().GetRenderer().SetFrameSlot(syg::ptr_fun(videocb)); AMeteor::_sound.GetSpeaker().SetFrameSlot(syg::ptr_fun(soundcb)); first = false; @@ -150,5 +148,30 @@ EXPORT uint8_t *libmeteor_getmemoryarea(int which) return AMeteor::_memory.GetMemoryArea(which); } +EXPORT int libmeteor_loadsaveram(const void *data, unsigned size) +{ + return AMeteor::_memory.LoadCart((const uint8_t*)data, size); +} + +EXPORT int libmeteor_savesaveram(void **data, unsigned *size) +{ + return AMeteor::_memory.SaveCart((uint8_t **)data, size); +} + +EXPORT void libmeteor_savesaveram_destroy(void *data) +{ + AMeteor::_memory.SaveCartDestroy((uint8_t *)data); +} + +EXPORT int libmeteor_hassaveram() +{ + return AMeteor::_memory.HasCart(); +} + +EXPORT void libmeteor_clearsaveram() +{ + AMeteor::_memory.DeleteCart(); +} + // TODO: cartram and system bus memory domains diff --git a/libmeteor/include/ameteor/clock.hpp b/libmeteor/include/ameteor/clock.hpp index 8d001f962b..b711080538 100644 --- a/libmeteor/include/ameteor/clock.hpp +++ b/libmeteor/include/ameteor/clock.hpp @@ -81,15 +81,15 @@ namespace AMeteor return m_timer[num]; } - void SetBattery (uint32_t cycles) - { - m_battery = cycles; - } - void DisableBattery () - { - m_battery = INT_MAX; + //void SetBattery (uint32_t cycles) + //{ + // m_battery = cycles; + //} + //void DisableBattery () + //{ + // m_battery = INT_MAX; // no need to SetFirst since battery will be disabled only in TimeEvent - } + //} bool SaveState (std::ostream& stream); bool LoadState (std::istream& stream); @@ -100,7 +100,7 @@ namespace AMeteor unsigned short m_cycles; unsigned short m_first; - int m_lcd, m_timer[4], m_sound, m_battery; + int m_lcd, m_timer[4], m_sound;//, m_battery; unsigned int m_count; diff --git a/libmeteor/include/ameteor/memory.hpp b/libmeteor/include/ameteor/memory.hpp index 0b167cfe8c..d55cb7ff27 100644 --- a/libmeteor/include/ameteor/memory.hpp +++ b/libmeteor/include/ameteor/memory.hpp @@ -60,10 +60,10 @@ namespace AMeteor // erases cartridge memory void SetCartTypeFromSize (uint32_t size); void SetCartType (uint8_t type); - void SetCartFile (const char* filename) - { - m_cartfile = filename; - } + //void SetCartFile (const char* filename) + //{ + // m_cartfile = filename; + //} void Reset (uint32_t params = ~0); void ClearWbram (); @@ -85,10 +85,23 @@ namespace AMeteor } bool LoadRom (const char* filename); void LoadRom (const uint8_t* data, uint32_t size); - CartError LoadCart (); + //CartError LoadCart (); + bool LoadCart (const uint8_t* data, uint32_t size); + bool SaveCart (uint8_t** data, uint32_t* size); + void SaveCartDestroy(uint8_t* data); #ifdef __LIBRETRO__ bool LoadCartInferred (); #endif + bool HasCart () const + { + return m_cart; + } + + void DeleteCart() + { + if (m_cart) + delete m_cart; + } bool HasBios () const { @@ -141,7 +154,7 @@ namespace AMeteor uint8_t m_carttype; CartMem* m_cart; - std::string m_cartfile; + //std::string m_cartfile; uint8_t ReadCart (uint16_t add); void WriteCart (uint16_t add, uint8_t val); diff --git a/libmeteor/libmeteor.vcxproj b/libmeteor/libmeteor.vcxproj index 7a9a1207b5..89cb51c975 100644 --- a/libmeteor/libmeteor.vcxproj +++ b/libmeteor/libmeteor.vcxproj @@ -51,7 +51,7 @@ Level3 Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBMETEOR_EXPORTS;%(PreprocessorDefinitions);METDEBUG;METDEBUGLOG;_ITERATOR_DEBUG_LEVEL=0 + WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBMETEOR_EXPORTS;%(PreprocessorDefinitions);METDEBUG;METDEBUGLOG;_ITERATOR_DEBUG_LEVEL=0;NO_MEMMEM 4396;4800 @@ -67,7 +67,7 @@ MaxSpeed true true - WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBMETEOR_EXPORTS;%(PreprocessorDefinitions) + WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBMETEOR_EXPORTS;%(PreprocessorDefinitions);NO_MEMMEM 4396;4800 diff --git a/libmeteor/source/clock.cpp b/libmeteor/source/clock.cpp index 7f21980ed3..4600a7250e 100644 --- a/libmeteor/source/clock.cpp +++ b/libmeteor/source/clock.cpp @@ -27,7 +27,7 @@ namespace AMeteor // lcd is enabled by default m_first = m_count = m_cycles = m_lcd = m_sound = 0; // timers and battery are disabled by default - m_battery = m_timer[0] = m_timer[1] = m_timer[2] = m_timer[3] = + /*m_battery =*/ m_timer[0] = m_timer[1] = m_timer[2] = m_timer[3] = INT_MAX; } @@ -67,7 +67,7 @@ namespace AMeteor COMMIT(timer[1], TIMER1) COMMIT(timer[2], TIMER2) COMMIT(timer[3], TIMER3) - COMMIT(battery, MEM) + //COMMIT(battery, MEM) #undef COMMIT SetFirst(); @@ -91,7 +91,7 @@ namespace AMeteor SETFIRST(timer[2]); SETFIRST(timer[3]); SETFIRST(sound); - SETFIRST(battery); + //SETFIRST(battery); } #undef SETFIRST @@ -101,7 +101,7 @@ namespace AMeteor SS_WRITE_VAR(m_first); SS_WRITE_VAR(m_lcd); SS_WRITE_VAR(m_sound); - SS_WRITE_VAR(m_battery); + //SS_WRITE_VAR(m_battery); SS_WRITE_ARRAY(m_timer); @@ -114,7 +114,7 @@ namespace AMeteor SS_READ_VAR(m_first); SS_READ_VAR(m_lcd); SS_READ_VAR(m_sound); - SS_READ_VAR(m_battery); + //SS_READ_VAR(m_battery); SS_READ_ARRAY(m_timer); diff --git a/libmeteor/source/memory.cpp b/libmeteor/source/memory.cpp index 5532ea2f53..f82ac18aec 100644 --- a/libmeteor/source/memory.cpp +++ b/libmeteor/source/memory.cpp @@ -99,29 +99,39 @@ namespace AMeteor void Memory::SetCartType (uint8_t type) { if (m_cart) + { delete m_cart; + print_bizhawk("Cart Memory unloaded.\n"); + } switch (type) { case CTYPE_UNKNOWN: m_cart = NULL; + print_bizhawk("Cart Memory set to .\n"); break; case CTYPE_FLASH64: m_cart = new Flash(false); + print_bizhawk("Cart Memory set to FLASH64\n"); break; case CTYPE_FLASH128: m_cart = new Flash(true); + print_bizhawk("Cart Memory set to FLASH128\n"); break; case CTYPE_EEPROM512: m_cart = new Eeprom(false); + print_bizhawk("Cart Memory set to EEPROM512\n"); break; case CTYPE_EEPROM8192: m_cart = new Eeprom(true); + print_bizhawk("Cart Memory set to EEPROM8192\n"); break; case CTYPE_SRAM: m_cart = new Sram(); + print_bizhawk("Cart Memory set to SRAM\n"); break; default: met_abort("Unknown cartridge memory type"); + print_bizhawk("Problem setting Cart Memory. This is bad.\n"); break; } m_carttype = type; @@ -168,7 +178,7 @@ namespace AMeteor if (params & UNIT_MEMORY_ROM) std::memset(m_rom , 0, 0x02000000); SetCartType(CTYPE_UNKNOWN); - m_cartfile.clear(); + //m_cartfile.clear(); } void Memory::ClearWbram () @@ -204,6 +214,7 @@ namespace AMeteor void Memory::TimeEvent () { + /* if (!m_cartfile.empty()) { // FIXME, this may fail, we should do something to inform user @@ -211,6 +222,7 @@ namespace AMeteor m_cart->Save(f); } CLOCK.DisableBattery(); + */ } bool Memory::LoadBios (const char* filename) @@ -251,6 +263,38 @@ namespace AMeteor std::memset(m_rom+until, 0, 0x02000000-until); } + bool Memory::LoadCart(const uint8_t* data, uint32_t size) + { + SetCartTypeFromSize(size); + if (!m_cart) + return false; + std::stringstream ss = std::stringstream(std::string((const char*)data, size), std::ios_base::in | std::ios_base::binary); + return m_cart->Load(ss); + } + + bool Memory::SaveCart(uint8_t** data, uint32_t* size) + { + if (!m_cart) + return false; + if (!data || !size) + return false; + std::stringstream ss = std::stringstream(std::ios_base::out | std::ios_base::binary); + if (!m_cart->Save(ss)) + return false; + std::string s = ss.str(); + uint8_t *ret = (uint8_t *)std::malloc(s.length()); + std::memcpy(ret, s.data(), s.length()); + *data = ret; + *size = s.length(); + return true; + } + + void Memory::SaveCartDestroy(uint8_t* data) + { + std::free(data); + } + + /* Memory::CartError Memory::LoadCart () { struct stat buf; @@ -262,6 +306,7 @@ namespace AMeteor return CERR_FAIL; return CERR_NO_ERROR; } + */ #ifdef __LIBRETRO__ bool Memory::LoadCartInferred () @@ -761,8 +806,9 @@ namespace AMeteor else met_abort("Unknown size for EEPROM DMA"); - if (eeprom->Write((uint16_t*)GetRealAddress(src), size)) - CLOCK.SetBattery(CART_SAVE_TIME); + //if (eeprom->Write((uint16_t*)GetRealAddress(src), size)) + // CLOCK.SetBattery(CART_SAVE_TIME); + eeprom->Write((uint16_t*)GetRealAddress(src), size); } #if 0 @@ -777,7 +823,6 @@ namespace AMeteor } #endif -#define NO_MEMMEM #ifdef NO_MEMMEM // memmem() is a GNU extension, and does not exist in at least MinGW. #define memmem memmem_compat // Implementation from Git. @@ -817,8 +862,9 @@ namespace AMeteor } else SetCartType(CTYPE_SRAM); - if (m_cart->Write(add, val)) - CLOCK.SetBattery(CART_SAVE_TIME); + //if (m_cart->Write(add, val)) + // CLOCK.SetBattery(CART_SAVE_TIME); + m_cart->Write(add, val); } uint8_t *Memory::GetMemoryArea(int which)