Create an abstract base class for waterbox cores, and adapt Virtual Boyee to use it. Not sure yet how useful this is...
This commit is contained in:
parent
02242e8997
commit
6f60eb5efc
File diff suppressed because it is too large
Load Diff
|
@ -1276,6 +1276,7 @@
|
|||
<Compile Include="Libretro\LibretroCore_Description.cs" />
|
||||
<Compile Include="Libretro\LibretroCore_InputCallbacks.cs" />
|
||||
<Compile Include="Waterbox\Heap.cs" />
|
||||
<Compile Include="Waterbox\LibWaterboxCore.cs" />
|
||||
<Compile Include="Waterbox\MapHeap.cs" />
|
||||
<Compile Include="Waterbox\MemoryBlock.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
|
@ -1292,6 +1293,7 @@
|
|||
<Compile Include="Waterbox\PeRunner.cs" />
|
||||
<Compile Include="Waterbox\PeWrapper.cs" />
|
||||
<Compile Include="Waterbox\Swappable.cs" />
|
||||
<Compile Include="Waterbox\WaterboxCore.cs" />
|
||||
<Compile Include="Waterbox\WaterboxUtils.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -1,148 +1,85 @@
|
|||
using BizHawk.Common.BizInvoke;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.VB
|
||||
{
|
||||
public abstract class LibVirtualBoyee
|
||||
{
|
||||
private const CallingConvention CC = CallingConvention.Cdecl;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Rect
|
||||
{
|
||||
public int X;
|
||||
public int Y;
|
||||
public int W;
|
||||
public int H;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)] // TODO: find out why Sequential is sometimes ignored on the native layout
|
||||
public class EmulateSpec
|
||||
{
|
||||
// Pitch(32-bit) must be equal to width and >= the "fb_width" specified in the MDFNGI struct for the emulated system.
|
||||
// Height must be >= to the "fb_height" specified in the MDFNGI struct for the emulated system.
|
||||
// The framebuffer pointed to by surface->pixels is written to by the system emulation code.
|
||||
[FieldOffset(0)]
|
||||
public IntPtr Pixels;
|
||||
|
||||
// Pointer to sound buffer, set by the driver code, that the emulation code should render sound to.
|
||||
// Guaranteed to be at least 500ms in length, but emulation code really shouldn't exceed 40ms or so. Additionally, if emulation code
|
||||
// generates >= 100ms,
|
||||
// DEPRECATED: Emulation code may set this pointer to a sound buffer internal to the emulation module.
|
||||
[FieldOffset(8)]
|
||||
public IntPtr SoundBuf;
|
||||
|
||||
// Number of cycles that this frame consumed, using MDFNGI::MasterClock as a time base.
|
||||
// Set by emulation code.
|
||||
[FieldOffset(16)]
|
||||
public long MasterCycles;
|
||||
|
||||
// Set by the system emulation code every frame, to denote the horizontal and vertical offsets of the image, and the size
|
||||
// of the image. If the emulated system sets the elements of LineWidths, then the width(w) of this structure
|
||||
// is ignored while drawing the image.
|
||||
[FieldOffset(24)]
|
||||
public Rect DisplayRect;
|
||||
|
||||
// Maximum size of the sound buffer, in frames. Set by the driver code.
|
||||
[FieldOffset(40)]
|
||||
public int SoundBufMaxSize;
|
||||
|
||||
// Number of frames currently in internal sound buffer. Set by the system emulation code, to be read by the driver code.
|
||||
[FieldOffset(44)]
|
||||
public int SoundBufSize;
|
||||
|
||||
// 0 UDLR SelectStartBA UDLR(right dpad) LtrigRtrig 13
|
||||
[FieldOffset(48)]
|
||||
public Buttons Buttons;
|
||||
|
||||
[FieldOffset(52)]
|
||||
public bool Lagged;
|
||||
}
|
||||
|
||||
public enum MemoryArea : int
|
||||
{
|
||||
Wram, Sram, Rom
|
||||
}
|
||||
|
||||
public enum Buttons : int
|
||||
{
|
||||
Up = 0x200,
|
||||
Down = 0x100,
|
||||
Left = 0x80,
|
||||
Right = 0x40,
|
||||
Select = 0x800,
|
||||
Start = 0x400,
|
||||
B = 0x2,
|
||||
A = 0x1,
|
||||
Up_R = 0x10,
|
||||
Down_R = 0x200,
|
||||
Left_R = 0x1000,
|
||||
Right_R = 0x2000,
|
||||
L = 0x8,
|
||||
R = 0x4
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class NativeSettings
|
||||
{
|
||||
public int InstantReadHack;
|
||||
public int DisableParallax;
|
||||
public int ThreeDeeMode;
|
||||
public int SwapViews;
|
||||
public int AnaglyphPreset;
|
||||
public int AnaglyphCustomLeftColor;
|
||||
public int AnaglyphCustomRightColor;
|
||||
public int NonAnaglyphColor;
|
||||
public int LedOnScale;
|
||||
public int InterlacePrescale;
|
||||
public int SideBySideSeparation;
|
||||
|
||||
private static int ConvertColor(Color c)
|
||||
{
|
||||
return c.ToArgb();
|
||||
}
|
||||
|
||||
public static NativeSettings FromFrontendSettings(VirtualBoyee.Settings s, VirtualBoyee.SyncSettings ss)
|
||||
{
|
||||
return new NativeSettings
|
||||
{
|
||||
InstantReadHack = ss.InstantReadHack ? 1 : 0,
|
||||
DisableParallax = ss.DisableParallax ? 1 : 0,
|
||||
ThreeDeeMode = (int)s.ThreeDeeMode,
|
||||
SwapViews = s.SwapViews ? 1 : 0,
|
||||
AnaglyphPreset = (int)s.AnaglyphPreset,
|
||||
AnaglyphCustomLeftColor = ConvertColor(s.AnaglyphCustomLeftColor),
|
||||
AnaglyphCustomRightColor = ConvertColor(s.AnaglyphCustomRightColor),
|
||||
NonAnaglyphColor = ConvertColor(s.NonAnaglyphColor),
|
||||
LedOnScale = s.LedOnScale,
|
||||
InterlacePrescale = s.InterlacePrescale,
|
||||
SideBySideSeparation = s.SideBySideSeparation
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedFunctionPointer(CC)]
|
||||
public delegate void InputCallback();
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract bool Load(byte[] rom, int length, [In]NativeSettings settings);
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract void GetMemoryArea(MemoryArea which, ref IntPtr ptr, ref int size);
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract void Emulate(EmulateSpec espec);
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract void HardReset();
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract void SetInputCallback(InputCallback callback);
|
||||
}
|
||||
}
|
||||
using BizHawk.Common.BizInvoke;
|
||||
using BizHawk.Emulation.Cores.Waterbox;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.VB
|
||||
{
|
||||
public abstract class LibVirtualBoyee : LibWaterboxCore
|
||||
{
|
||||
public enum Buttons : int
|
||||
{
|
||||
Up = 0x200,
|
||||
Down = 0x100,
|
||||
Left = 0x80,
|
||||
Right = 0x40,
|
||||
Select = 0x800,
|
||||
Start = 0x400,
|
||||
B = 0x2,
|
||||
A = 0x1,
|
||||
Up_R = 0x10,
|
||||
Down_R = 0x200,
|
||||
Left_R = 0x1000,
|
||||
Right_R = 0x2000,
|
||||
L = 0x8,
|
||||
R = 0x4
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public new class FrameInfo : LibWaterboxCore.FrameInfo
|
||||
{
|
||||
public Buttons Buttons;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class NativeSettings
|
||||
{
|
||||
public int InstantReadHack;
|
||||
public int DisableParallax;
|
||||
public int ThreeDeeMode;
|
||||
public int SwapViews;
|
||||
public int AnaglyphPreset;
|
||||
public int AnaglyphCustomLeftColor;
|
||||
public int AnaglyphCustomRightColor;
|
||||
public int NonAnaglyphColor;
|
||||
public int LedOnScale;
|
||||
public int InterlacePrescale;
|
||||
public int SideBySideSeparation;
|
||||
|
||||
private static int ConvertColor(Color c)
|
||||
{
|
||||
return c.ToArgb();
|
||||
}
|
||||
|
||||
public static NativeSettings FromFrontendSettings(VirtualBoyee.Settings s, VirtualBoyee.SyncSettings ss)
|
||||
{
|
||||
return new NativeSettings
|
||||
{
|
||||
InstantReadHack = ss.InstantReadHack ? 1 : 0,
|
||||
DisableParallax = ss.DisableParallax ? 1 : 0,
|
||||
ThreeDeeMode = (int)s.ThreeDeeMode,
|
||||
SwapViews = s.SwapViews ? 1 : 0,
|
||||
AnaglyphPreset = (int)s.AnaglyphPreset,
|
||||
AnaglyphCustomLeftColor = ConvertColor(s.AnaglyphCustomLeftColor),
|
||||
AnaglyphCustomRightColor = ConvertColor(s.AnaglyphCustomRightColor),
|
||||
NonAnaglyphColor = ConvertColor(s.NonAnaglyphColor),
|
||||
LedOnScale = s.LedOnScale,
|
||||
InterlacePrescale = s.InterlacePrescale,
|
||||
SideBySideSeparation = s.SideBySideSeparation
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract bool Load(byte[] rom, int length, [In]NativeSettings settings);
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract void HardReset();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,26 +18,31 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.VB
|
|||
{
|
||||
[CoreAttributes("Virtual Boyee", "Ryphecha", true, true, "0.9.44.1",
|
||||
"https://mednafen.github.io/releases/", false)]
|
||||
public class VirtualBoyee : IEmulator, IVideoProvider, ISoundProvider, IStatable,
|
||||
IInputPollable, ISaveRam, ISettable<VirtualBoyee.Settings, VirtualBoyee.SyncSettings>
|
||||
public class VirtualBoyee : WaterboxCore, ISettable<VirtualBoyee.Settings, VirtualBoyee.SyncSettings>
|
||||
{
|
||||
private PeRunner _exe;
|
||||
private LibVirtualBoyee _boyee;
|
||||
|
||||
[CoreConstructor("VB")]
|
||||
public VirtualBoyee(CoreComm comm, byte[] rom, Settings settings, SyncSettings syncSettings)
|
||||
:base(comm, new Configuration
|
||||
{
|
||||
DefaultFpsNumerator = 20000000,
|
||||
DefaultFpsDenominator = 397824,
|
||||
DefaultWidth = 384,
|
||||
DefaultHeight = 224,
|
||||
MaxWidth = 1024,
|
||||
MaxHeight = 1024,
|
||||
MaxSamples = 8192,
|
||||
SystemId = "VB"
|
||||
})
|
||||
{
|
||||
ServiceProvider = new BasicServiceProvider(this);
|
||||
CoreComm = comm;
|
||||
|
||||
_settings = settings ?? new Settings();
|
||||
_syncSettings = syncSettings ?? new SyncSettings();
|
||||
// TODO: the way settings work in this core, changing the non-sync ones will invalidate savestates
|
||||
var nativeSettings = LibVirtualBoyee.NativeSettings.FromFrontendSettings(_settings, _syncSettings);
|
||||
|
||||
_exe = new PeRunner(new PeRunnerOptions
|
||||
_boyee = PreInit<LibVirtualBoyee>(new PeRunnerOptions
|
||||
{
|
||||
Path = comm.CoreFileProvider.DllPath(),
|
||||
Filename = "vb.wbx",
|
||||
SbrkHeapSizeKB = 256,
|
||||
SealedHeapSizeKB = 4 * 1024,
|
||||
|
@ -45,76 +50,20 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.VB
|
|||
PlainHeapSizeKB = 256
|
||||
});
|
||||
|
||||
_boyee = BizInvoker.GetInvoker<LibVirtualBoyee>(_exe, _exe);
|
||||
|
||||
if (!_boyee.Load(rom, rom.Length, nativeSettings))
|
||||
{
|
||||
throw new InvalidOperationException("Core rejected the rom");
|
||||
}
|
||||
|
||||
_exe.Seal();
|
||||
|
||||
_inputCallback = InputCallbacks.Call;
|
||||
InitMemoryDomains();
|
||||
InitSaveram();
|
||||
throw new InvalidOperationException("Core rejected the rom");
|
||||
|
||||
PostInit();
|
||||
}
|
||||
|
||||
private bool _disposed = false;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
_exe.Dispose();
|
||||
_exe = null;
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public IEmulatorServiceProvider ServiceProvider { get; private set; }
|
||||
|
||||
public unsafe void FrameAdvance(IController controller, bool render, bool rendersound = true)
|
||||
{
|
||||
_boyee.SetInputCallback(InputCallbacks.Count > 0 ? _inputCallback : null);
|
||||
|
||||
protected override LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller)
|
||||
{
|
||||
if (controller.IsPressed("Power"))
|
||||
_boyee.HardReset();
|
||||
|
||||
fixed (int* vp = _videoBuffer)
|
||||
fixed (short* sp = _soundBuffer)
|
||||
{
|
||||
var spec = new LibVirtualBoyee.EmulateSpec
|
||||
{
|
||||
Pixels = (IntPtr)vp,
|
||||
SoundBuf = (IntPtr)sp,
|
||||
SoundBufMaxSize = _soundBuffer.Length / 2,
|
||||
Buttons = GetButtons(controller)
|
||||
};
|
||||
|
||||
_boyee.Emulate(spec);
|
||||
BufferWidth = spec.DisplayRect.W;
|
||||
BufferHeight = spec.DisplayRect.H;
|
||||
_numSamples = spec.SoundBufSize;
|
||||
|
||||
Frame++;
|
||||
|
||||
IsLagFrame = spec.Lagged;
|
||||
if (IsLagFrame)
|
||||
LagCount++;
|
||||
}
|
||||
_boyee.HardReset();
|
||||
|
||||
return new LibVirtualBoyee.FrameInfo { Buttons = GetButtons(controller) };
|
||||
}
|
||||
|
||||
public int Frame { get; private set; }
|
||||
|
||||
public void ResetCounters()
|
||||
{
|
||||
Frame = 0;
|
||||
}
|
||||
|
||||
public string SystemId { get { return "VB"; } }
|
||||
public bool DeterministicEmulation { get { return true; } }
|
||||
public CoreComm CoreComm { get; private set; }
|
||||
|
||||
#region Controller
|
||||
|
||||
private LibVirtualBoyee.Buttons GetButtons(IController c)
|
||||
|
@ -165,157 +114,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.VB
|
|||
.ToList()
|
||||
};
|
||||
|
||||
public ControllerDefinition ControllerDefinition => VirtualBoyController;
|
||||
|
||||
#endregion
|
||||
|
||||
#region IVideoProvider
|
||||
|
||||
private int[] _videoBuffer = new int[1024 * 1024];
|
||||
|
||||
public int[] GetVideoBuffer()
|
||||
{
|
||||
return _videoBuffer;
|
||||
}
|
||||
|
||||
public int VirtualWidth => BufferWidth;
|
||||
public int VirtualHeight => BufferWidth;
|
||||
|
||||
public int BufferWidth { get; private set; } = 384;
|
||||
public int BufferHeight { get; private set; } = 224;
|
||||
|
||||
public int VsyncNumerator { get; private set; } = 20000000;
|
||||
|
||||
public int VsyncDenominator { get; private set; } = 397824;
|
||||
|
||||
public int BackgroundColor => unchecked((int)0xff000000);
|
||||
|
||||
#endregion
|
||||
|
||||
#region ISoundProvider
|
||||
|
||||
private short[] _soundBuffer = new short[16384];
|
||||
private int _numSamples;
|
||||
|
||||
public void SetSyncMode(SyncSoundMode mode)
|
||||
{
|
||||
if (mode == SyncSoundMode.Async)
|
||||
{
|
||||
throw new NotSupportedException("Async mode is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
public void GetSamplesSync(out short[] samples, out int nsamp)
|
||||
{
|
||||
samples = _soundBuffer;
|
||||
nsamp = _numSamples;
|
||||
}
|
||||
|
||||
public void GetSamplesAsync(short[] samples)
|
||||
{
|
||||
throw new InvalidOperationException("Async mode is not supported.");
|
||||
}
|
||||
|
||||
public void DiscardSamples()
|
||||
{
|
||||
}
|
||||
|
||||
public bool CanProvideAsync => false;
|
||||
|
||||
public SyncSoundMode SyncMode => SyncSoundMode.Sync;
|
||||
|
||||
#endregion
|
||||
|
||||
public int LagCount { get; set; }
|
||||
public bool IsLagFrame { get; set; }
|
||||
|
||||
private LibVirtualBoyee.InputCallback _inputCallback;
|
||||
|
||||
public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem();
|
||||
|
||||
#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!
|
||||
_boyee.SetInputCallback(null);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
#region Memory Domains
|
||||
|
||||
private unsafe void InitMemoryDomains()
|
||||
{
|
||||
var domains = new List<MemoryDomain>();
|
||||
|
||||
var domainInfo = new[]
|
||||
{
|
||||
new { name = "WRAM", area = LibVirtualBoyee.MemoryArea.Wram, writable = true },
|
||||
new { name = "CARTRAM", area = LibVirtualBoyee.MemoryArea.Sram, writable = true },
|
||||
new { name = "ROM", area = LibVirtualBoyee.MemoryArea.Rom, writable = false }
|
||||
};
|
||||
|
||||
foreach (var a in domainInfo)
|
||||
{
|
||||
IntPtr ptr = IntPtr.Zero;
|
||||
int size = 0;
|
||||
|
||||
_boyee.GetMemoryArea(a.area, ref ptr, ref size);
|
||||
|
||||
if (ptr != IntPtr.Zero && size > 0)
|
||||
{
|
||||
domains.Add(new MemoryDomainIntPtrMonitor(a.name, MemoryDomain.Endian.Little,
|
||||
ptr, size, a.writable, 4, _exe));
|
||||
}
|
||||
}
|
||||
(ServiceProvider as BasicServiceProvider).Register<IMemoryDomains>(new MemoryDomainList(domains));
|
||||
}
|
||||
public override ControllerDefinition ControllerDefinition => VirtualBoyController;
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -450,57 +249,5 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.VB
|
|||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ISaveRam
|
||||
|
||||
private const int SaveramSize = 65536;
|
||||
private IntPtr _saveRamPtr;
|
||||
|
||||
private void InitSaveram()
|
||||
{
|
||||
int unused = 0;
|
||||
_boyee.GetMemoryArea(LibVirtualBoyee.MemoryArea.Sram, ref _saveRamPtr, ref unused);
|
||||
}
|
||||
|
||||
public unsafe bool SaveRamModified
|
||||
{
|
||||
get
|
||||
{
|
||||
using (_exe.EnterExit())
|
||||
{
|
||||
int* p = (int*)_saveRamPtr;
|
||||
int* pend = p + SaveramSize / sizeof(int);
|
||||
|
||||
while (p < pend)
|
||||
{
|
||||
if (*p++ != 0)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] CloneSaveRam()
|
||||
{
|
||||
using (_exe.EnterExit())
|
||||
{
|
||||
var ret = new byte[SaveramSize];
|
||||
Marshal.Copy(_saveRamPtr, ret, 0, SaveramSize);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
public void StoreSaveRam(byte[] data)
|
||||
{
|
||||
using (_exe.EnterExit())
|
||||
{
|
||||
if (data.Length != SaveramSize)
|
||||
throw new InvalidOperationException("Saveram size mismatch");
|
||||
Marshal.Copy(data, 0, _saveRamPtr, SaveramSize);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion ISaveRam
|
||||
}
|
||||
}
|
||||
|
|
|
@ -174,7 +174,7 @@ namespace BizHawk.Emulation.Cores
|
|||
{
|
||||
foreach (var typ in assy.GetTypes())
|
||||
{
|
||||
if (typ.GetInterfaces().Contains(typeof(IEmulator)))
|
||||
if (!typ.IsAbstract && typ.GetInterfaces().Contains(typeof(IEmulator)))
|
||||
{
|
||||
var coreattr = typ.GetCustomAttributes(typeof(CoreAttributes), false);
|
||||
if (coreattr.Length != 1)
|
||||
|
|
|
@ -0,0 +1,194 @@
|
|||
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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,339 @@
|
|||
using BizHawk.Common;
|
||||
using BizHawk.Common.BizInvoke;
|
||||
using BizHawk.Common.BufferExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Waterbox
|
||||
{
|
||||
public abstract class WaterboxCore : IEmulator, IVideoProvider, ISoundProvider, IStatable,
|
||||
IInputPollable, ISaveRam
|
||||
{
|
||||
protected LibWaterboxCore _core;
|
||||
protected PeRunner _exe;
|
||||
protected LibWaterboxCore.MemoryArea[] _memoryAreas;
|
||||
private LibWaterboxCore.EmptyCallback _inputCallback;
|
||||
|
||||
public class Configuration
|
||||
{
|
||||
public int MaxWidth;
|
||||
public int MaxHeight;
|
||||
public int DefaultWidth;
|
||||
public int DefaultHeight;
|
||||
public int DefaultFpsNumerator;
|
||||
public int DefaultFpsDenominator;
|
||||
public int MaxSamples;
|
||||
public string SystemId;
|
||||
}
|
||||
|
||||
protected WaterboxCore(CoreComm comm, Configuration c)
|
||||
{
|
||||
BufferWidth = c.DefaultWidth;
|
||||
BufferHeight = c.DefaultHeight;
|
||||
_videoBuffer = new int[c.MaxWidth * c.MaxHeight];
|
||||
_soundBuffer = new short[c.MaxSamples * 2];
|
||||
VsyncNumerator = c.DefaultFpsNumerator;
|
||||
VsyncDenominator = c.DefaultFpsDenominator;
|
||||
_serviceProvider = new BasicServiceProvider(this);
|
||||
SystemId = c.SystemId;
|
||||
CoreComm = comm;
|
||||
_inputCallback = InputCallbacks.Call;
|
||||
}
|
||||
|
||||
protected T PreInit<T>(PeRunnerOptions options)
|
||||
where T : LibWaterboxCore
|
||||
{
|
||||
if (options.Path == null)
|
||||
options.Path = CoreComm.CoreFileProvider.DllPath();
|
||||
_exe = new PeRunner(options);
|
||||
using (_exe.EnterExit())
|
||||
{
|
||||
var ret = BizInvoker.GetInvoker<T>(_exe, _exe);
|
||||
_core = ret;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
protected void PostInit()
|
||||
{
|
||||
using (_exe.EnterExit())
|
||||
{
|
||||
var areas = new LibWaterboxCore.MemoryArea[256];
|
||||
_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)
|
||||
.ToArray();
|
||||
_saveramSize = (int)_saveramAreas.Sum(a => a.Size);
|
||||
|
||||
var memoryDomains = _memoryAreas.Select(a => new LibWaterboxCore.WaterboxMemoryDomain(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);
|
||||
_exe.Seal();
|
||||
}
|
||||
}
|
||||
|
||||
#region ISaveRam
|
||||
|
||||
private LibWaterboxCore.MemoryArea[] _saveramAreas;
|
||||
private int _saveramSize;
|
||||
|
||||
public unsafe bool SaveRamModified
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_saveramSize == 0)
|
||||
return false;
|
||||
using (_exe.EnterExit())
|
||||
{
|
||||
foreach (var area in _saveramAreas)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (*p++ != cmp)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] CloneSaveRam()
|
||||
{
|
||||
if (_saveramSize == 0)
|
||||
return null;
|
||||
using (_exe.EnterExit())
|
||||
{
|
||||
var ret = new byte[_saveramSize];
|
||||
var offs = 0;
|
||||
foreach (var area in _saveramAreas)
|
||||
{
|
||||
Marshal.Copy(area.Data, ret, offs, (int)area.Size);
|
||||
offs += (int)area.Size;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
public void StoreSaveRam(byte[] data)
|
||||
{
|
||||
using (_exe.EnterExit())
|
||||
{
|
||||
if (data.Length != _saveramSize)
|
||||
throw new InvalidOperationException("Saveram size mismatch");
|
||||
using (_exe.EnterExit())
|
||||
{
|
||||
var offs = 0;
|
||||
foreach (var area in _saveramAreas)
|
||||
{
|
||||
Marshal.Copy(data, offs, area.Data, (int)area.Size);
|
||||
offs += (int)area.Size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion ISaveRam
|
||||
|
||||
#region IEmulator
|
||||
|
||||
protected abstract LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller);
|
||||
|
||||
public unsafe void FrameAdvance(IController controller, bool render, bool rendersound = true)
|
||||
{
|
||||
using (_exe.EnterExit())
|
||||
{
|
||||
_core.SetInputCallback(InputCallbacks.Count > 0 ? _inputCallback : null);
|
||||
|
||||
fixed (int* vp = _videoBuffer)
|
||||
fixed (short* sp = _soundBuffer)
|
||||
{
|
||||
var frame = FrameAdvancePrep(controller);
|
||||
frame.VideoBuffer = (IntPtr)vp;
|
||||
frame.SoundBuffer = (IntPtr)sp;
|
||||
|
||||
_core.FrameAdvance(frame);
|
||||
|
||||
Frame++;
|
||||
if (IsLagFrame = frame.Lagged != 0)
|
||||
LagCount++;
|
||||
|
||||
BufferWidth = frame.Width;
|
||||
BufferHeight = frame.Height;
|
||||
_numSamples = frame.Samples;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _disposed = false;
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
_exe.Dispose();
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public CoreComm CoreComm { get; }
|
||||
public int Frame { get; private set; }
|
||||
public int LagCount { get; set; }
|
||||
public bool IsLagFrame { get; set; }
|
||||
|
||||
public void ResetCounters()
|
||||
{
|
||||
Frame = 0;
|
||||
}
|
||||
|
||||
protected readonly BasicServiceProvider _serviceProvider;
|
||||
public IEmulatorServiceProvider ServiceProvider => _serviceProvider;
|
||||
public string SystemId { get; }
|
||||
public bool DeterministicEmulation => true;
|
||||
public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem();
|
||||
public abstract ControllerDefinition ControllerDefinition { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region IStatable
|
||||
|
||||
public bool BinarySaveStatesPreferred => true;
|
||||
|
||||
public void SaveStateText(TextWriter writer)
|
||||
{
|
||||
var temp = SaveStateBinary();
|
||||
temp.SaveAsHexFast(writer);
|
||||
}
|
||||
|
||||
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();
|
||||
BufferWidth = reader.ReadInt32();
|
||||
BufferHeight = reader.ReadInt32();
|
||||
// reset pointers here!
|
||||
_core.SetInputCallback(null);
|
||||
}
|
||||
|
||||
public void SaveStateBinary(BinaryWriter writer)
|
||||
{
|
||||
_exe.SaveStateBinary(writer);
|
||||
// other variables
|
||||
writer.Write(Frame);
|
||||
writer.Write(LagCount);
|
||||
writer.Write(IsLagFrame);
|
||||
writer.Write(BufferWidth);
|
||||
writer.Write(BufferHeight);
|
||||
}
|
||||
|
||||
public byte[] SaveStateBinary()
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
var bw = new BinaryWriter(ms);
|
||||
SaveStateBinary(bw);
|
||||
bw.Flush();
|
||||
ms.Close();
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// called after the base core saves state. the core must save any other
|
||||
/// variables that it needs to.
|
||||
/// the default implementation does nothing
|
||||
/// </summary>
|
||||
/// <param name="writer"></param>
|
||||
protected virtual void SaveStateBinaryInternal(BinaryWriter writer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// called after the base core loads state. the core must load any other variables
|
||||
/// that were in SaveStateBinaryInternal and reset any native pointers.
|
||||
/// the default implementation does nothing
|
||||
/// </summary>
|
||||
/// <param name="reader"></param>
|
||||
protected virtual void LoadStateBinaryInternal(BinaryReader reader)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ISoundProvider
|
||||
|
||||
public void SetSyncMode(SyncSoundMode mode)
|
||||
{
|
||||
if (mode == SyncSoundMode.Async)
|
||||
{
|
||||
throw new NotSupportedException("Async mode is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
public void GetSamplesSync(out short[] samples, out int nsamp)
|
||||
{
|
||||
samples = _soundBuffer;
|
||||
nsamp = _numSamples;
|
||||
}
|
||||
|
||||
public void GetSamplesAsync(short[] samples)
|
||||
{
|
||||
throw new InvalidOperationException("Async mode is not supported.");
|
||||
}
|
||||
|
||||
public void DiscardSamples()
|
||||
{
|
||||
}
|
||||
|
||||
protected readonly short[] _soundBuffer;
|
||||
protected int _numSamples;
|
||||
public bool CanProvideAsync => false;
|
||||
public SyncSoundMode SyncMode => SyncSoundMode.Sync;
|
||||
|
||||
#endregion
|
||||
|
||||
#region IVideoProvider
|
||||
|
||||
public int[] GetVideoBuffer()
|
||||
{
|
||||
return _videoBuffer;
|
||||
}
|
||||
|
||||
protected readonly int[] _videoBuffer;
|
||||
public virtual int VirtualWidth => BufferWidth;
|
||||
public virtual int VirtualHeight => BufferWidth;
|
||||
public int BufferWidth { get; private set; }
|
||||
public int BufferHeight { get; private set; }
|
||||
public virtual int VsyncNumerator { get; protected set; }
|
||||
public virtual int VsyncDenominator { get; protected set; }
|
||||
public int BackgroundColor => unchecked((int)0xff000000);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,39 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t* VideoBuffer;
|
||||
int16_t* SoundBuffer;
|
||||
int64_t Cycles;
|
||||
int32_t Width;
|
||||
int32_t Height;
|
||||
int32_t Samples;
|
||||
int32_t Lagged;
|
||||
} FrameInfo;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void* Data;
|
||||
const char* Name;
|
||||
int64_t Size;
|
||||
int32_t Flags;
|
||||
} MemoryArea;
|
||||
|
||||
#define MEMORYAREA_FLAGS_WRITABLE 1
|
||||
#define MEMORYAREA_FLAGS_SAVERAMMABLE 2
|
||||
#define MEMORYAREA_FLAGS_ONEFILLED 4
|
||||
#define MEMORYAREA_FLAGS_PRIMARY 8
|
||||
#define MEMORYAREA_FLAGS_YUGEENDIAN 16
|
||||
#define MEMORYAREA_FLAGS_WORDSIZE1 32
|
||||
#define MEMORYAREA_FLAGS_WORDSIZE2 64
|
||||
#define MEMORYAREA_FLAGS_WORDSIZE4 128
|
||||
#define MEMORYAREA_FLAGS_WORDSIZE8 256
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
1598
waterbox/vb/vb.cpp
1598
waterbox/vb/vb.cpp
File diff suppressed because it is too large
Load Diff
238
waterbox/vb/vb.h
238
waterbox/vb/vb.h
|
@ -1,114 +1,124 @@
|
|||
/******************************************************************************/
|
||||
/* Mednafen Virtual Boy Emulation Module */
|
||||
/******************************************************************************/
|
||||
/* vb.h:
|
||||
** Copyright (C) 2010-2016 Mednafen Team
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or
|
||||
** modify it under the terms of the GNU General Public License
|
||||
** as published by the Free Software Foundation; either version 2
|
||||
** of the License, or (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
|
||||
typedef uint8_t uint8;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint32_t uint32;
|
||||
typedef uint64_t uint64;
|
||||
typedef int8_t int8;
|
||||
typedef int16_t int16;
|
||||
typedef int32_t int32;
|
||||
typedef int64_t int64;
|
||||
|
||||
#define MDFN_FASTCALL
|
||||
#define INLINE inline
|
||||
#define MDFN_COLD
|
||||
#define NO_INLINE
|
||||
//#define MDFN_ASSUME_ALIGNED(p, align) ((decltype(p))__builtin_assume_aligned((p), (align)))
|
||||
#define MDFN_ASSUME_ALIGNED(p, align) (p)
|
||||
#define trio_snprintf snprintf
|
||||
#define TRUE true
|
||||
#define FALSE false
|
||||
#ifndef __alignas_is_defined
|
||||
#define alignas(p)
|
||||
#endif
|
||||
|
||||
#include "endian.h"
|
||||
#include "math_ops.h"
|
||||
#include "blip/Blip_Buffer.h"
|
||||
#include "v810/v810_fp_ops.h"
|
||||
#include "v810/v810_cpu.h"
|
||||
|
||||
#include "git.h"
|
||||
|
||||
#include "vsu.h"
|
||||
#include "vip.h"
|
||||
#include "timer.h"
|
||||
#include "input.h"
|
||||
|
||||
|
||||
namespace MDFN_IEN_VB
|
||||
{
|
||||
|
||||
enum
|
||||
{
|
||||
VB3DMODE_ANAGLYPH = 0,
|
||||
VB3DMODE_CSCOPE = 1,
|
||||
VB3DMODE_SIDEBYSIDE = 2,
|
||||
VB3DMODE_OVERUNDER = 3,
|
||||
VB3DMODE_VLI,
|
||||
VB3DMODE_HLI
|
||||
};
|
||||
|
||||
#define VB_MASTER_CLOCK 20000000.0
|
||||
|
||||
enum
|
||||
{
|
||||
VB_EVENT_VIP = 0,
|
||||
VB_EVENT_TIMER,
|
||||
VB_EVENT_INPUT,
|
||||
// VB_EVENT_COMM
|
||||
};
|
||||
|
||||
#define VB_EVENT_NONONO 0x7fffffff
|
||||
|
||||
void VB_SetEvent(const int type, const v810_timestamp_t next_timestamp);
|
||||
|
||||
#define VBIRQ_SOURCE_INPUT 0
|
||||
#define VBIRQ_SOURCE_TIMER 1
|
||||
#define VBIRQ_SOURCE_EXPANSION 2
|
||||
#define VBIRQ_SOURCE_COMM 3
|
||||
#define VBIRQ_SOURCE_VIP 4
|
||||
|
||||
void VBIRQ_Assert(int source, bool assert);
|
||||
|
||||
void VB_ExitLoop(void);
|
||||
|
||||
void ForceEventUpdates(const v810_timestamp_t timestamp);
|
||||
|
||||
uint8 MDFN_FASTCALL MemRead8(v810_timestamp_t ×tamp, uint32 A);
|
||||
uint16 MDFN_FASTCALL MemRead16(v810_timestamp_t ×tamp, uint32 A);
|
||||
|
||||
void MDFN_FASTCALL MemWrite8(v810_timestamp_t ×tamp, uint32 A, uint8 V);
|
||||
void MDFN_FASTCALL MemWrite16(v810_timestamp_t ×tamp, uint32 A, uint16 V);
|
||||
|
||||
extern int32 VB_InDebugPeek;
|
||||
}
|
||||
/******************************************************************************/
|
||||
/* Mednafen Virtual Boy Emulation Module */
|
||||
/******************************************************************************/
|
||||
/* vb.h:
|
||||
** Copyright (C) 2010-2016 Mednafen Team
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or
|
||||
** modify it under the terms of the GNU General Public License
|
||||
** as published by the Free Software Foundation; either version 2
|
||||
** of the License, or (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
|
||||
typedef uint8_t uint8;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint32_t uint32;
|
||||
typedef uint64_t uint64;
|
||||
typedef int8_t int8;
|
||||
typedef int16_t int16;
|
||||
typedef int32_t int32;
|
||||
typedef int64_t int64;
|
||||
|
||||
#define MDFN_FASTCALL
|
||||
#define INLINE inline
|
||||
#define MDFN_COLD
|
||||
#define NO_INLINE
|
||||
//#define MDFN_ASSUME_ALIGNED(p, align) ((decltype(p))__builtin_assume_aligned((p), (align)))
|
||||
#define MDFN_ASSUME_ALIGNED(p, align) (p)
|
||||
#define trio_snprintf snprintf
|
||||
#define TRUE true
|
||||
#define FALSE false
|
||||
#ifndef __alignas_is_defined
|
||||
#define alignas(p)
|
||||
#endif
|
||||
|
||||
struct MyFrameInfo
|
||||
{
|
||||
uint32_t* VideoBuffer;
|
||||
int16_t* SoundBuffer;
|
||||
int64_t Cycles;
|
||||
int32_t Width;
|
||||
int32_t Height;
|
||||
int32_t Samples;
|
||||
int32_t Lagged;
|
||||
int32_t Buttons;
|
||||
};
|
||||
|
||||
#include "endian.h"
|
||||
#include "math_ops.h"
|
||||
#include "blip/Blip_Buffer.h"
|
||||
#include "v810/v810_fp_ops.h"
|
||||
#include "v810/v810_cpu.h"
|
||||
|
||||
#include "git.h"
|
||||
|
||||
#include "vsu.h"
|
||||
#include "vip.h"
|
||||
#include "timer.h"
|
||||
#include "input.h"
|
||||
|
||||
|
||||
namespace MDFN_IEN_VB
|
||||
{
|
||||
|
||||
enum
|
||||
{
|
||||
VB3DMODE_ANAGLYPH = 0,
|
||||
VB3DMODE_CSCOPE = 1,
|
||||
VB3DMODE_SIDEBYSIDE = 2,
|
||||
VB3DMODE_OVERUNDER = 3,
|
||||
VB3DMODE_VLI,
|
||||
VB3DMODE_HLI
|
||||
};
|
||||
|
||||
#define VB_MASTER_CLOCK 20000000.0
|
||||
|
||||
enum
|
||||
{
|
||||
VB_EVENT_VIP = 0,
|
||||
VB_EVENT_TIMER,
|
||||
VB_EVENT_INPUT,
|
||||
// VB_EVENT_COMM
|
||||
};
|
||||
|
||||
#define VB_EVENT_NONONO 0x7fffffff
|
||||
|
||||
void VB_SetEvent(const int type, const v810_timestamp_t next_timestamp);
|
||||
|
||||
#define VBIRQ_SOURCE_INPUT 0
|
||||
#define VBIRQ_SOURCE_TIMER 1
|
||||
#define VBIRQ_SOURCE_EXPANSION 2
|
||||
#define VBIRQ_SOURCE_COMM 3
|
||||
#define VBIRQ_SOURCE_VIP 4
|
||||
|
||||
void VBIRQ_Assert(int source, bool assert);
|
||||
|
||||
void VB_ExitLoop(void);
|
||||
|
||||
void ForceEventUpdates(const v810_timestamp_t timestamp);
|
||||
|
||||
uint8 MDFN_FASTCALL MemRead8(v810_timestamp_t ×tamp, uint32 A);
|
||||
uint16 MDFN_FASTCALL MemRead16(v810_timestamp_t ×tamp, uint32 A);
|
||||
|
||||
void MDFN_FASTCALL MemWrite8(v810_timestamp_t ×tamp, uint32 A, uint8 V);
|
||||
void MDFN_FASTCALL MemWrite16(v810_timestamp_t ×tamp, uint32 A, uint16 V);
|
||||
}
|
||||
|
|
2787
waterbox/vb/vip.cpp
2787
waterbox/vb/vip.cpp
File diff suppressed because it is too large
Load Diff
|
@ -1,82 +1,82 @@
|
|||
/******************************************************************************/
|
||||
/* Mednafen Virtual Boy Emulation Module */
|
||||
/******************************************************************************/
|
||||
/* vip.h:
|
||||
** Copyright (C) 2010-2016 Mednafen Team
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or
|
||||
** modify it under the terms of the GNU General Public License
|
||||
** as published by the Free Software Foundation; either version 2
|
||||
** of the License, or (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace MDFN_IEN_VB
|
||||
{
|
||||
void VIP_Init(void) MDFN_COLD;
|
||||
void VIP_Power(void) MDFN_COLD;
|
||||
|
||||
void VIP_SetInstantDisplayHack(bool) MDFN_COLD;
|
||||
void VIP_SetAllowDrawSkip(bool) MDFN_COLD;
|
||||
void VIP_Set3DMode(uint32 mode, bool reverse, uint32 prescale, uint32 sbs_separation) MDFN_COLD;
|
||||
void VIP_SetParallaxDisable(bool disabled) MDFN_COLD;
|
||||
void VIP_SetDefaultColor(uint32 default_color) MDFN_COLD;
|
||||
void VIP_SetAnaglyphColors(uint32 lcolor, uint32 rcolor) MDFN_COLD; // R << 16, G << 8, B << 0
|
||||
void VIP_SetLEDOnScale(float coeff) MDFN_COLD;
|
||||
|
||||
v810_timestamp_t MDFN_FASTCALL VIP_Update(const v810_timestamp_t timestamp);
|
||||
void VIP_ResetTS(void);
|
||||
|
||||
void VIP_StartFrame(EmulateSpecStruct *espec);
|
||||
|
||||
MDFN_FASTCALL uint8 VIP_Read8(v810_timestamp_t ×tamp, uint32 A);
|
||||
MDFN_FASTCALL uint16 VIP_Read16(v810_timestamp_t ×tamp, uint32 A);
|
||||
|
||||
MDFN_FASTCALL void VIP_Write8(v810_timestamp_t ×tamp, uint32 A, uint8 V);
|
||||
MDFN_FASTCALL void VIP_Write16(v810_timestamp_t ×tamp, uint32 A, uint16 V);
|
||||
|
||||
enum
|
||||
{
|
||||
VIP_GSREG_IPENDING = 0, // Current pending interrupt(bits)
|
||||
VIP_GSREG_IENABLE,
|
||||
|
||||
VIP_GSREG_DPCTRL,
|
||||
|
||||
VIP_GSREG_BRTA,
|
||||
VIP_GSREG_BRTB,
|
||||
VIP_GSREG_BRTC,
|
||||
VIP_GSREG_REST,
|
||||
VIP_GSREG_FRMCYC,
|
||||
VIP_GSREG_XPCTRL,
|
||||
|
||||
VIP_GSREG_SPT0,
|
||||
VIP_GSREG_SPT1,
|
||||
VIP_GSREG_SPT2,
|
||||
VIP_GSREG_SPT3,
|
||||
|
||||
VIP_GSREG_GPLT0,
|
||||
VIP_GSREG_GPLT1,
|
||||
VIP_GSREG_GPLT2,
|
||||
VIP_GSREG_GPLT3,
|
||||
|
||||
VIP_GSREG_JPLT0,
|
||||
VIP_GSREG_JPLT1,
|
||||
VIP_GSREG_JPLT2,
|
||||
VIP_GSREG_JPLT3,
|
||||
|
||||
VIP_GSREG_BKCOL,
|
||||
};
|
||||
|
||||
uint32 VIP_GetRegister(const unsigned int id, char *special, const uint32 special_len);
|
||||
void VIP_SetRegister(const unsigned int id, const uint32 value);
|
||||
}
|
||||
/******************************************************************************/
|
||||
/* Mednafen Virtual Boy Emulation Module */
|
||||
/******************************************************************************/
|
||||
/* vip.h:
|
||||
** Copyright (C) 2010-2016 Mednafen Team
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or
|
||||
** modify it under the terms of the GNU General Public License
|
||||
** as published by the Free Software Foundation; either version 2
|
||||
** of the License, or (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace MDFN_IEN_VB
|
||||
{
|
||||
void VIP_Init(void) MDFN_COLD;
|
||||
void VIP_Power(void) MDFN_COLD;
|
||||
|
||||
void VIP_SetInstantDisplayHack(bool) MDFN_COLD;
|
||||
void VIP_SetAllowDrawSkip(bool) MDFN_COLD;
|
||||
void VIP_Set3DMode(uint32 mode, bool reverse, uint32 prescale, uint32 sbs_separation) MDFN_COLD;
|
||||
void VIP_SetParallaxDisable(bool disabled) MDFN_COLD;
|
||||
void VIP_SetDefaultColor(uint32 default_color) MDFN_COLD;
|
||||
void VIP_SetAnaglyphColors(uint32 lcolor, uint32 rcolor) MDFN_COLD; // R << 16, G << 8, B << 0
|
||||
void VIP_SetLEDOnScale(float coeff) MDFN_COLD;
|
||||
|
||||
v810_timestamp_t MDFN_FASTCALL VIP_Update(const v810_timestamp_t timestamp);
|
||||
void VIP_ResetTS(void);
|
||||
|
||||
void VIP_StartFrame(MyFrameInfo* frame);
|
||||
|
||||
MDFN_FASTCALL uint8 VIP_Read8(v810_timestamp_t ×tamp, uint32 A);
|
||||
MDFN_FASTCALL uint16 VIP_Read16(v810_timestamp_t ×tamp, uint32 A);
|
||||
|
||||
MDFN_FASTCALL void VIP_Write8(v810_timestamp_t ×tamp, uint32 A, uint8 V);
|
||||
MDFN_FASTCALL void VIP_Write16(v810_timestamp_t ×tamp, uint32 A, uint16 V);
|
||||
|
||||
enum
|
||||
{
|
||||
VIP_GSREG_IPENDING = 0, // Current pending interrupt(bits)
|
||||
VIP_GSREG_IENABLE,
|
||||
|
||||
VIP_GSREG_DPCTRL,
|
||||
|
||||
VIP_GSREG_BRTA,
|
||||
VIP_GSREG_BRTB,
|
||||
VIP_GSREG_BRTC,
|
||||
VIP_GSREG_REST,
|
||||
VIP_GSREG_FRMCYC,
|
||||
VIP_GSREG_XPCTRL,
|
||||
|
||||
VIP_GSREG_SPT0,
|
||||
VIP_GSREG_SPT1,
|
||||
VIP_GSREG_SPT2,
|
||||
VIP_GSREG_SPT3,
|
||||
|
||||
VIP_GSREG_GPLT0,
|
||||
VIP_GSREG_GPLT1,
|
||||
VIP_GSREG_GPLT2,
|
||||
VIP_GSREG_GPLT3,
|
||||
|
||||
VIP_GSREG_JPLT0,
|
||||
VIP_GSREG_JPLT1,
|
||||
VIP_GSREG_JPLT2,
|
||||
VIP_GSREG_JPLT3,
|
||||
|
||||
VIP_GSREG_BKCOL,
|
||||
};
|
||||
|
||||
uint32 VIP_GetRegister(const unsigned int id, char *special, const uint32 special_len);
|
||||
void VIP_SetRegister(const unsigned int id, const uint32 value);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue