savestates for vb. this includes savestates for mmap_heap. unfortunately, usage of mmap_heap was scrapped as the things going into it were better suited for invisible/sealed. it may be eventually useful
This commit is contained in:
parent
3677f55992
commit
2887ba5823
|
@ -8,6 +8,7 @@ namespace BizHawk.Common.BufferExtensions
|
||||||
{
|
{
|
||||||
public static class BufferExtensions
|
public static class BufferExtensions
|
||||||
{
|
{
|
||||||
|
[Obsolete] // do we know of any situation where SaveAsHexFast doesn't work?
|
||||||
public static void SaveAsHex(this byte[] buffer, TextWriter writer)
|
public static void SaveAsHex(this byte[] buffer, TextWriter writer)
|
||||||
{
|
{
|
||||||
foreach (var b in buffer)
|
foreach (var b in buffer)
|
||||||
|
@ -39,6 +40,7 @@ namespace BizHawk.Common.BufferExtensions
|
||||||
writer.WriteLine();
|
writer.WriteLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Obsolete] // do we know of any situation where SaveAsHexFast doesn't work?
|
||||||
public static void SaveAsHex(this byte[] buffer, TextWriter writer, int length)
|
public static void SaveAsHex(this byte[] buffer, TextWriter writer, int length)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < length; i++)
|
for (int i = 0; i < length; i++)
|
||||||
|
|
|
@ -33,10 +33,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES9X
|
||||||
{
|
{
|
||||||
Path = comm.CoreFileProvider.DllPath(),
|
Path = comm.CoreFileProvider.DllPath(),
|
||||||
Filename = "snes9x.wbx",
|
Filename = "snes9x.wbx",
|
||||||
NormalHeapSizeKB = 1024,
|
SbrkHeapSizeKB = 1024,
|
||||||
SealedHeapSizeKB = 12 * 1024,
|
SealedHeapSizeKB = 12 * 1024,
|
||||||
InvisibleHeapSizeKB = 6 * 1024,
|
InvisibleHeapSizeKB = 6 * 1024,
|
||||||
SpecialHeapSizeKB = 64
|
PlainHeapSizeKB = 64
|
||||||
});
|
});
|
||||||
|
|
||||||
_core = BizInvoker.GetInvoker<LibSnes9x>(_exe, _exe);
|
_core = BizInvoker.GetInvoker<LibSnes9x>(_exe, _exe);
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
using BizHawk.Common.BizInvoke;
|
using BizHawk.Common.BizInvoke;
|
||||||
|
using BizHawk.Common.BufferExtensions;
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
using BizHawk.Emulation.Cores.Waterbox;
|
using BizHawk.Emulation.Cores.Waterbox;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -11,7 +13,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.VB
|
||||||
{
|
{
|
||||||
[CoreAttributes("Virtual Boyee", "???", true, false, "0.9.44.1",
|
[CoreAttributes("Virtual Boyee", "???", true, false, "0.9.44.1",
|
||||||
"https://mednafen.github.io/releases/", false)]
|
"https://mednafen.github.io/releases/", false)]
|
||||||
public class VirtualBoyee : IEmulator, IVideoProvider, ISoundProvider
|
public class VirtualBoyee : IEmulator, IVideoProvider, ISoundProvider, IStatable
|
||||||
{
|
{
|
||||||
private PeRunner _exe;
|
private PeRunner _exe;
|
||||||
private LibVirtualBoyee _boyee;
|
private LibVirtualBoyee _boyee;
|
||||||
|
@ -26,11 +28,10 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.VB
|
||||||
{
|
{
|
||||||
Path = comm.CoreFileProvider.DllPath(),
|
Path = comm.CoreFileProvider.DllPath(),
|
||||||
Filename = "vb.wbx",
|
Filename = "vb.wbx",
|
||||||
NormalHeapSizeKB = 4 * 1024,
|
SbrkHeapSizeKB = 256,
|
||||||
SealedHeapSizeKB = 12 * 1024,
|
SealedHeapSizeKB = 4 * 1024,
|
||||||
InvisibleHeapSizeKB = 6 * 1024,
|
InvisibleHeapSizeKB = 256,
|
||||||
SpecialHeapSizeKB = 64,
|
PlainHeapSizeKB = 256
|
||||||
MmapHeapSizeKB = 16 * 1024
|
|
||||||
});
|
});
|
||||||
|
|
||||||
_boyee = BizInvoker.GetInvoker<LibVirtualBoyee>(_exe, _exe);
|
_boyee = BizInvoker.GetInvoker<LibVirtualBoyee>(_exe, _exe);
|
||||||
|
@ -39,6 +40,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.VB
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Core rejected the rom");
|
throw new InvalidOperationException("Core rejected the rom");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_exe.Seal();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool _disposed = false;
|
private bool _disposed = false;
|
||||||
|
@ -191,5 +194,63 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.VB
|
||||||
public SyncSoundMode SyncMode => SyncSoundMode.Sync;
|
public SyncSoundMode SyncMode => SyncSoundMode.Sync;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
public int LagCount { get; set; }
|
||||||
|
public bool IsLagFrame { get; set; }
|
||||||
|
|
||||||
|
#region IStatable
|
||||||
|
|
||||||
|
public bool BinarySaveStatesPreferred
|
||||||
|
{
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveStateText(TextWriter writer)
|
||||||
|
{
|
||||||
|
var temp = SaveStateBinary();
|
||||||
|
temp.SaveAsHexFast(writer);
|
||||||
|
// write extra copy of stuff we don't use
|
||||||
|
writer.WriteLine("Frame {0}", Frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadStateText(TextReader reader)
|
||||||
|
{
|
||||||
|
string hex = reader.ReadLine();
|
||||||
|
byte[] state = new byte[hex.Length / 2];
|
||||||
|
state.ReadFromHexFast(hex);
|
||||||
|
LoadStateBinary(new BinaryReader(new MemoryStream(state)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadStateBinary(BinaryReader reader)
|
||||||
|
{
|
||||||
|
_exe.LoadStateBinary(reader);
|
||||||
|
// other variables
|
||||||
|
Frame = reader.ReadInt32();
|
||||||
|
LagCount = reader.ReadInt32();
|
||||||
|
IsLagFrame = reader.ReadBoolean();
|
||||||
|
// any managed pointers that we sent to the core need to be resent now!
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveStateBinary(BinaryWriter writer)
|
||||||
|
{
|
||||||
|
_exe.SaveStateBinary(writer);
|
||||||
|
// other variables
|
||||||
|
writer.Write(Frame);
|
||||||
|
writer.Write(LagCount);
|
||||||
|
writer.Write(IsLagFrame);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] SaveStateBinary()
|
||||||
|
{
|
||||||
|
var ms = new MemoryStream();
|
||||||
|
var bw = new BinaryWriter(ms);
|
||||||
|
SaveStateBinary(bw);
|
||||||
|
bw.Flush();
|
||||||
|
ms.Close();
|
||||||
|
return ms.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,10 +45,10 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx64
|
||||||
{
|
{
|
||||||
Path = comm.CoreFileProvider.DllPath(),
|
Path = comm.CoreFileProvider.DllPath(),
|
||||||
Filename = "gpgx.wbx",
|
Filename = "gpgx.wbx",
|
||||||
NormalHeapSizeKB = 256,
|
SbrkHeapSizeKB = 256,
|
||||||
SealedHeapSizeKB = 36 * 1024,
|
SealedHeapSizeKB = 36 * 1024,
|
||||||
InvisibleHeapSizeKB = 4 * 1024,
|
InvisibleHeapSizeKB = 4 * 1024,
|
||||||
SpecialHeapSizeKB = 64
|
PlainHeapSizeKB = 64
|
||||||
});
|
});
|
||||||
|
|
||||||
Core = BizInvoker.GetInvoker<LibGPGX>(_elf, _elf);
|
Core = BizInvoker.GetInvoker<LibGPGX>(_elf, _elf);
|
||||||
|
|
|
@ -73,7 +73,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
{
|
{
|
||||||
if (!Sealed)
|
if (!Sealed)
|
||||||
{
|
{
|
||||||
Memory.Protect(Memory.Start, Memory.Size, MemoryBlock.Protection.R);
|
Memory.Protect(Memory.Start, Used, MemoryBlock.Protection.R);
|
||||||
_hash = WaterboxUtils.Hash(Memory.GetStream(Memory.Start, Used, false));
|
_hash = WaterboxUtils.Hash(Memory.GetStream(Memory.Start, Used, false));
|
||||||
Sealed = true;
|
Sealed = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,10 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Name { get; private set; }
|
public string Name { get; private set; }
|
||||||
|
|
||||||
public byte[] XorHash { get; private set; }
|
/// <summary>
|
||||||
|
/// total number of bytes allocated
|
||||||
|
/// </summary>
|
||||||
|
public ulong Used { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// get a page index within the block
|
/// get a page index within the block
|
||||||
|
@ -39,9 +42,22 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
|
|
||||||
private class Bin
|
private class Bin
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// first page# in this bin, inclusive
|
||||||
|
/// </summary>
|
||||||
public int StartPage;
|
public int StartPage;
|
||||||
|
/// <summary>
|
||||||
|
/// numbe of pages in this bin
|
||||||
|
/// </summary>
|
||||||
public int PageCount;
|
public int PageCount;
|
||||||
|
/// <summary>
|
||||||
|
/// first page# not in this bin
|
||||||
|
/// </summary>
|
||||||
|
public int EndPage => StartPage + PageCount;
|
||||||
public MemoryBlock.Protection Protection;
|
public MemoryBlock.Protection Protection;
|
||||||
|
/// <summary>
|
||||||
|
/// true if not mapped (we distinguish between PROT_NONE and not mapped)
|
||||||
|
/// </summary>
|
||||||
public bool Free
|
public bool Free
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
@ -78,6 +94,17 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// activate the protection specified by this block
|
||||||
|
/// </summary>
|
||||||
|
public void ApplyProtection(MemoryBlock m)
|
||||||
|
{
|
||||||
|
var prot = Free ? MemoryBlock.Protection.None : Protection;
|
||||||
|
var start = ((ulong)StartPage << WaterboxUtils.PageShift) + m.Start;
|
||||||
|
var length = (ulong)PageCount << WaterboxUtils.PageShift;
|
||||||
|
m.Protect(start, length, prot);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Bin _root;
|
private Bin _root;
|
||||||
|
@ -153,19 +180,30 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
best.Protection = prot;
|
best.Protection = prot;
|
||||||
|
|
||||||
var ret = GetStartAddr(best.StartPage);
|
var ret = GetStartAddr(best.StartPage);
|
||||||
Memory.Protect(ret, ((ulong)numPages) << WaterboxUtils.PageShift, prot);
|
var totalSize = ((ulong)numPages) << WaterboxUtils.PageShift;
|
||||||
|
Memory.Protect(ret, totalSize, prot);
|
||||||
|
Used += totalSize;
|
||||||
|
Console.WriteLine($"Allocated {totalSize} bytes on {Name}, utilization {Used}/{Memory.Size} ({100.0 * Used / Memory.Size:0.#}%)");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ulong Remap(ulong start, ulong oldSize, ulong newSize, bool canMove)
|
public ulong Remap(ulong start, ulong oldSize, ulong newSize, bool canMove)
|
||||||
{
|
{
|
||||||
|
// TODO: what is the expected behavior when everything requested for remap is allocated,
|
||||||
|
// but with different protections?
|
||||||
|
|
||||||
if (start < Memory.Start || start + oldSize > Memory.End)
|
if (start < Memory.Start || start + oldSize > Memory.End)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
var oldStartPage = GetPage(start);
|
var oldStartPage = GetPage(start);
|
||||||
var oldStartBin = GetBinForStartPage(oldStartPage);
|
var oldStartBin = GetBinForStartPage(oldStartPage);
|
||||||
if (oldSize == 0 && canMove)
|
if (oldSize == 0 && canMove)
|
||||||
return Map(newSize, oldStartBin.Protection);
|
{
|
||||||
|
if (oldStartBin.Free)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return Map(newSize, oldStartBin.Protection);
|
||||||
|
}
|
||||||
|
|
||||||
var oldNumPages = WaterboxUtils.PagesNeeded(oldSize);
|
var oldNumPages = WaterboxUtils.PagesNeeded(oldSize);
|
||||||
var oldEndPage = oldStartPage + oldNumPages;
|
var oldEndPage = oldStartPage + oldNumPages;
|
||||||
|
@ -181,14 +219,22 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
// increase size
|
// increase size
|
||||||
// the only way this will work in place is if all of the remaining space is free
|
// the only way this will work in place is if all of the remaining space is free
|
||||||
Bin nextBin;
|
Bin nextBin;
|
||||||
if (oldEndBin.StartPage + oldEndBin.PageCount == oldEndPage // if end bin is too bag, space after that is used by something else
|
if (oldEndBin.EndPage == oldEndPage // if end bin is too bag, space after that is used by something else
|
||||||
&& (nextBin = oldEndBin.Next) != null // can't go off the edge
|
&& (nextBin = oldEndBin.Next) != null // can't go off the edge
|
||||||
&& nextBin.Free
|
&& nextBin.Free
|
||||||
&& nextBin.StartPage + nextBin.PageCount >= newEndPage)
|
&& nextBin.EndPage >= newEndPage)
|
||||||
{
|
{
|
||||||
nextBin.Protection = oldStartBin.Protection;
|
nextBin.Protection = oldStartBin.Protection;
|
||||||
if (nextBin.Cleave(newEndPage - nextBin.StartPage))
|
if (nextBin.Cleave(newEndPage - nextBin.StartPage))
|
||||||
nextBin.Next.Free = true;
|
nextBin.Next.Free = true;
|
||||||
|
|
||||||
|
nextBin.ApplyProtection(Memory);
|
||||||
|
|
||||||
|
var oldTotalSize = ((ulong)oldNumPages) << WaterboxUtils.PageShift;
|
||||||
|
var newTotalSize = ((ulong)newNumPages) << WaterboxUtils.PageShift;
|
||||||
|
Used += newTotalSize;
|
||||||
|
Used -= oldTotalSize;
|
||||||
|
Console.WriteLine($"Reallocated from {oldTotalSize} bytes to {newTotalSize} bytes on {Name}, utilization {Used}/{Memory.Size} ({100.0 * Used / Memory.Size:0.#}%)");
|
||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
// could not increase in place, so move
|
// could not increase in place, so move
|
||||||
|
@ -270,17 +316,21 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
freeBin.Free = true;
|
freeBin.Free = true;
|
||||||
}
|
}
|
||||||
MemoryBlock.Protection lastEaten = MemoryBlock.Protection.None;
|
MemoryBlock.Protection lastEaten = MemoryBlock.Protection.None;
|
||||||
while (freeBin.StartPage + freeBin.PageCount < endPage)
|
while (freeBin.EndPage < endPage)
|
||||||
{
|
{
|
||||||
freeBin.PageCount += freeBin.Next.PageCount;
|
freeBin.PageCount += freeBin.Next.PageCount;
|
||||||
lastEaten = freeBin.Next.Protection;
|
lastEaten = freeBin.Next.Protection;
|
||||||
freeBin.Next = freeBin.Next.Next;
|
freeBin.Next = freeBin.Next.Next;
|
||||||
}
|
}
|
||||||
if (freeBin.Cleave(freeBin.StartPage + freeBin.PageCount - endPage))
|
if (freeBin.Cleave(freeBin.EndPage - endPage))
|
||||||
{
|
{
|
||||||
freeBin.Next.Protection = lastEaten;
|
freeBin.Next.Protection = lastEaten;
|
||||||
}
|
}
|
||||||
Memory.Protect(GetStartAddr(startPage), ((ulong)numPages) << WaterboxUtils.PageShift, MemoryBlock.Protection.None);
|
freeBin.ApplyProtection(Memory);
|
||||||
|
|
||||||
|
var totalSize = ((ulong)numPages) << WaterboxUtils.PageShift;
|
||||||
|
Used -= totalSize;
|
||||||
|
Console.WriteLine($"Freed {totalSize} bytes on {Name}, utilization {Used}/{Memory.Size} ({100.0 * Used / Memory.Size:0.#}%)");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
@ -292,12 +342,76 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SaveStateBinary(BinaryWriter writer)
|
public void SaveStateBinary(BinaryWriter bw)
|
||||||
{
|
{
|
||||||
|
bw.Write(Name);
|
||||||
|
bw.Write(Memory.Size);
|
||||||
|
bw.Write(Used);
|
||||||
|
bw.Write(Memory.XorHash);
|
||||||
|
var bin = _root;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
bw.Write(bin.PageCount);
|
||||||
|
bw.Write((byte)bin.Protection);
|
||||||
|
if (!bin.Free)
|
||||||
|
{
|
||||||
|
var start = GetStartAddr(bin.StartPage);
|
||||||
|
var length = (ulong)bin.PageCount << WaterboxUtils.PageShift;
|
||||||
|
if (bin.Protection == MemoryBlock.Protection.None)
|
||||||
|
Memory.Protect(start, length, MemoryBlock.Protection.R);
|
||||||
|
Memory.GetXorStream(start, length, false).CopyTo(bw.BaseStream);
|
||||||
|
if (bin.Protection == MemoryBlock.Protection.None)
|
||||||
|
Memory.Protect(start, length, MemoryBlock.Protection.None);
|
||||||
|
}
|
||||||
|
bin = bin.Next;
|
||||||
|
} while (bin != null);
|
||||||
|
bw.Write(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadStateBinary(BinaryReader reader)
|
public void LoadStateBinary(BinaryReader br)
|
||||||
{
|
{
|
||||||
|
var name = br.ReadString();
|
||||||
|
if (name != Name)
|
||||||
|
throw new InvalidOperationException(string.Format("Name did not match for mapheap {0}", Name));
|
||||||
|
var size = br.ReadUInt64();
|
||||||
|
if (size != Memory.Size)
|
||||||
|
throw new InvalidOperationException(string.Format("Size did not match for mapheap {0}", Name));
|
||||||
|
var used = br.ReadUInt64();
|
||||||
|
var hash = br.ReadBytes(Memory.XorHash.Length);
|
||||||
|
if (!hash.SequenceEqual(Memory.XorHash))
|
||||||
|
throw new InvalidOperationException(string.Format("Hash did not match for mapheap {0}. Is this the same rom?", Name));
|
||||||
|
|
||||||
|
Used = 0;
|
||||||
|
|
||||||
|
int startPage = 0;
|
||||||
|
int pageCount;
|
||||||
|
Bin scratch = new Bin(), curr = scratch;
|
||||||
|
while ((pageCount = br.ReadInt32()) != -1)
|
||||||
|
{
|
||||||
|
var next = new Bin
|
||||||
|
{
|
||||||
|
StartPage = startPage,
|
||||||
|
PageCount = pageCount,
|
||||||
|
Protection = (MemoryBlock.Protection)br.ReadByte()
|
||||||
|
};
|
||||||
|
startPage += pageCount;
|
||||||
|
if (!next.Free)
|
||||||
|
{
|
||||||
|
var start = GetStartAddr(next.StartPage);
|
||||||
|
var length = (ulong)pageCount << WaterboxUtils.PageShift;
|
||||||
|
Memory.Protect(start, length, MemoryBlock.Protection.RW);
|
||||||
|
WaterboxUtils.CopySome(br.BaseStream, Memory.GetXorStream(start, length, true), (long)length);
|
||||||
|
Used += length;
|
||||||
|
}
|
||||||
|
next.ApplyProtection(Memory);
|
||||||
|
curr.Next = next;
|
||||||
|
curr = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (used != Used)
|
||||||
|
throw new InvalidOperationException(string.Format("Inernal error loading mapheap {0}", Name));
|
||||||
|
|
||||||
|
_root = scratch.Next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,25 +28,25 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
/// how large the normal heap should be. it services sbrk calls
|
/// how large the normal heap should be. it services sbrk calls
|
||||||
/// can be 0, but sbrk calls will crash.
|
/// can be 0, but sbrk calls will crash.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public uint NormalHeapSizeKB { get; set; }
|
public uint SbrkHeapSizeKB { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// how large the sealed heap should be. it services special allocations that become readonly after init
|
/// how large the sealed heap should be. it services special allocations that become readonly after init
|
||||||
/// Must be > 0 and at least large enough to store argv and envp
|
/// Must be > 0 and at least large enough to store argv and envp, and any alloc_sealed() calls
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public uint SealedHeapSizeKB { get; set; }
|
public uint SealedHeapSizeKB { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// how large the invisible heap should be. it services special allocations which are not savestated
|
/// how large the invisible heap should be. it services special allocations which are not savestated
|
||||||
/// Must be > 0 and at least large enough for the internal vtables
|
/// Must be > 0 and at least large enough for the internal vtables, and any alloc_invisible() calls
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public uint InvisibleHeapSizeKB { get; set; }
|
public uint InvisibleHeapSizeKB { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// how large the special heap should be. it is savestated, and contains ??
|
/// how large the "plain" heap should be. it is savestated, and contains
|
||||||
/// Must be > 0 and at least large enough for the internal pthread structure
|
/// Must be > 0 and at least large enough for the internal pthread structure, and any alloc_plain() calls
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public uint SpecialHeapSizeKB { get; set; }
|
public uint PlainHeapSizeKB { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// how large the mmap heap should be. it is savestated.
|
/// how large the mmap heap should be. it is savestated.
|
||||||
|
@ -205,6 +205,12 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
return Z.US(_parent._invisibleheap.Allocate((ulong)size, 16));
|
return Z.US(_parent._invisibleheap.Allocate((ulong)size, 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[BizExport(CallingConvention.Cdecl, EntryPoint = "alloc_plain")]
|
||||||
|
public IntPtr AllocPlain(UIntPtr size)
|
||||||
|
{
|
||||||
|
return Z.US(_parent._plainheap.Allocate((ulong)size, 16));
|
||||||
|
}
|
||||||
|
|
||||||
[BizExport(CallingConvention.Cdecl, EntryPoint = "_debug_puts")]
|
[BizExport(CallingConvention.Cdecl, EntryPoint = "_debug_puts")]
|
||||||
public void DebugPuts(IntPtr s)
|
public void DebugPuts(IntPtr s)
|
||||||
{
|
{
|
||||||
|
@ -229,7 +235,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
{
|
{
|
||||||
// as the inits are done in a defined order with a defined memory map,
|
// as the inits are done in a defined order with a defined memory map,
|
||||||
// we don't need to savestate _pthreadSelf
|
// we don't need to savestate _pthreadSelf
|
||||||
_pthreadSelf = Z.US(_parent._specheap.Allocate(65536, 1));
|
_pthreadSelf = Z.US(_parent._plainheap.Allocate(65536, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
[BizExport(CallingConvention.Cdecl, EntryPoint = "log_output")]
|
[BizExport(CallingConvention.Cdecl, EntryPoint = "log_output")]
|
||||||
|
@ -241,7 +247,6 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
[BizExport(CallingConvention.Cdecl, EntryPoint = "n12")]
|
[BizExport(CallingConvention.Cdecl, EntryPoint = "n12")]
|
||||||
public UIntPtr Brk(UIntPtr _p)
|
public UIntPtr Brk(UIntPtr _p)
|
||||||
{
|
{
|
||||||
// does MUSL use this?
|
|
||||||
var heap = _parent._heap;
|
var heap = _parent._heap;
|
||||||
|
|
||||||
var start = heap.Memory.Start;
|
var start = heap.Memory.Start;
|
||||||
|
@ -570,7 +575,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// extra savestated heap
|
/// extra savestated heap
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private Heap _specheap;
|
private Heap _plainheap;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// memory map emulation
|
/// memory map emulation
|
||||||
|
@ -678,10 +683,10 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
ConnectAllImports();
|
ConnectAllImports();
|
||||||
|
|
||||||
// load all heaps
|
// load all heaps
|
||||||
_heap = CreateHeapHelper(opt.NormalHeapSizeKB, "brk-heap", true);
|
_heap = CreateHeapHelper(opt.SbrkHeapSizeKB, "brk-heap", true);
|
||||||
_sealedheap = CreateHeapHelper(opt.SealedHeapSizeKB, "sealed-heap", true);
|
_sealedheap = CreateHeapHelper(opt.SealedHeapSizeKB, "sealed-heap", true);
|
||||||
_invisibleheap = CreateHeapHelper(opt.InvisibleHeapSizeKB, "invisible-heap", false);
|
_invisibleheap = CreateHeapHelper(opt.InvisibleHeapSizeKB, "invisible-heap", false);
|
||||||
_specheap = CreateHeapHelper(opt.SpecialHeapSizeKB, "special-heap", true);
|
_plainheap = CreateHeapHelper(opt.PlainHeapSizeKB, "plain-heap", true);
|
||||||
|
|
||||||
if (opt.MmapHeapSizeKB != 0)
|
if (opt.MmapHeapSizeKB != 0)
|
||||||
{
|
{
|
||||||
|
@ -695,7 +700,11 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
|
|
||||||
_syscalls.Init();
|
_syscalls.Init();
|
||||||
|
|
||||||
//System.Diagnostics.Debugger.Break();
|
if (System.Diagnostics.Debugger.IsAttached)
|
||||||
|
{
|
||||||
|
Console.WriteLine("About to enter unmanaged code");
|
||||||
|
System.Diagnostics.Debugger.Break();
|
||||||
|
}
|
||||||
|
|
||||||
// run unmanaged init code
|
// run unmanaged init code
|
||||||
var libcEnter = _exports["libc.so"].SafeResolve("__libc_entry_routine");
|
var libcEnter = _exports["libc.so"].SafeResolve("__libc_entry_routine");
|
||||||
|
@ -748,6 +757,8 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
{
|
{
|
||||||
pe.SealImportsAndTakeXorSnapshot();
|
pe.SealImportsAndTakeXorSnapshot();
|
||||||
}
|
}
|
||||||
|
if (_mmapheap != null)
|
||||||
|
_mmapheap.Memory.SaveXorSnapshot();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -811,7 +822,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
_heap = null;
|
_heap = null;
|
||||||
_sealedheap = null;
|
_sealedheap = null;
|
||||||
_invisibleheap = null;
|
_invisibleheap = null;
|
||||||
_specheap = null;
|
_plainheap = null;
|
||||||
_mmapheap = null;
|
_mmapheap = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
|
@ -3,4 +3,5 @@
|
||||||
// this is just used to build a dummy .so file that isn't used
|
// this is just used to build a dummy .so file that isn't used
|
||||||
void *alloc_sealed(size_t size) { return NULL; }
|
void *alloc_sealed(size_t size) { return NULL; }
|
||||||
void *alloc_invisible(size_t size) { return NULL; }
|
void *alloc_invisible(size_t size) { return NULL; }
|
||||||
|
void *alloc_plain(size_t size) { return NULL; }
|
||||||
void _debug_puts(const char *s) { }
|
void _debug_puts(const char *s) { }
|
||||||
|
|
|
@ -23,6 +23,11 @@ void *alloc_sealed(size_t size);
|
||||||
// you are absolutely sure will not harm savestates
|
// you are absolutely sure will not harm savestates
|
||||||
void *alloc_invisible(size_t size);
|
void *alloc_invisible(size_t size);
|
||||||
|
|
||||||
|
// allocate memory from the "plain" pool. this memory can never be freed.
|
||||||
|
// this memory is savestated normally.
|
||||||
|
// useful to avoid malloc() overhead for things that will never be freed
|
||||||
|
void *alloc_plain(size_t size);
|
||||||
|
|
||||||
// send a debug string somewhere, bypassing stdio
|
// send a debug string somewhere, bypassing stdio
|
||||||
void _debug_puts(const char *);
|
void _debug_puts(const char *);
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ CCFLAGS:= -I. -I../emulibc \
|
||||||
-Wall -Werror=pointer-to-int-cast -Werror=int-to-pointer-cast -Werror=implicit-function-declaration \
|
-Wall -Werror=pointer-to-int-cast -Werror=int-to-pointer-cast -Werror=implicit-function-declaration \
|
||||||
-std=c++0x -fomit-frame-pointer -fvisibility=hidden -fno-exceptions -fno-rtti \
|
-std=c++0x -fomit-frame-pointer -fvisibility=hidden -fno-exceptions -fno-rtti \
|
||||||
-DLSB_FIRST \
|
-DLSB_FIRST \
|
||||||
-O0 -g
|
-O3 -flto
|
||||||
|
|
||||||
TARGET = vb.wbx
|
TARGET = vb.wbx
|
||||||
|
|
||||||
|
@ -29,8 +29,8 @@ $(TARGET).in: $(OBJS)
|
||||||
@$(CC) -o $@ $(LDFLAGS) $(CCFLAGS) $(OBJS) ../emulibc/libemuhost.so
|
@$(CC) -o $@ $(LDFLAGS) $(CCFLAGS) $(OBJS) ../emulibc/libemuhost.so
|
||||||
|
|
||||||
$(TARGET): $(TARGET).in
|
$(TARGET): $(TARGET).in
|
||||||
# strip $< -o $@ -R /4 -R /14 -R /29 -R /41 -R /55 -R /67 -R /78 -R /89 -R /104
|
strip $< -o $@ -R /4 -R /14 -R /29 -R /41 -R /55 -R /67 -R /78 -R /89 -R /104
|
||||||
cp $< $@
|
# cp $< $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(OBJ_DIR)
|
rm -rf $(OBJ_DIR)
|
||||||
|
|
|
@ -42,6 +42,7 @@ found freely through public domain sources.
|
||||||
// CPU routines
|
// CPU routines
|
||||||
|
|
||||||
#include "vb.h"
|
#include "vb.h"
|
||||||
|
#include <emulibc.h>
|
||||||
|
|
||||||
//#include "pcfx.h"
|
//#include "pcfx.h"
|
||||||
//#include "debug.h"
|
//#include "debug.h"
|
||||||
|
@ -70,7 +71,7 @@ V810::V810()
|
||||||
IOWrite16 = NULL;
|
IOWrite16 = NULL;
|
||||||
IOWrite32 = NULL;
|
IOWrite32 = NULL;
|
||||||
|
|
||||||
memset(FastMap, 0, sizeof(FastMap));
|
FastMap = (uint8**)alloc_sealed((1ULL << 32) / V810_FAST_MAP_PSIZE * sizeof(*FastMap));
|
||||||
|
|
||||||
memset(MemReadBus32, 0, sizeof(MemReadBus32));
|
memset(MemReadBus32, 0, sizeof(MemReadBus32));
|
||||||
memset(MemWriteBus32, 0, sizeof(MemWriteBus32));
|
memset(MemWriteBus32, 0, sizeof(MemWriteBus32));
|
||||||
|
@ -81,7 +82,6 @@ V810::V810()
|
||||||
|
|
||||||
V810::~V810()
|
V810::~V810()
|
||||||
{
|
{
|
||||||
Kill();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
INLINE void V810::RecalcIPendingCache(void)
|
INLINE void V810::RecalcIPendingCache(void)
|
||||||
|
@ -344,11 +344,6 @@ bool V810::Init(V810_Emu_Mode mode, bool vb_mode)
|
||||||
return (TRUE);
|
return (TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void V810::Kill(void)
|
|
||||||
{
|
|
||||||
FastMapAllocList.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void V810::SetInt(int level)
|
void V810::SetInt(int level)
|
||||||
{
|
{
|
||||||
assert(level >= -1 && level <= 15);
|
assert(level >= -1 && level <= 15);
|
||||||
|
@ -357,7 +352,7 @@ void V810::SetInt(int level)
|
||||||
RecalcIPendingCache();
|
RecalcIPendingCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8 *V810::SetFastMap(uint32 addresses[], uint32 length, unsigned int num_addresses, const char *name)
|
uint8* V810::SetFastMap(void *(*allocator)(size_t size), uint32 addresses[], uint32 length, unsigned int num_addresses, const char *name)
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < num_addresses; i++)
|
for (unsigned int i = 0; i < num_addresses; i++)
|
||||||
{
|
{
|
||||||
|
@ -365,8 +360,7 @@ uint8 *V810::SetFastMap(uint32 addresses[], uint32 length, unsigned int num_addr
|
||||||
}
|
}
|
||||||
assert((length & (V810_FAST_MAP_PSIZE - 1)) == 0);
|
assert((length & (V810_FAST_MAP_PSIZE - 1)) == 0);
|
||||||
|
|
||||||
FastMapAllocList.emplace_back(std::unique_ptr<uint8[]>(new uint8[length + V810_FAST_MAP_TRAMPOLINE_SIZE]));
|
auto ret = (uint8*)allocator(length + V810_FAST_MAP_TRAMPOLINE_SIZE);
|
||||||
uint8 *ret = FastMapAllocList.back().get();
|
|
||||||
|
|
||||||
for (unsigned int i = length; i < length + V810_FAST_MAP_TRAMPOLINE_SIZE; i += 2)
|
for (unsigned int i = length; i < length + V810_FAST_MAP_TRAMPOLINE_SIZE; i += 2)
|
||||||
{
|
{
|
||||||
|
|
|
@ -142,7 +142,6 @@ class V810
|
||||||
|
|
||||||
// Pass TRUE for vb_mode if we're emulating a VB-specific enhanced V810 CPU core
|
// Pass TRUE for vb_mode if we're emulating a VB-specific enhanced V810 CPU core
|
||||||
bool Init(V810_Emu_Mode mode, bool vb_mode) MDFN_COLD;
|
bool Init(V810_Emu_Mode mode, bool vb_mode) MDFN_COLD;
|
||||||
void Kill(void) MDFN_COLD;
|
|
||||||
|
|
||||||
void SetInt(int level);
|
void SetInt(int level);
|
||||||
|
|
||||||
|
@ -156,7 +155,7 @@ class V810
|
||||||
void SetIOWriteHandlers(void MDFN_FASTCALL (*write8)(v810_timestamp_t &, uint32, uint8), void MDFN_FASTCALL (*write16)(v810_timestamp_t &, uint32, uint16), void MDFN_FASTCALL (*write32)(v810_timestamp_t &, uint32, uint32)) MDFN_COLD;
|
void SetIOWriteHandlers(void MDFN_FASTCALL (*write8)(v810_timestamp_t &, uint32, uint8), void MDFN_FASTCALL (*write16)(v810_timestamp_t &, uint32, uint16), void MDFN_FASTCALL (*write32)(v810_timestamp_t &, uint32, uint32)) MDFN_COLD;
|
||||||
|
|
||||||
// Length specifies the number of bytes to map in, at each location specified by addresses[] (for mirroring)
|
// Length specifies the number of bytes to map in, at each location specified by addresses[] (for mirroring)
|
||||||
uint8 *SetFastMap(uint32 addresses[], uint32 length, unsigned int num_addresses, const char *name) MDFN_COLD;
|
uint8 *SetFastMap(void *(*allocator)(size_t size), uint32 addresses[], uint32 length, unsigned int num_addresses, const char *name) MDFN_COLD;
|
||||||
|
|
||||||
INLINE void ResetTS(v810_timestamp_t new_base_timestamp)
|
INLINE void ResetTS(v810_timestamp_t new_base_timestamp)
|
||||||
{
|
{
|
||||||
|
@ -295,8 +294,7 @@ class V810
|
||||||
uint32 dst_cache;
|
uint32 dst_cache;
|
||||||
bool have_src_cache, have_dst_cache;
|
bool have_src_cache, have_dst_cache;
|
||||||
|
|
||||||
uint8 *FastMap[(1ULL << 32) / V810_FAST_MAP_PSIZE];
|
uint8** FastMap;
|
||||||
std::vector<std::unique_ptr<uint8[]>> FastMapAllocList;
|
|
||||||
|
|
||||||
// For CacheDump and CacheRestore
|
// For CacheDump and CacheRestore
|
||||||
void CacheOpMemStore(v810_timestamp_t ×tamp, uint32 A, uint32 V);
|
void CacheOpMemStore(v810_timestamp_t ×tamp, uint32 A, uint32 V);
|
||||||
|
|
|
@ -582,7 +582,7 @@ EXPORT int Load(const uint8 *rom, int length)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WRAM = VB_V810->SetFastMap(&Map_Addresses[0], 65536, Map_Addresses.size(), "WRAM");
|
WRAM = VB_V810->SetFastMap(alloc_plain, &Map_Addresses[0], 65536, Map_Addresses.size(), "WRAM");
|
||||||
Map_Addresses.clear();
|
Map_Addresses.clear();
|
||||||
|
|
||||||
// Round up the ROM size to 65536(we mirror it a little later)
|
// Round up the ROM size to 65536(we mirror it a little later)
|
||||||
|
@ -597,7 +597,7 @@ EXPORT int Load(const uint8 *rom, int length)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GPROM = VB_V810->SetFastMap(&Map_Addresses[0], GPROM_Mask + 1, Map_Addresses.size(), "Cart ROM");
|
GPROM = VB_V810->SetFastMap(alloc_sealed, &Map_Addresses[0], GPROM_Mask + 1, Map_Addresses.size(), "Cart ROM");
|
||||||
Map_Addresses.clear();
|
Map_Addresses.clear();
|
||||||
|
|
||||||
memcpy(GPROM, rom, rom_size);
|
memcpy(GPROM, rom, rom_size);
|
||||||
|
@ -633,7 +633,7 @@ EXPORT int Load(const uint8 *rom, int length)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GPRAM = VB_V810->SetFastMap(&Map_Addresses[0], GPRAM_Mask + 1, Map_Addresses.size(), "Cart RAM");
|
GPRAM = VB_V810->SetFastMap(alloc_plain, &Map_Addresses[0], GPRAM_Mask + 1, Map_Addresses.size(), "Cart RAM");
|
||||||
Map_Addresses.clear();
|
Map_Addresses.clear();
|
||||||
|
|
||||||
memset(GPRAM, 0, GPRAM_Mask + 1);
|
memset(GPRAM, 0, GPRAM_Mask + 1);
|
||||||
|
|
|
@ -374,10 +374,6 @@ void VIP_Init(void)
|
||||||
VidSettingsDirty = true;
|
VidSettingsDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VIP_Kill(void)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void VIP_Power(void)
|
void VIP_Power(void)
|
||||||
{
|
{
|
||||||
Repeat = 0;
|
Repeat = 0;
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
namespace MDFN_IEN_VB
|
namespace MDFN_IEN_VB
|
||||||
{
|
{
|
||||||
void VIP_Init(void) MDFN_COLD;
|
void VIP_Init(void) MDFN_COLD;
|
||||||
void VIP_Kill(void) MDFN_COLD;
|
|
||||||
void VIP_Power(void) MDFN_COLD;
|
void VIP_Power(void) MDFN_COLD;
|
||||||
|
|
||||||
void VIP_SetInstantDisplayHack(bool) MDFN_COLD;
|
void VIP_SetInstantDisplayHack(bool) MDFN_COLD;
|
||||||
|
|
Loading…
Reference in New Issue