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 b7f72ab639..60c0071725 100644
--- a/BizHawk.Client.Common/config/Config.cs
+++ b/BizHawk.Client.Common/config/Config.cs
@@ -554,6 +554,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.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..f524b4bb13 100644
--- a/BizHawk.Client.EmuHawk/MainForm.Events.cs
+++ b/BizHawk.Client.EmuHawk/MainForm.Events.cs
@@ -1215,6 +1215,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 +1309,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;
diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs
index 28f0311d31..a7a40b17aa 100644
--- a/BizHawk.Client.EmuHawk/MainForm.cs
+++ b/BizHawk.Client.EmuHawk/MainForm.cs
@@ -2997,7 +2997,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,7 +3036,7 @@ namespace BizHawk.Client.EmuHawk
UpdateToolsAfter(SuppressLua);
}
- if (!PauseAvi)
+ if (!PauseAvi && new_frame)
{
AvFrameAdvance();
}
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..dda627b813 100644
--- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
+++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
@@ -1201,6 +1201,30 @@
+
+
+ SubNESHawk.cs
+
+
+ SubNESHawk.cs
+
+
+ SubNESHawk.cs
+
+
+ SubNESHawk.cs
+
+
+ SubNESHawk.cs
+
+
+ SubNESHawk.cs
+
+
+ SubNESHawk.cs
+
+
+
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 1cebe9f5b4..dc431a50fc 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/Gambatte.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
index 1f1891e1a5..b0bdd405d9 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
@@ -344,7 +344,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
LibGambatte.gambatte_setlayers(GambatteState, (_settings.DisplayBG ? 1 : 0) | (_settings.DisplayOBJ ? 2 : 0) | (_settings.DisplayWindow ? 4 : 0));
}
- internal void FrameAdvancePost()
+ internal bool FrameAdvancePost()
{
if (IsLagFrame)
{
@@ -352,6 +352,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
}
endofframecallback?.Invoke(LibGambatte.gambatte_cpuread(GambatteState, 0xff40));
+
+ return true;
}
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..851291e2a1 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs
@@ -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()
{
@@ -311,7 +311,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 +377,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 +409,50 @@ 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;
+ public byte ctrl_1 = 0;
+ public byte ctrl_2 = 0;
+ public byte ctrl_1_new = 0;
+ public byte ctrl_2_new = 0;
+ public int shift_1;
+ public int shift_2;
+ public bool use_sub_input = 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(out bool cont_read, out bool frame_done)
+ {
+ 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 +774,27 @@ 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;
+
+ if (use_sub_input)
+ {
+ shift_1 = 7;
+ shift_2 = 7;
+
+ ctrl_1 = ctrl_1_new;
+ ctrl_2 = ctrl_2_new;
+ }
+ }
+
+ if (use_sub_input && new_strobe)
+ {
+ shift_1 = 7;
+ shift_2 = 7;
+ }
}
byte read_joyport(int addr)
@@ -743,14 +802,35 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
InputCallbacks.Call();
lagged = false;
byte ret = 0;
- if (_isVS)
+
+ if (use_sub_input)
{
- // for whatever reason, in VS left and right controller have swapped regs
- ret = addr == 0x4017 ? ControllerDeck.ReadA(_controller) : ControllerDeck.ReadB(_controller);
+ if (addr == 0x4016)
+ {
+ if (shift_1 >= 0) { ret = (byte)((ctrl_1 >> shift_1) & 1); }
+ else { ret = 1; }
+
+ if (!current_strobe) { shift_1 -= 1; }
+ }
+ else
+ {
+ if (shift_2 >= 0) { ret = (byte)((ctrl_2 >> shift_2) & 1); }
+ else { ret = 1; }
+
+ if (!current_strobe) { shift_2 -= 1; }
+ }
}
else
{
- ret = addr == 0x4016 ? ControllerDeck.ReadA(_controller) : ControllerDeck.ReadB(_controller);
+ if (_isVS)
+ {
+ // for whatever reason, in VS left and right controller have swapped regs
+ ret = addr == 0x4017 ? ControllerDeck.ReadA(_controller) : ControllerDeck.ReadB(_controller);
+ }
+ else
+ {
+ ret = addr == 0x4016 ? ControllerDeck.ReadA(_controller) : ControllerDeck.ReadB(_controller);
+ }
}
ret &= 0x1f;
@@ -810,7 +890,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..7c7b3f7f17 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IStatable.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IStatable.cs
@@ -82,7 +82,16 @@ 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.Sync("ctrl_1", ref ctrl_1);
+ ser.Sync("ctrl_2", ref ctrl_2);
+ ser.Sync("shift_1", ref shift_1);
+ ser.Sync("shift_2", ref shift_2);
+ ser.Sync("use_sub_input", ref use_sub_input);
+
+ 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..3fef3f0d45
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IEmulator.cs
@@ -0,0 +1,215 @@
+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 => _controllerDeck.Definition;
+
+ 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();
+ }
+
+ if (controller.IsPressed("Reset"))
+ {
+ SoftReset();
+ }
+
+ _islag = true;
+ subnes.alt_lag = true;
+
+ GetControllerState(controller);
+
+ do_frame();
+
+ bool ret = pass_a_frame;
+
+ if (pass_a_frame)
+ {
+ subnes.videoProvider.FillFrameBuffer();
+ }
+
+ _islag = subnes.alt_lag;
+
+ if (_islag)
+ {
+ _lagcount++;
+ }
+
+ return ret;
+ }
+
+ public bool stop_cur_frame;
+ public bool pass_new_input;
+ public bool pass_a_frame;
+ public byte ctrl_byte_1;
+ public byte ctrl_byte_2;
+
+ public void do_frame()
+ {
+ stop_cur_frame = false;
+ while (!stop_cur_frame)
+ {
+ subnes.do_single_step(out pass_new_input, out pass_a_frame);
+ stop_cur_frame |= pass_a_frame;
+ stop_cur_frame |= pass_new_input;
+ }
+ }
+
+ public void GetControllerState(IController controller)
+ {
+ InputCallbacks.Call();
+
+ ctrl_byte_1 = _controllerDeck.ReadPort1(controller);
+ ctrl_byte_2 = _controllerDeck.ReadPort2(controller);
+
+ subnes.ctrl_1_new = ctrl_byte_1;
+ subnes.ctrl_2_new = ctrl_byte_2;
+ }
+
+ 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.ISettable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.ISettable.cs
new file mode 100644
index 0000000000..9db3f0acc1
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.ISettable.cs
@@ -0,0 +1,58 @@
+using System;
+
+using BizHawk.Common;
+using BizHawk.Emulation.Common;
+using BizHawk.Emulation.Cores.Nintendo.NES;
+
+namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk
+{
+ public partial class SubNESHawk : IEmulator, IStatable, ISettable
+ {
+ public SubNESHawkSettings GetSettings()
+ {
+ return subnesSettings.Clone();
+ }
+
+ public SubNESHawkSyncSettings GetSyncSettings()
+ {
+ return subnesSyncSettings.Clone();
+ }
+
+ public bool PutSettings(SubNESHawkSettings o)
+ {
+ subnesSettings = o;
+ return false;
+ }
+
+ public bool PutSyncSettings(SubNESHawkSyncSettings o)
+ {
+ bool ret = SubNESHawkSyncSettings.NeedsReboot(subnesSyncSettings, o);
+ subnesSyncSettings = o;
+ return ret;
+ }
+
+ private SubNESHawkSettings subnesSettings = new SubNESHawkSettings();
+ public SubNESHawkSyncSettings subnesSyncSettings = new SubNESHawkSyncSettings();
+
+ public class SubNESHawkSettings
+ {
+ public SubNESHawkSettings Clone()
+ {
+ return (SubNESHawkSettings)MemberwiseClone();
+ }
+ }
+
+ public class SubNESHawkSyncSettings
+ {
+ public SubNESHawkSyncSettings Clone()
+ {
+ return (SubNESHawkSyncSettings)MemberwiseClone();
+ }
+
+ public static bool NeedsReboot(SubNESHawkSyncSettings x, SubNESHawkSyncSettings y)
+ {
+ return !DeepEquality.DeepEquals(x, y);
+ }
+ }
+ }
+}
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..d6a092971e
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IStatable.cs
@@ -0,0 +1,63 @@
+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("pass_new_input", ref pass_new_input);
+ ser.Sync("ctrl_byte_1", ref ctrl_byte_1);
+ ser.Sync("ctrl_byte_2", ref ctrl_byte_2);
+
+ _controllerDeck.SyncState(ser);
+ }
+ }
+}
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..a04a68f7f8
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs
@@ -0,0 +1,80 @@
+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
+ {
+ public NES.NES subnes;
+
+ [CoreConstructor("NES")]
+ public SubNESHawk(CoreComm comm, GameInfo game, byte[] rom, /*string gameDbFn,*/ object settings, object syncSettings)
+ {
+ var ser = new BasicServiceProvider(this);
+
+ subnesSettings = (SubNESHawkSettings)settings ?? new SubNESHawkSettings();
+ subnesSyncSettings = (SubNESHawkSyncSettings)syncSettings ?? new SubNESHawkSyncSettings();
+ _controllerDeck = new SubNESHawkControllerDeck(SubNESHawkControllerDeck.DefaultControllerName, SubNESHawkControllerDeck.DefaultControllerName);
+
+ CoreComm = comm;
+
+ var temp_set = new NES.NES.NESSettings();
+
+ var temp_sync = new NES.NES.NESSyncSettings();
+
+ subnes = new NES.NES(new CoreComm(comm.ShowMessage, comm.Notify) { CoreFileProvider = comm.CoreFileProvider },
+ game, rom, temp_set, temp_sync);
+
+ ser.Register(subnes.videoProvider);
+ ser.Register(subnes.magicSoundProvider);
+
+ _tracer = new TraceBuffer { Header = subnes.cpu.TraceHeader };
+ ser.Register(_tracer);
+
+ ServiceProvider = ser;
+
+ SetupMemoryDomains();
+
+ HardReset();
+
+ // input override for subframe input
+ subnes.use_sub_input = true;
+ }
+
+ public void HardReset()
+ {
+ subnes.HardReset();
+ }
+
+ public void SoftReset()
+ {
+ subnes.Board.NESSoftReset();
+ subnes.cpu.NESSoftReset();
+ subnes.apu.NESSoftReset();
+ subnes.ppu.NESSoftReset();
+ }
+
+ public DisplayType Region => DisplayType.NTSC;
+
+ public int _frame = 0;
+
+ private readonly SubNESHawkControllerDeck _controllerDeck;
+
+ private readonly ITraceable _tracer;
+
+ private void ExecFetch(ushort addr)
+ {
+ MemoryCallbacks.CallExecutes(addr, "System Bus");
+ }
+ }
+}
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawkControllerDeck.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawkControllerDeck.cs
new file mode 100644
index 0000000000..7f2ecfae40
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawkControllerDeck.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using BizHawk.Common;
+using BizHawk.Common.ReflectionExtensions;
+using BizHawk.Emulation.Common;
+
+namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk
+{
+ public class SubNESHawkControllerDeck
+ {
+ public SubNESHawkControllerDeck(string controller1Name, string controller2Name)
+ {
+ if (!ValidControllerTypes.ContainsKey(controller1Name))
+ {
+ throw new InvalidOperationException("Invalid controller type: " + controller1Name);
+ }
+
+ if (!ValidControllerTypes.ContainsKey(controller2Name))
+ {
+ throw new InvalidOperationException("Invalid controller type: " + controller2Name);
+ }
+
+ Port1 = (IPort)Activator.CreateInstance(ValidControllerTypes[controller1Name], 1);
+ Port2 = (IPort)Activator.CreateInstance(ValidControllerTypes[controller2Name], 2);
+
+ Definition = new ControllerDefinition
+ {
+ Name = Port1.Definition.Name,
+ BoolButtons = Port1.Definition.BoolButtons
+ .Concat(Port2.Definition.BoolButtons)
+ .Concat(new[]
+ {
+ "Power",
+ "Reset",
+ })
+ .ToList()
+ };
+ }
+
+ public byte ReadPort1(IController c)
+ {
+ return Port1.Read(c);
+ }
+
+ public byte ReadPort2(IController c)
+ {
+ return Port2.Read(c);
+ }
+
+ public ControllerDefinition Definition { get; }
+
+ public void SyncState(Serializer ser)
+ {
+ ser.BeginSection("Port1");
+ Port1.SyncState(ser);
+ ser.EndSection();
+
+ ser.BeginSection("Port2");
+ Port2.SyncState(ser);
+ ser.EndSection();
+ }
+
+ private readonly IPort Port1;
+ private readonly IPort Port2;
+
+ private static Dictionary _controllerTypes;
+
+ public static Dictionary ValidControllerTypes
+ {
+ get
+ {
+ if (_controllerTypes == null)
+ {
+ _controllerTypes = typeof(SubNESHawkControllerDeck).Assembly
+ .GetTypes()
+ .Where(t => typeof(IPort).IsAssignableFrom(t))
+ .Where(t => !t.IsAbstract && !t.IsInterface)
+ .ToDictionary(tkey => tkey.DisplayName());
+ }
+
+ return _controllerTypes;
+ }
+ }
+
+ public static string DefaultControllerName => typeof(StandardControls).DisplayName();
+ }
+}
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawkControllers.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawkControllers.cs
new file mode 100644
index 0000000000..44e9e5e98d
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawkControllers.cs
@@ -0,0 +1,94 @@
+using System;
+
+using System.ComponentModel;
+using System.Linq;
+
+using BizHawk.Common;
+using BizHawk.Emulation.Common;
+
+namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk
+{
+ ///
+ /// Represents a Standard Nintendo Controller
+ ///
+ public interface IPort
+ {
+ byte Read(IController c);
+
+ ControllerDefinition Definition { get; }
+
+ void SyncState(Serializer ser);
+
+ int PortNum { get; }
+ }
+
+ [DisplayName("NES Controller")]
+ public class StandardControls : IPort
+ {
+ public StandardControls(int portNum)
+ {
+ PortNum = portNum;
+ Definition = new ControllerDefinition
+ {
+ Name = "NES Controller",
+ BoolButtons = BaseDefinition
+ .Select(b => "P" + PortNum + " " + b)
+ .ToList()
+ };
+ }
+
+ public int PortNum { get; }
+
+ public ControllerDefinition Definition { get; }
+
+ public byte Read(IController c)
+ {
+ byte result = 0;
+
+ if (c.IsPressed(Definition.BoolButtons[0]))
+ {
+ result |= 8;
+ }
+ if (c.IsPressed(Definition.BoolButtons[1]))
+ {
+ result |= 4;
+ }
+ if (c.IsPressed(Definition.BoolButtons[2]))
+ {
+ result |= 2;
+ }
+ if (c.IsPressed(Definition.BoolButtons[3]))
+ {
+ result |= 1;
+ }
+ if (c.IsPressed(Definition.BoolButtons[4]))
+ {
+ result |= 16;
+ }
+ if (c.IsPressed(Definition.BoolButtons[5]))
+ {
+ result |= 32;
+ }
+ if (c.IsPressed(Definition.BoolButtons[6]))
+ {
+ result |= 64;
+ }
+ if (c.IsPressed(Definition.BoolButtons[7]))
+ {
+ result |= 128;
+ }
+
+ return result;
+ }
+
+ private static readonly string[] BaseDefinition =
+ {
+ "Up", "Down", "Left", "Right", "Start", "Select", "B", "A"
+ };
+
+ public void SyncState(Serializer ser)
+ {
+ //nothing
+ }
+ }
+}
\ No newline at end of file
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;