Move ngp over to nyma core and update to latest mednafen
It's seen some upstream updates recently, so that's cool
This commit is contained in:
parent
bf544e02fa
commit
2afe356fc9
Binary file not shown.
|
@ -529,7 +529,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
nextEmulator = new TerboGrafix(game, new[] { disc }, nextComm,
|
||||
(Emulation.Cores.Waterbox.NymaCore.NymaSettings)GetCoreSettings<TerboGrafix>(),
|
||||
(Emulation.Cores.Waterbox.NymaCore.NymaSyncSettings)GetCoreSyncSettings<TerboGrafix>());
|
||||
(Emulation.Cores.Waterbox.NymaCore.NymaSyncSettings)GetCoreSyncSettings<TerboGrafix>(), Deterministic);
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
|
@ -11,22 +11,22 @@ using BizHawk.Emulation.DiscSystem;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.NEC.PCE
|
||||
{
|
||||
[Core(CoreNames.TurboNyma, "Mednafen Team", true, false, "1.24.3", "", false)]
|
||||
[Core(CoreNames.TurboNyma, "Mednafen Team", true, false, "1.24.3", "https://mednafen.github.io/releases/", false)]
|
||||
public class TerboGrafix : NymaCore, IRegionable, IPceGpuView
|
||||
{
|
||||
private readonly LibTerboGrafix _terboGrafix;
|
||||
|
||||
[CoreConstructor(new[] { "PCE", "SGX" })]
|
||||
public TerboGrafix(GameInfo game, byte[] rom, CoreComm comm, string extension,
|
||||
NymaSettings settings, NymaSyncSettings syncSettings)
|
||||
NymaSettings settings, NymaSyncSettings syncSettings, bool deterministic)
|
||||
: base(comm, "PCE", "PC Engine Controller", settings, syncSettings)
|
||||
{
|
||||
if (game["BRAM"])
|
||||
SettingsOverrides["pce.disable_bram_hucard"] = "0";
|
||||
_terboGrafix = DoInit<LibTerboGrafix>(game, rom, null, "pce.wbx", extension);
|
||||
_terboGrafix = DoInit<LibTerboGrafix>(game, rom, null, "pce.wbx", extension, deterministic);
|
||||
}
|
||||
public TerboGrafix(GameInfo game, Disc[] discs, CoreComm comm,
|
||||
NymaSettings settings, NymaSyncSettings syncSettings)
|
||||
NymaSettings settings, NymaSyncSettings syncSettings, bool deterministic)
|
||||
: base(comm, "PCE", "PC Engine Controller", settings, syncSettings)
|
||||
{
|
||||
var firmwares = new Dictionary<string, byte[]>();
|
||||
|
@ -36,7 +36,7 @@ namespace BizHawk.Emulation.Cores.Consoles.NEC.PCE
|
|||
firmwares.Add("FIRMWARE:syscard3.pce", comm.CoreFileProvider.GetFirmware("PCECD", "Bios", true));
|
||||
if (types.Contains(DiscType.TurboGECD))
|
||||
firmwares.Add("FIRMWARE:gecard.pce", comm.CoreFileProvider.GetFirmware("PCECD", "GE-Bios", true));
|
||||
_terboGrafix = DoInit<LibTerboGrafix>(game, null, discs, "pce.wbx", null, firmwares);
|
||||
_terboGrafix = DoInit<LibTerboGrafix>(game, null, discs, "pce.wbx", null, deterministic, firmwares);
|
||||
}
|
||||
|
||||
public override string SystemId => IsSgx ? "SGX" : "PCE";
|
||||
|
|
|
@ -1,344 +0,0 @@
|
|||
using BizHawk.Common;
|
||||
using BizHawk.BizInvoke;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Sound;
|
||||
using BizHawk.Emulation.Cores.Waterbox;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.SNK
|
||||
{
|
||||
[Core("Dual NeoPop", "Thomas Klausner, Mednafen Team, natt", true, false, "0.9.44.1",
|
||||
"https://mednafen.github.io/releases/", false)]
|
||||
public class DualNeoGeoPort : IEmulator
|
||||
{
|
||||
private NeoGeoPort _left;
|
||||
private NeoGeoPort _right;
|
||||
private readonly BasicServiceProvider _serviceProvider;
|
||||
private bool _disposed = false;
|
||||
private readonly DualSyncSound _soundProvider;
|
||||
private readonly SideBySideVideo _videoProvider;
|
||||
private readonly LinkInterop _leftEnd;
|
||||
private readonly LinkInterop _rightEnd;
|
||||
private readonly LinkCable _linkCable;
|
||||
|
||||
[CoreConstructor("DNGP")]
|
||||
public DualNeoGeoPort(CoreComm comm, byte[] rom, bool deterministic)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
// // this will throw on construct: we need to compile two different copies of ngp at different starts
|
||||
// CoreComm = comm;
|
||||
// _left = new NeoGeoPort(comm, rom, new NeoGeoPort.SyncSettings { Language = LibNeoGeoPort.Language.English }, deterministic, WaterboxHost.CanonicalStart);
|
||||
// _right = new NeoGeoPort(comm, rom, new NeoGeoPort.SyncSettings { Language = LibNeoGeoPort.Language.English }, deterministic, WaterboxHost.CanonicalStart);
|
||||
// _linkCable = new LinkCable();
|
||||
// _leftEnd = new LinkInterop(_left, _linkCable.LeftIn, _linkCable.LeftOut);
|
||||
// _rightEnd = new LinkInterop(_right, _linkCable.RightIn, _linkCable.RightOut);
|
||||
|
||||
|
||||
// _serviceProvider = new BasicServiceProvider(this);
|
||||
// _soundProvider = new DualSyncSound(_left, _right);
|
||||
// _serviceProvider.Register<ISoundProvider>(_soundProvider);
|
||||
// _videoProvider = new SideBySideVideo(_left, _right);
|
||||
// _serviceProvider.Register<IVideoProvider>(_videoProvider);
|
||||
}
|
||||
|
||||
public bool FrameAdvance(IController controller, bool render, bool rendersound = true)
|
||||
{
|
||||
var t1 = Task.Run(() =>
|
||||
{
|
||||
_left.FrameAdvance(new PrefixController(controller, "P1 "), render, rendersound);
|
||||
_leftEnd.SignalEndOfFrame();
|
||||
});
|
||||
var t2 = Task.Run(() =>
|
||||
{
|
||||
_right.FrameAdvance(new PrefixController(controller, "P2 "), render, rendersound);
|
||||
_rightEnd.SignalEndOfFrame();
|
||||
});
|
||||
var t3 = Task.Run(() =>
|
||||
{
|
||||
_linkCable.RunFrame();
|
||||
});
|
||||
Task.WaitAll(t1, t2, t3);
|
||||
Frame++;
|
||||
_soundProvider.Fetch();
|
||||
_videoProvider.Fetch();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private class LinkCable
|
||||
{
|
||||
public readonly BlockingCollection<LinkRequest> LeftIn = new BlockingCollection<LinkRequest>();
|
||||
public readonly BlockingCollection<LinkResult> LeftOut = new BlockingCollection<LinkResult>();
|
||||
public readonly BlockingCollection<LinkRequest> RightIn = new BlockingCollection<LinkRequest>();
|
||||
public readonly BlockingCollection<LinkResult> RightOut = new BlockingCollection<LinkResult>();
|
||||
|
||||
private readonly Queue<byte> _leftData = new Queue<byte>();
|
||||
private readonly Queue<byte> _rightData = new Queue<byte>();
|
||||
|
||||
public void RunFrame()
|
||||
{
|
||||
LinkRequest l = LeftIn.Take();
|
||||
LinkRequest r = RightIn.Take();
|
||||
while (true)
|
||||
{
|
||||
switch (l.RequestType)
|
||||
{
|
||||
case LinkRequest.RequestTypes.EndOfFrame:
|
||||
if (r.RequestType == LinkRequest.RequestTypes.EndOfFrame)
|
||||
{
|
||||
Console.WriteLine("\nEnd of Frame {0} {1}", _leftData.Count, _rightData.Count);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case LinkRequest.RequestTypes.Write:
|
||||
Console.Write("LW ");
|
||||
_leftData.Enqueue(l.Data);
|
||||
l = LeftIn.Take();
|
||||
continue;
|
||||
case LinkRequest.RequestTypes.Read:
|
||||
case LinkRequest.RequestTypes.Poll:
|
||||
if (_rightData.Count > 0)
|
||||
{
|
||||
if (l.RequestType == LinkRequest.RequestTypes.Read)
|
||||
Console.Write("LR ");
|
||||
LeftOut.Add(new LinkResult
|
||||
{
|
||||
Data = l.RequestType == LinkRequest.RequestTypes.Read ? _rightData.Dequeue() : _rightData.Peek(),
|
||||
Return = true
|
||||
});
|
||||
l = LeftIn.Take();
|
||||
continue;
|
||||
}
|
||||
else if (r.RequestType != LinkRequest.RequestTypes.Write)
|
||||
{
|
||||
if (l.RequestType == LinkRequest.RequestTypes.Read)
|
||||
Console.Write("L! ");
|
||||
LeftOut.Add(new LinkResult
|
||||
{
|
||||
Data = l.Data,
|
||||
Return = false
|
||||
});
|
||||
l = LeftIn.Take();
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (r.RequestType)
|
||||
{
|
||||
case LinkRequest.RequestTypes.Write:
|
||||
Console.Write("RW ");
|
||||
_rightData.Enqueue(r.Data);
|
||||
r = RightIn.Take();
|
||||
continue;
|
||||
case LinkRequest.RequestTypes.Read:
|
||||
case LinkRequest.RequestTypes.Poll:
|
||||
if (_leftData.Count > 0)
|
||||
{
|
||||
if (r.RequestType == LinkRequest.RequestTypes.Read)
|
||||
Console.Write("RR ");
|
||||
RightOut.Add(new LinkResult
|
||||
{
|
||||
Data = r.RequestType == LinkRequest.RequestTypes.Read ? _leftData.Dequeue() : _leftData.Peek(),
|
||||
Return = true
|
||||
});
|
||||
r = RightIn.Take();
|
||||
continue;
|
||||
}
|
||||
else if (l.RequestType != LinkRequest.RequestTypes.Write)
|
||||
{
|
||||
if (r.RequestType == LinkRequest.RequestTypes.Read)
|
||||
Console.Write("R! ");
|
||||
RightOut.Add(new LinkResult
|
||||
{
|
||||
Data = r.Data,
|
||||
Return = false
|
||||
});
|
||||
r = RightIn.Take();
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct LinkRequest
|
||||
{
|
||||
public enum RequestTypes : byte
|
||||
{
|
||||
Read,
|
||||
Poll,
|
||||
Write,
|
||||
EndOfFrame
|
||||
}
|
||||
public RequestTypes RequestType;
|
||||
public byte Data;
|
||||
}
|
||||
public struct LinkResult
|
||||
{
|
||||
public byte Data;
|
||||
public bool Return;
|
||||
}
|
||||
|
||||
private unsafe class LinkInterop
|
||||
{
|
||||
private readonly BlockingCollection<LinkRequest> _push;
|
||||
private readonly BlockingCollection<LinkResult> _pull;
|
||||
private NeoGeoPort _core;
|
||||
private readonly IntPtr _readcb;
|
||||
private readonly IntPtr _pollcb;
|
||||
private readonly IntPtr _writecb;
|
||||
private readonly IImportResolver _exporter;
|
||||
|
||||
public LinkInterop(NeoGeoPort core, BlockingCollection<LinkRequest> push, BlockingCollection<LinkResult> pull)
|
||||
{
|
||||
_core = core;
|
||||
_push = push;
|
||||
_pull = pull;
|
||||
_exporter = BizExvoker.GetExvoker(this, CallingConventionAdapters.Waterbox);
|
||||
_readcb = _exporter.GetProcAddrOrThrow("CommsReadCallback");
|
||||
_pollcb = _exporter.GetProcAddrOrThrow("CommsPollCallback");
|
||||
_writecb = _exporter.GetProcAddrOrThrow("CommsWriteCallback");
|
||||
ConnectPointers();
|
||||
}
|
||||
|
||||
private void ConnectPointers()
|
||||
{
|
||||
_core._neopop.SetCommsCallbacks(_readcb, _pollcb, _writecb);
|
||||
}
|
||||
|
||||
private bool CommsPollNoBuffer()
|
||||
{
|
||||
_push.Add(new LinkRequest
|
||||
{
|
||||
RequestType = LinkRequest.RequestTypes.Poll
|
||||
});
|
||||
return _pull.Take().Return;
|
||||
}
|
||||
|
||||
[BizExport(CallingConvention.Cdecl)]
|
||||
public bool CommsReadCallback(byte* buffer)
|
||||
{
|
||||
if (buffer == null)
|
||||
return CommsPollNoBuffer();
|
||||
_push.Add(new LinkRequest
|
||||
{
|
||||
RequestType = LinkRequest.RequestTypes.Read,
|
||||
Data = *buffer
|
||||
});
|
||||
var r = _pull.Take();
|
||||
*buffer = r.Data;
|
||||
return r.Return;
|
||||
}
|
||||
[BizExport(CallingConvention.Cdecl)]
|
||||
public bool CommsPollCallback(byte* buffer)
|
||||
{
|
||||
if (buffer == null)
|
||||
return CommsPollNoBuffer();
|
||||
_push.Add(new LinkRequest
|
||||
{
|
||||
RequestType = LinkRequest.RequestTypes.Poll,
|
||||
Data = *buffer
|
||||
});
|
||||
var r = _pull.Take();
|
||||
*buffer = r.Data;
|
||||
return r.Return;
|
||||
}
|
||||
[BizExport(CallingConvention.Cdecl)]
|
||||
public void CommsWriteCallback(byte data)
|
||||
{
|
||||
_push.Add(new LinkRequest
|
||||
{
|
||||
RequestType = LinkRequest.RequestTypes.Write,
|
||||
Data = data
|
||||
});
|
||||
}
|
||||
|
||||
public void SignalEndOfFrame()
|
||||
{
|
||||
_push.Add(new LinkRequest
|
||||
{
|
||||
RequestType = LinkRequest.RequestTypes.EndOfFrame
|
||||
});
|
||||
}
|
||||
|
||||
public void PostLoadState()
|
||||
{
|
||||
ConnectPointers();
|
||||
}
|
||||
}
|
||||
|
||||
private class PrefixController : IController
|
||||
{
|
||||
public PrefixController(IController controller, string prefix)
|
||||
{
|
||||
_controller = controller;
|
||||
_prefix = prefix;
|
||||
}
|
||||
|
||||
private readonly IController _controller;
|
||||
private readonly string _prefix;
|
||||
|
||||
public ControllerDefinition Definition => null;
|
||||
|
||||
public int AxisValue(string name)
|
||||
{
|
||||
return _controller.AxisValue(_prefix + name);
|
||||
}
|
||||
|
||||
public bool IsPressed(string button)
|
||||
{
|
||||
return _controller.IsPressed(_prefix + button);
|
||||
}
|
||||
}
|
||||
|
||||
public ControllerDefinition ControllerDefinition => DualNeoGeoPortController;
|
||||
|
||||
private static readonly ControllerDefinition DualNeoGeoPortController = new ControllerDefinition
|
||||
{
|
||||
BoolButtons =
|
||||
{
|
||||
"P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 A", "P1 B", "P1 Option", "P1 Power",
|
||||
"P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 A", "P2 B", "P2 Option", "P2 Power"
|
||||
},
|
||||
Name = "Dual NeoGeo Portable Controller"
|
||||
};
|
||||
|
||||
public void ResetCounters()
|
||||
{
|
||||
Frame = 0;
|
||||
}
|
||||
|
||||
public int Frame { get; private set; }
|
||||
|
||||
public IEmulatorServiceProvider ServiceProvider => _serviceProvider;
|
||||
|
||||
public CoreComm CoreComm { get; }
|
||||
|
||||
public bool DeterministicEmulation => _left.DeterministicEmulation && _right.DeterministicEmulation;
|
||||
|
||||
public string SystemId => "DNGP";
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
_left.Dispose();
|
||||
_right.Dispose();
|
||||
_left = null;
|
||||
_right = null;
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,35 +5,11 @@ using System.Runtime.InteropServices;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.SNK
|
||||
{
|
||||
public abstract class LibNeoGeoPort : LibWaterboxCore
|
||||
public abstract class LibNeoGeoPort : LibNymaCore
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public new class FrameInfo : LibWaterboxCore.FrameInfo
|
||||
{
|
||||
public long FrontendTime;
|
||||
public int SkipRendering;
|
||||
public int Buttons;
|
||||
}
|
||||
public enum Language
|
||||
{
|
||||
Japanese, English
|
||||
}
|
||||
[UnmanagedFunctionPointer(CC)]
|
||||
public delegate void SaveRamCallback(IntPtr data, int length);
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract bool LoadSystem(byte[] rom, int romlength, Language language);
|
||||
public abstract bool GetSaveRam();
|
||||
[BizImport(CC)]
|
||||
public abstract void SetLayers(int enable); // 1, 2, 4 bg,fg,sprites
|
||||
[BizImport(CC)]
|
||||
public abstract void HardReset();
|
||||
[BizImport(CC)]
|
||||
public abstract void SetCommsCallbacks(IntPtr readcb, IntPtr pollcb, IntPtr writecb);
|
||||
[BizImport(CC)]
|
||||
public abstract bool HasSaveRam();
|
||||
[BizImport(CC)]
|
||||
public abstract bool PutSaveRam(byte[] data, int length);
|
||||
[BizImport(CC)]
|
||||
public abstract void GetSaveRam(SaveRamCallback callback);
|
||||
public abstract bool PutSaveRam();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,188 +9,47 @@ using System.Runtime.InteropServices;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.SNK
|
||||
{
|
||||
[Core("NeoPop", "Thomas Klausner, Mednafen Team", true, true, "0.9.44.1",
|
||||
[Core("NeoPop", "Thomas Klausner, Mednafen Team", true, true, "1.24.3",
|
||||
"https://mednafen.github.io/releases/", false)]
|
||||
public class NeoGeoPort : WaterboxCore,
|
||||
ISaveRam, // NGP provides its own saveram interface
|
||||
ISettable<object, NeoGeoPort.SyncSettings>
|
||||
public class NeoGeoPort : NymaCore,
|
||||
ISaveRam // NGP provides its own saveram interface
|
||||
{
|
||||
internal LibNeoGeoPort _neopop;
|
||||
private readonly LibNeoGeoPort _neopop;
|
||||
|
||||
[CoreConstructor("NGP")]
|
||||
public NeoGeoPort(CoreComm comm, byte[] rom, SyncSettings syncSettings, bool deterministic)
|
||||
: this(comm, rom, syncSettings, deterministic, WaterboxHost.CanonicalStart)
|
||||
public NeoGeoPort(CoreComm comm, byte[] rom, GameInfo game,
|
||||
NymaSettings settings, NymaSyncSettings syncSettings, bool deterministic, string extension)
|
||||
: base(comm, "NGP", "NeoGeo Portable Controller", settings, syncSettings)
|
||||
{
|
||||
_neopop = DoInit<LibNeoGeoPort>(game, rom, null, "ngp.wbx", extension, deterministic);
|
||||
}
|
||||
|
||||
internal NeoGeoPort(CoreComm comm, byte[] rom, SyncSettings syncSettings, bool deterministic, ulong startAddress)
|
||||
:base(comm, new Configuration
|
||||
public new bool SaveRamModified
|
||||
{
|
||||
DefaultFpsNumerator = 6144000,
|
||||
DefaultFpsDenominator = 515 * 198,
|
||||
DefaultWidth = 160,
|
||||
DefaultHeight = 152,
|
||||
MaxWidth = 160,
|
||||
MaxHeight = 152,
|
||||
MaxSamples = 8192,
|
||||
SystemId = "NGP"
|
||||
})
|
||||
get
|
||||
{
|
||||
if (rom.Length > 4 * 1024 * 1024)
|
||||
throw new InvalidOperationException("ROM too big!");
|
||||
|
||||
_syncSettings = syncSettings ?? new SyncSettings();
|
||||
|
||||
_neopop = PreInit<LibNeoGeoPort>(new WaterboxOptions
|
||||
{
|
||||
Filename = "ngp.wbx",
|
||||
SbrkHeapSizeKB = 256,
|
||||
SealedHeapSizeKB = 5 * 1024, // must be a bit larger than the ROM size
|
||||
InvisibleHeapSizeKB = 4,
|
||||
PlainHeapSizeKB = 5 * 1024, // must be a bit larger than the ROM size
|
||||
StartAddress = startAddress,
|
||||
SkipCoreConsistencyCheck = comm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxCoreConsistencyCheck),
|
||||
SkipMemoryConsistencyCheck = comm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxMemoryConsistencyCheck),
|
||||
});
|
||||
|
||||
if (!_neopop.LoadSystem(rom, rom.Length, _syncSettings.Language))
|
||||
throw new InvalidOperationException("Core rejected the rom");
|
||||
|
||||
PostInit();
|
||||
|
||||
DeterministicEmulation = deterministic || !_syncSettings.UseRealTime;
|
||||
InitializeRtc(_syncSettings.InitialTime);
|
||||
}
|
||||
|
||||
protected override LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller, bool render, bool rendersound)
|
||||
{
|
||||
if (controller.IsPressed("Power"))
|
||||
_neopop.HardReset();
|
||||
|
||||
return new LibNeoGeoPort.FrameInfo
|
||||
{
|
||||
FrontendTime = GetRtcTime(!DeterministicEmulation),
|
||||
Buttons = GetButtons(controller),
|
||||
SkipRendering = render ? 0 : 1,
|
||||
};
|
||||
}
|
||||
|
||||
private static int GetButtons(IController c)
|
||||
{
|
||||
var ret = 0;
|
||||
var val = 1;
|
||||
foreach (var s in CoreButtons)
|
||||
{
|
||||
if (c.IsPressed(s))
|
||||
ret |= val;
|
||||
val <<= 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static readonly string[] CoreButtons =
|
||||
{
|
||||
"Up", "Down", "Left", "Right", "A", "B", "Option"
|
||||
};
|
||||
|
||||
private static readonly Dictionary<string, int> ButtonOrdinals = new Dictionary<string, int>
|
||||
{
|
||||
["Up"] = 1,
|
||||
["Down"] = 2,
|
||||
["Left"] = 3,
|
||||
["Right"] = 4,
|
||||
["B"] = 9,
|
||||
["A"] = 10,
|
||||
["R"] = 11,
|
||||
["L"] = 12,
|
||||
["Option"] = 13
|
||||
};
|
||||
|
||||
private static readonly ControllerDefinition NeoGeoPortableController = new ControllerDefinition
|
||||
{
|
||||
Name = "NeoGeo Portable Controller",
|
||||
BoolButtons = CoreButtons
|
||||
.OrderBy(b => ButtonOrdinals[b])
|
||||
.Concat(new[] { "Power" })
|
||||
.ToList()
|
||||
};
|
||||
|
||||
public override ControllerDefinition ControllerDefinition => NeoGeoPortableController;
|
||||
|
||||
private SyncSettings _syncSettings;
|
||||
|
||||
public class SyncSettings
|
||||
{
|
||||
[DisplayName("Language")]
|
||||
[Description("Language of the system. Only affects some games.")]
|
||||
[DefaultValue(LibNeoGeoPort.Language.Japanese)]
|
||||
public LibNeoGeoPort.Language Language { get; set; }
|
||||
|
||||
[DisplayName("Initial Time")]
|
||||
[Description("Initial time of emulation. Only relevant when UseRealTime is false.")]
|
||||
[DefaultValue(typeof(DateTime), "2010-01-01")]
|
||||
public DateTime InitialTime { get; set; }
|
||||
|
||||
[DisplayName("Use RealTime")]
|
||||
[Description("If true, RTC clock will be based off of real time instead of emulated time. Ignored (set to false) when recording a movie.")]
|
||||
[DefaultValue(false)]
|
||||
public bool UseRealTime { get; set; }
|
||||
|
||||
public SyncSettings Clone()
|
||||
{
|
||||
return (SyncSettings)MemberwiseClone();
|
||||
}
|
||||
|
||||
public static bool NeedsReboot(SyncSettings x, SyncSettings y)
|
||||
{
|
||||
return !DeepEquality.DeepEquals(x, y);
|
||||
}
|
||||
|
||||
public SyncSettings()
|
||||
{
|
||||
SettingsUtil.SetDefaultValues(this);
|
||||
_exe.AddTransientFile(new byte[0], "SAV:flash");
|
||||
if (!_neopop.GetSaveRam())
|
||||
throw new InvalidOperationException("Error divining saveram");
|
||||
return _exe.RemoveTransientFile("SAV:flash").Length > 0;
|
||||
}
|
||||
}
|
||||
|
||||
public object GetSettings()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public SyncSettings GetSyncSettings()
|
||||
{
|
||||
return _syncSettings.Clone();
|
||||
}
|
||||
|
||||
public PutSettingsDirtyBits PutSettings(object o)
|
||||
{
|
||||
return PutSettingsDirtyBits.None;
|
||||
}
|
||||
|
||||
public PutSettingsDirtyBits PutSyncSettings(SyncSettings o)
|
||||
{
|
||||
var ret = SyncSettings.NeedsReboot(_syncSettings, o);
|
||||
_syncSettings = o;
|
||||
return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None;
|
||||
}
|
||||
|
||||
public new bool SaveRamModified => _neopop.HasSaveRam();
|
||||
|
||||
public new byte[] CloneSaveRam()
|
||||
{
|
||||
byte[] ret = null;
|
||||
_neopop.GetSaveRam((data, size) =>
|
||||
{
|
||||
ret = new byte[size];
|
||||
Marshal.Copy(data, ret, 0, size);
|
||||
});
|
||||
return ret;
|
||||
_exe.AddTransientFile(new byte[0], "SAV:flash");
|
||||
|
||||
if (!_neopop.GetSaveRam())
|
||||
throw new InvalidOperationException("Error returning saveram");
|
||||
return _exe.RemoveTransientFile("SAV:flash");
|
||||
}
|
||||
|
||||
public new void StoreSaveRam(byte[] data)
|
||||
{
|
||||
if (!_neopop.PutSaveRam(data, data.Length))
|
||||
_exe.AddTransientFile(data, "SAV:flash");
|
||||
if (!_neopop.PutSaveRam())
|
||||
throw new InvalidOperationException("Core rejected the saveram");
|
||||
_exe.RemoveTransientFile("SAV:flash");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,6 +88,10 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
/// raw data for each input port, assumed to be MAX_PORTS * MAX_PORT_DATA long
|
||||
/// </summary>
|
||||
public byte* InputPortData;
|
||||
/// <summary>
|
||||
/// If the core calls time functions, this is the value that will be used
|
||||
/// </summary>
|
||||
public long FrontendTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
@ -77,7 +78,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
return new NymaSyncSettings
|
||||
{
|
||||
MednafenValues = new Dictionary<string, string>(MednafenValues),
|
||||
PortDevices = new Dictionary<int, string>(PortDevices)
|
||||
PortDevices = new Dictionary<int, string>(PortDevices),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -95,7 +96,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
}
|
||||
}
|
||||
|
||||
private void SettingsQuery(string name, IntPtr dest)
|
||||
protected string SettingsQuery(string name)
|
||||
{
|
||||
SettingsOverrides.TryGetValue(name, out var val);
|
||||
if (val == null)
|
||||
|
@ -112,7 +113,12 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
}
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
private void SettingsQuery(string name, IntPtr dest)
|
||||
{
|
||||
var val = SettingsQuery(name);
|
||||
var bytes = Encoding.UTF8.GetBytes(val);
|
||||
if (bytes.Length > 255)
|
||||
throw new InvalidOperationException($"Value {val} for setting {name} was too long");
|
||||
|
@ -230,6 +236,8 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
Value = Mershul.PtrToStringUtf8(s.Value);
|
||||
}
|
||||
}
|
||||
public MednaSetting()
|
||||
{}
|
||||
public MednaSetting(MednaSettingS s)
|
||||
{
|
||||
Name = Mershul.PtrToStringUtf8(s.Name);
|
||||
|
@ -320,7 +328,34 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
}
|
||||
|
||||
s.HiddenSettings = new HashSet<string>(SettingsOverrides.Keys);
|
||||
foreach (var ss in ExtraSettings)
|
||||
{
|
||||
s.Settings.Add(ss);
|
||||
s.SettingsByKey.Add(ss.SettingsKey, ss);
|
||||
}
|
||||
SettingsInfo = s;
|
||||
}
|
||||
|
||||
private static IReadOnlyCollection<NymaSettingsInfo.MednaSetting> ExtraSettings = new List<NymaSettingsInfo.MednaSetting>
|
||||
{
|
||||
new NymaSettingsInfo.MednaSetting
|
||||
{
|
||||
Name = "Initial Time",
|
||||
Description = "Initial time of emulation. Only relevant when UseRealTime is false.\nEnter as IS0-8601.",
|
||||
SettingsKey = "nyma.rtcinitialtime",
|
||||
DefaultValue = "2010-01-01",
|
||||
Flags = NymaSettingsInfo.MednaSetting.SettingFlags.EMU_STATE,
|
||||
Type = NymaSettingsInfo.MednaSetting.SettingType.STRING
|
||||
},
|
||||
new NymaSettingsInfo.MednaSetting
|
||||
{
|
||||
Name = "Use RealTime",
|
||||
Description = "If true, RTC clock will be based off of real time instead of emulated time. Ignored (set to false) when recording a movie.",
|
||||
SettingsKey = "nyma.rtcrealtime",
|
||||
DefaultValue = "0",
|
||||
Flags = NymaSettingsInfo.MednaSetting.SettingFlags.EMU_STATE,
|
||||
Type = NymaSettingsInfo.MednaSetting.SettingType.BOOL
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
}
|
||||
|
||||
private LibNymaCore _nyma;
|
||||
protected T DoInit<T>(GameInfo game, byte[] rom, Disc[] discs, string wbxFilename, string extension,
|
||||
protected T DoInit<T>(GameInfo game, byte[] rom, Disc[] discs, string wbxFilename, string extension, bool deterministic,
|
||||
ICollection<KeyValuePair<string, byte[]>> firmwares = null)
|
||||
where T : LibNymaCore
|
||||
{
|
||||
|
@ -115,12 +115,25 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
|
||||
InitControls();
|
||||
_nyma.SetFrontendSettingQuery(null);
|
||||
if (_disks != null)
|
||||
_nyma.SetCDCallbacks(null, null);
|
||||
PostInit();
|
||||
SettingsInfo.LayerNames = GetLayerData();
|
||||
_nyma.SetFrontendSettingQuery(_settingsQueryDelegate);
|
||||
if (_disks != null)
|
||||
_nyma.SetCDCallbacks(_cdTocCallback, _cdSectorCallback);
|
||||
PutSettings(_settings);
|
||||
DateTime RtcStart = DateTime.Parse("2010-01-01");
|
||||
try
|
||||
{
|
||||
RtcStart = DateTime.Parse(SettingsQuery("nyma.rtcinitialtime"));
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.Error.WriteLine($"Couldn't parse DateTime \"{SettingsQuery("nyma.rtcinitialtime")}\"");
|
||||
}
|
||||
DeterministicEmulation = deterministic || SettingsQuery("nyma.rtcrealtime") == "0";
|
||||
InitializeRtc(RtcStart);
|
||||
}
|
||||
|
||||
return t;
|
||||
|
@ -129,6 +142,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
protected override void LoadStateBinaryInternal(BinaryReader reader)
|
||||
{
|
||||
_nyma.SetFrontendSettingQuery(_settingsQueryDelegate);
|
||||
if (_disks != null)
|
||||
_nyma.SetCDCallbacks(_cdTocCallback, _cdSectorCallback);
|
||||
}
|
||||
|
||||
|
@ -149,7 +163,8 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
: controller.IsPressed("Reset")
|
||||
? LibNymaCore.CommandType.RESET
|
||||
: LibNymaCore.CommandType.NONE,
|
||||
InputPortData = (byte*)_frameAdvanceInputLock.AddrOfPinnedObject()
|
||||
InputPortData = (byte*)_frameAdvanceInputLock.AddrOfPinnedObject(),
|
||||
FrontendTime = GetRtcTime(SettingsQuery("nyma.rtcrealtime") != "0"),
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# These are already ignored, but for some reason vscode won't pick it up
|
||||
# and stop showing me things I don't want to see without this
|
||||
/obj
|
|
@ -5,6 +5,7 @@
|
|||
#include "mednafen/src/mempatcher.h"
|
||||
#include "mednafen/src/mednafen-driver.h"
|
||||
#include "mednafen/src/player.h"
|
||||
#include "mednafen/src/Time.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
@ -193,4 +194,30 @@ namespace Mednafen
|
|||
{}
|
||||
void Player_Draw(MDFN_Surface *surface, MDFN_Rect *dr, int CurrentSong, int16 *samples, int32 sampcount)
|
||||
{}
|
||||
|
||||
namespace Time
|
||||
{
|
||||
void Time_Init(void)
|
||||
{}
|
||||
int64 EpochTime(void)
|
||||
{
|
||||
return FrontendTime;
|
||||
}
|
||||
struct tm LocalTime(const int64 ept)
|
||||
{
|
||||
// musl's localtime_r gets into a lot of unfun syscalls, and we wouldn't allow changable timezone anyway
|
||||
return UTCTime(ept);
|
||||
}
|
||||
struct tm UTCTime(const int64 ept)
|
||||
{
|
||||
struct tm tout;
|
||||
time_t tt = (time_t)ept;
|
||||
if(!gmtime_r(&tt, &tout))
|
||||
{
|
||||
ErrnoHolder ene(errno);
|
||||
throw MDFN_Error(ene.Errno(), _("%s failed: %s"), "gmtime_r()", ene.StrError());
|
||||
}
|
||||
return tout;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ static uint8_t InputPortData[(MAX_PORTS + 1) * MAX_PORT_DATA];
|
|||
|
||||
bool LagFlag;
|
||||
void (*InputCallback)();
|
||||
int64_t FrontendTime = 1555555555555;
|
||||
|
||||
ECL_EXPORT void PreInit()
|
||||
{
|
||||
|
@ -36,8 +37,8 @@ ECL_EXPORT void PreInit()
|
|||
|
||||
static void Setup()
|
||||
{
|
||||
pixels = new uint32_t[Game->fb_width * Game->fb_height];
|
||||
samples = new int16_t[22050 * 2];
|
||||
pixels = (uint32_t*)alloc_invisible(Game->fb_width * Game->fb_height * sizeof(*pixels));
|
||||
samples = (int16_t*)alloc_invisible(22050 * 2 * sizeof(*samples));
|
||||
Surf = new MDFN_Surface(
|
||||
pixels, Game->fb_width, Game->fb_height, Game->fb_width,
|
||||
MDFN_PixelFormat(MDFN_COLORSPACE_RGB, 16, 8, 0, 24)
|
||||
|
@ -105,10 +106,12 @@ struct MyFrameInfo: public FrameInfo
|
|||
int32_t Command;
|
||||
// raw data for each input port, assumed to be MAX_PORTS * MAX_PORT_DATA long
|
||||
uint8_t* InputPortData;
|
||||
int64_t FrontendTime;
|
||||
};
|
||||
|
||||
ECL_EXPORT void FrameAdvance(MyFrameInfo& frame)
|
||||
{
|
||||
FrontendTime = frame.FrontendTime;
|
||||
LagFlag = true;
|
||||
EES->skip = frame.SkipRendering;
|
||||
|
||||
|
@ -117,6 +120,7 @@ ECL_EXPORT void FrameAdvance(MyFrameInfo& frame)
|
|||
|
||||
memcpy(InputPortData, frame.InputPortData, sizeof(InputPortData));
|
||||
|
||||
if (Game->TransformInput)
|
||||
Game->TransformInput();
|
||||
Game->Emulate(EES);
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
#include <stdlib.h>
|
||||
#include <emulibc.h>
|
||||
|
||||
// for systems that do not include cds, we need just a bit of stub code
|
||||
|
||||
void StartGameWithCds(int numdisks)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
ECL_EXPORT void SetCDCallbacks()
|
||||
{
|
||||
abort();
|
||||
}
|
|
@ -39,7 +39,6 @@ SRCS := \
|
|||
mednafen/src/file.cpp \
|
||||
mednafen/src/NativeVFS.cpp \
|
||||
mednafen/src/IPSPatcher.cpp \
|
||||
mednafen/src/Time.cpp \
|
||||
mednafen/src/git.cpp \
|
||||
mednafen/src/endian.cpp \
|
||||
$(call cppdir,string) \
|
||||
|
|
|
@ -16,3 +16,4 @@ CheatArea* FindCheatArea(uint32_t address);
|
|||
|
||||
extern bool LagFlag;
|
||||
extern void (*InputCallback)();
|
||||
extern int64_t FrontendTime;
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit fe36c52dffe228848e41680d7d4008e76816c381
|
||||
Subproject commit 593da4feb3846c476973d93f44b20f493a44738f
|
|
@ -2,6 +2,8 @@
|
|||
#include "nyma.h"
|
||||
#include <emulibc.h>
|
||||
#include "mednafen/src/ngp/neopop.h"
|
||||
#include <src/ngp/flash.h>
|
||||
#include <waterboxcore.h>
|
||||
|
||||
using namespace MDFN_IEN_NGP;
|
||||
|
||||
|
@ -11,3 +13,51 @@ void SetupMDFNGameInfo()
|
|||
{
|
||||
Mednafen::MDFNGameInfo = &EmulatedNGP;
|
||||
}
|
||||
|
||||
ECL_EXPORT bool GetSaveRam()
|
||||
{
|
||||
try
|
||||
{
|
||||
FLASH_SaveNV();
|
||||
return true;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
ECL_EXPORT bool PutSaveRam()
|
||||
{
|
||||
try
|
||||
{
|
||||
FLASH_LoadNV();
|
||||
return true;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
namespace MDFN_IEN_NGP
|
||||
{
|
||||
extern uint8 CPUExRAM[16384];
|
||||
}
|
||||
|
||||
ECL_EXPORT void GetMemoryAreas(MemoryArea* m)
|
||||
{
|
||||
m[0].Data = CPUExRAM;
|
||||
m[0].Name = "RAM";
|
||||
m[0].Size = 16384;
|
||||
m[0].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_PRIMARY | MEMORYAREA_FLAGS_WORDSIZE4;
|
||||
|
||||
m[1].Data = ngpc_rom.data;
|
||||
m[1].Name = "ROM";
|
||||
m[1].Size = ngpc_rom.length;
|
||||
m[1].Flags = MEMORYAREA_FLAGS_WORDSIZE4;
|
||||
|
||||
m[2].Data = ngpc_rom.orig_data;
|
||||
m[2].Name = "ORIGINAL ROM";
|
||||
m[2].Size = ngpc_rom.length;
|
||||
m[2].Flags = MEMORYAREA_FLAGS_WORDSIZE4;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ include common.mak
|
|||
SRCS += \
|
||||
$(call cppdir,ngp) \
|
||||
$(call cppdir,hw_cpu/z80-fuse) \
|
||||
cdrom_dummy.cpp \
|
||||
ngp.cpp
|
||||
|
||||
include ../common.mak
|
||||
|
|
Loading…
Reference in New Issue