NGP: It works and stuff

This commit is contained in:
nattthebear 2017-05-30 18:35:44 -04:00
parent 1a54ff1818
commit d799624e9c
13 changed files with 308 additions and 187 deletions

View File

@ -1210,8 +1210,8 @@
<Compile Include="Consoles\Sega\SMS\VDP.ModeTMS.cs" />
<Compile Include="Consoles\Sega\SMS\VDP.Mode4.cs" />
<Compile Include="Consoles\Sega\SMS\VDP.Tables.cs" />
<Compile Include="Consoles\SNK\LibNeoGeo.cs" />
<Compile Include="Consoles\SNK\NeoGeo.cs" />
<Compile Include="Consoles\SNK\LibNeoGeoPort.cs" />
<Compile Include="Consoles\SNK\NeoGeoPort.cs" />
<Compile Include="Consoles\Sony\PSP\PPSSPPDll.cs" />
<Compile Include="Consoles\Sony\PSP\PSP.cs" />
<Compile Include="Consoles\Sony\PSX\Octoshock.cs">

View File

@ -225,7 +225,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.VB
#endregion
// TODO
public int LagCount { get; set; }
public bool IsLagFrame { get; set; }

View File

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

View File

@ -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<LibNeoGeo>(_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
}
}

View File

@ -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<LibNeoGeoPort>(_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<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 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
}
}

View File

@ -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")]

View File

@ -6,6 +6,7 @@
"algorithm": "cpp",
"vector": "cpp",
"xstring": "cpp",
"xutility": "cpp"
"xutility": "cpp",
"xmemory0": "cpp"
}
}

View File

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

View File

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

View File

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

View File

@ -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<true>(&FastReadMap[address >> 16][address]));
if (address == 0x6f82)
{
lagged = false;
if (inputcallback)
inputcallback();
}
uint16 *ptr = (uint16 *)translate_address_read(address);
if (ptr)
return MDFN_de16lsb<true>(ptr);

View File

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

View File

@ -15,6 +15,7 @@
#include "neopop.h"
#include "flash.h"
#include "interrupt.h"
#include <emulibc.h>
//=============================================================================
@ -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;
}
}
}
//=============================================================================