diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
index e7df197953..0ff66a8a21 100644
--- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
+++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
@@ -110,6 +110,9 @@
False
..\References\OpenTK.dll
+
+ ..\References\PeNet.dll
+
3.5
@@ -208,7 +211,7 @@
C64.cs
- C64.cs
+ C64.cs
C64.cs
@@ -220,7 +223,7 @@
-
+
@@ -1247,7 +1250,7 @@
-
+
@@ -1269,7 +1272,8 @@
-
+
+
@@ -1281,6 +1285,8 @@
+
+
@@ -1346,4 +1352,4 @@
-->
-
+
\ No newline at end of file
diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.cs
index c54a7d7892..6707e53448 100644
--- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.cs
@@ -4,6 +4,7 @@ using System.Runtime.InteropServices;
using BizHawk.Common.BizInvoke;
using BizHawk.Emulation.Common;
+using BizHawk.Emulation.Cores.Waterbox;
namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx64
{
diff --git a/BizHawk.Emulation.Cores/ElfRunner.cs b/BizHawk.Emulation.Cores/Waterbox/ElfRunner.cs
similarity index 67%
rename from BizHawk.Emulation.Cores/ElfRunner.cs
rename to BizHawk.Emulation.Cores/Waterbox/ElfRunner.cs
index 0f6f1dfaa8..d72ce948fc 100644
--- a/BizHawk.Emulation.Cores/ElfRunner.cs
+++ b/BizHawk.Emulation.Cores/Waterbox/ElfRunner.cs
@@ -13,9 +13,9 @@ using System.IO;
using System.Collections.Concurrent;
using System.Threading;
-namespace BizHawk.Emulation.Cores
+namespace BizHawk.Emulation.Cores.Waterbox
{
- public sealed class ElfRunner : IImportResolver, IDisposable, IMonitor
+ public sealed class ElfRunner : Swappable, IImportResolver, IDisposable
{
// TODO: a lot of things only work with our elves and aren't fully generalized
@@ -41,11 +41,6 @@ namespace BizHawk.Emulation.Cores
///
private Heap _invisibleheap;
- ///
- /// _base.Start, or 0 if we were relocated and so don't need to be swapped
- ///
- private ulong _lockkey;
-
private long _loadoffset;
private Dictionary> _symdict;
private List> _symlist;
@@ -55,11 +50,6 @@ namespace BizHawk.Emulation.Cores
///
private List _disposeList = new List();
- ///
- /// everything to swap in for context switches
- ///
- private List _memoryBlocks = new List();
-
private ulong GetHeapStart(ulong prevend)
{
// if relocatable, we won't have constant pointers, so put the heap anywhere
@@ -72,7 +62,7 @@ namespace BizHawk.Emulation.Cores
{
using (var fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
- _elfhash = Hash(fs);
+ _elfhash = WaterboxUtils.Hash(fs);
}
// todo: hack up this baby to take Streams
@@ -87,12 +77,12 @@ namespace BizHawk.Emulation.Cores
{
_base = new MemoryBlock((ulong)(orig_end - orig_start));
_loadoffset = (long)_base.Start - orig_start;
- _lockkey = 0;
+ Initialize(0);
}
else
{
- _lockkey = (ulong)orig_start;
- _base = new MemoryBlock(_lockkey, (ulong)(orig_end - orig_start));
+ Initialize((ulong)orig_start);
+ _base = new MemoryBlock((ulong)orig_start, (ulong)(orig_end - orig_start));
_loadoffset = 0;
Enter();
}
@@ -100,7 +90,7 @@ namespace BizHawk.Emulation.Cores
try
{
_disposeList.Add(_base);
- _memoryBlocks.Add(_base);
+ AddMemoryBlock(_base);
_base.Activate();
_base.Protect(_base.Start, _base.Size, MemoryBlock.Protection.RW);
@@ -130,7 +120,7 @@ namespace BizHawk.Emulation.Cores
_heap.Memory.Activate();
end = _heap.Memory.End;
_disposeList.Add(_heap);
- _memoryBlocks.Add(_heap.Memory);
+ AddMemoryBlock(_heap.Memory);
}
if (sealedheapsize > 0)
@@ -139,7 +129,7 @@ namespace BizHawk.Emulation.Cores
_sealedheap.Memory.Activate();
end = _sealedheap.Memory.End;
_disposeList.Add(_sealedheap);
- _memoryBlocks.Add(_sealedheap.Memory);
+ AddMemoryBlock(_sealedheap.Memory);
}
if (invisibleheapsize > 0)
@@ -148,7 +138,7 @@ namespace BizHawk.Emulation.Cores
_invisibleheap.Memory.Activate();
end = _invisibleheap.Memory.End;
_disposeList.Add(_invisibleheap);
- _memoryBlocks.Add(_invisibleheap.Memory);
+ AddMemoryBlock(_invisibleheap.Memory);
}
ConnectAllClibPatches();
@@ -306,7 +296,7 @@ namespace BizHawk.Emulation.Cores
foreach (var d in _disposeList)
d.Dispose();
_disposeList.Clear();
- _memoryBlocks.Clear();
+ PurgeMemoryBlocks();
_base = null;
_heap = null;
_sealedheap = null;
@@ -425,67 +415,6 @@ namespace BizHawk.Emulation.Cores
}
}
- ///
- /// true if the IMonitor should be used for native calls
- ///
- public bool ShouldMonitor { get { return _lockkey != 0; } }
-
- // any ElfRunner is assumed to conflict with any other ElfRunner at the same base address,
- // but not any other starting address. so don't put them too close together!
-
- private class LockInfo
- {
- public object Sync;
- public ElfRunner Loaded;
- }
-
- private static readonly ConcurrentDictionary LockInfos = new ConcurrentDictionary();
-
- static ElfRunner()
- {
- LockInfos.GetOrAdd(0, new LockInfo()); // any errant attempt to lock when ShouldMonitor == false will result in NRE
- }
-
- ///
- /// acquire lock and swap this into memory
- ///
- public void Enter()
- {
- var li = LockInfos.GetOrAdd(_lockkey, new LockInfo { Sync = new object() });
- Monitor.Enter(li.Sync);
- if (li.Loaded != this)
- {
- if (li.Loaded != null)
- li.Loaded.DeactivateInternal();
- li.Loaded = null;
- ActivateInternal();
- li.Loaded = this;
- }
- }
-
- ///
- /// release lock
- ///
- public void Exit()
- {
- var li = LockInfos.GetOrAdd(_lockkey, new LockInfo { Sync = new object() });
- Monitor.Exit(li.Sync);
- }
-
- private void DeactivateInternal()
- {
- Console.WriteLine("ElfRunner DeactivateInternal {0}", GetHashCode());
- foreach (var m in _memoryBlocks)
- m.Deactivate();
- }
-
- private void ActivateInternal()
- {
- Console.WriteLine("ElfRunner ActivateInternal {0}", GetHashCode());
- foreach (var m in _memoryBlocks)
- m.Activate();
- }
-
#region state
const ulong MAGIC = 0xb00b1e5b00b1e569;
@@ -533,7 +462,7 @@ namespace BizHawk.Emulation.Cores
if (sec.Size != len)
throw new InvalidOperationException("Unexpected section size for " + sec.Name);
var ms = _base.GetStream((ulong)(sec.LoadAddress + _loadoffset), (ulong)sec.Size, true);
- CopySome(br.BaseStream, ms, len);
+ WaterboxUtils.CopySome(br.BaseStream, ms, len);
}
if (_heap != null) _heap.LoadStateBinary(br);
@@ -555,33 +484,6 @@ namespace BizHawk.Emulation.Cores
#region utils
- private static void CopySome(Stream src, Stream dst, long len)
- {
- var buff = new byte[4096];
- while (len > 0)
- {
- int r = src.Read(buff, 0, (int)Math.Min(len, 4096));
- dst.Write(buff, 0, r);
- len -= r;
- }
- }
-
- private static byte[] Hash(byte[] data)
- {
- using (var h = SHA1.Create())
- {
- return h.ComputeHash(data);
- }
- }
-
- private static byte[] Hash(Stream s)
- {
- using (var h = SHA1.Create())
- {
- return h.ComputeHash(s);
- }
- }
-
private byte[] HashSection(ulong ptr, ulong len)
{
using (var h = SHA1.Create())
@@ -591,132 +493,6 @@ namespace BizHawk.Emulation.Cores
}
}
- ///
- /// a simple grow-only fixed max size heap
- ///
- private sealed class Heap : IDisposable
- {
- public MemoryBlock Memory { get; private set; }
- ///
- /// name, used in identifying errors
- ///
- public string Name { get; private set; }
- ///
- /// total number of bytes used
- ///
- public ulong Used { get; private set; }
-
- ///
- /// true if the heap has been sealed, preventing further changes
- ///
- public bool Sealed { get; private set; }
-
- private byte[] _hash;
-
- public Heap(ulong start, ulong size, string name)
- {
- Memory = new MemoryBlock(start, size);
- Used = 0;
- Name = name;
- }
-
- private void EnsureAlignment(int align)
- {
- if (align > 1)
- {
- ulong newused = ((Used - 1) | (ulong)(align - 1)) + 1;
- if (newused > Memory.Size)
- {
- throw new InvalidOperationException(string.Format("Failed to meet alignment {0} on heap {1}", align, Name));
- }
- Used = newused;
- }
- }
-
- public ulong Allocate(ulong size, int align)
- {
- if (Sealed)
- throw new InvalidOperationException(string.Format("Attempt made to allocate from sealed heap {0}", Name));
-
- EnsureAlignment(align);
-
- ulong newused = Used + size;
- if (newused > Memory.Size)
- {
- throw new InvalidOperationException(string.Format("Failed to allocate {0} bytes from heap {1}", size, Name));
- }
- ulong ret = Memory.Start + Used;
- Memory.Protect(ret, newused - Used, MemoryBlock.Protection.RW);
- Used = newused;
- Console.WriteLine("Allocated {0} bytes on {1}", size, Name);
- return ret;
- }
-
- public void Seal()
- {
- if (!Sealed)
- {
- Memory.Protect(Memory.Start, Memory.Size, MemoryBlock.Protection.R);
- _hash = Hash(Memory.GetStream(Memory.Start, Used, false));
- Sealed = true;
- }
- else
- {
- throw new InvalidOperationException(string.Format("Attempt to reseal heap {0}", Name));
- }
- }
-
- public void SaveStateBinary(BinaryWriter bw)
- {
- bw.Write(Name);
- bw.Write(Used);
- if (!Sealed)
- {
- var ms = Memory.GetStream(Memory.Start, Used, false);
- ms.CopyTo(bw.BaseStream);
- }
- else
- {
- bw.Write(_hash);
- }
- }
-
- public void LoadStateBinary(BinaryReader br)
- {
- var name = br.ReadString();
- if (name != Name)
- throw new InvalidOperationException(string.Format("Name did not match for heap {0}", Name));
- var used = br.ReadUInt64();
- if (used > Memory.Size)
- throw new InvalidOperationException(string.Format("Heap {0} used {1} larger than available {2}", Name, used, Memory.Size));
- if (!Sealed)
- {
- Memory.Protect(Memory.Start, Memory.Size, MemoryBlock.Protection.None);
- Memory.Protect(Memory.Start, used, MemoryBlock.Protection.RW);
- var ms = Memory.GetStream(Memory.Start, used, true);
- CopySome(br.BaseStream, ms, (long)used);
- Used = used;
- }
- else
- {
- var hash = br.ReadBytes(_hash.Length);
- if (!hash.SequenceEqual(_hash))
- {
- throw new InvalidOperationException(string.Format("Hash did not match for heap {0}. Is this the same rom?"));
- }
- }
- }
-
- public void Dispose()
- {
- if (Memory != null)
- {
- Memory.Dispose();
- Memory = null;
- }
- }
- }
-
#endregion
}
}
diff --git a/BizHawk.Emulation.Cores/Waterbox/Heap.cs b/BizHawk.Emulation.Cores/Waterbox/Heap.cs
new file mode 100644
index 0000000000..1d83e7618d
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Waterbox/Heap.cs
@@ -0,0 +1,134 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace BizHawk.Emulation.Cores.Waterbox
+{
+ ///
+ /// a simple grow-only fixed max size heap
+ ///
+ internal sealed class Heap : IDisposable
+ {
+ public MemoryBlock Memory { get; private set; }
+ ///
+ /// name, used in identifying errors
+ ///
+ public string Name { get; private set; }
+ ///
+ /// total number of bytes used
+ ///
+ public ulong Used { get; private set; }
+
+ ///
+ /// true if the heap has been sealed, preventing further changes
+ ///
+ public bool Sealed { get; private set; }
+
+ private byte[] _hash;
+
+ public Heap(ulong start, ulong size, string name)
+ {
+ Memory = new MemoryBlock(start, size);
+ Used = 0;
+ Name = name;
+ }
+
+ private void EnsureAlignment(int align)
+ {
+ if (align > 1)
+ {
+ ulong newused = ((Used - 1) | (ulong)(align - 1)) + 1;
+ if (newused > Memory.Size)
+ {
+ throw new InvalidOperationException(string.Format("Failed to meet alignment {0} on heap {1}", align, Name));
+ }
+ Used = newused;
+ }
+ }
+
+ public ulong Allocate(ulong size, int align)
+ {
+ if (Sealed)
+ throw new InvalidOperationException(string.Format("Attempt made to allocate from sealed heap {0}", Name));
+
+ EnsureAlignment(align);
+
+ ulong newused = Used + size;
+ if (newused > Memory.Size)
+ {
+ throw new InvalidOperationException(string.Format("Failed to allocate {0} bytes from heap {1}", size, Name));
+ }
+ ulong ret = Memory.Start + Used;
+ Memory.Protect(ret, newused - Used, MemoryBlock.Protection.RW);
+ Used = newused;
+ Console.WriteLine("Allocated {0} bytes on {1}", size, Name);
+ return ret;
+ }
+
+ public void Seal()
+ {
+ if (!Sealed)
+ {
+ Memory.Protect(Memory.Start, Memory.Size, MemoryBlock.Protection.R);
+ _hash = WaterboxUtils.Hash(Memory.GetStream(Memory.Start, Used, false));
+ Sealed = true;
+ }
+ else
+ {
+ throw new InvalidOperationException(string.Format("Attempt to reseal heap {0}", Name));
+ }
+ }
+
+ public void SaveStateBinary(BinaryWriter bw)
+ {
+ bw.Write(Name);
+ bw.Write(Used);
+ if (!Sealed)
+ {
+ var ms = Memory.GetStream(Memory.Start, Used, false);
+ ms.CopyTo(bw.BaseStream);
+ }
+ else
+ {
+ bw.Write(_hash);
+ }
+ }
+
+ public void LoadStateBinary(BinaryReader br)
+ {
+ var name = br.ReadString();
+ if (name != Name)
+ throw new InvalidOperationException(string.Format("Name did not match for heap {0}", Name));
+ var used = br.ReadUInt64();
+ if (used > Memory.Size)
+ throw new InvalidOperationException(string.Format("Heap {0} used {1} larger than available {2}", Name, used, Memory.Size));
+ if (!Sealed)
+ {
+ Memory.Protect(Memory.Start, Memory.Size, MemoryBlock.Protection.None);
+ Memory.Protect(Memory.Start, used, MemoryBlock.Protection.RW);
+ var ms = Memory.GetStream(Memory.Start, used, true);
+ WaterboxUtils.CopySome(br.BaseStream, ms, (long)used);
+ Used = used;
+ }
+ else
+ {
+ var hash = br.ReadBytes(_hash.Length);
+ if (!hash.SequenceEqual(_hash))
+ {
+ throw new InvalidOperationException(string.Format("Hash did not match for heap {0}. Is this the same rom?"));
+ }
+ }
+ }
+
+ public void Dispose()
+ {
+ if (Memory != null)
+ {
+ Memory.Dispose();
+ Memory = null;
+ }
+ }
+ }
+}
diff --git a/BizHawk.Emulation.Cores/MemoryBlock.cs b/BizHawk.Emulation.Cores/Waterbox/MemoryBlock.cs
similarity index 99%
rename from BizHawk.Emulation.Cores/MemoryBlock.cs
rename to BizHawk.Emulation.Cores/Waterbox/MemoryBlock.cs
index 5bdea3a105..beaf8b45ab 100644
--- a/BizHawk.Emulation.Cores/MemoryBlock.cs
+++ b/BizHawk.Emulation.Cores/Waterbox/MemoryBlock.cs
@@ -5,7 +5,7 @@ using System.Text;
using System.Runtime.InteropServices;
using System.IO;
-namespace BizHawk.Emulation.Cores
+namespace BizHawk.Emulation.Cores.Waterbox
{
public static class Z
{
diff --git a/BizHawk.Emulation.Cores/Waterbox/Swappable.cs b/BizHawk.Emulation.Cores/Waterbox/Swappable.cs
new file mode 100644
index 0000000000..d6046dbb31
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Waterbox/Swappable.cs
@@ -0,0 +1,104 @@
+using BizHawk.Common;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+
+namespace BizHawk.Emulation.Cores.Waterbox
+{
+ ///
+ /// represents an object that can be swapped in and out of memory to compete with other objects in the same memory
+ /// not suited for general purpose stuff
+ ///
+ public abstract class Swappable : IMonitor
+ {
+ ///
+ /// start address, or 0 if we don't need to be swapped
+ ///
+ private ulong _lockkey = 0;
+
+ ///
+ /// everything to swap in for context switches
+ ///
+ private List _memoryBlocks = new List();
+
+ protected void AddMemoryBlock(MemoryBlock block)
+ {
+ _memoryBlocks.Add(block);
+ }
+
+ protected void PurgeMemoryBlocks()
+ {
+ _memoryBlocks = null;
+ }
+
+ protected void Initialize(ulong lockkey)
+ {
+ _lockkey = lockkey;
+ }
+
+ ///
+ /// true if the IMonitor should be used for native calls
+ ///
+ public bool ShouldMonitor { get { return _lockkey != 0; } }
+
+ // any Swappable is assumed to conflict with any other Swappable at the same base address,
+ // but not any other starting address. so don't put them too close together!
+
+ private class LockInfo
+ {
+ public object Sync;
+ public Swappable Loaded;
+ }
+
+ private static readonly ConcurrentDictionary LockInfos = new ConcurrentDictionary();
+
+ static Swappable()
+ {
+ LockInfos.GetOrAdd(0, new LockInfo()); // any errant attempt to lock when ShouldMonitor == false will result in NRE
+ }
+
+ ///
+ /// acquire lock and swap this into memory
+ ///
+ public void Enter()
+ {
+ var li = LockInfos.GetOrAdd(_lockkey, new LockInfo { Sync = new object() });
+ Monitor.Enter(li.Sync);
+ if (li.Loaded != this)
+ {
+ if (li.Loaded != null)
+ li.Loaded.DeactivateInternal();
+ li.Loaded = null;
+ ActivateInternal();
+ li.Loaded = this;
+ }
+ }
+
+ ///
+ /// release lock
+ ///
+ public void Exit()
+ {
+ var li = LockInfos.GetOrAdd(_lockkey, new LockInfo { Sync = new object() });
+ Monitor.Exit(li.Sync);
+ }
+
+ private void DeactivateInternal()
+ {
+ Console.WriteLine("Swappable DeactivateInternal {0}", GetHashCode());
+ foreach (var m in _memoryBlocks)
+ m.Deactivate();
+ }
+
+ private void ActivateInternal()
+ {
+ Console.WriteLine("Swappable ActivateInternal {0}", GetHashCode());
+ foreach (var m in _memoryBlocks)
+ m.Activate();
+ }
+
+ }
+}
diff --git a/BizHawk.Emulation.Cores/Waterbox/WaterboxUtils.cs b/BizHawk.Emulation.Cores/Waterbox/WaterboxUtils.cs
new file mode 100644
index 0000000000..74540e47ef
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Waterbox/WaterboxUtils.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace BizHawk.Emulation.Cores.Waterbox
+{
+ public static class WaterboxUtils
+ {
+ ///
+ /// copy `len` bytes from `src` to `dest`
+ ///
+ ///
+ ///
+ ///
+ public static void CopySome(Stream src, Stream dst, long len)
+ {
+ var buff = new byte[4096];
+ while (len > 0)
+ {
+ int r = src.Read(buff, 0, (int)Math.Min(len, 4096));
+ dst.Write(buff, 0, r);
+ len -= r;
+ }
+ }
+
+ public static byte[] Hash(byte[] data)
+ {
+ using (var h = SHA1.Create())
+ {
+ return h.ComputeHash(data);
+ }
+ }
+
+ public static byte[] Hash(Stream s)
+ {
+ using (var h = SHA1.Create())
+ {
+ return h.ComputeHash(s);
+ }
+ }
+
+ }
+}
diff --git a/References/PeNet.dll b/References/PeNet.dll
new file mode 100644
index 0000000000..f2c887f476
Binary files /dev/null and b/References/PeNet.dll differ