diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
index 569944da34..9897fac5b4 100644
--- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
+++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
@@ -1210,8 +1210,8 @@
-
-
+
+
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/VB/VirtualBoyee.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/VB/VirtualBoyee.cs
index d4b03d898a..439fab0884 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/VB/VirtualBoyee.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/VB/VirtualBoyee.cs
@@ -225,7 +225,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.VB
#endregion
- // TODO
public int LagCount { get; set; }
public bool IsLagFrame { get; set; }
diff --git a/BizHawk.Emulation.Cores/Consoles/SNK/LibNeoGeo.cs b/BizHawk.Emulation.Cores/Consoles/SNK/LibNeoGeoPort.cs
similarity index 80%
rename from BizHawk.Emulation.Cores/Consoles/SNK/LibNeoGeo.cs
rename to BizHawk.Emulation.Cores/Consoles/SNK/LibNeoGeoPort.cs
index b0bfb58289..f5ccba49e6 100644
--- a/BizHawk.Emulation.Cores/Consoles/SNK/LibNeoGeo.cs
+++ b/BizHawk.Emulation.Cores/Consoles/SNK/LibNeoGeoPort.cs
@@ -8,16 +8,19 @@ using System.Threading.Tasks;
namespace BizHawk.Emulation.Cores.Consoles.SNK
{
- public abstract class LibNeoGeo
+ public abstract class LibNeoGeoPort
{
private const CallingConvention CC = CallingConvention.Cdecl;
+ [UnmanagedFunctionPointer(CC)]
+ public delegate void InputCallback();
[StructLayout(LayoutKind.Sequential)]
public class EmulateSpec
{
public IntPtr Pixels;
public IntPtr SoundBuff;
public long MasterCycles;
+ public long FrontendTime;
public int SoundBufMaxSize;
public int SoundBufSize;
public int SkipRendering;
@@ -32,5 +35,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SNK
public abstract void FrameAdvance([In, Out]EmulateSpec espec);
[BizImport(CC)]
public abstract void HardReset();
+ [BizImport(CC)]
+ public abstract void SetInputCallback(InputCallback callback);
}
}
diff --git a/BizHawk.Emulation.Cores/Consoles/SNK/NeoGeo.cs b/BizHawk.Emulation.Cores/Consoles/SNK/NeoGeo.cs
deleted file mode 100644
index e648568c30..0000000000
--- a/BizHawk.Emulation.Cores/Consoles/SNK/NeoGeo.cs
+++ /dev/null
@@ -1,153 +0,0 @@
-using BizHawk.Common.BizInvoke;
-using BizHawk.Emulation.Common;
-using BizHawk.Emulation.Cores.Waterbox;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace BizHawk.Emulation.Cores.Consoles.SNK
-{
- [CoreAttributes("NeoPop", "Thomas Klausner", true, false, "0.9.44.1",
- "https://mednafen.github.io/releases/", false)]
- public class NeoGeo : IEmulator, IVideoProvider, ISoundProvider
- {
- private PeRunner _exe;
- private LibNeoGeo _neopop;
-
- [CoreConstructor("NGP")]
- public NeoGeo(CoreComm comm, byte[] rom)
- {
- ServiceProvider = new BasicServiceProvider(this);
- CoreComm = comm;
-
- _exe = new PeRunner(new PeRunnerOptions
- {
- Path = comm.CoreFileProvider.DllPath(),
- Filename = "ngp.wbx",
- SbrkHeapSizeKB = 16 * 1024,
- SealedHeapSizeKB = 16 * 1024,
- InvisibleHeapSizeKB = 16 * 1024,
- PlainHeapSizeKB = 16 * 1024,
- MmapHeapSizeKB = 16 * 1024
- });
-
- _neopop = BizInvoker.GetInvoker(_exe, _exe);
-
- if (!_neopop.LoadSystem(rom, rom.Length, 1))
- {
- throw new InvalidOperationException("Core rejected the rom");
- }
-
- _exe.Seal();
- }
-
- public unsafe void FrameAdvance(IController controller, bool render, bool rendersound = true)
- {
- if (controller.IsPressed("Power"))
- _neopop.HardReset();
-
- fixed (int* vp = _videoBuffer)
- fixed (short* sp = _soundBuffer)
- {
- var spec = new LibNeoGeo.EmulateSpec
- {
- Pixels = (IntPtr)vp,
- SoundBuff = (IntPtr)sp,
- SoundBufMaxSize = _soundBuffer.Length / 2,
- Buttons = 0,
- SkipRendering = render ? 0 : 1
- };
-
- _neopop.FrameAdvance(spec);
- _numSamples = spec.SoundBufSize;
-
- Frame++;
-
- /*IsLagFrame = spec.Lagged;
- if (IsLagFrame)
- LagCount++;*/
- }
- }
-
- private bool _disposed = false;
-
- public void Dispose()
- {
- if (!_disposed)
- {
- _exe.Dispose();
- _exe = null;
- _disposed = true;
- }
- }
-
- public int Frame { get; private set; }
-
- public void ResetCounters()
- {
- Frame = 0;
- }
-
- public IEmulatorServiceProvider ServiceProvider { get; private set; }
- public string SystemId { get { return "NGP"; } }
- public bool DeterministicEmulation { get { return true; } }
- public CoreComm CoreComm { get; }
-
- public ControllerDefinition ControllerDefinition => NullController.Instance.Definition;
-
- #region IVideoProvider
-
- private int[] _videoBuffer = new int[160 * 152];
-
- public int[] GetVideoBuffer()
- {
- return _videoBuffer;
- }
-
- public int VirtualWidth => 160;
- public int VirtualHeight => 152;
- public int BufferWidth => 160;
- public int BufferHeight => 152;
- public int VsyncNumerator { get; private set; } = 6144000;
- public int VsyncDenominator { get; private set; } = 515 * 198;
- public int BackgroundColor => unchecked((int)0xff000000);
-
- #endregion
-
- #region ISoundProvider
-
- private short[] _soundBuffer = new short[16384];
- private int _numSamples;
-
- public void SetSyncMode(SyncSoundMode mode)
- {
- if (mode == SyncSoundMode.Async)
- {
- throw new NotSupportedException("Async mode is not supported.");
- }
- }
-
- public void GetSamplesSync(out short[] samples, out int nsamp)
- {
- samples = _soundBuffer;
- nsamp = _numSamples;
- }
-
- public void GetSamplesAsync(short[] samples)
- {
- throw new InvalidOperationException("Async mode is not supported.");
- }
-
- public void DiscardSamples()
- {
- }
-
- public bool CanProvideAsync => false;
-
- public SyncSoundMode SyncMode => SyncSoundMode.Sync;
-
- #endregion
- }
-}
diff --git a/BizHawk.Emulation.Cores/Consoles/SNK/NeoGeoPort.cs b/BizHawk.Emulation.Cores/Consoles/SNK/NeoGeoPort.cs
new file mode 100644
index 0000000000..f7b1b44242
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Consoles/SNK/NeoGeoPort.cs
@@ -0,0 +1,261 @@
+using BizHawk.Common.BizInvoke;
+using BizHawk.Common.BufferExtensions;
+using BizHawk.Emulation.Common;
+using BizHawk.Emulation.Cores.Waterbox;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BizHawk.Emulation.Cores.Consoles.SNK
+{
+ [CoreAttributes("NeoPop", "Thomas Klausner", true, false, "0.9.44.1",
+ "https://mednafen.github.io/releases/", false)]
+ public class NeoGeoPort : IEmulator, IVideoProvider, ISoundProvider, IStatable, IInputPollable
+ {
+ private PeRunner _exe;
+ private LibNeoGeoPort _neopop;
+
+ [CoreConstructor("NGP")]
+ public NeoGeoPort(CoreComm comm, byte[] rom)
+ {
+ ServiceProvider = new BasicServiceProvider(this);
+ CoreComm = comm;
+
+ _exe = new PeRunner(new PeRunnerOptions
+ {
+ Path = comm.CoreFileProvider.DllPath(),
+ Filename = "ngp.wbx",
+ SbrkHeapSizeKB = 256,
+ SealedHeapSizeKB = 10 * 1024, // must be a bit larger than twice the ROM size
+ InvisibleHeapSizeKB = 4,
+ PlainHeapSizeKB = 4
+ });
+
+ _neopop = BizInvoker.GetInvoker(_exe, _exe);
+
+ if (!_neopop.LoadSystem(rom, rom.Length, 1))
+ {
+ throw new InvalidOperationException("Core rejected the rom");
+ }
+
+ _exe.Seal();
+
+ _inputCallback = InputCallbacks.Call;
+ }
+
+ public unsafe void FrameAdvance(IController controller, bool render, bool rendersound = true)
+ {
+ _neopop.SetInputCallback(InputCallbacks.Count > 0 ? _inputCallback : null);
+
+ if (controller.IsPressed("Power"))
+ _neopop.HardReset();
+
+ fixed (int* vp = _videoBuffer)
+ fixed (short* sp = _soundBuffer)
+ {
+ var spec = new LibNeoGeoPort.EmulateSpec
+ {
+ Pixels = (IntPtr)vp,
+ SoundBuff = (IntPtr)sp,
+ SoundBufMaxSize = _soundBuffer.Length / 2,
+ Buttons = GetButtons(controller),
+ SkipRendering = render ? 0 : 1
+ };
+
+ _neopop.FrameAdvance(spec);
+ _numSamples = spec.SoundBufSize;
+
+ Frame++;
+
+ IsLagFrame = spec.Lagged != 0;
+ if (IsLagFrame)
+ LagCount++;
+ }
+ }
+
+ private bool _disposed = false;
+
+ public void Dispose()
+ {
+ if (!_disposed)
+ {
+ _exe.Dispose();
+ _exe = null;
+ _disposed = true;
+ }
+ }
+
+ public int Frame { get; private set; }
+ public int LagCount { get; set; }
+ public bool IsLagFrame { get; set; }
+ public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem();
+ private LibNeoGeoPort.InputCallback _inputCallback;
+
+ public void ResetCounters()
+ {
+ Frame = 0;
+ }
+
+ public IEmulatorServiceProvider ServiceProvider { get; private set; }
+ public string SystemId { get { return "NGP"; } }
+ public bool DeterministicEmulation { get { return true; } }
+ public CoreComm CoreComm { get; }
+
+ #region IStatable
+
+ public bool BinarySaveStatesPreferred
+ {
+ get { return true; }
+ }
+
+ public void SaveStateText(TextWriter writer)
+ {
+ var temp = SaveStateBinary();
+ temp.SaveAsHexFast(writer);
+ // write extra copy of stuff we don't use
+ writer.WriteLine("Frame {0}", Frame);
+ }
+
+ public void LoadStateText(TextReader reader)
+ {
+ string hex = reader.ReadLine();
+ byte[] state = new byte[hex.Length / 2];
+ state.ReadFromHexFast(hex);
+ LoadStateBinary(new BinaryReader(new MemoryStream(state)));
+ }
+
+ public void LoadStateBinary(BinaryReader reader)
+ {
+ _exe.LoadStateBinary(reader);
+ // other variables
+ Frame = reader.ReadInt32();
+ LagCount = reader.ReadInt32();
+ IsLagFrame = reader.ReadBoolean();
+ // any managed pointers that we sent to the core need to be resent now!
+ _neopop.SetInputCallback(null);
+ }
+
+ public void SaveStateBinary(BinaryWriter writer)
+ {
+ _exe.SaveStateBinary(writer);
+ // other variables
+ writer.Write(Frame);
+ writer.Write(LagCount);
+ writer.Write(IsLagFrame);
+ }
+
+ public byte[] SaveStateBinary()
+ {
+ var ms = new MemoryStream();
+ var bw = new BinaryWriter(ms);
+ SaveStateBinary(bw);
+ bw.Flush();
+ ms.Close();
+ return ms.ToArray();
+ }
+
+ #endregion
+
+ #region Controller
+
+ 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 ButtonOrdinals = new Dictionary
+ {
+ ["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 ControllerDefinition ControllerDefinition => NeoGeoPortableController;
+
+ #endregion
+
+ #region IVideoProvider
+
+ private int[] _videoBuffer = new int[160 * 152];
+
+ public int[] GetVideoBuffer()
+ {
+ return _videoBuffer;
+ }
+
+ public int VirtualWidth => 160;
+ public int VirtualHeight => 152;
+ public int BufferWidth => 160;
+ public int BufferHeight => 152;
+ public int VsyncNumerator { get; private set; } = 6144000;
+ public int VsyncDenominator { get; private set; } = 515 * 198;
+ public int BackgroundColor => unchecked((int)0xff000000);
+
+ #endregion
+
+ #region ISoundProvider
+
+ private short[] _soundBuffer = new short[16384];
+ private int _numSamples;
+
+ public void SetSyncMode(SyncSoundMode mode)
+ {
+ if (mode == SyncSoundMode.Async)
+ {
+ throw new NotSupportedException("Async mode is not supported.");
+ }
+ }
+
+ public void GetSamplesSync(out short[] samples, out int nsamp)
+ {
+ samples = _soundBuffer;
+ nsamp = _numSamples;
+ }
+
+ public void GetSamplesAsync(short[] samples)
+ {
+ throw new InvalidOperationException("Async mode is not supported.");
+ }
+
+ public void DiscardSamples()
+ {
+ }
+
+ public bool CanProvideAsync => false;
+
+ public SyncSoundMode SyncMode => SyncSoundMode.Sync;
+
+ #endregion
+ }
+}
diff --git a/BizHawk.Emulation.Cores/Waterbox/PeRunner.cs b/BizHawk.Emulation.Cores/Waterbox/PeRunner.cs
index 3e04a91008..a15521678a 100644
--- a/BizHawk.Emulation.Cores/Waterbox/PeRunner.cs
+++ b/BizHawk.Emulation.Cores/Waterbox/PeRunner.cs
@@ -234,8 +234,8 @@ namespace BizHawk.Emulation.Cores.Waterbox
public void Init()
{
// as the inits are done in a defined order with a defined memory map,
- // we don't need to savestate _pthreadSelf
- _pthreadSelf = Z.US(_parent._plainheap.Allocate(65536, 1));
+ // we don't need to savestate _pthreadSelf, only its contents
+ _pthreadSelf = Z.US(_parent._plainheap.Allocate(512, 1));
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "log_output")]
diff --git a/waterbox/ngp/.vscode/settings.json b/waterbox/ngp/.vscode/settings.json
index 109dd034cd..1035572a13 100644
--- a/waterbox/ngp/.vscode/settings.json
+++ b/waterbox/ngp/.vscode/settings.json
@@ -6,6 +6,7 @@
"algorithm": "cpp",
"vector": "cpp",
"xstring": "cpp",
- "xutility": "cpp"
+ "xutility": "cpp",
+ "xmemory0": "cpp"
}
}
\ No newline at end of file
diff --git a/waterbox/ngp/Makefile b/waterbox/ngp/Makefile
index 22aaf5b968..67181161a6 100644
--- a/waterbox/ngp/Makefile
+++ b/waterbox/ngp/Makefile
@@ -4,7 +4,7 @@ CCFLAGS:= -I. -I../emulibc \
-Wall -Werror=pointer-to-int-cast -Werror=int-to-pointer-cast -Werror=implicit-function-declaration \
-std=c++0x -fomit-frame-pointer -fvisibility=hidden -fno-exceptions -fno-rtti \
-DLSB_FIRST \
- -O0 -g
+ -O3 -flto
TARGET = ngp.wbx
diff --git a/waterbox/ngp/defs.h b/waterbox/ngp/defs.h
index 294dd421ec..08b902450b 100644
--- a/waterbox/ngp/defs.h
+++ b/waterbox/ngp/defs.h
@@ -52,6 +52,9 @@ struct EmulateSpecStruct
// Set by emulation code.
int64 MasterCycles;
+ // unix time for RTC
+ int64 FrontendTime;
+
// Maximum size of the sound buffer, in frames. Set by the driver code.
int32 SoundBufMaxSize;
diff --git a/waterbox/ngp/gfx.cpp b/waterbox/ngp/gfx.cpp
index 36380ddd40..b9aece94b8 100644
--- a/waterbox/ngp/gfx.cpp
+++ b/waterbox/ngp/gfx.cpp
@@ -31,7 +31,7 @@ NGPGFX_CLASS::NGPGFX_CLASS(void)
int g = ((x >> 4) & 0xF) * 17;
int b = ((x >> 8) & 0xF) * 17;
- ColorMap[x] = r | g << 8 | b << 16 | 0xff000000;
+ ColorMap[x] = b | g << 8 | r << 16 | 0xff000000;
}
}
diff --git a/waterbox/ngp/mem.cpp b/waterbox/ngp/mem.cpp
index 82ab5c7a87..457eadffff 100644
--- a/waterbox/ngp/mem.cpp
+++ b/waterbox/ngp/mem.cpp
@@ -27,6 +27,8 @@
namespace MDFN_IEN_NGP
{
extern uint8 settings_language;
+extern bool lagged;
+extern void (*inputcallback)();
//Hack way of returning good Flash status.
bool FlashStatusEnable = FALSE;
@@ -200,6 +202,13 @@ uint8 loadB(uint32 address)
if (FastReadMap[address >> 16])
return (FastReadMap[address >> 16][address]);
+ if (address == 0x6f82)
+ {
+ lagged = false;
+ if (inputcallback)
+ inputcallback();
+ }
+
uint8 *ptr = (uint8 *)translate_address_read(address);
if (ptr)
@@ -255,6 +264,13 @@ uint16 loadW(uint32 address)
if (FastReadMap[address >> 16])
return (MDFN_de16lsb(&FastReadMap[address >> 16][address]));
+ if (address == 0x6f82)
+ {
+ lagged = false;
+ if (inputcallback)
+ inputcallback();
+ }
+
uint16 *ptr = (uint16 *)translate_address_read(address);
if (ptr)
return MDFN_de16lsb(ptr);
diff --git a/waterbox/ngp/neopop.cpp b/waterbox/ngp/neopop.cpp
index 81a0fff569..fd4528e7ea 100644
--- a/waterbox/ngp/neopop.cpp
+++ b/waterbox/ngp/neopop.cpp
@@ -27,6 +27,9 @@
namespace MDFN_IEN_NGP
{
+bool lagged;
+void (*inputcallback)();
+
extern uint8 CPUExRAM[16384];
@@ -72,11 +75,13 @@ static int32 z80_runtime;
static void Emulate(EmulateSpecStruct *espec)
{
+ lagged = true;
bool MeowMeow = 0;
MDFN_Surface surface;
surface.pixels = espec->pixels;
surface.pitch32 = 160;
+ frontend_time = espec->FrontendTime;
storeB(0x6f82, espec->Buttons);
ngpc_soundTS = 0;
@@ -115,6 +120,7 @@ static void Emulate(EmulateSpecStruct *espec)
espec->MasterCycles = ngpc_soundTS;
espec->SoundBufSize = MDFNNGPCSOUND_Flush(espec->SoundBuf, espec->SoundBufMaxSize);
+ espec->Lagged = lagged;
}
static MDFN_COLD bool Load(const uint8* romdata, int32 romlength)
@@ -126,7 +132,7 @@ static MDFN_COLD bool Load(const uint8* romdata, int32 romlength)
//throw MDFN_Error(0, _("NGP/NGPC ROM image is too large."));
ngpc_rom.length = fp_size;
- ngpc_rom.data = new uint8[ngpc_rom.length];
+ ngpc_rom.data = (uint8*)alloc_sealed(ngpc_rom.length);
memcpy(ngpc_rom.data, romdata, romlength);
rom_loaded();
@@ -266,3 +272,8 @@ EXPORT void HardReset()
{
reset();
}
+
+EXPORT void SetInputCallback(void (*callback)())
+{
+ inputcallback = callback;
+}
diff --git a/waterbox/ngp/rom.cpp b/waterbox/ngp/rom.cpp
index b209f1e0e1..57f057d6fd 100644
--- a/waterbox/ngp/rom.cpp
+++ b/waterbox/ngp/rom.cpp
@@ -15,6 +15,7 @@
#include "neopop.h"
#include "flash.h"
#include "interrupt.h"
+#include
//=============================================================================
@@ -104,33 +105,10 @@ void rom_loaded(void)
rom_display_header();
- ngpc_rom.orig_data = new uint8[ngpc_rom.length];
+ ngpc_rom.orig_data = (uint8*)alloc_sealed(ngpc_rom.length);
memcpy(ngpc_rom.orig_data, ngpc_rom.data, ngpc_rom.length);
}
-//-----------------------------------------------------------------------------
-// rom_unload()
-//-----------------------------------------------------------------------------
-void rom_unload(void)
-{
- if(ngpc_rom.data)
- {
- delete[] ngpc_rom.data;
- ngpc_rom.data = NULL;
- ngpc_rom.length = 0;
- rom_header = 0;
-
- for(int i = 0; i < 16; i++)
- ngpc_rom.name[i] = 0;
- }
-
- if(ngpc_rom.orig_data)
- {
- delete[] ngpc_rom.orig_data;
- ngpc_rom.orig_data = NULL;
- }
-}
-
}
//=============================================================================