Finish getting saveram working on PCE (theoretically)

This actually makes saveram saving and loading somewhat slower on all waterbox cores, but whatever... it's more important to be simple and readable in this code than fast.
This commit is contained in:
nattthebear 2020-05-25 13:49:47 -04:00
parent f9b5b9e374
commit 9ec8536a5e
3 changed files with 132 additions and 26 deletions

View File

@ -0,0 +1,91 @@
using System;
using System.IO;
using BizHawk.Common;
namespace BizHawk.Emulation.Common
{
public class MemoryDomainStream : Stream
{
public MemoryDomainStream(MemoryDomain d)
{
_d = d;
}
private readonly MemoryDomain _d;
public override bool CanRead => true;
public override bool CanSeek => true;
public override bool CanWrite => _d.Writable;
public override long Length => _d.Size;
public override long Position { get; set; }
public override void Flush()
{
}
public override int ReadByte()
{
if (Position >= Length)
return -1;
return _d.PeekByte(Position++);
}
public override void WriteByte(byte value)
{
if (Position >= Length)
throw new IOException("Can't resize stream");
_d.PokeByte(Position++, value);
}
public override int Read(byte[] buffer, int offset, int count)
{
if (offset < 0 || offset + count > buffer.Length)
throw new ArgumentOutOfRangeException("offset");
count = (int)Math.Min(count, Length - Position);
if (count == 0)
return 0;
// TODO: Memory domain doesn't have the overload we need :(
var poop = new byte[count];
// TODO: Range has the wrong end value
_d.BulkPeekByte(new MutableRange<long>(Position, Position + count - 1), poop);
Array.Copy(poop, 0, buffer, offset, count);
Position += count;
return count;
}
public override void Write(byte[] buffer, int offset, int count)
{
if (offset < 0 || offset + count > buffer.Length)
throw new ArgumentOutOfRangeException("offset");
for (var i = offset; i < offset + count; i++)
_d.PokeByte(Position++, buffer[i]);
}
public override long Seek(long offset, SeekOrigin origin)
{
switch (origin)
{
case SeekOrigin.Begin:
Position = offset;
break;
case SeekOrigin.Current:
Position += offset;
break;
case SeekOrigin.End:
Position = Length + offset;
break;
default:
throw new ArgumentOutOfRangeException("origin");
}
return Position;
}
public override void SetLength(long value)
{
throw new NotSupportedException("Stream cannot be resized");
}
}
}

View File

@ -64,18 +64,21 @@ namespace BizHawk.Emulation.Cores.Waterbox
_core.GetMemoryAreas(areas);
_memoryAreas = areas.Where(a => a.Data != IntPtr.Zero && a.Size != 0)
.ToArray();
_saveramAreas = _memoryAreas.Where(a => (a.Flags & LibWaterboxCore.MemoryDomainFlags.Saverammable) != 0)
var memoryDomains = _memoryAreas.Select(a => WaterboxMemoryDomain.Create(a, _exe)).ToList();
var primaryDomain = memoryDomains
.Where(md => md.Definition.Flags.HasFlag(LibWaterboxCore.MemoryDomainFlags.Primary))
.Single();
var mdl = new MemoryDomainList(memoryDomains.Cast<MemoryDomain>().ToList());
mdl.MainMemory = primaryDomain;
_serviceProvider.Register<IMemoryDomains>(mdl);
_saveramAreas = memoryDomains
.Where(md => md.Definition.Flags.HasFlag(LibWaterboxCore.MemoryDomainFlags.Saverammable))
.ToArray();
_saveramSize = (int)_saveramAreas.Sum(a => a.Size);
var memoryDomains = _memoryAreas.Select(a => WaterboxMemoryDomain.Create(a, _exe));
var primaryIndex = _memoryAreas
.Select((a, i) => new { a, i })
.Single(a => (a.a.Flags & LibWaterboxCore.MemoryDomainFlags.Primary) != 0).i;
var mdl = new MemoryDomainList(memoryDomains.Cast<MemoryDomain>().ToList());
mdl.MainMemory = mdl[primaryIndex];
_serviceProvider.Register<IMemoryDomains>(mdl);
var sr = _core as ICustomSaveram;
if (sr != null)
_serviceProvider.Register<ISaveRam>(new CustomSaverammer(sr)); // override the default implementation
@ -110,7 +113,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
}
}
private LibWaterboxCore.MemoryArea[] _saveramAreas;
private WaterboxMemoryDomain[] _saveramAreas;
private int _saveramSize;
public unsafe bool SaveRamModified
@ -119,18 +122,29 @@ namespace BizHawk.Emulation.Cores.Waterbox
{
if (_saveramSize == 0)
return false;
var buff = new byte[4096];
using (_exe.EnterExit())
{
foreach (var area in _saveramAreas)
fixed(byte* bp = buff)
{
int* p = (int*)area.Data;
int* pend = p + area.Size / sizeof(int);
int cmp = (area.Flags & LibWaterboxCore.MemoryDomainFlags.OneFilled) != 0 ? -1 : 0;
while (p < pend)
foreach (var area in _saveramAreas)
{
if (*p++ != cmp)
return true;
var stream = new MemoryDomainStream(area);
int cmp = (area.Definition.Flags & LibWaterboxCore.MemoryDomainFlags.OneFilled) != 0 ? -1 : 0;
while (true)
{
int nread = stream.Read(buff, 0, 4096);
if (nread == 0)
break;
int* p = (int*)bp;
int* pend = p + nread / sizeof(int);
while (p < pend)
{
if (*p++ != cmp)
return true;
}
}
}
}
}
@ -145,11 +159,10 @@ namespace BizHawk.Emulation.Cores.Waterbox
using (_exe.EnterExit())
{
var ret = new byte[_saveramSize];
var offs = 0;
var dest = new MemoryStream(ret, true);
foreach (var area in _saveramAreas)
{
Marshal.Copy(area.Data, ret, offs, (int)area.Size);
offs += (int)area.Size;
new MemoryDomainStream(area).CopyTo(dest);
}
return ret;
}
@ -163,11 +176,10 @@ namespace BizHawk.Emulation.Cores.Waterbox
throw new InvalidOperationException("Saveram size mismatch");
using (_exe.EnterExit())
{
var offs = 0;
var source = new MemoryStream(data, false);
foreach (var area in _saveramAreas)
{
Marshal.Copy(data, offs, area.Data, (int)area.Size);
offs += (int)area.Size;
WaterboxUtils.CopySome(source, new MemoryDomainStream(area), area.Size);
}
}
}

View File

@ -15,10 +15,12 @@ namespace BizHawk.Emulation.Cores.Waterbox
protected readonly IMonitor _monitor;
protected readonly long _addressMangler;
public static MemoryDomain Create(MemoryArea m, IMonitor monitor)
public MemoryArea Definition { get; }
public static WaterboxMemoryDomain Create(MemoryArea m, IMonitor monitor)
{
return m.Flags.HasFlag(MemoryDomainFlags.FunctionHook)
? (MemoryDomain)new WaterboxMemoryDomainFunc(m, monitor)
? (WaterboxMemoryDomain)new WaterboxMemoryDomainFunc(m, monitor)
: new WaterboxMemoryDomainPointer(m, monitor);
}
@ -48,6 +50,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
{
_addressMangler = 0;
}
Definition = m;
}
}