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,
|
nextEmulator = new TerboGrafix(game, new[] { disc }, nextComm,
|
||||||
(Emulation.Cores.Waterbox.NymaCore.NymaSettings)GetCoreSettings<TerboGrafix>(),
|
(Emulation.Cores.Waterbox.NymaCore.NymaSettings)GetCoreSettings<TerboGrafix>(),
|
||||||
(Emulation.Cores.Waterbox.NymaCore.NymaSyncSettings)GetCoreSyncSettings<TerboGrafix>());
|
(Emulation.Cores.Waterbox.NymaCore.NymaSyncSettings)GetCoreSyncSettings<TerboGrafix>(), Deterministic);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -11,22 +11,22 @@ using BizHawk.Emulation.DiscSystem;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Consoles.NEC.PCE
|
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
|
public class TerboGrafix : NymaCore, IRegionable, IPceGpuView
|
||||||
{
|
{
|
||||||
private readonly LibTerboGrafix _terboGrafix;
|
private readonly LibTerboGrafix _terboGrafix;
|
||||||
|
|
||||||
[CoreConstructor(new[] { "PCE", "SGX" })]
|
[CoreConstructor(new[] { "PCE", "SGX" })]
|
||||||
public TerboGrafix(GameInfo game, byte[] rom, CoreComm comm, string extension,
|
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)
|
: base(comm, "PCE", "PC Engine Controller", settings, syncSettings)
|
||||||
{
|
{
|
||||||
if (game["BRAM"])
|
if (game["BRAM"])
|
||||||
SettingsOverrides["pce.disable_bram_hucard"] = "0";
|
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,
|
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)
|
: base(comm, "PCE", "PC Engine Controller", settings, syncSettings)
|
||||||
{
|
{
|
||||||
var firmwares = new Dictionary<string, byte[]>();
|
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));
|
firmwares.Add("FIRMWARE:syscard3.pce", comm.CoreFileProvider.GetFirmware("PCECD", "Bios", true));
|
||||||
if (types.Contains(DiscType.TurboGECD))
|
if (types.Contains(DiscType.TurboGECD))
|
||||||
firmwares.Add("FIRMWARE:gecard.pce", comm.CoreFileProvider.GetFirmware("PCECD", "GE-Bios", true));
|
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";
|
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
|
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)]
|
[BizImport(CC)]
|
||||||
public abstract bool LoadSystem(byte[] rom, int romlength, Language language);
|
public abstract bool GetSaveRam();
|
||||||
[BizImport(CC)]
|
[BizImport(CC)]
|
||||||
public abstract void SetLayers(int enable); // 1, 2, 4 bg,fg,sprites
|
public abstract bool PutSaveRam();
|
||||||
[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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,188 +9,47 @@ using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Consoles.SNK
|
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)]
|
"https://mednafen.github.io/releases/", false)]
|
||||||
public class NeoGeoPort : WaterboxCore,
|
public class NeoGeoPort : NymaCore,
|
||||||
ISaveRam, // NGP provides its own saveram interface
|
ISaveRam // NGP provides its own saveram interface
|
||||||
ISettable<object, NeoGeoPort.SyncSettings>
|
|
||||||
{
|
{
|
||||||
internal LibNeoGeoPort _neopop;
|
private readonly LibNeoGeoPort _neopop;
|
||||||
|
|
||||||
[CoreConstructor("NGP")]
|
[CoreConstructor("NGP")]
|
||||||
public NeoGeoPort(CoreComm comm, byte[] rom, SyncSettings syncSettings, bool deterministic)
|
public NeoGeoPort(CoreComm comm, byte[] rom, GameInfo game,
|
||||||
: this(comm, rom, syncSettings, deterministic, WaterboxHost.CanonicalStart)
|
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)
|
public new bool SaveRamModified
|
||||||
:base(comm, new Configuration
|
|
||||||
{
|
|
||||||
DefaultFpsNumerator = 6144000,
|
|
||||||
DefaultFpsDenominator = 515 * 198,
|
|
||||||
DefaultWidth = 160,
|
|
||||||
DefaultHeight = 152,
|
|
||||||
MaxWidth = 160,
|
|
||||||
MaxHeight = 152,
|
|
||||||
MaxSamples = 8192,
|
|
||||||
SystemId = "NGP"
|
|
||||||
})
|
|
||||||
{
|
{
|
||||||
if (rom.Length > 4 * 1024 * 1024)
|
get
|
||||||
throw new InvalidOperationException("ROM too big!");
|
|
||||||
|
|
||||||
_syncSettings = syncSettings ?? new SyncSettings();
|
|
||||||
|
|
||||||
_neopop = PreInit<LibNeoGeoPort>(new WaterboxOptions
|
|
||||||
{
|
{
|
||||||
Filename = "ngp.wbx",
|
_exe.AddTransientFile(new byte[0], "SAV:flash");
|
||||||
SbrkHeapSizeKB = 256,
|
if (!_neopop.GetSaveRam())
|
||||||
SealedHeapSizeKB = 5 * 1024, // must be a bit larger than the ROM size
|
throw new InvalidOperationException("Error divining saveram");
|
||||||
InvisibleHeapSizeKB = 4,
|
return _exe.RemoveTransientFile("SAV:flash").Length > 0;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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()
|
public new byte[] CloneSaveRam()
|
||||||
{
|
{
|
||||||
byte[] ret = null;
|
_exe.AddTransientFile(new byte[0], "SAV:flash");
|
||||||
_neopop.GetSaveRam((data, size) =>
|
|
||||||
{
|
if (!_neopop.GetSaveRam())
|
||||||
ret = new byte[size];
|
throw new InvalidOperationException("Error returning saveram");
|
||||||
Marshal.Copy(data, ret, 0, size);
|
return _exe.RemoveTransientFile("SAV:flash");
|
||||||
});
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public new void StoreSaveRam(byte[] data)
|
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");
|
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
|
/// raw data for each input port, assumed to be MAX_PORTS * MAX_PORT_DATA long
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte* InputPortData;
|
public byte* InputPortData;
|
||||||
|
/// <summary>
|
||||||
|
/// If the core calls time functions, this is the value that will be used
|
||||||
|
/// </summary>
|
||||||
|
public long FrontendTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
@ -77,7 +78,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
return new NymaSyncSettings
|
return new NymaSyncSettings
|
||||||
{
|
{
|
||||||
MednafenValues = new Dictionary<string, string>(MednafenValues),
|
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);
|
SettingsOverrides.TryGetValue(name, out var val);
|
||||||
if (val == null)
|
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);
|
var bytes = Encoding.UTF8.GetBytes(val);
|
||||||
if (bytes.Length > 255)
|
if (bytes.Length > 255)
|
||||||
throw new InvalidOperationException($"Value {val} for setting {name} was too long");
|
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);
|
Value = Mershul.PtrToStringUtf8(s.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public MednaSetting()
|
||||||
|
{}
|
||||||
public MednaSetting(MednaSettingS s)
|
public MednaSetting(MednaSettingS s)
|
||||||
{
|
{
|
||||||
Name = Mershul.PtrToStringUtf8(s.Name);
|
Name = Mershul.PtrToStringUtf8(s.Name);
|
||||||
|
@ -320,7 +328,34 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
}
|
}
|
||||||
|
|
||||||
s.HiddenSettings = new HashSet<string>(SettingsOverrides.Keys);
|
s.HiddenSettings = new HashSet<string>(SettingsOverrides.Keys);
|
||||||
|
foreach (var ss in ExtraSettings)
|
||||||
|
{
|
||||||
|
s.Settings.Add(ss);
|
||||||
|
s.SettingsByKey.Add(ss.SettingsKey, ss);
|
||||||
|
}
|
||||||
SettingsInfo = s;
|
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;
|
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)
|
ICollection<KeyValuePair<string, byte[]>> firmwares = null)
|
||||||
where T : LibNymaCore
|
where T : LibNymaCore
|
||||||
{
|
{
|
||||||
|
@ -115,12 +115,25 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
|
|
||||||
InitControls();
|
InitControls();
|
||||||
_nyma.SetFrontendSettingQuery(null);
|
_nyma.SetFrontendSettingQuery(null);
|
||||||
_nyma.SetCDCallbacks(null, null);
|
if (_disks != null)
|
||||||
|
_nyma.SetCDCallbacks(null, null);
|
||||||
PostInit();
|
PostInit();
|
||||||
SettingsInfo.LayerNames = GetLayerData();
|
SettingsInfo.LayerNames = GetLayerData();
|
||||||
_nyma.SetFrontendSettingQuery(_settingsQueryDelegate);
|
_nyma.SetFrontendSettingQuery(_settingsQueryDelegate);
|
||||||
_nyma.SetCDCallbacks(_cdTocCallback, _cdSectorCallback);
|
if (_disks != null)
|
||||||
|
_nyma.SetCDCallbacks(_cdTocCallback, _cdSectorCallback);
|
||||||
PutSettings(_settings);
|
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;
|
return t;
|
||||||
|
@ -129,7 +142,8 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
protected override void LoadStateBinaryInternal(BinaryReader reader)
|
protected override void LoadStateBinaryInternal(BinaryReader reader)
|
||||||
{
|
{
|
||||||
_nyma.SetFrontendSettingQuery(_settingsQueryDelegate);
|
_nyma.SetFrontendSettingQuery(_settingsQueryDelegate);
|
||||||
_nyma.SetCDCallbacks(_cdTocCallback, _cdSectorCallback);
|
if (_disks != null)
|
||||||
|
_nyma.SetCDCallbacks(_cdTocCallback, _cdSectorCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: bleh
|
// todo: bleh
|
||||||
|
@ -149,7 +163,8 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
: controller.IsPressed("Reset")
|
: controller.IsPressed("Reset")
|
||||||
? LibNymaCore.CommandType.RESET
|
? LibNymaCore.CommandType.RESET
|
||||||
: LibNymaCore.CommandType.NONE,
|
: LibNymaCore.CommandType.NONE,
|
||||||
InputPortData = (byte*)_frameAdvanceInputLock.AddrOfPinnedObject()
|
InputPortData = (byte*)_frameAdvanceInputLock.AddrOfPinnedObject(),
|
||||||
|
FrontendTime = GetRtcTime(SettingsQuery("nyma.rtcrealtime") != "0"),
|
||||||
};
|
};
|
||||||
return ret;
|
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/mempatcher.h"
|
||||||
#include "mednafen/src/mednafen-driver.h"
|
#include "mednafen/src/mednafen-driver.h"
|
||||||
#include "mednafen/src/player.h"
|
#include "mednafen/src/player.h"
|
||||||
|
#include "mednafen/src/Time.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.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)
|
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;
|
bool LagFlag;
|
||||||
void (*InputCallback)();
|
void (*InputCallback)();
|
||||||
|
int64_t FrontendTime = 1555555555555;
|
||||||
|
|
||||||
ECL_EXPORT void PreInit()
|
ECL_EXPORT void PreInit()
|
||||||
{
|
{
|
||||||
|
@ -36,8 +37,8 @@ ECL_EXPORT void PreInit()
|
||||||
|
|
||||||
static void Setup()
|
static void Setup()
|
||||||
{
|
{
|
||||||
pixels = new uint32_t[Game->fb_width * Game->fb_height];
|
pixels = (uint32_t*)alloc_invisible(Game->fb_width * Game->fb_height * sizeof(*pixels));
|
||||||
samples = new int16_t[22050 * 2];
|
samples = (int16_t*)alloc_invisible(22050 * 2 * sizeof(*samples));
|
||||||
Surf = new MDFN_Surface(
|
Surf = new MDFN_Surface(
|
||||||
pixels, Game->fb_width, Game->fb_height, Game->fb_width,
|
pixels, Game->fb_width, Game->fb_height, Game->fb_width,
|
||||||
MDFN_PixelFormat(MDFN_COLORSPACE_RGB, 16, 8, 0, 24)
|
MDFN_PixelFormat(MDFN_COLORSPACE_RGB, 16, 8, 0, 24)
|
||||||
|
@ -105,10 +106,12 @@ struct MyFrameInfo: public FrameInfo
|
||||||
int32_t Command;
|
int32_t Command;
|
||||||
// raw data for each input port, assumed to be MAX_PORTS * MAX_PORT_DATA long
|
// raw data for each input port, assumed to be MAX_PORTS * MAX_PORT_DATA long
|
||||||
uint8_t* InputPortData;
|
uint8_t* InputPortData;
|
||||||
|
int64_t FrontendTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
ECL_EXPORT void FrameAdvance(MyFrameInfo& frame)
|
ECL_EXPORT void FrameAdvance(MyFrameInfo& frame)
|
||||||
{
|
{
|
||||||
|
FrontendTime = frame.FrontendTime;
|
||||||
LagFlag = true;
|
LagFlag = true;
|
||||||
EES->skip = frame.SkipRendering;
|
EES->skip = frame.SkipRendering;
|
||||||
|
|
||||||
|
@ -117,7 +120,8 @@ ECL_EXPORT void FrameAdvance(MyFrameInfo& frame)
|
||||||
|
|
||||||
memcpy(InputPortData, frame.InputPortData, sizeof(InputPortData));
|
memcpy(InputPortData, frame.InputPortData, sizeof(InputPortData));
|
||||||
|
|
||||||
Game->TransformInput();
|
if (Game->TransformInput)
|
||||||
|
Game->TransformInput();
|
||||||
Game->Emulate(EES);
|
Game->Emulate(EES);
|
||||||
|
|
||||||
EES->VideoFormatChanged = false;
|
EES->VideoFormatChanged = false;
|
||||||
|
|
|
@ -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/file.cpp \
|
||||||
mednafen/src/NativeVFS.cpp \
|
mednafen/src/NativeVFS.cpp \
|
||||||
mednafen/src/IPSPatcher.cpp \
|
mednafen/src/IPSPatcher.cpp \
|
||||||
mednafen/src/Time.cpp \
|
|
||||||
mednafen/src/git.cpp \
|
mednafen/src/git.cpp \
|
||||||
mednafen/src/endian.cpp \
|
mednafen/src/endian.cpp \
|
||||||
$(call cppdir,string) \
|
$(call cppdir,string) \
|
||||||
|
|
|
@ -16,3 +16,4 @@ CheatArea* FindCheatArea(uint32_t address);
|
||||||
|
|
||||||
extern bool LagFlag;
|
extern bool LagFlag;
|
||||||
extern void (*InputCallback)();
|
extern void (*InputCallback)();
|
||||||
|
extern int64_t FrontendTime;
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit fe36c52dffe228848e41680d7d4008e76816c381
|
Subproject commit 593da4feb3846c476973d93f44b20f493a44738f
|
|
@ -2,6 +2,8 @@
|
||||||
#include "nyma.h"
|
#include "nyma.h"
|
||||||
#include <emulibc.h>
|
#include <emulibc.h>
|
||||||
#include "mednafen/src/ngp/neopop.h"
|
#include "mednafen/src/ngp/neopop.h"
|
||||||
|
#include <src/ngp/flash.h>
|
||||||
|
#include <waterboxcore.h>
|
||||||
|
|
||||||
using namespace MDFN_IEN_NGP;
|
using namespace MDFN_IEN_NGP;
|
||||||
|
|
||||||
|
@ -11,3 +13,51 @@ void SetupMDFNGameInfo()
|
||||||
{
|
{
|
||||||
Mednafen::MDFNGameInfo = &EmulatedNGP;
|
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 += \
|
SRCS += \
|
||||||
$(call cppdir,ngp) \
|
$(call cppdir,ngp) \
|
||||||
$(call cppdir,hw_cpu/z80-fuse) \
|
$(call cppdir,hw_cpu/z80-fuse) \
|
||||||
|
cdrom_dummy.cpp \
|
||||||
ngp.cpp
|
ngp.cpp
|
||||||
|
|
||||||
include ../common.mak
|
include ../common.mak
|
||||||
|
|
Loading…
Reference in New Issue