gba: saveram support. not tested too much because controller isn't hooked up yet. (and path config appears to be dumping them in the wrong place). also remove the silly system where the core tracks timing on when to write the saveram file to disk.
This commit is contained in:
parent
af355f6d5b
commit
235d7a9a03
|
@ -55,7 +55,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.GBA
|
|||
/// <param name="datalen">length of data in bytes</param>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void libmeteor_loadrom(byte[] data, uint datalen);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// load a bios image
|
||||
/// </summary>
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -146,5 +146,43 @@ namespace BizHawk.Emulation.Consoles.Nintendo.GBA
|
|||
/// <param name="callback">null to clear</param>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void libmeteor_settracecallback(TraceCallback callback);
|
||||
|
||||
/// <summary>
|
||||
/// load saveram from a byte buffer
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="size"></param>
|
||||
/// <returns>success</returns>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool libmeteor_loadsaveram(byte[] data, uint size);
|
||||
|
||||
/// <summary>
|
||||
/// save saveram to a byte buffer
|
||||
/// </summary>
|
||||
/// <param name="data">buffer generated by core. coyp from, but do not modify</param>
|
||||
/// <param name="size">length of buffer</param>
|
||||
/// <returns>success</returns>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool libmeteor_savesaveram(ref IntPtr data, ref uint size);
|
||||
|
||||
/// <summary>
|
||||
/// destroy a buffer previously returned by libmeteor_savesaveram() to avoid leakage
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void libmeteor_savesaveram_destroy(IntPtr data);
|
||||
|
||||
/// <summary>
|
||||
/// return true if there is saveram installed on currently loaded cart
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool libmeteor_hassaveram();
|
||||
|
||||
/// <summary>
|
||||
/// resets the current cart's saveram
|
||||
/// </summary>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void libmeteor_clearsaveram();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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) { }
|
||||
|
|
Binary file not shown.
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBMETEOR_EXPORTS;%(PreprocessorDefinitions);METDEBUG;METDEBUGLOG;_ITERATOR_DEBUG_LEVEL=0</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBMETEOR_EXPORTS;%(PreprocessorDefinitions);METDEBUG;METDEBUGLOG;_ITERATOR_DEBUG_LEVEL=0;NO_MEMMEM</PreprocessorDefinitions>
|
||||
<DisableSpecificWarnings>4396;4800</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
|
@ -67,7 +67,7 @@
|
|||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBMETEOR_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBMETEOR_EXPORTS;%(PreprocessorDefinitions);NO_MEMMEM</PreprocessorDefinitions>
|
||||
<DisableSpecificWarnings>4396;4800</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 <empty>.\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)
|
||||
|
|
Loading…
Reference in New Issue