BizHawk/BizHawk.Emulation.Cores/Waterbox/LibWaterboxCore.cs

195 lines
5.0 KiB
C#
Raw Normal View History

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);
}
}