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:
parent
f9b5b9e374
commit
9ec8536a5e
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue