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:
nattthebear 2020-05-27 18:42:51 -04:00
parent bf544e02fa
commit 2afe356fc9
18 changed files with 195 additions and 552 deletions

Binary file not shown.

View File

@ -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;

View File

@ -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";

View File

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

View File

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

View File

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

View File

@ -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>

View File

@ -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
},
};
}
}

View File

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

3
waterbox/nyma/.gitignore vendored Normal file
View File

@ -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

View File

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

View File

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

View File

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

View File

@ -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) \

View File

@ -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

View File

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

View File

@ -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