diff --git a/BizHawk.Client.Common/RomLoader.cs b/BizHawk.Client.Common/RomLoader.cs index 3a4b1d69a6..f06cf75020 100644 --- a/BizHawk.Client.Common/RomLoader.cs +++ b/BizHawk.Client.Common/RomLoader.cs @@ -973,7 +973,14 @@ namespace BizHawk.Client.Common if (preference == "neshawk") { - core = CoreInventory.Instance["NES", "NesHawk"]; + if (Global.Config.UseSubNESHawk) + { + core = CoreInventory.Instance["NES", "SubNESHawk"]; + } + else + { + core = CoreInventory.Instance["NES", "NesHawk"]; + } } else { diff --git a/BizHawk.Client.Common/config/Config.cs b/BizHawk.Client.Common/config/Config.cs index 1ced4b01f1..2ff5988861 100644 --- a/BizHawk.Client.Common/config/Config.cs +++ b/BizHawk.Client.Common/config/Config.cs @@ -560,6 +560,7 @@ namespace BizHawk.Client.Common // as this setting spans multiple cores and doesn't actually affect the behavior of any core, // it hasn't been absorbed into the new system public bool GB_AsSGB = false; + public bool UseSubNESHawk = false; public bool NES_InQuickNES = true; public bool SNES_InSnes9x = true; public bool GBA_UsemGBA = true; diff --git a/BizHawk.Client.Common/movie/bk2/Bk2Movie.IO.cs b/BizHawk.Client.Common/movie/bk2/Bk2Movie.IO.cs index f56331b533..c7d63a4c8d 100644 --- a/BizHawk.Client.Common/movie/bk2/Bk2Movie.IO.cs +++ b/BizHawk.Client.Common/movie/bk2/Bk2Movie.IO.cs @@ -166,6 +166,12 @@ namespace BizHawk.Client.Common protected virtual void Write(string fn, bool backup = false) { + if (Global.Emulator is BizHawk.Emulation.Cores.Nintendo.SubNESHawk.SubNESHawk) + { + var _subnes = (BizHawk.Emulation.Cores.Nintendo.SubNESHawk.SubNESHawk)Global.Emulator; + Header["VBlankCount"] = _subnes.VBL_CNT.ToString(); + } + var file = new FileInfo(fn); if (!file.Directory.Exists) { diff --git a/BizHawk.Client.Common/movie/conversions/MovieConversionExtensions.cs b/BizHawk.Client.Common/movie/conversions/MovieConversionExtensions.cs index dd5c1e36c4..0cd32aa7ef 100644 --- a/BizHawk.Client.Common/movie/conversions/MovieConversionExtensions.cs +++ b/BizHawk.Client.Common/movie/conversions/MovieConversionExtensions.cs @@ -4,6 +4,7 @@ using System.Linq; using BizHawk.Emulation.Common; using BizHawk.Emulation.Cores.Nintendo.Gameboy; +using BizHawk.Emulation.Cores.Nintendo.SubNESHawk; using BizHawk.Emulation.Cores.Sega.MasterSystem; using BizHawk.Emulation.Common.IEmulatorExtensions; using BizHawk.Emulation.Cores.Consoles.Sega.gpgx; @@ -336,6 +337,11 @@ namespace BizHawk.Client.Common.MovieConversionExtensions movie.HeaderEntries.Add("Is32X", "1"); } + if (Global.Emulator is SubNESHawk) + { + movie.HeaderEntries.Add("VBlankCount", "0"); + } + movie.Core = ((CoreAttribute)Attribute .GetCustomAttribute(Global.Emulator.GetType(), typeof(CoreAttribute))) .CoreName; diff --git a/BizHawk.Client.EmuHawk/MainForm.Designer.cs b/BizHawk.Client.EmuHawk/MainForm.Designer.cs index 092908ba95..b7df5e2f76 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Designer.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Designer.cs @@ -199,6 +199,7 @@ this.GBGambatteMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.GBGBHawkMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.GBInSGBMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.SubNESHawkMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem16 = new System.Windows.Forms.ToolStripSeparator(); this.allowGameDBCoreOverridesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator8 = new System.Windows.Forms.ToolStripSeparator(); @@ -1845,6 +1846,7 @@ this.SGBCoreSubmenu, this.GBCoreSubmenu, this.GBInSGBMenuItem, + this.SubNESHawkMenuItem, this.toolStripMenuItem16, this.allowGameDBCoreOverridesToolStripMenuItem, this.toolStripSeparator8, @@ -1982,6 +1984,13 @@ this.GBInSGBMenuItem.Text = "GB in SGB"; this.GBInSGBMenuItem.Click += new System.EventHandler(this.GbInSgbMenuItem_Click); // + // SubNESHawkMenuItem + // + this.SubNESHawkMenuItem.Name = "SubNESHawkMenuItem"; + this.SubNESHawkMenuItem.Size = new System.Drawing.Size(239, 22); + this.SubNESHawkMenuItem.Text = "SubNESHawk"; + this.SubNESHawkMenuItem.Click += new System.EventHandler(this.SubNESHawkMenuItem_Click); + // // toolStripMenuItem16 // this.toolStripMenuItem16.Name = "toolStripMenuItem16"; @@ -4532,6 +4541,7 @@ private System.Windows.Forms.ToolStripMenuItem MovieSettingsMenuItem; private System.Windows.Forms.ToolStripMenuItem CoresSubMenu; private System.Windows.Forms.ToolStripMenuItem GBInSGBMenuItem; + private System.Windows.Forms.ToolStripMenuItem SubNESHawkMenuItem; private System.Windows.Forms.ToolStripMenuItem batchRunnerToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem DisplayConfigMenuItem; private System.Windows.Forms.ToolStripMenuItem PCEtileViewerToolStripMenuItem; diff --git a/BizHawk.Client.EmuHawk/MainForm.Events.cs b/BizHawk.Client.EmuHawk/MainForm.Events.cs index e9bce5e5aa..1475a7e2dd 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Events.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Events.cs @@ -10,6 +10,7 @@ using BizHawk.Emulation.Cores.Atari.A7800Hawk; using BizHawk.Emulation.Cores.Calculators; using BizHawk.Emulation.Cores.ColecoVision; using BizHawk.Emulation.Cores.Nintendo.NES; +using BizHawk.Emulation.Cores.Nintendo.SubNESHawk; using BizHawk.Emulation.Cores.Nintendo.N64; using BizHawk.Emulation.Cores.Nintendo.SNES; using BizHawk.Emulation.Cores.Nintendo.SNES9X; @@ -1215,6 +1216,7 @@ namespace BizHawk.Client.EmuHawk private void CoresSubMenu_DropDownOpened(object sender, EventArgs e) { GBInSGBMenuItem.Checked = Global.Config.GB_AsSGB; + SubNESHawkMenuItem.Checked = Global.Config.UseSubNESHawk; allowGameDBCoreOverridesToolStripMenuItem.Checked = Global.Config.CoreForcingViaGameDB; } @@ -1308,6 +1310,16 @@ namespace BizHawk.Client.EmuHawk } } + private void SubNESHawkMenuItem_Click(object sender, EventArgs e) + { + Global.Config.UseSubNESHawk ^= true; + + if (!Emulator.IsNull()) + { + FlagNeedsReboot(); + } + } + private void AllowGameDBCoreOverridesToolStripMenuItem_Click(object sender, EventArgs e) { Global.Config.CoreForcingViaGameDB ^= true; @@ -1623,6 +1635,10 @@ namespace BizHawk.Client.EmuHawk { new NESGraphicsConfig().ShowDialog(this); } + else if (Emulator is SubNESHawk) + { + new NESGraphicsConfig().ShowDialog(this); + } else if (Emulator is QuickNES) { new QuickNesConfig().ShowDialog(this); @@ -1693,6 +1709,10 @@ namespace BizHawk.Client.EmuHawk { new NesControllerSettings().ShowDialog(); } + else if (Emulator is SubNESHawk) + { + new NesControllerSettings().ShowDialog(); + } else if (Emulator is QuickNES) { GenericCoreConfig.DoDialog(this, "QuickNES Controller Settings", true, false); diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 78a1fa21bd..c93ebb1d99 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -2950,10 +2950,6 @@ namespace BizHawk.Client.EmuHawk GlobalWin.Tools.UpdateToolsBefore(); } - _framesSinceLastFpsUpdate++; - - UpdateFpsDisplay(currentTimestamp, isRewinding, isFastForwarding); - CaptureRewind(isRewinding); // Set volume, if enabled @@ -2997,7 +2993,7 @@ namespace BizHawk.Client.EmuHawk } bool render = !_throttle.skipNextFrame || (_currAviWriter?.UsesVideo ?? false); - Emulator.FrameAdvance(Global.ControllerOutput, render, renderSound); + bool new_frame = Emulator.FrameAdvance(Global.ControllerOutput, render, renderSound); Global.MovieSession.HandleMovieAfterFrameLoop(); @@ -3036,11 +3032,18 @@ namespace BizHawk.Client.EmuHawk UpdateToolsAfter(SuppressLua); } - if (!PauseAvi) + if (!PauseAvi && new_frame) { AvFrameAdvance(); } + if (new_frame) + { + _framesSinceLastFpsUpdate++; + + UpdateFpsDisplay(currentTimestamp, isRewinding, isFastForwarding); + } + if (GlobalWin.Tools.IsLoaded() && GlobalWin.Tools.TAStudio.LastPositionFrame == Emulator.Frame) { diff --git a/BizHawk.Client.EmuHawk/config/NES/NESGraphicsConfig.cs b/BizHawk.Client.EmuHawk/config/NES/NESGraphicsConfig.cs index f8c41e16ee..64b371ddc6 100644 --- a/BizHawk.Client.EmuHawk/config/NES/NESGraphicsConfig.cs +++ b/BizHawk.Client.EmuHawk/config/NES/NESGraphicsConfig.cs @@ -5,6 +5,7 @@ using System.Windows.Forms; using BizHawk.Common; using BizHawk.Client.Common; using BizHawk.Emulation.Cores.Nintendo.NES; +using BizHawk.Emulation.Cores.Nintendo.SubNESHawk; namespace BizHawk.Client.EmuHawk { @@ -15,6 +16,7 @@ namespace BizHawk.Client.EmuHawk // Hotkeys for BG & Sprite display toggle // NTSC filter settings? Hue, Tint (This should probably be a client thing, not a nes specific thing?) private NES _nes; + private SubNESHawk _subneshawk; private NES.NESSettings _settings; private Bitmap _bmp; @@ -25,8 +27,17 @@ namespace BizHawk.Client.EmuHawk private void NESGraphicsConfig_Load(object sender, EventArgs e) { - _nes = (NES)Global.Emulator; - _settings = _nes.GetSettings(); + if (Global.Emulator is NES) + { + _nes = (NES)Global.Emulator; + _settings = _nes.GetSettings(); + } + else + { + _subneshawk = (SubNESHawk)Global.Emulator; + _settings = _subneshawk.GetSettings(); + } + LoadStuff(); } @@ -146,7 +157,15 @@ namespace BizHawk.Client.EmuHawk _settings.BackgroundColor &= 0x00FFFFFF; } - _nes.PutSettings(_settings); + if (Global.Emulator is NES) + { + _nes.PutSettings(_settings); + } + else + { + _subneshawk.PutSettings(_settings); + } + Close(); } diff --git a/BizHawk.Client.EmuHawk/config/NES/NesControllerSettings.cs b/BizHawk.Client.EmuHawk/config/NES/NesControllerSettings.cs index 068711825f..4141bf067e 100644 --- a/BizHawk.Client.EmuHawk/config/NES/NesControllerSettings.cs +++ b/BizHawk.Client.EmuHawk/config/NES/NesControllerSettings.cs @@ -4,6 +4,7 @@ using System.Windows.Forms; using BizHawk.Client.Common; using BizHawk.Emulation.Cores.Nintendo.NES; +using BizHawk.Emulation.Cores.Nintendo.SubNESHawk; namespace BizHawk.Client.EmuHawk { @@ -14,7 +15,15 @@ namespace BizHawk.Client.EmuHawk public NesControllerSettings() { InitializeComponent(); - _syncSettings = ((NES)Global.Emulator).GetSyncSettings(); + if (Global.Emulator is NES) + { + _syncSettings = ((NES)Global.Emulator).GetSyncSettings(); + } + else + { + _syncSettings = ((SubNESHawk)Global.Emulator).GetSyncSettings(); + } + // TODO: use combobox extension and add descriptions to enum values comboBoxFamicom.Items.AddRange(NESControlSettings.GetFamicomExpansionValues().ToArray()); diff --git a/BizHawk.Emulation.Common/Base Implementations/NullEmulator.cs b/BizHawk.Emulation.Common/Base Implementations/NullEmulator.cs index 034d1dfbaf..0983f9651c 100644 --- a/BizHawk.Emulation.Common/Base Implementations/NullEmulator.cs +++ b/BizHawk.Emulation.Common/Base Implementations/NullEmulator.cs @@ -33,23 +33,23 @@ namespace BizHawk.Emulation.Common public ControllerDefinition ControllerDefinition => NullController.Instance.Definition; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { if (render == false) { - return; + return true; } if (!_settings.SnowyDisplay) { if (_frameBufferClear) { - return; + return true; } _frameBufferClear = true; Array.Clear(_frameBuffer, 0, 256 * 192); - return; + return true; } _frameBufferClear = false; @@ -70,6 +70,8 @@ namespace BizHawk.Emulation.Common } Frame++; + + return true; } public int Frame { get; private set; } diff --git a/BizHawk.Emulation.Common/Interfaces/IEmulator.cs b/BizHawk.Emulation.Common/Interfaces/IEmulator.cs index 4d3926d6fc..6920136d94 100644 --- a/BizHawk.Emulation.Common/Interfaces/IEmulator.cs +++ b/BizHawk.Emulation.Common/Interfaces/IEmulator.cs @@ -34,7 +34,7 @@ namespace BizHawk.Emulation.Common /// Whether or not to render video, cores will pass false here in cases such as frame skipping /// Whether or not to render audio, cores will pass here false here in cases such as fast forwarding where bypassing sound may improve speed /// - void FrameAdvance(IController controller, bool render, bool rendersound = true); + bool FrameAdvance(IController controller, bool render, bool rendersound = true); /// /// Gets the current frame count diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index 744a7d8c27..f6bf415a2a 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -317,9 +317,9 @@ - + - + @@ -327,23 +327,23 @@ - NECUPD765.cs - + NECUPD765.cs + - NECUPD765.cs - + NECUPD765.cs + - NECUPD765.cs - + NECUPD765.cs + - NECUPD765.cs - + NECUPD765.cs + - NECUPD765.cs - + NECUPD765.cs + - NECUPD765.cs - + NECUPD765.cs + @@ -375,93 +375,93 @@ - SpectrumBase.cs - + SpectrumBase.cs + - SpectrumBase.cs - + SpectrumBase.cs + - SpectrumBase.cs - - - SpectrumBase.cs - - - - + SpectrumBase.cs + + + SpectrumBase.cs + + + + - ZX48.cs - - - ZX48.cs - + ZX48.cs + + + ZX48.cs + - - + + - ZX128.cs - + ZX128.cs + - ZX128.cs - + ZX128.cs + - - + + - ZX128Plus2a.cs - + ZX128Plus2a.cs + - ZX128Plus2a.cs - - - + ZX128Plus2a.cs + + + - ZX128Plus3.cs - + ZX128Plus3.cs + - ZX128Plus3.cs - + ZX128Plus3.cs + - Pentagon128.cs - + Pentagon128.cs + - Pentagon128.cs - - - - + Pentagon128.cs + + + + - ZXSpectrum.cs - + ZXSpectrum.cs + - ZXSpectrum.cs - + ZXSpectrum.cs + - ZXSpectrum.cs - + ZXSpectrum.cs + - ZXSpectrum.cs - + ZXSpectrum.cs + - ZXSpectrum.cs - + ZXSpectrum.cs + - ZXSpectrum.cs - + ZXSpectrum.cs + - ZXSpectrum.cs - + ZXSpectrum.cs + - ZXSpectrum.cs - + ZXSpectrum.cs + - ZXSpectrum.cs - - - ZXSpectrum.cs - + ZXSpectrum.cs + + + ZXSpectrum.cs + Atari2600.cs @@ -789,7 +789,7 @@ VBANext.cs - + GBHawkLink.cs @@ -1201,6 +1201,25 @@ + + + SubNESHawk.cs + + + SubNESHawk.cs + + + SubNESHawk.cs + + + SubNESHawk.cs + + + SubNESHawk.cs + + + SubNESHawk.cs + diff --git a/BizHawk.Emulation.Cores/CPUs/MOS 6502X/MOS6502X.cs b/BizHawk.Emulation.Cores/CPUs/MOS 6502X/MOS6502X.cs index 83d94aad78..2b0965e0ed 100644 --- a/BizHawk.Emulation.Cores/CPUs/MOS 6502X/MOS6502X.cs +++ b/BizHawk.Emulation.Cores/CPUs/MOS 6502X/MOS6502X.cs @@ -74,7 +74,7 @@ namespace BizHawk.Emulation.Cores.Components.M6502 "{0:X4}: {1,-9} {2} ", PC, rawbytes, disasm).PadRight(32), RegisterInfo = string.Format( - "A:{0:X2} X:{1:X2} Y:{2:X2} SP:{4:X2} P:{3:X2} {6}{7}{8}{9}{10}{11}{12}{13} Cy:{5}", + "A:{0:X2} X:{1:X2} Y:{2:X2} SP:{4:X2} P:{3:X2} {6}{7}{8}{9}{10}{11}{12}{13} Cy:{5} PPU-Cy:{15}", A, X, Y, P, S, TotalExecutedCycles, FlagN ? "N" : "n", FlagV ? "V" : "v", @@ -84,7 +84,8 @@ namespace BizHawk.Emulation.Cores.Components.M6502 FlagI ? "I" : "i", FlagZ ? "Z" : "z", FlagC ? "C" : "c", - !RDY ? "R" : "r") + !RDY ? "R" : "r", + ext_ppu_cycle) }; } @@ -120,6 +121,9 @@ namespace BizHawk.Emulation.Cores.Components.M6502 public bool NMI; public bool RDY; + // ppu cycle (used with SubNESHawk) + public int ext_ppu_cycle = 0; + public void SyncState(Serializer ser) { ser.BeginSection("MOS6502X"); @@ -143,6 +147,7 @@ namespace BizHawk.Emulation.Cores.Components.M6502 ser.Sync("interrupt_pending", ref interrupt_pending); ser.Sync("branch_irq_hack", ref branch_irq_hack); ser.Sync("rdy_freeze", ref rdy_freeze); + ser.Sync("ext_ppu_cycle", ref ext_ppu_cycle); ser.EndSection(); } diff --git a/BizHawk.Emulation.Cores/Calculator/TI83.IEmulator.cs b/BizHawk.Emulation.Cores/Calculator/TI83.IEmulator.cs index 622664bcc7..ba1f2efde3 100644 --- a/BizHawk.Emulation.Cores/Calculator/TI83.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Calculator/TI83.IEmulator.cs @@ -8,7 +8,7 @@ namespace BizHawk.Emulation.Cores.Calculators public ControllerDefinition ControllerDefinition => TI83Controller; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { _controller = controller; _lagged = true; @@ -59,6 +59,8 @@ namespace BizHawk.Emulation.Cores.Calculators } _isLag = _lagged; + + return true; } public int Frame diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/AmstradCPC.IEmulator.cs b/BizHawk.Emulation.Cores/Computers/AmstradCPC/AmstradCPC.IEmulator.cs index 23a2bfb521..bb7fe9b5f3 100644 --- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/AmstradCPC.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Computers/AmstradCPC/AmstradCPC.IEmulator.cs @@ -12,7 +12,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC public ControllerDefinition ControllerDefinition { get; set; } - public void FrameAdvance(IController controller, bool render, bool renderSound) + public bool FrameAdvance(IController controller, bool render, bool renderSound) { _controller = controller; @@ -42,6 +42,8 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC { _lagCount++; } + + return true; } public int Frame diff --git a/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IEmulator.cs b/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IEmulator.cs index 8e41c8ba8c..903fc365bd 100644 --- a/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IEmulator.cs @@ -14,9 +14,11 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII public bool DeterministicEmulation => true; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { FrameAdv(controller, render, rendersound); + + return true; } public void ResetCounters() diff --git a/BizHawk.Emulation.Cores/Computers/Commodore64/C64.IEmulator.cs b/BizHawk.Emulation.Cores/Computers/Commodore64/C64.IEmulator.cs index 358a02fcff..29aea5b261 100644 --- a/BizHawk.Emulation.Cores/Computers/Commodore64/C64.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Computers/Commodore64/C64.IEmulator.cs @@ -8,7 +8,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64 public ControllerDefinition ControllerDefinition => C64ControllerDefinition; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { _board.Controller = controller; @@ -47,6 +47,8 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64 DoCycle(); } while (_frameCycles != 0); + + return true; } public int Frame => _frame; diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.IEmulator.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.IEmulator.cs index 1276521373..56e9f0d376 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.IEmulator.cs @@ -12,7 +12,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public ControllerDefinition ControllerDefinition { get; set; } - public void FrameAdvance(IController controller, bool render, bool renderSound) + public bool FrameAdvance(IController controller, bool render, bool renderSound) { _controller = controller; @@ -42,6 +42,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { _lagCount++; } + + return true; } public int Frame diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IEmulator.cs index 1dad16b1d3..23585fb39f 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IEmulator.cs @@ -9,7 +9,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 public ControllerDefinition ControllerDefinition => _controllerDeck.Definition; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { _controller = controller; @@ -75,6 +75,8 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 } _tia.LineCount = 0; + + return true; } public int Frame => _frame; diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IEmulator.cs index 11ce9c8f23..667ee16c13 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IEmulator.cs @@ -57,7 +57,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk public bool slow_access = false; public int slow_countdown; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { if (_tracer.Enabled) { @@ -88,6 +88,8 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk { _lagcount++; } + + return true; } public void RunCPUCycle() diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/lynx/Lynx.cs b/BizHawk.Emulation.Cores/Consoles/Atari/lynx/Lynx.cs index e234ae4455..24fb8a0095 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/lynx/Lynx.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/lynx/Lynx.cs @@ -120,7 +120,7 @@ namespace BizHawk.Emulation.Cores.Atari.Lynx public IEmulatorServiceProvider ServiceProvider { get; } - public void FrameAdvance(IController controller, bool render, bool rendersound = true) + public bool FrameAdvance(IController controller, bool render, bool rendersound = true) { Frame++; if (controller.IsPressed("Power")) @@ -135,6 +135,8 @@ namespace BizHawk.Emulation.Cores.Atari.Lynx { LagCount++; } + + return true; } public int Frame { get; private set; } diff --git a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IEmulator.cs index 6d9dda125f..8d8c7b8b48 100644 --- a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IEmulator.cs @@ -10,7 +10,7 @@ namespace BizHawk.Emulation.Cores.ColecoVision public ControllerDefinition ControllerDefinition => ControllerDeck.Definition; - public void FrameAdvance(IController controller, bool render, bool renderSound) + public bool FrameAdvance(IController controller, bool render, bool renderSound) { _controller = controller; @@ -163,6 +163,8 @@ namespace BizHawk.Emulation.Cores.ColecoVision { _lagCount++; } + + return true; } public bool use_SGM = false; diff --git a/BizHawk.Emulation.Cores/Consoles/Intellivision/Intellivision.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Intellivision/Intellivision.IEmulator.cs index 7f7c1e717d..0d0dd5dee2 100644 --- a/BizHawk.Emulation.Cores/Consoles/Intellivision/Intellivision.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Intellivision/Intellivision.IEmulator.cs @@ -8,7 +8,7 @@ namespace BizHawk.Emulation.Cores.Intellivision public ControllerDefinition ControllerDefinition => _controllerDeck.Definition; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { if (_tracer.Enabled) { @@ -124,6 +124,8 @@ namespace BizHawk.Emulation.Cores.Intellivision { SoftReset(); } + + return true; } public int Frame => _frame; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/MGBAHawk.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/MGBAHawk.cs index 0028c7b4e9..264d658e98 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/MGBAHawk.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/MGBAHawk.cs @@ -67,7 +67,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA public ControllerDefinition ControllerDefinition => GBA.GBAController; - public void FrameAdvance(IController controller, bool render, bool rendersound = true) + public bool FrameAdvance(IController controller, bool render, bool rendersound = true) { Frame++; if (controller.IsPressed("Power")) @@ -97,6 +97,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA // this should be called in hblank on the appropriate line, but until we implement that, just do it here _scanlinecb?.Invoke(); + + return true; } public int Frame { get; private set; } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs index 676210608f..247d7fd68d 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs @@ -95,7 +95,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA public IEmulatorServiceProvider ServiceProvider { get; private set; } - public void FrameAdvance(IController controller, bool render, bool rendersound = true) + public bool FrameAdvance(IController controller, bool render, bool rendersound = true) { Frame++; @@ -108,6 +108,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA if (IsLagFrame) LagCount++; + + return true; } public int Frame { get; private set; } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs index e0aa0baeef..ca42c1472e 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs @@ -19,7 +19,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk public bool in_vblank; public bool vblank_rise; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { //Console.WriteLine("-----------------------FRAME-----------------------"); @@ -74,6 +74,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk { _lagcount++; } + + return true; } public void do_frame() diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs index dee9cfa0e3..df9029b226 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs @@ -14,7 +14,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink public ControllerDefinition ControllerDefinition => _controllerDeck.Definition; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { //Console.WriteLine("-----------------------FRAME-----------------------"); //Update the color palette if a setting changed @@ -86,6 +86,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink { _lagcount++; } + + return true; } public void do_frame() diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IEmulator.cs index 2b55424647..c0b371b389 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IEmulator.cs @@ -12,7 +12,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy public ControllerDefinition ControllerDefinition => GbController; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { FrameAdvancePrep(controller); if (_syncSettings.EqualLengthFrames) @@ -68,6 +68,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy } FrameAdvancePost(); + + return true; } public int Frame { get; private set; } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IEmulator.cs index 3a835ee5a2..c10f340eae 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IEmulator.cs @@ -9,7 +9,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy public ControllerDefinition ControllerDefinition => DualGbController; - public void FrameAdvance(IController controller, bool render, bool rendersound = true) + public bool FrameAdvance(IController controller, bool render, bool rendersound = true) { LCont.Clear(); RCont.Clear(); @@ -148,6 +148,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy { LagCount++; } + + return true; } public int Frame { get; private set; } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.cs index b4c68bf03f..342eaef8c4 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.cs @@ -221,7 +221,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64 RunThreadAction(() => { _pendingThreadTerminate = true; }); } - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { _inputProvider.Controller = controller; @@ -258,6 +258,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64 if(!api.IsCrashed) Frame++; + + return true; } public string SystemId { get { return "N64"; } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/ExROM.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/ExROM.cs index 61a0c5fe7c..ce0e72510f 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/ExROM.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/ExROM.cs @@ -244,7 +244,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES int bank_1k = addr >> 10; int ofs = addr & ((1 << 10) - 1); - if (exram_mode == 1 && NES.ppu.ppuphase == PPU.PPUPHASE.BG) + if (exram_mode == 1 && NES.ppu.ppuphase == PPU.PPU_PHASE_BG) { int exram_addr = last_nt_read; int bank_4k = EXRAM[exram_addr] & 0x3F; @@ -261,9 +261,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES if (NES.ppu.reg_2000.obj_size_16) { bool isPattern = NES.ppu.PPUON; - if (NES.ppu.ppuphase == PPU.PPUPHASE.OBJ && isPattern) + if (NES.ppu.ppuphase == PPU.PPU_PHASE_OBJ && isPattern) bank_1k = a_banks_1k[bank_1k]; - else if (NES.ppu.ppuphase == PPU.PPUPHASE.BG && isPattern) + else if (NES.ppu.ppuphase == PPU.PPU_PHASE_BG && isPattern) bank_1k = b_banks_1k[bank_1k]; else { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/UNIF/UNIF_UNL-TF1201.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/UNIF/UNIF_UNL-TF1201.cs index 04df29aadc..c8df6cac0d 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/UNIF/UNIF_UNL-TF1201.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/UNIF/UNIF_UNL-TF1201.cs @@ -80,7 +80,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES case 0xF003: IRQa = value.Bit(1); IRQSignal = false; - if (NES.ppu.ppuphase !=PPU.PPUPHASE.VBL) + if (NES.ppu.ppuphase !=PPU.PPU_PHASE_VBL) IRQCount -= 8; break; } @@ -88,7 +88,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public override void ClockPPU() { - if ((NES.ppu.ppuphase != PPU.PPUPHASE.VBL))// && IRQa) + if ((NES.ppu.ppuphase != PPU.PPU_PHASE_VBL))// && IRQa) { IRQpre--; if (IRQpre==0) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs index 5d5a01ed83..ac9f0d3b26 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs @@ -31,7 +31,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public int cpuclockrate { get; private set; } //user configuration - int[] palette_compiled = new int[64 * 8]; + public int[] palette_compiled = new int[64 * 8]; //variable set when VS system games are running internal bool _isVS = false; @@ -79,7 +79,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES magicSoundProvider = null; } - class MagicSoundProvider : ISoundProvider, IDisposable + public class MagicSoundProvider : ISoundProvider, IDisposable { BlipBuffer blip; NES nes; @@ -157,7 +157,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } } } - MagicSoundProvider magicSoundProvider; + public MagicSoundProvider magicSoundProvider; public void HardReset() { @@ -197,6 +197,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } } + // Add in the reset timing float control for subneshawk + if (using_reset_timing && (ControllerDefinition.FloatControls.Count() == 0)) + { + ControllerDefinition.FloatControls.Add("Reset Cycle"); + ControllerDefinition.FloatRanges.Add(new ControllerDefinition.FloatRange(0, 0, 500000)); + } + // don't replace the magicSoundProvider on reset, as it's not needed // if (magicSoundProvider != null) magicSoundProvider.Dispose(); @@ -311,7 +318,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES bool resetSignal; bool hardResetSignal; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { _controller = controller; @@ -377,12 +384,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } else { - ppu.ppu_init_frame(); - - ppu.do_vbl = true; - ppu.do_active_sl = true; - ppu.do_pre_vbl = true; - // do the vbl ticks seperate, that will save us a few checks that don't happen in active region while (ppu.do_vbl) { @@ -415,6 +416,47 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES // turn off all cheats // any cheats still active will be re-applied by the buspoke at the start of the next frame num_cheats = 0; + + return true; + } + + // these variables are for subframe input control + public bool controller_was_latched; + public bool frame_is_done; + public bool current_strobe; + public bool new_strobe; + public bool alt_lag; + // variable used with subneshawk to trigger reset at specific cycle after reset + public bool using_reset_timing = false; + // this function will run one step of the ppu + // it will return whether the controller is read or not. + public void do_single_step(IController controller, out bool cont_read, out bool frame_done) + { + _controller = controller; + + controller_was_latched = false; + frame_is_done = false; + + current_strobe = new_strobe; + if (ppu.ppudead > 0) + { + ppu.NewDeadPPU(); + } + else if (ppu.do_vbl) + { + ppu.TickPPU_VBL(); + } + else if (ppu.do_active_sl) + { + ppu.TickPPU_active(); + } + else if (ppu.do_pre_vbl) + { + ppu.TickPPU_preVBL(); + } + + cont_read = controller_was_latched; + frame_done = frame_is_done; } //PAL: @@ -736,6 +778,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES var si = new StrobeInfo(latched4016, value); ControllerDeck.Strobe(si, _controller); latched4016 = value; + new_strobe = (value & 1) > 0; + if (current_strobe && !new_strobe) + { + controller_was_latched = true; + alt_lag = false; + } } byte read_joyport(int addr) @@ -743,6 +791,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES InputCallbacks.Call(); lagged = false; byte ret = 0; + if (_isVS) { // for whatever reason, in VS left and right controller have swapped regs @@ -752,7 +801,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES { ret = addr == 0x4016 ? ControllerDeck.ReadA(_controller) : ControllerDeck.ReadB(_controller); } - + ret &= 0x1f; ret |= (byte)(0xe0 & DB); return ret; @@ -810,7 +859,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public byte DummyReadMemory(ushort addr) { return 0; } - private void ApplySystemBusPoke(int addr, byte value) + public void ApplySystemBusPoke(int addr, byte value) { if (addr < 0x2000) { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IStatable.cs index e2dd212602..eeda0a5fd7 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IStatable.cs @@ -82,7 +82,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES ser.Sync("VS_Coin", ref VS_coin_inserted); ser.Sync("VS_ROM_Control", ref VS_ROM_control); - ser.BeginSection("Board"); + // single cycle execution related + ser.Sync("current_strobe", ref current_strobe); + ser.Sync("new_strobe", ref new_strobe); + + ser.BeginSection("Board"); Board.SyncState(ser); if (Board is NESBoardBase && !((NESBoardBase)Board).SyncStateFlag) throw new InvalidOperationException("the current NES mapper didnt call base.SyncState"); diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs index 5da37f44c4..62d534f935 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs @@ -126,7 +126,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public DisplayType Region { get { return _display_type; } } - class MyVideoProvider : IVideoProvider + public class MyVideoProvider : IVideoProvider { //public int ntsc_top = 8; //public int ntsc_bottom = 231; @@ -246,7 +246,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public int VsyncDenominator => emu.VsyncDen; } - MyVideoProvider videoProvider; + public MyVideoProvider videoProvider; [Obsolete] // with the changes to both nes and quicknes cores, nothing uses this anymore public static readonly ControllerDefinition NESController = diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs index 36df0ab4c3..b04744f5f8 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs @@ -158,11 +158,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES return nes.Board.PeekPPU(addr); } - public enum PPUPHASE - { - VBL, BG, OBJ - }; - public PPUPHASE ppuphase; + public static int PPU_PHASE_VBL = 0; + public static int PPU_PHASE_BG = 1; + public static int PPU_PHASE_OBJ = 2; + + public int ppuphase; private readonly NES nes; public PPU(NES nes) @@ -247,6 +247,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES ser.Sync("OAM", ref OAM, false); ser.Sync("soam", ref soam, false); ser.Sync("PALRAM", ref PALRAM, false); + ser.Sync("ppuphase", ref ppuphase); ser.Sync("Reg2002_objoverflow", ref Reg2002_objoverflow); ser.Sync("Reg2002_objhit", ref Reg2002_objhit); diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.regs.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.regs.cs index 0fa0bc98cd..739338840a 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.regs.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.regs.cs @@ -551,7 +551,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES //does this take 4x longer? nestopia indicates so perhaps... int addr = ppur.get_2007access(); - if (ppuphase == PPUPHASE.BG) + if (ppuphase == PPU_PHASE_BG) { if (show_bg_new) { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.run.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.run.cs index 3b2199bf06..ead5ce61b5 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.run.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.run.cs @@ -151,7 +151,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES // These things happen at the start of every frame //Reg2002_vblank_active = true; //Reg2002_vblank_active_pending = true; - ppuphase = PPUPHASE.VBL; + ppuphase = PPU_PHASE_VBL; bgdata = new BGDataRecord[34]; } @@ -194,6 +194,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES { do_vbl = false; ppur.status.sl = 0; + do_active_sl = true; } } } @@ -216,7 +217,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES sprite_zero_in_range = false; yp = ppur.status.sl - 1; - ppuphase = PPUPHASE.BG; + ppuphase = PPU_PHASE_BG; // "If PPUADDR is not less then 8 when rendering starts, the first 8 bytes in OAM are written to from // the current location of PPUADDR" @@ -615,7 +616,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES if (soam_index_prev > 8 && !nes.Settings.AllowMoreThanEightSprites) soam_index_prev = 8; - ppuphase = PPUPHASE.OBJ; + ppuphase = PPU_PHASE_OBJ; spriteHeight = reg_2000.obj_size_16 ? 16 : 8; @@ -926,7 +927,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES { if (ppur.status.cycle == 320) { - ppuphase = PPUPHASE.BG; + ppuphase = PPU_PHASE_BG; xt = 0; xp = 0; } @@ -992,6 +993,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES if (ppur.status.sl == 241) { do_active_sl = false; + do_pre_vbl = true; } } } @@ -1012,6 +1014,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES if (ppur.status.sl == 241 + preNMIlines) { do_pre_vbl = false; + do_vbl = true; + + ppu_init_frame(); + nes.frame_is_done = true; } } } @@ -1033,6 +1039,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES if (ppur.status.cycle == 241 * 341 - start_up_offset) { ppudead--; + + ppu_init_frame(); + + do_vbl = true; + + nes.frame_is_done = true; } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs index 899ae0254f..aad8579a37 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs @@ -179,7 +179,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES #endregion - public void FrameAdvance(IController controller, bool render, bool rendersound = true) + public bool FrameAdvance(IController controller, bool render, bool rendersound = true) { CheckDisposed(); using (FP.Save()) @@ -211,6 +211,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES if (CB1 != null) CB1(); if (CB2 != null) CB2(); } + + return true; } IntPtr Context; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.IEmulator.cs index a245fbdbbf..e16511cbaa 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.IEmulator.cs @@ -10,7 +10,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES public ControllerDefinition ControllerDefinition => _controllerDeck.Definition; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { _controller = controller; @@ -80,6 +80,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES { LagCount++; } + + return true; } public int Frame diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/ReadMe.txt b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/ReadMe.txt new file mode 100644 index 0000000000..bc60bf4b01 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/ReadMe.txt @@ -0,0 +1 @@ +TODO: diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IDebuggable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IDebuggable.cs new file mode 100644 index 0000000000..fe41918f23 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IDebuggable.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; + +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk +{ + public partial class SubNESHawk : IDebuggable + { + public IDictionary GetCpuFlagsAndRegisters() + { + return new Dictionary + { + /* + ["A"] = cpu.A, + ["X"] = cpu.X, + ["Y"] = cpu.Y, + ["S"] = cpu.S, + ["PC"] = cpu.PC, + ["Flag C"] = cpu.FlagC, + ["Flag Z"] = cpu.FlagZ, + ["Flag I"] = cpu.FlagI, + ["Flag D"] = cpu.FlagD, + ["Flag B"] = cpu.FlagB, + ["Flag V"] = cpu.FlagV, + ["Flag N"] = cpu.FlagN, + ["Flag T"] = cpu.FlagT + */ + }; + } + + public void SetCpuRegister(string register, int value) + { + switch (register) + { + default: + throw new InvalidOperationException(); + case "A": + //cpu.A = (byte)value; + break; + case "X": + //cpu.X = (byte)value; + break; + case "Y": + //cpu.Y = (byte)value; + break; + case "S": + //cpu.S = (byte)value; + break; + case "PC": + //cpu.PC = (ushort)value; + break; + case "Flag I": + //cpu.FlagI = value > 0; + break; + } + } + + public bool CanStep(StepType type) + { + return false; + } + + public IMemoryCallbackSystem MemoryCallbacks { get; private set; } + + [FeatureNotImplemented] + public void Step(StepType type) { throw new NotImplementedException(); } + + public long TotalExecutedCycles + { + get { return subnes.cpu.TotalExecutedCycles; } + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IEmulator.cs new file mode 100644 index 0000000000..ba5b1c0638 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IEmulator.cs @@ -0,0 +1,221 @@ +using System; + +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Cores.Nintendo.NES; + +namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk +{ + public partial class SubNESHawk : IEmulator + { + public IEmulatorServiceProvider ServiceProvider { get; } + + public ControllerDefinition ControllerDefinition => subnes.ControllerDefinition; + + public bool FrameAdvance(IController controller, bool render, bool rendersound) + { + //Console.WriteLine("-----------------------FRAME-----------------------"); + if (_tracer.Enabled) + { + subnes.cpu.TraceCallback = s => _tracer.Put(s); + } + else + { + subnes.cpu.TraceCallback = null; + } + + _frame++; + + if (controller.IsPressed("Power")) + { + HardReset(); + } + + reset_frame = false; + if (controller.IsPressed("Reset")) + { + reset_frame = true; + } + + reset_cycle = controller.GetFloat("Reset Cycle"); + reset_cycle_int = (int)Math.Floor(reset_cycle); + + _islag = true; + subnes.alt_lag = true; + + InputCallbacks.Call(); + + do_frame(controller); + + bool ret = pass_a_frame; + + if (pass_a_frame) + { + subnes.videoProvider.FillFrameBuffer(); + current_cycle = 0; + subnes.cpu.ext_ppu_cycle = current_cycle; + } + + _islag = subnes.alt_lag; + + if (_islag) + { + _lagcount++; + VBL_CNT++; + } + + reset_frame = false; + return ret; + } + + public bool stop_cur_frame; + public bool pass_new_input; + public bool pass_a_frame; + public bool reset_frame; + public int current_cycle; + public float reset_cycle; + public int reset_cycle_int; + + public void do_frame(IController controller) + { + stop_cur_frame = false; + while (!stop_cur_frame) + { + if (reset_frame && (current_cycle == reset_cycle_int)) + { + SoftReset(); + reset_frame = false; + } + subnes.do_single_step(controller, out pass_new_input, out pass_a_frame); + current_cycle++; + subnes.cpu.ext_ppu_cycle = current_cycle; + stop_cur_frame |= pass_a_frame; + stop_cur_frame |= pass_new_input; + } + } + + public int Frame => _frame; + + public string SystemId => "NES"; + + public bool DeterministicEmulation { get; set; } + + public void ResetCounters() + { + _frame = 0; + _lagcount = 0; + _islag = false; + } + + public CoreComm CoreComm { get; } + + public void Dispose() + { + subnes.Dispose(); + } + /* + #region Video provider + + public int _frameHz = 60; + + public int[] _vidbuffer = new int[160 * 2 * 144]; + public int[] buff_L = new int[160 * 144]; + public int[] buff_R = new int[160 * 144]; + + public int[] GetVideoBuffer() + { + // combine the 2 video buffers from the instances + for (int i = 0; i < 144; i++) + { + for (int j = 0; j < 160; j++) + { + _vidbuffer[i * 320 + j] = buff_L[i * 160 + j]; + _vidbuffer[i * 320 + j + 160] = buff_R[i * 160 + j]; + } + } + + return _vidbuffer; + } + + public int VirtualWidth => 160 * 2; + public int VirtualHeight => 144; + public int BufferWidth => 160 * 2; + public int BufferHeight => 144; + public int BackgroundColor => unchecked((int)0xFF000000); + public int VsyncNumerator => _frameHz; + public int VsyncDenominator => 1; + + public static readonly uint[] color_palette_BW = { 0xFFFFFFFF , 0xFFAAAAAA, 0xFF555555, 0xFF000000 }; + public static readonly uint[] color_palette_Gr = { 0xFFA4C505, 0xFF88A905, 0xFF1D551D, 0xFF052505 }; + + public uint[] color_palette = new uint[4]; + + #endregion + + #region audio + + public bool CanProvideAsync => false; + + public void SetSyncMode(SyncSoundMode mode) + { + if (mode != SyncSoundMode.Sync) + { + throw new InvalidOperationException("Only Sync mode is supported_"); + } + } + + public SyncSoundMode SyncMode => SyncSoundMode.Sync; + + public void GetSamplesSync(out short[] samples, out int nsamp) + { + short[] temp_samp_L; + short[] temp_samp_R; + + int nsamp_L; + int nsamp_R; + + L.audio.GetSamplesSync(out temp_samp_L, out nsamp_L); + R.audio.GetSamplesSync(out temp_samp_R, out nsamp_R); + + if (linkSettings.AudioSet == GBLinkSettings.AudioSrc.Left) + { + samples = temp_samp_L; + nsamp = nsamp_L; + } + else if (linkSettings.AudioSet == GBLinkSettings.AudioSrc.Right) + { + samples = temp_samp_R; + nsamp = nsamp_R; + } + else + { + samples = new short[0]; + nsamp = 0; + } + } + + public void GetSamplesAsync(short[] samples) + { + throw new NotSupportedException("Async is not available"); + } + + public void DiscardSamples() + { + L.audio.DiscardSamples(); + R.audio.DiscardSamples(); + } + + private void GetSamples(short[] samples) + { + + } + + public void DisposeSound() + { + L.audio.DisposeSound(); + R.audio.DisposeSound(); + } + + #endregion + */ + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IInputPollable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IInputPollable.cs new file mode 100644 index 0000000000..04c6faea5c --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IInputPollable.cs @@ -0,0 +1,24 @@ +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk +{ + public partial class SubNESHawk : IInputPollable + { + public int LagCount + { + get { return _lagcount; } + set { _lagcount = value; } + } + + public bool IsLagFrame + { + get { return _islag; } + set { _islag = value; } + } + + public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem(); + + public bool _islag = true; + private int _lagcount; + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IMemoryDomains.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IMemoryDomains.cs new file mode 100644 index 0000000000..b1aafedaf7 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IMemoryDomains.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk +{ + public partial class SubNESHawk + { + private MemoryDomainList _memoryDomains; + private bool _memoryDomainsSetup = false; + + private void SetupMemoryDomains() + { + var domains = new List(); + var RAM = new MemoryDomainByteArray("RAM", MemoryDomain.Endian.Little, subnes.ram, true, 1); + var SystemBus = new MemoryDomainDelegate("System Bus", 0x10000, MemoryDomain.Endian.Little, + addr => subnes.PeekMemory((ushort)addr), (addr, value) => subnes.ApplySystemBusPoke((int)addr, value), 1); + var PPUBus = new MemoryDomainDelegate("PPU Bus", 0x4000, MemoryDomain.Endian.Little, + addr => subnes.ppu.ppubus_peek((int)addr), (addr, value) => subnes.ppu.ppubus_write((int)addr, value), 1); + var CIRAMdomain = new MemoryDomainByteArray("CIRAM (nametables)", MemoryDomain.Endian.Little, subnes.CIRAM, true, 1); + var OAMdoman = new MemoryDomainByteArray("OAM", MemoryDomain.Endian.Unknown, subnes.ppu.OAM, true, 1); + + domains.Add(RAM); + domains.Add(SystemBus); + domains.Add(PPUBus); + domains.Add(CIRAMdomain); + domains.Add(OAMdoman); + + if (!(subnes.Board is NES.FDS) && subnes.Board.SaveRam != null) + { + var BatteryRam = new MemoryDomainByteArray("Battery RAM", MemoryDomain.Endian.Little, subnes.Board.SaveRam, true, 1); + domains.Add(BatteryRam); + } + + if (subnes.Board.ROM != null) + { + var PRGROM = new MemoryDomainByteArray("PRG ROM", MemoryDomain.Endian.Little, subnes.Board.ROM, true, 1); + domains.Add(PRGROM); + } + + if (subnes.Board.VROM != null) + { + var CHRROM = new MemoryDomainByteArray("CHR VROM", MemoryDomain.Endian.Little, subnes.Board.VROM, true, 1); + domains.Add(CHRROM); + } + + if (subnes.Board.VRAM != null) + { + var VRAM = new MemoryDomainByteArray("VRAM", MemoryDomain.Endian.Little, subnes.Board.VRAM, true, 1); + domains.Add(VRAM); + } + + if (subnes.Board.WRAM != null) + { + var WRAM = new MemoryDomainByteArray("WRAM", MemoryDomain.Endian.Little, subnes.Board.WRAM, true, 1); + domains.Add(WRAM); + } + + // if there were more boards with special ram sets, we'd want to do something more general + if (subnes.Board is NES.FDS) + { + domains.Add((subnes.Board as NES.FDS).GetDiskPeeker()); + } + else if (subnes.Board is NES.ExROM) + { + domains.Add((subnes.Board as NES.ExROM).GetExRAM()); + } + + if (!_memoryDomainsSetup) + { + _memoryDomains = new MemoryDomainList(domains); + (ServiceProvider as BasicServiceProvider).Register(_memoryDomains); + _memoryDomainsSetup = true; + } + else + { + var src = new MemoryDomainList(domains); + _memoryDomains.MergeList(src); + } + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.ISaveRam.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.ISaveRam.cs new file mode 100644 index 0000000000..1d61877e5b --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.ISaveRam.cs @@ -0,0 +1,42 @@ +using System; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk +{ + public partial class SubNESHawk : ISaveRam + { + public bool SaveRamModified + { + get + { + if (subnes.Board == null) return false; + if (subnes.Board is NES.FDS) return true; + if (subnes.Board.SaveRam == null) return false; + return true; + } + } + + public byte[] CloneSaveRam() + { + if (subnes.Board is NES.FDS) + return (subnes.Board as NES.FDS).ReadSaveRam(); + + if (subnes.Board == null || subnes.Board.SaveRam == null) + return null; + return (byte[])subnes.Board.SaveRam.Clone(); + } + + public void StoreSaveRam(byte[] data) + { + if (subnes.Board is NES.FDS) + { + (subnes.Board as NES.FDS).StoreSaveRam(data); + return; + } + + if (subnes.Board == null || subnes.Board.SaveRam == null) + return; + Array.Copy(data, subnes.Board.SaveRam, data.Length); + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IStatable.cs new file mode 100644 index 0000000000..110e5274b0 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IStatable.cs @@ -0,0 +1,64 @@ +using System.IO; + +using BizHawk.Common; +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Cores.Nintendo.NES; + +namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk +{ + public partial class SubNESHawk : IStatable + { + public bool BinarySaveStatesPreferred => true; + + public void SaveStateText(TextWriter writer) + { + subnes.SaveStateText(writer); + SyncState(new Serializer(writer)); + } + + public void LoadStateText(TextReader reader) + { + subnes.LoadStateText(reader); + SyncState(new Serializer(reader)); + } + + public void SaveStateBinary(BinaryWriter bw) + { + subnes.SaveStateBinary(bw); + // other variables + SyncState(new Serializer(bw)); + } + + public void LoadStateBinary(BinaryReader br) + { + subnes.LoadStateBinary(br); + // other variables + SyncState(new Serializer(br)); + } + + public byte[] SaveStateBinary() + { + MemoryStream ms = new MemoryStream(); + BinaryWriter bw = new BinaryWriter(ms); + SaveStateBinary(bw); + bw.Flush(); + return ms.ToArray(); + } + + //private JsonSerializer ser = new JsonSerializer { Formatting = Formatting.Indented }; + + private void SyncState(Serializer ser) + { + ser.Sync("Lag", ref _lagcount); + ser.Sync("Frame", ref _frame); + ser.Sync("IsLag", ref _islag); + ser.Sync("pass_a_frame", ref pass_a_frame); + ser.Sync("reset_frame", ref reset_frame); + ser.Sync("pass_new_input", ref pass_new_input); + ser.Sync("current_cycle", ref current_cycle); + ser.Sync("reset_cycle", ref reset_cycle); + ser.Sync("reset_cycle_int", ref reset_cycle_int); + ser.Sync("VBL_CNT", ref VBL_CNT); + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs new file mode 100644 index 0000000000..d74af9ed40 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs @@ -0,0 +1,229 @@ +using System; + +using BizHawk.Emulation.Common; + +using BizHawk.Emulation.Cores.Nintendo.NES; + +namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk +{ + [Core( + "SubNESHawk", + "", + isPorted: false, + isReleased: false)] + [ServiceNotApplicable(typeof(IDriveLight))] + public partial class SubNESHawk : IEmulator, ISaveRam, IDebuggable, IStatable, IInputPollable, IRegionable, + ISettable, INESPPUViewable + { + public NES.NES subnes; + + // needed for movies to accurately calculate timing + public int VBL_CNT; + + [CoreConstructor("NES")] + public SubNESHawk(CoreComm comm, GameInfo game, byte[] rom, /*string gameDbFn,*/ object settings, object syncSettings) + { + var ser = new BasicServiceProvider(this); + + subnesSettings = (NES.NES.NESSettings)settings ?? new NES.NES.NESSettings(); + subnesSyncSettings = (NES.NES.NESSyncSettings)syncSettings ?? new NES.NES.NESSyncSettings(); + + CoreComm = comm; + + subnes = new NES.NES(new CoreComm(comm.ShowMessage, comm.Notify) { CoreFileProvider = comm.CoreFileProvider }, + game, rom, subnesSettings, subnesSyncSettings); + + ser.Register(subnes.videoProvider); + ser.Register(subnes.magicSoundProvider); + + _tracer = new TraceBuffer { Header = "6502: PC, machine code, mnemonic, operands, registers (A, X, Y, P, SP), flags (NVTBDIZCR), CPU Cycle, PPU Cycle" }; + ser.Register(_tracer); + + ServiceProvider = ser; + + SetupMemoryDomains(); + + subnes.using_reset_timing = true; + HardReset(); + current_cycle = 0; + subnes.cpu.ext_ppu_cycle = current_cycle; + VBL_CNT = 0; + } + + public void HardReset() + { + subnes.HardReset(); + } + + public void SoftReset() + { + subnes.Board.NESSoftReset(); + subnes.cpu.NESSoftReset(); + subnes.apu.NESSoftReset(); + subnes.ppu.NESSoftReset(); + current_cycle = 0; + subnes.cpu.ext_ppu_cycle = current_cycle; + } + + public DisplayType Region => DisplayType.NTSC; + + public int _frame = 0; + + private readonly ITraceable _tracer; + + private void ExecFetch(ushort addr) + { + MemoryCallbacks.CallExecutes(addr, "System Bus"); + } + + #region ISettable + private NES.NES.NESSettings subnesSettings = new NES.NES.NESSettings(); + public NES.NES.NESSyncSettings subnesSyncSettings = new NES.NES.NESSyncSettings(); + + public NES.NES.NESSettings GetSettings() + { + return subnesSettings.Clone(); + } + + public NES.NES.NESSyncSettings GetSyncSettings() + { + return subnesSyncSettings.Clone(); + } + + public bool PutSettings(NES.NES.NESSettings o) + { + subnesSettings = o; + if (subnesSettings.ClipLeftAndRight) + { + subnes.videoProvider.left = 8; + subnes.videoProvider.right = 247; + } + else + { + subnes.videoProvider.left = 0; + subnes.videoProvider.right = 255; + } + + CoreComm.ScreenLogicalOffsetX = subnes.videoProvider.left; + CoreComm.ScreenLogicalOffsetY = Region == DisplayType.NTSC ? subnesSettings.NTSC_TopLine : subnesSettings.PAL_TopLine; + + subnes.SetPalette(subnesSettings.Palette); + + subnes.apu.m_vol = subnesSettings.APU_vol; + + return false; + } + + public bool PutSyncSettings(NES.NES.NESSyncSettings o) + { + bool ret = NES.NES.NESSyncSettings.NeedsReboot(subnesSyncSettings, o); + subnesSyncSettings = o; + return ret; + } + #endregion + + #region PPU Viewable + + public int[] GetPalette() + { + return subnes.palette_compiled; + } + + public bool BGBaseHigh + { + get { return subnes.ppu.reg_2000.bg_pattern_hi; } + } + + public bool SPBaseHigh + { + get { return subnes.ppu.reg_2000.obj_pattern_hi; } + } + + public bool SPTall + { + get { return subnes.ppu.reg_2000.obj_size_16; } + } + + public byte[] GetPPUBus() + { + byte[] ret = new byte[0x3000]; + for (int i = 0; i < 0x3000; i++) + { + ret[i] = subnes.ppu.ppubus_peek(i); + } + return ret; + } + + public byte[] GetPalRam() + { + return subnes.ppu.PALRAM; + } + + public byte[] GetOam() + { + return subnes.ppu.OAM; + } + + public byte PeekPPU(int addr) + { + return subnes.Board.PeekPPU(addr); + } + + public byte[] GetExTiles() + { + if (subnes.Board is ExROM) + { + return subnes.Board.VROM ?? subnes.Board.VRAM; + } + else + { + throw new InvalidOperationException(); + } + } + + public bool ExActive + { + get { return subnes.Board is ExROM && (subnes.Board as ExROM).ExAttrActive; } + } + + public byte[] GetExRam() + { + if (subnes.Board is ExROM) + { + return (subnes.Board as ExROM).GetExRAMArray(); + } + else + { + throw new InvalidOperationException(); + } + } + + public MemoryDomain GetCHRROM() + { + return _memoryDomains["CHR VROM"]; + } + + + public void InstallCallback1(Action cb, int sl) + { + subnes.ppu.NTViewCallback = new PPU.DebugCallback { Callback = cb, Scanline = sl }; + } + + public void InstallCallback2(Action cb, int sl) + { + subnes.ppu.PPUViewCallback = new PPU.DebugCallback { Callback = cb, Scanline = sl }; + } + + public void RemoveCallback1() + { + subnes.ppu.NTViewCallback = null; + } + + public void RemoveCallback2() + { + subnes.ppu.PPUViewCallback = null; + } + + #endregion + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/PC Engine/PCEngine.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/PC Engine/PCEngine.IEmulator.cs index 5fa7f01d7e..6b46010327 100644 --- a/BizHawk.Emulation.Cores/Consoles/PC Engine/PCEngine.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/PC Engine/PCEngine.IEmulator.cs @@ -8,7 +8,7 @@ namespace BizHawk.Emulation.Cores.PCEngine public ControllerDefinition ControllerDefinition => _controllerDeck.Definition; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { _controller = controller; _lagged = true; @@ -39,6 +39,8 @@ namespace BizHawk.Emulation.Cores.PCEngine { _isLag = false; } + + return true; } public int Frame diff --git a/BizHawk.Emulation.Cores/Consoles/SNK/DualNeoGeoPort.cs b/BizHawk.Emulation.Cores/Consoles/SNK/DualNeoGeoPort.cs index 462b62fbee..ae20720922 100644 --- a/BizHawk.Emulation.Cores/Consoles/SNK/DualNeoGeoPort.cs +++ b/BizHawk.Emulation.Cores/Consoles/SNK/DualNeoGeoPort.cs @@ -47,7 +47,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SNK _serviceProvider.Register(_videoProvider); } - public void FrameAdvance(IController controller, bool render, bool rendersound = true) + public bool FrameAdvance(IController controller, bool render, bool rendersound = true) { var t1 = Task.Run(() => { @@ -67,6 +67,8 @@ namespace BizHawk.Emulation.Cores.Consoles.SNK Frame++; _soundProvider.Fetch(); _videoProvider.Fetch(); + + return true; } #region link cable diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IEmulator.cs index 1ac7e86924..d3fbefd440 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IEmulator.cs @@ -37,7 +37,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem } } - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { _controller = controller; _lagged = true; @@ -86,6 +86,8 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem { _isLag = false; } + + return true; } public int Frame => _frame; diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IEmulator.cs index e0a3ac20b1..475d1562fc 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IEmulator.cs @@ -7,45 +7,45 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx { public IEmulatorServiceProvider ServiceProvider { get; private set; } - public ControllerDefinition ControllerDefinition { get; private set; } - - // TODO: use render and rendersound - public void FrameAdvance(IController controller, bool render, bool rendersound = true) + public ControllerDefinition ControllerDefinition { get; private set; } + + // TODO: use render and rendersound + public bool FrameAdvance(IController controller, bool render, bool rendersound = true) { if (controller.IsPressed("Reset")) Core.gpgx_reset(false); if (controller.IsPressed("Power")) - Core.gpgx_reset(true); - if (_cds != null) - { - var prev = controller.IsPressed("Previous Disk"); - var next = controller.IsPressed("Next Disk"); - int newDisk = _discIndex; - if (prev && !_prevDiskPressed) - newDisk--; - if (next && !_nextDiskPressed) - newDisk++; - - _prevDiskPressed = prev; - _nextDiskPressed = next; - - if (newDisk < -1) - newDisk = -1; - if (newDisk >= _cds.Length) - newDisk = _cds.Length - 1; - - if (newDisk != _discIndex) - { - _discIndex = newDisk; - Core.gpgx_swap_disc(_discIndex == -1 ? null : GetCDDataStruct(_cds[_discIndex])); - Console.WriteLine("IMMA CHANGING MAH DISKS"); - } - } - - // this shouldn't be needed, as nothing has changed - // if (!Core.gpgx_get_control(input, inputsize)) - // throw new Exception("gpgx_get_control() failed!"); - + Core.gpgx_reset(true); + if (_cds != null) + { + var prev = controller.IsPressed("Previous Disk"); + var next = controller.IsPressed("Next Disk"); + int newDisk = _discIndex; + if (prev && !_prevDiskPressed) + newDisk--; + if (next && !_nextDiskPressed) + newDisk++; + + _prevDiskPressed = prev; + _nextDiskPressed = next; + + if (newDisk < -1) + newDisk = -1; + if (newDisk >= _cds.Length) + newDisk = _cds.Length - 1; + + if (newDisk != _discIndex) + { + _discIndex = newDisk; + Core.gpgx_swap_disc(_discIndex == -1 ? null : GetCDDataStruct(_cds[_discIndex])); + Console.WriteLine("IMMA CHANGING MAH DISKS"); + } + } + + // this shouldn't be needed, as nothing has changed + // if (!Core.gpgx_get_control(input, inputsize)) + // throw new Exception("gpgx_get_control() failed!"); + ControlConverter.ScreenWidth = vwidth; ControlConverter.ScreenHeight = vheight; ControlConverter.Convert(controller, input); @@ -66,6 +66,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx if (_cds != null) DriveLightOn = _drivelight; + + return true; } public int Frame { get; private set; } @@ -96,7 +98,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx if (_elf != null) _elf.Dispose(); if (_cds != null) - foreach (var cd in _cds) + foreach (var cd in _cds) cd.Dispose(); _disposed = true; } diff --git a/BizHawk.Emulation.Cores/Consoles/Sony/PSP/PSP.cs b/BizHawk.Emulation.Cores/Consoles/Sony/PSP/PSP.cs index 5c43900826..55157f7abe 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sony/PSP/PSP.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sony/PSP/PSP.cs @@ -131,7 +131,7 @@ namespace BizHawk.Emulation.Cores.Sony.PSP } - public void FrameAdvance(IController controller, bool render, bool rendersound = true) + public bool FrameAdvance(IController controller, bool render, bool rendersound = true) { Frame++; UpdateInput(controller); @@ -147,6 +147,8 @@ namespace BizHawk.Emulation.Cores.Sony.PSP //nsampavail = PPSSPPDll.mixsound(audiobuffer, audiobuffer.Length / 2); LogFlush(); //Console.WriteLine("Audio Service: {0}", nsampavail); + + return true; } public int Frame diff --git a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs index 807558d6b3..eca318a577 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs @@ -743,7 +743,7 @@ namespace BizHawk.Emulation.Cores.Sony.PSX private IController _controller; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { _controller = controller; FrameAdvance_PrepDiscState(); @@ -801,7 +801,7 @@ namespace BizHawk.Emulation.Cores.Sony.PSX LagCount++; //what happens to sound in this case? - if (render == false) return; + if (render == false) return true; OctoshockDll.ShockFramebufferInfo fb = new OctoshockDll.ShockFramebufferInfo(); @@ -843,6 +843,8 @@ namespace BizHawk.Emulation.Cores.Sony.PSX if (sbuffcontains * 2 > sbuff.Length) throw new InvalidOperationException("shock_GetSamples returned too many samples: " + sbuffcontains); OctoshockDll.shock_GetSamples(psx, samples); } + + return true; } public ControllerDefinition ControllerDefinition { get; private set; } diff --git a/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs b/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs index 49f91a1824..b5224065ea 100644 --- a/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs +++ b/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs @@ -61,7 +61,7 @@ namespace BizHawk.Emulation.Cores.WonderSwan } } - public void FrameAdvance(IController controller, bool render, bool rendersound = true) + public bool FrameAdvance(IController controller, bool render, bool rendersound = true) { Frame++; IsLagFrame = true; @@ -79,6 +79,8 @@ namespace BizHawk.Emulation.Cores.WonderSwan if (IsLagFrame) LagCount++; + + return true; } public CoreComm CoreComm { get; private set; } diff --git a/BizHawk.Emulation.Cores/Libretro/LibretroCore.cs b/BizHawk.Emulation.Cores/Libretro/LibretroCore.cs index f52709963b..3d3fca7bb9 100644 --- a/BizHawk.Emulation.Cores/Libretro/LibretroCore.cs +++ b/BizHawk.Emulation.Cores/Libretro/LibretroCore.cs @@ -154,11 +154,13 @@ namespace BizHawk.Emulation.Cores.Libretro private IController _controller; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { _controller = controller; api.CMD_Run(); timeFrameCounter++; + + return true; } GCHandle vidBufferHandle; diff --git a/BizHawk.Emulation.Cores/Waterbox/WaterboxCore.cs b/BizHawk.Emulation.Cores/Waterbox/WaterboxCore.cs index 3c717bb65f..f202a6b3dd 100644 --- a/BizHawk.Emulation.Cores/Waterbox/WaterboxCore.cs +++ b/BizHawk.Emulation.Cores/Waterbox/WaterboxCore.cs @@ -191,7 +191,7 @@ namespace BizHawk.Emulation.Cores.Waterbox protected virtual void FrameAdvancePost() { } - public unsafe void FrameAdvance(IController controller, bool render, bool rendersound = true) + public unsafe bool FrameAdvance(IController controller, bool render, bool rendersound = true) { using (_exe.EnterExit()) { @@ -218,6 +218,8 @@ namespace BizHawk.Emulation.Cores.Waterbox FrameAdvancePost(); } } + + return true; } private bool _disposed = false;