diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs index 248d56f9d2..7c84b3dda1 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs @@ -30,44 +30,51 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES [CoreConstructor("NES")] public QuickNES(CoreComm comm, byte[] file, object settings, object syncSettings) { - ServiceProvider = new BasicServiceProvider(this); - CoreComm = comm; + FP = OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows + ? (IFPCtrl) new Win32_FPCtrl() + : new Unix_FPCtrl(); - Context = QN.qn_new(); - if (Context == IntPtr.Zero) + using (FP.Save()) { - throw new InvalidOperationException($"{nameof(QN.qn_new)}() returned NULL"); - } + ServiceProvider = new BasicServiceProvider(this); + CoreComm = comm; - try - { + Context = QN.qn_new(); + if (Context == IntPtr.Zero) + { + throw new InvalidOperationException($"{nameof(QN.qn_new)}() returned NULL"); + } - file = FixInesHeader(file); - LibQuickNES.ThrowStringError(QN.qn_loadines(Context, file, file.Length)); + try + { - InitSaveRamBuff(); - InitSaveStateBuff(); - InitAudio(); - InitMemoryDomains(); + file = FixInesHeader(file); + LibQuickNES.ThrowStringError(QN.qn_loadines(Context, file, file.Length)); - int mapper = 0; - string mappername = Marshal.PtrToStringAnsi(QN.qn_get_mapper(Context, ref mapper)); - Console.WriteLine("QuickNES: Booted with Mapper #{0} \"{1}\"", mapper, mappername); - BoardName = mappername; - PutSettings((QuickNESSettings)settings ?? new QuickNESSettings()); + InitSaveRamBuff(); + InitSaveStateBuff(); + InitAudio(); + InitMemoryDomains(); - _syncSettings = (QuickNESSyncSettings)syncSettings ?? new QuickNESSyncSettings(); - _syncSettingsNext = _syncSettings.Clone(); + int mapper = 0; + string mappername = Marshal.PtrToStringAnsi(QN.qn_get_mapper(Context, ref mapper)); + Console.WriteLine("QuickNES: Booted with Mapper #{0} \"{1}\"", mapper, mappername); + BoardName = mappername; + PutSettings((QuickNESSettings)settings ?? new QuickNESSettings()); - SetControllerDefinition(); - ComputeBootGod(); + _syncSettings = (QuickNESSyncSettings)syncSettings ?? new QuickNESSyncSettings(); + _syncSettingsNext = _syncSettings.Clone(); - ConnectTracer(); - } - catch - { - Dispose(); - throw; + SetControllerDefinition(); + ComputeBootGod(); + + ConnectTracer(); + } + catch + { + Dispose(); + throw; + } } } @@ -76,6 +83,53 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES 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 public ControllerDefinition ControllerDefinition { get; private set; } @@ -149,34 +203,37 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES public bool FrameAdvance(IController controller, bool render, bool rendersound = true) { CheckDisposed(); - if (controller.IsPressed("Power")) - QN.qn_reset(Context, true); - if (controller.IsPressed("Reset")) - QN.qn_reset(Context, false); + using (FP.Save()) + { + if (controller.IsPressed("Power")) + QN.qn_reset(Context, true); + if (controller.IsPressed("Reset")) + QN.qn_reset(Context, false); - int j1, j2; - SetPads(controller, out j1, out j2); + int j1, j2; + SetPads(controller, out j1, out j2); - if (Tracer.Enabled) - QN.qn_set_tracecb(Context, _tracecb); - else - QN.qn_set_tracecb(Context, null); + if (Tracer.Enabled) + QN.qn_set_tracecb(Context, _tracecb); + else + QN.qn_set_tracecb(Context, null); - Frame++; - LibQuickNES.ThrowStringError(QN.qn_emulate_frame(Context, j1, j2)); - IsLagFrame = QN.qn_get_joypad_read_count(Context) == 0; - if (IsLagFrame) - LagCount++; + Frame++; + LibQuickNES.ThrowStringError(QN.qn_emulate_frame(Context, j1, j2)); + IsLagFrame = QN.qn_get_joypad_read_count(Context) == 0; + if (IsLagFrame) + LagCount++; - if (render) - Blit(); - if (rendersound) - DrainAudio(); + if (render) + Blit(); + if (rendersound) + DrainAudio(); - if (CB1 != null) CB1(); - if (CB2 != null) CB2(); + if (CB1 != null) CB1(); + if (CB2 != null) CB2(); - return true; + return true; + } } IntPtr Context;