sameboy: SAVERAMS

This commit is contained in:
nattthebear 2017-07-19 19:49:23 -04:00
parent cf8013af4a
commit 57ca86710b
4 changed files with 157 additions and 13 deletions

View File

@ -42,5 +42,14 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy
[BizImport(CC)]
public abstract byte GetIoReg(byte port);
[BizImport(CC)]
public abstract void PutSaveRam();
[BizImport(CC)]
public abstract void GetSaveRam();
[BizImport(CC)]
public abstract bool HasSaveRam();
}
}

View File

@ -13,7 +13,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy
{
[Core("SameBoy", "LIJI32", true, false, "efc11783c7fb6da66e1dd084e41ba6a85c0bd17e",
"https://sameboy.github.io/", false)]
public class Sameboy : WaterboxCore, IGameboyCommon
public class Sameboy : WaterboxCore, IGameboyCommon, ISaveRam
{
/// <summary>
/// the nominal length of one frame
@ -147,6 +147,26 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy
#endregion
#region ISaveram
public new bool SaveRamModified => _core.HasSaveRam();
public new byte[] CloneSaveRam()
{
_exe.AddTransientFile(null, "save.ram");
_core.GetSaveRam();
return _exe.RemoveTransientFile("save.ram");
}
public new void StoreSaveRam(byte[] data)
{
_exe.AddReadonlyFile(data, "save.ram");
_core.PutSaveRam();
_exe.RemoveReadonlyFile("save.ram");
}
#endregion
protected override LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller, bool render, bool rendersound)
{
return new LibSameboy.FrameInfo

View File

@ -308,6 +308,68 @@ namespace BizHawk.Emulation.Cores.Waterbox
}
}
private class TransientFile : IFileObject
{
private bool _inUse = false;
public string Name { get; }
public Stream Stream { get; }
public bool Close()
{
if (_inUse)
{
_inUse = false;
return true;
}
else
{
return false;
}
}
public bool Open(FileAccess access)
{
if (_inUse)
{
return false;
}
else
{
// TODO: if access != RW, the resultant handle lets you do those all anyway
_inUse = true;
Stream.Position = 0;
return true;
}
}
public void LoadStateBinary(BinaryReader br)
{
throw new InvalidOperationException("Internal savestate error!");
}
public void SaveStateBinary(BinaryWriter bw)
{
throw new InvalidOperationException("Transient files cannot be savestated!");
}
public TransientFile(byte[] data, string name)
{
Stream = new MemoryStream();
Name = name;
if (data != null)
{
Stream.Write(data, 0, data.Length);
Stream.Position = 0;
}
}
public byte[] GetContents()
{
if (_inUse)
throw new InvalidOperationException();
return ((MemoryStream)Stream).ToArray();
}
}
private readonly List<IFileObject> _openFiles = new List<IFileObject>();
private readonly Dictionary<string, IFileObject> _availableFiles = new Dictionary<string, IFileObject>();
@ -697,6 +759,21 @@ namespace BizHawk.Emulation.Cores.Waterbox
}
}
private T RemoveFileInternal<T>(string name)
where T : IFileObject
{
IFileObject o;
if (!_availableFiles.TryGetValue(name, out o))
throw new InvalidOperationException("File was never registered!");
if (o.GetType() != typeof(T))
throw new InvalidOperationException("Object was not a the right kind of file");
if (_openFiles.Contains(o))
throw new InvalidOperationException("Core never closed the file!");
_availableFiles.Remove(name);
return (T)o;
}
public void AddReadonlyFile(byte[] data, string name)
{
_availableFiles.Add(name, new ReadonlyFirmware(data, name));
@ -704,15 +781,16 @@ namespace BizHawk.Emulation.Cores.Waterbox
public void RemoveReadonlyFile(string name)
{
IFileObject o;
if (!_availableFiles.TryGetValue(name, out o))
throw new InvalidOperationException("Firmware was never registered!");
var f = o as ReadonlyFirmware;
if (f == null)
throw new InvalidOperationException("Object was not a firmware!");
if (_openFiles.Contains(o))
throw new InvalidOperationException("Core never closed the firmware!");
_availableFiles.Remove(name);
RemoveFileInternal<ReadonlyFirmware>(name);
}
public void AddTransientFile(byte[] data, string name)
{
_availableFiles.Add(name, new TransientFile(data, name));
}
public byte[] RemoveTransientFile(string name)
{
return RemoveFileInternal<TransientFile>(name).GetContents();
}
}
@ -1090,6 +1168,24 @@ namespace BizHawk.Emulation.Cores.Waterbox
_syscalls.RemoveReadonlyFile(name);
}
/// <summary>
/// Add a transient file that will appear to the waterbox core's libc. The file will be readable
/// and writable. Any attempt to save state while the file is loaded will fail.
/// </summary>
public void AddTransientFile(byte[] data, string name)
{
_syscalls.AddTransientFile(data, name); // don't need to clone data, as it's used at init only
}
/// <summary>
/// Remove a file previously added by AddTransientFile
/// </summary>
/// <returns>The state of the file when it was removed</returns>
public byte[] RemoveTransientFile(string name)
{
return _syscalls.RemoveTransientFile(name);
}
public void SaveStateBinary(BinaryWriter bw)
{
bw.Write(_createstamp);

View File

@ -15,7 +15,7 @@ extern "C" {
static GB_gameboy_t GB;
static uint32_t GBPixels[160 * 144];
static uint32_t* CurrentFramebuffer;
static uint32_t *CurrentFramebuffer;
static bool sgb;
static void VBlankCallback(GB_gameboy_t *gb)
{
@ -94,7 +94,7 @@ static void SgbSampleCallback(int16_t sl, int16_t sr, uint64_t clock)
sample_sgb.right = sr;
}
ECL_EXPORT bool Init(bool cgb, const uint8_t* spc, int spclen)
ECL_EXPORT bool Init(bool cgb, const uint8_t *spc, int spclen)
{
if (spc)
{
@ -145,7 +145,7 @@ ECL_EXPORT void FrameAdvance(MyFrameInfo &f)
{
if (sgb)
{
sgb_set_controller_data((uint8_t*)&f.Keys);
sgb_set_controller_data((uint8_t *)&f.Keys);
}
else
{
@ -225,6 +225,25 @@ ECL_EXPORT uint8_t GetIoReg(uint8_t port)
return GB.io_registers[port];
}
ECL_EXPORT void PutSaveRam()
{
GB_load_battery(&GB, "save.ram");
}
ECL_EXPORT void GetSaveRam()
{
GB_save_battery(&GB, "save.ram");
}
ECL_EXPORT bool HasSaveRam()
{
if (!GB.cartridge_type->has_battery)
return false; // Nothing to save.
if (GB.mbc_ram_size == 0 && !GB.cartridge_type->has_rtc)
return false; /* Claims to have battery, but has no RAM or RTC */
return true;
}
int main()
{
return 0;