QuickNes: Re-add FPU precision, but just for windows (for now)

This commit is contained in:
Asnivor 2019-01-26 13:31:57 +00:00
parent 739f2a61d9
commit 5e21d0640e
1 changed files with 110 additions and 54 deletions

View File

@ -30,51 +30,105 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
[CoreConstructor("NES")] [CoreConstructor("NES")]
public QuickNES(CoreComm comm, byte[] file, object settings, object syncSettings) public QuickNES(CoreComm comm, byte[] file, object settings, object syncSettings)
{ {
ServiceProvider = new BasicServiceProvider(this); if (!PlatformLinkedLibSingleton.RunningOnUnix)
CoreComm = comm; FP = new Win32_FPCtrl();
else
FP = new Unix_FPCtrl();
Context = QN.qn_new(); using (FP.Save())
if (Context == IntPtr.Zero)
{ {
throw new InvalidOperationException("qn_new() returned NULL"); ServiceProvider = new BasicServiceProvider(this);
} CoreComm = comm;
try Context = QN.qn_new();
{ if (Context == IntPtr.Zero)
{
throw new InvalidOperationException("qn_new() returned NULL");
}
file = FixInesHeader(file); try
LibQuickNES.ThrowStringError(QN.qn_loadines(Context, file, file.Length)); {
file = FixInesHeader(file);
LibQuickNES.ThrowStringError(QN.qn_loadines(Context, file, file.Length));
InitSaveRamBuff(); InitSaveRamBuff();
InitSaveStateBuff(); InitSaveStateBuff();
InitAudio(); InitAudio();
InitMemoryDomains(); InitMemoryDomains();
int mapper = 0; int mapper = 0;
string mappername = Marshal.PtrToStringAnsi(QN.qn_get_mapper(Context, ref mapper)); string mappername = Marshal.PtrToStringAnsi(QN.qn_get_mapper(Context, ref mapper));
Console.WriteLine("QuickNES: Booted with Mapper #{0} \"{1}\"", mapper, mappername); Console.WriteLine("QuickNES: Booted with Mapper #{0} \"{1}\"", mapper, mappername);
BoardName = mappername; BoardName = mappername;
PutSettings((QuickNESSettings)settings ?? new QuickNESSettings()); PutSettings((QuickNESSettings)settings ?? new QuickNESSettings());
_syncSettings = (QuickNESSyncSettings)syncSettings ?? new QuickNESSyncSettings(); _syncSettings = (QuickNESSyncSettings)syncSettings ?? new QuickNESSyncSettings();
_syncSettingsNext = _syncSettings.Clone(); _syncSettingsNext = _syncSettings.Clone();
SetControllerDefinition(); SetControllerDefinition();
ComputeBootGod(); ComputeBootGod();
ConnectTracer(); ConnectTracer();
} }
catch catch
{ {
Dispose(); Dispose();
throw; throw;
} }
}
} }
static readonly LibQuickNES QN; static readonly LibQuickNES QN;
static readonly DynamicLibraryImportResolver Resolver; static readonly DynamicLibraryImportResolver Resolver;
public IEmulatorServiceProvider ServiceProvider { get; private set; } public IEmulatorServiceProvider ServiceProvider { get; private set; }
#region FPU precision
private interface IFPCtrl : IDisposable
{
IDisposable Save();
}
private class Win32_FPCtrl : IFPCtrl
{
[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern uint _control87(uint @new, uint mask);
public static void PrintCurrentFP()
{
uint curr = _control87(0, 0);
Console.WriteLine("Current FP word: 0x{0:x8}", curr);
}
uint cw;
public IDisposable Save()
{
cw = _control87(0, 0);
_control87(0x00000, 0x30000);
return this;
}
public void Dispose()
{
_control87(cw, 0x30000);
}
}
private class Unix_FPCtrl : IFPCtrl
{
public IDisposable Save()
{
return this;
}
public void Dispose()
{ }
}
IFPCtrl FP;
#endregion
#region Controller #region Controller
@ -149,35 +203,37 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
public bool FrameAdvance(IController controller, bool render, bool rendersound = true) public bool FrameAdvance(IController controller, bool render, bool rendersound = true)
{ {
CheckDisposed(); CheckDisposed();
using (FP.Save())
{
if (controller.IsPressed("Power"))
QN.qn_reset(Context, true);
if (controller.IsPressed("Reset"))
QN.qn_reset(Context, false);
if (controller.IsPressed("Power")) int j1, j2;
QN.qn_reset(Context, true); SetPads(controller, out j1, out j2);
if (controller.IsPressed("Reset"))
QN.qn_reset(Context, false);
int j1, j2; if (Tracer.Enabled)
SetPads(controller, out j1, out j2); QN.qn_set_tracecb(Context, _tracecb);
else
QN.qn_set_tracecb(Context, null);
if (Tracer.Enabled) Frame++;
QN.qn_set_tracecb(Context, _tracecb); LibQuickNES.ThrowStringError(QN.qn_emulate_frame(Context, j1, j2));
else IsLagFrame = QN.qn_get_joypad_read_count(Context) == 0;
QN.qn_set_tracecb(Context, null); if (IsLagFrame)
LagCount++;
Frame++; if (render)
LibQuickNES.ThrowStringError(QN.qn_emulate_frame(Context, j1, j2)); Blit();
IsLagFrame = QN.qn_get_joypad_read_count(Context) == 0; if (rendersound)
if (IsLagFrame) DrainAudio();
LagCount++;
if (render) if (CB1 != null) CB1();
Blit(); if (CB2 != null) CB2();
if (rendersound)
DrainAudio();
if (CB1 != null) CB1(); return true;
if (CB2 != null) CB2(); }
return true;
} }
IntPtr Context; IntPtr Context;