diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/GPGX.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/GPGX.cs index 587e824671..246b08825b 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/GPGX.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/GPGX.cs @@ -8,6 +8,8 @@ using BizHawk.Emulation.Common; using System.Runtime.InteropServices; +using System.IO; + namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx { @@ -308,30 +310,99 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx #region saveram + // this all feels very messy + + struct SaveRamInfo + { + public int totalsize; + public IntPtr[] areas; + public int[] sizes; + + public int arraysize { get { return totalsize + 4 * LibGPGX.MAX_SRAM_TYPES; } } + } + + SaveRamInfo GetSaveRamInfo() + { + SaveRamInfo ret = new SaveRamInfo + { + areas = new IntPtr[LibGPGX.MAX_SRAM_TYPES], + sizes = new int[LibGPGX.MAX_SRAM_TYPES], + }; + for (int i = 0; i < LibGPGX.MAX_SRAM_TYPES; i++) + { + IntPtr area = IntPtr.Zero; + int size = 0; + LibGPGX.gpgx_get_sram(ref area, ref size, i); + ret.areas[i] = area; + ret.sizes[i] = size; + ret.totalsize += size; + } + return ret; + } + public byte[] ReadSaveRam() { - throw new NotImplementedException(); + var sri = GetSaveRamInfo(); + if (sri.totalsize == 0) + return new byte[0]; + + byte[] ret = new byte[sri.arraysize]; + + MemoryStream ms = new MemoryStream(ret, true); + BinaryWriter bw = new BinaryWriter(ms); + + for (int i = 0; i < LibGPGX.MAX_SRAM_TYPES; i++) + { + bw.Write(sri.sizes[i]); + if (sri.areas[i] != IntPtr.Zero) + { + byte[] data = new byte[sri.sizes[i]]; + Marshal.Copy(sri.areas[i], data, 0, sri.sizes[i]); + bw.Write(data); + } + } + bw.Flush(); + ms.Close(); + return ret; } public void StoreSaveRam(byte[] data) { - throw new NotImplementedException(); + var sri = GetSaveRamInfo(); + if (sri.arraysize!= data.Length) + throw new Exception("Unexpected SaveRam size"); + + MemoryStream ms = new MemoryStream(data, false); + BinaryReader br = new BinaryReader(ms); + + for (int i = 0; i < LibGPGX.MAX_SRAM_TYPES; i++) + { + int size = br.ReadInt32(); + if (size != sri.sizes[i]) + throw new Exception("Unexpected SaveRam size"); + if (sri.areas[i] != IntPtr.Zero) + { + byte[] tmp = new byte[sri.sizes[i]]; + br.Read(tmp, 0, sri.sizes[i]); + Marshal.Copy(tmp, 0, sri.areas[i], sri.sizes[i]); + } + } } public void ClearSaveRam() { - throw new NotImplementedException(); + LibGPGX.gpgx_clear_sram(); } public bool SaveRamModified { get { - return false; + return GetSaveRamInfo().totalsize > 0; } set { - throw new NotImplementedException(); + throw new Exception(); } } diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/LibGPGX.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/LibGPGX.cs index 3dd13cfd89..fde17bd54b 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/LibGPGX.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/LibGPGX.cs @@ -38,6 +38,13 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx [DllImport("libgenplusgx.dll", CallingConvention = CallingConvention.Cdecl)] public static extern bool gpgx_put_control(IntPtr src, int bytes); + public const int MAX_SRAM_TYPES = 3; + [DllImport("libgenplusgx.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void gpgx_get_sram(ref IntPtr area, ref int size, int type); + + [DllImport("libgenplusgx.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void gpgx_clear_sram(); + public static bool gpgx_get_control(InputData dest) { int bytes = Marshal.SizeOf(typeof(InputData)); diff --git a/genplus-gx/cinterface/cinterface.c b/genplus-gx/cinterface/cinterface.c index a5921effa4..17bf49a2d3 100644 --- a/genplus-gx/cinterface/cinterface.c +++ b/genplus-gx/cinterface/cinterface.c @@ -168,6 +168,70 @@ GPGX_EX void gpgx_advance(void) } +static uint8_t brm_format[0x40] = +{ + 0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x00,0x00,0x00,0x00,0x40, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x53,0x45,0x47,0x41,0x5f,0x43,0x44,0x5f,0x52,0x4f,0x4d,0x00,0x01,0x00,0x00,0x00, + 0x52,0x41,0x4d,0x5f,0x43,0x41,0x52,0x54,0x52,0x49,0x44,0x47,0x45,0x5f,0x5f,0x5f +}; + +GPGX_EX void gpgx_clear_sram(void) +{ + // clear sram + if (sram.sram) + memset(sram.sram, 0, 0x10000); + + // clear and format bram + memset(scd.bram, 0, 0x2000); + brm_format[0x10] = brm_format[0x12] = brm_format[0x14] = brm_format[0x16] = 0x00; + brm_format[0x11] = brm_format[0x13] = brm_format[0x15] = brm_format[0x17] = (sizeof(scd.bram) / 64) - 3; + memcpy(scd.bram + 0x2000 - 0x40, brm_format, 0x40); + + // clear and format ebram + memset(scd.cartridge.area, 0x00, scd.cartridge.mask + 1); + brm_format[0x10] = brm_format[0x12] = brm_format[0x14] = brm_format[0x16] = (((scd.cartridge.mask + 1) / 64) - 3) >> 8; + brm_format[0x11] = brm_format[0x13] = brm_format[0x15] = brm_format[0x17] = (((scd.cartridge.mask + 1) / 64) - 3) & 0xff; + memcpy(scd.cartridge.area + scd.cartridge.mask + 1 - 0x40, brm_format, 0x40); +} + +GPGX_EX void gpgx_get_sram(void **area, int *size, int type) +{ + if (type == 0) + { + // cart sram + if (sram.on) + { + if (area) + *area = sram.sram; + if (size) + *size = 0x10000; + } + } + else if (type == 1) + { + // bram + if (cdd.loaded) + { + if (area) + *area = scd.bram; + if (size) + *size = 0x2000; + } + } + else if (type == 2) + { + // external bram + if (scd.cartridge.id) + { + if (area) + *area = scd.cartridge.area; + if (size) + *size = scd.cartridge.mask + 1; + } + } +} + GPGX_EX int gpgx_init(const char *feromextension, int (*feload_archive_cb)(const char *filename, unsigned char *buffer, int maxsize), int sixbutton, char system_a, char system_b) { memset(&bitmap, 0, sizeof(bitmap)); @@ -240,6 +304,7 @@ GPGX_EX int gpgx_init(const char *feromextension, int (*feload_archive_cb)(const system_reset(); update_viewport(); + gpgx_clear_sram(); return 1; } diff --git a/output/dll/libgenplusgx.dll b/output/dll/libgenplusgx.dll index e1ad16272a..923b0678c2 100644 Binary files a/output/dll/libgenplusgx.dll and b/output/dll/libgenplusgx.dll differ