195 lines
5.0 KiB
C#
195 lines
5.0 KiB
C#
using BizHawk.Common;
|
|
using BizHawk.Common.BizInvoke;
|
|
using BizHawk.Emulation.Common;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace BizHawk.Emulation.Cores.Waterbox
|
|
{
|
|
public abstract class LibWaterboxCore
|
|
{
|
|
public const CallingConvention CC = CallingConvention.Cdecl;
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
public class FrameInfo
|
|
{
|
|
/// <summary>
|
|
/// pointer to the video buffer; set by frontend, filled by backend
|
|
/// </summary>
|
|
public IntPtr VideoBuffer;
|
|
/// <summary>
|
|
/// pointer to the sound buffer; set by frontend, filled by backend
|
|
/// </summary>
|
|
public IntPtr SoundBuffer;
|
|
/// <summary>
|
|
/// total number of cycles emulated this frame; set by backend
|
|
/// </summary>
|
|
public long Cycles;
|
|
/// <summary>
|
|
/// width of the output image; set by backend
|
|
/// </summary>
|
|
public int Width;
|
|
/// <summary>
|
|
/// height of the output image; set by backend
|
|
/// </summary>
|
|
public int Height;
|
|
/// <summary>
|
|
/// total number of sample pairs produced; set by backend
|
|
/// </summary>
|
|
public int Samples;
|
|
/// <summary>
|
|
/// true if controllers were not read; set by backend
|
|
/// </summary>
|
|
public int Lagged;
|
|
}
|
|
|
|
[Flags]
|
|
public enum MemoryDomainFlags: int
|
|
{
|
|
None = 0,
|
|
/// <summary>
|
|
/// if false, the domain MUST NOT be written to.
|
|
/// in some cases, a segmentation violation might occur
|
|
/// </summary>
|
|
Writable = 1,
|
|
/// <summary>
|
|
/// if true, this memory domain should be used in saveram.
|
|
/// can be ignored if the core provides its own saveram implementation
|
|
/// </summary>
|
|
Saverammable = 2,
|
|
/// <summary>
|
|
/// if true, domain is filled with ones (FF) by default, instead of zeros.
|
|
/// used in calculating SaveRamModified
|
|
/// </summary>
|
|
OneFilled = 4,
|
|
/// <summary>
|
|
/// desginates the default memory domain
|
|
/// </summary>
|
|
Primary = 8,
|
|
/// <summary>
|
|
/// if true, the most significant bytes are first in multibyte words
|
|
/// </summary>
|
|
YugeEndian = 16,
|
|
/// <summary>
|
|
/// native wordsize. only a hint
|
|
/// </summary>
|
|
WordSize1 = 32,
|
|
/// <summary>
|
|
/// native wordsize. only a hint
|
|
/// </summary>
|
|
WordSize2 = 64,
|
|
/// <summary>
|
|
/// native wordsize. only a hint
|
|
/// </summary>
|
|
WordSize4 = 128,
|
|
/// <summary>
|
|
/// native wordsize. only a hint
|
|
/// </summary>
|
|
WordSize8 = 256
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
public struct MemoryArea
|
|
{
|
|
/// <summary>
|
|
/// pointer to the data in memory
|
|
/// </summary>
|
|
public IntPtr Data;
|
|
/// <summary>
|
|
/// null terminated strnig naming the memory domain
|
|
/// </summary>
|
|
public IntPtr Name;
|
|
/// <summary>
|
|
/// size of the domain
|
|
/// </summary>
|
|
public long Size;
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public MemoryDomainFlags Flags;
|
|
}
|
|
|
|
[UnmanagedFunctionPointer(CC)]
|
|
public delegate void EmptyCallback();
|
|
|
|
public unsafe class WaterboxMemoryDomain : MemoryDomain
|
|
{
|
|
private readonly IntPtr _data;
|
|
private readonly IMonitor _monitor;
|
|
private readonly long _addressMangler;
|
|
|
|
public override byte PeekByte(long addr)
|
|
{
|
|
if ((ulong)addr < (ulong)Size)
|
|
{
|
|
using (_monitor.EnterExit())
|
|
{
|
|
return ((byte*)_data)[addr ^ _addressMangler];
|
|
}
|
|
}
|
|
|
|
throw new ArgumentOutOfRangeException(nameof(addr));
|
|
}
|
|
|
|
public override void PokeByte(long addr, byte val)
|
|
{
|
|
if (Writable)
|
|
{
|
|
if ((ulong)addr < (ulong)Size)
|
|
{
|
|
using (_monitor.EnterExit())
|
|
{
|
|
((byte*)_data)[addr ^ _addressMangler] = val;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(addr));
|
|
}
|
|
}
|
|
}
|
|
|
|
public WaterboxMemoryDomain(MemoryArea m, IMonitor monitor)
|
|
{
|
|
Name = Marshal.PtrToStringAnsi(m.Name);
|
|
EndianType = (m.Flags & MemoryDomainFlags.YugeEndian) != 0 ? Endian.Big : Endian.Little;
|
|
_data = m.Data;
|
|
Size = m.Size;
|
|
Writable = (m.Flags & MemoryDomainFlags.Writable) != 0;
|
|
if ((m.Flags & MemoryDomainFlags.WordSize1) != 0)
|
|
WordSize = 1;
|
|
else if((m.Flags & MemoryDomainFlags.WordSize2) != 0)
|
|
WordSize = 2;
|
|
else if((m.Flags & MemoryDomainFlags.WordSize4) != 0)
|
|
WordSize = 4;
|
|
else if((m.Flags & MemoryDomainFlags.WordSize8) != 0)
|
|
WordSize = 8;
|
|
else
|
|
throw new InvalidOperationException("Unknown word size for memory domain");
|
|
_monitor = monitor;
|
|
if (EndianType == Endian.Big)
|
|
{
|
|
_addressMangler = WordSize - 1;
|
|
}
|
|
else
|
|
{
|
|
_addressMangler = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
[BizImport(CC)]
|
|
public abstract void FrameAdvance([In, Out] FrameInfo frame);
|
|
|
|
[BizImport(CC)]
|
|
public abstract void GetMemoryAreas([In, Out] MemoryArea[] areas);
|
|
|
|
[BizImport(CC)]
|
|
public abstract void SetInputCallback(EmptyCallback callback);
|
|
}
|
|
}
|