BSNESv115: add dedicated subframe core (#3281)
* BSNESv115: allow subframe inputs * BSNESv115: Implement ICycleTiming may be correct, not sure * BSNESv115: add dedicated subframe core I have probably overlooked something... * Don't implement ICycleTiming in the non-subframe core requires re-implementing the "FrameAdvance" function in the subframe core * Register previously missing services in the subframe core as well * Wire up SubBsnes everywhere in the frontend * Change reset cycle to reset instruction * Deduplicate some code * Slightly rework frame advance logic. The main intent here is to prevent a case where two frames are ran within a single "frame." The current code probably wouldn't crash due to that, but best not to do that. Also make SGB work here. A bit of a joke since you really can only abuse it for subframe resets, but might as well especially with the settings implying it's possible (and someone is bound to complain). Co-authored-by: CasualPokePlayer <50538166+CasualPokePlayer@users.noreply.github.com>
This commit is contained in:
parent
1a27aae45b
commit
929432086f
Binary file not shown.
|
@ -235,9 +235,9 @@ namespace BizHawk.Client.Common
|
|||
s.ShowOBJ_3 = GetSetting(args, 7);
|
||||
core.PutSettings(s);
|
||||
}
|
||||
void SetBsnes(BsnesCore core)
|
||||
void SetBsnes(ISettable<BsnesCore.SnesSettings, BsnesCore.SnesSyncSettings> settingsProvider)
|
||||
{
|
||||
var s = core.GetSettings();
|
||||
var s = settingsProvider.GetSettings();
|
||||
// TODO: This should probably support both prios inidividually but I have no idea whether changing this breaks anything
|
||||
s.ShowBG1_0 = s.ShowBG1_1 = GetSetting(args, 0);
|
||||
s.ShowBG2_0 = s.ShowBG2_1 = GetSetting(args, 1);
|
||||
|
@ -247,7 +247,7 @@ namespace BizHawk.Client.Common
|
|||
s.ShowOBJ_1 = GetSetting(args, 5);
|
||||
s.ShowOBJ_2 = GetSetting(args, 6);
|
||||
s.ShowOBJ_3 = GetSetting(args, 7);
|
||||
core.PutSettings(s);
|
||||
settingsProvider.PutSettings(s);
|
||||
}
|
||||
void SetCygne(WonderSwan ws)
|
||||
{
|
||||
|
@ -313,6 +313,9 @@ namespace BizHawk.Client.Common
|
|||
case BsnesCore bsnes:
|
||||
SetBsnes(bsnes);
|
||||
break;
|
||||
case SubBsnesCore subBsnes:
|
||||
SetBsnes(subBsnes.ServiceProvider.GetService<ISettable<BsnesCore.SnesSettings, BsnesCore.SnesSyncSettings>>());
|
||||
break;
|
||||
case NES nes:
|
||||
SetNesHawk(nes);
|
||||
break;
|
||||
|
|
|
@ -27,11 +27,11 @@ namespace BizHawk.Client.Common
|
|||
(new[] { VSystemID.Raw.NES },
|
||||
new[] { CoreNames.QuickNes, CoreNames.NesHawk, CoreNames.SubNesHawk }),
|
||||
(new[] { VSystemID.Raw.SNES },
|
||||
new[] { CoreNames.Faust, CoreNames.Snes9X, CoreNames.Bsnes, CoreNames.Bsnes115 }),
|
||||
new[] { CoreNames.Faust, CoreNames.Snes9X, CoreNames.Bsnes, CoreNames.Bsnes115, CoreNames.SubBsnes115 }),
|
||||
(new[] { VSystemID.Raw.N64 },
|
||||
new[] { CoreNames.Mupen64Plus, CoreNames.Ares64 }),
|
||||
(new[] { VSystemID.Raw.SGB },
|
||||
new[] { CoreNames.Gambatte, CoreNames.Bsnes, CoreNames.Bsnes115}),
|
||||
new[] { CoreNames.Gambatte, CoreNames.Bsnes, CoreNames.Bsnes115, CoreNames.SubBsnes115 }),
|
||||
(new[] { VSystemID.Raw.GB, VSystemID.Raw.GBC },
|
||||
new[] { CoreNames.Gambatte, CoreNames.Sameboy, CoreNames.GbHawk, CoreNames.SubGbHawk }),
|
||||
(new[] { VSystemID.Raw.GBL },
|
||||
|
|
|
@ -244,7 +244,9 @@ namespace BizHawk.Client.Common
|
|||
["Extra1"] = '1',
|
||||
["Extra2"] = '2',
|
||||
["Extra3"] = '3',
|
||||
["Extra4"] = '4'
|
||||
["Extra4"] = '4',
|
||||
|
||||
["Subframe"] = 'F'
|
||||
},
|
||||
[VSystemID.Raw.TI83] = new()
|
||||
{
|
||||
|
|
|
@ -1723,6 +1723,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
LibsnesCore => OpenOldBSNESGamepadSettingsDialog(GetSettingsAdapterForLoadedCore<LibsnesCore>()),
|
||||
BsnesCore => OpenBSNESGamepadSettingsDialog(GetSettingsAdapterForLoadedCore<BsnesCore>()),
|
||||
SubBsnesCore => OpenBSNESGamepadSettingsDialog(GetSettingsAdapterForLoadedCore<SubBsnesCore>()),
|
||||
_ => DialogResult.None
|
||||
};
|
||||
}
|
||||
|
@ -1744,6 +1745,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
LibsnesCore => OpenOldBSNESSettingsDialog(GetSettingsAdapterForLoadedCore<LibsnesCore>()),
|
||||
BsnesCore => OpenBSNESSettingsDialog(GetSettingsAdapterForLoadedCore<BsnesCore>()),
|
||||
SubBsnesCore => OpenBSNESSettingsDialog(GetSettingsAdapterForLoadedCore<SubBsnesCore>()),
|
||||
_ => DialogResult.None
|
||||
};
|
||||
}
|
||||
|
@ -2774,6 +2776,13 @@ namespace BizHawk.Client.EmuHawk
|
|||
bsnesSubmenu.DropDownOpened += (_, _) => bsnesGamepadSettingsItem.Enabled = MovieSession.Movie.NotActive() || Emulator is not BsnesCore;
|
||||
items.Add(bsnesSubmenu);
|
||||
|
||||
// SubBSNESv115+
|
||||
var subBsnesGamepadSettingsItem = CreateSettingsItem("Controller Configuration...", (_, _) => OpenBSNESGamepadSettingsDialog(GetSettingsAdapterFor<SubBsnesCore>()));
|
||||
var subBsnesSettingsItem = CreateSettingsItem("Options...", (_, _) => OpenBSNESSettingsDialog(GetSettingsAdapterFor<SubBsnesCore>()));
|
||||
var subBsnesSubmenu = CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.SubBsnes115, subBsnesGamepadSettingsItem, subBsnesSettingsItem);
|
||||
subBsnesSubmenu.DropDownOpened += (_, _) => subBsnesGamepadSettingsItem.Enabled = MovieSession.Movie.NotActive() || Emulator is not SubBsnesCore;
|
||||
items.Add(subBsnesSubmenu);
|
||||
|
||||
// C64Hawk
|
||||
items.Add(CreateCoreSubmenu(VSystemCategory.PCs, CoreNames.C64Hawk, CreateSettingsItem("Settings...", (_, _) => OpenC64HawkSettingsDialog())));
|
||||
|
||||
|
|
|
@ -1478,7 +1478,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
private void SNES_ToggleBg(int layer)
|
||||
{
|
||||
if (Emulator is not (BsnesCore or LibsnesCore or Snes9x) || !1.RangeTo(4).Contains(layer))
|
||||
if (Emulator is not (BsnesCore or SubBsnesCore or LibsnesCore or Snes9x) || !1.RangeTo(4).Contains(layer))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -1486,9 +1486,10 @@ namespace BizHawk.Client.EmuHawk
|
|||
bool result = false;
|
||||
switch (Emulator)
|
||||
{
|
||||
case BsnesCore bsnes:
|
||||
case BsnesCore or SubBsnesCore:
|
||||
{
|
||||
var s = bsnes.GetSettings();
|
||||
var settingsProvider = Emulator.ServiceProvider.GetService<ISettable<BsnesCore.SnesSettings, BsnesCore.SnesSyncSettings>>();
|
||||
var s = settingsProvider.GetSettings();
|
||||
switch (layer)
|
||||
{
|
||||
case 1:
|
||||
|
@ -1505,7 +1506,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
break;
|
||||
}
|
||||
|
||||
bsnes.PutSettings(s);
|
||||
settingsProvider.PutSettings(s);
|
||||
break;
|
||||
}
|
||||
case LibsnesCore libsnes:
|
||||
|
@ -2057,7 +2058,12 @@ namespace BizHawk.Client.EmuHawk
|
|||
SnesGfxDebuggerMenuItem.Visible = true;
|
||||
break;
|
||||
case VSystemID.Raw.SNES when Emulator is BsnesCore bsnesCore:
|
||||
SNESSubMenu.Text = bsnesCore.IsSGB ? "&SGB" : "&SNES";
|
||||
SNESSubMenu.Text = bsnesCore.IsSGB ? "&SGB" : "&SNES";
|
||||
SnesGfxDebuggerMenuItem.Visible = false;
|
||||
SNESSubMenu.Visible = true;
|
||||
break;
|
||||
case VSystemID.Raw.SNES when Emulator is SubBsnesCore subBsnesCore:
|
||||
SNESSubMenu.Text = subBsnesCore.IsSGB ? "&SGB" : "&SNES";
|
||||
SnesGfxDebuggerMenuItem.Visible = false;
|
||||
SNESSubMenu.Visible = true;
|
||||
break;
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
|||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract void snes_reset();
|
||||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract void snes_run();
|
||||
public abstract bool snes_run(bool breakOnLatch);
|
||||
|
||||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract void snes_serialize(byte[] serializedData, int serializedSize);
|
||||
|
@ -68,6 +68,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
|||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract bool snes_cpu_step();
|
||||
|
||||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract long snes_get_executed_cycles();
|
||||
|
||||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract bool snes_msu_sync();
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
|||
|
||||
public ControllerDefinition Definition { get; }
|
||||
|
||||
public BsnesControllers(BsnesCore.SnesSyncSettings ss)
|
||||
public BsnesControllers(BsnesCore.SnesSyncSettings ss, bool subframe = false)
|
||||
{
|
||||
_ports = new[]
|
||||
{
|
||||
|
@ -52,6 +52,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
|||
// add buttons that the core itself will handle
|
||||
Definition.BoolButtons.Add("Reset");
|
||||
Definition.BoolButtons.Add("Power");
|
||||
if (subframe)
|
||||
{
|
||||
// When set, only emulate until the next input latch (or until the frame ends)
|
||||
Definition.BoolButtons.Add("Subframe");
|
||||
// Amount of instructions to execute before resetting; range hopefully set large enough
|
||||
Definition.AddAxis("Reset Instruction", 0.RangeTo(200000), 0);
|
||||
}
|
||||
|
||||
Definition.MakeImmutable();
|
||||
}
|
||||
|
|
|
@ -89,12 +89,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
|||
}
|
||||
}
|
||||
|
||||
public long TotalExecutedCycles { get; private set; }
|
||||
public long TotalExecutedCycles => Api.core.snes_get_executed_cycles();
|
||||
|
||||
private void StepInto()
|
||||
{
|
||||
_framePassed = Api.core.snes_cpu_step();
|
||||
TotalExecutedCycles++;
|
||||
if (_framePassed)
|
||||
{
|
||||
Frame++;
|
||||
|
|
|
@ -10,13 +10,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
|||
|
||||
public bool FrameAdvance(IController controller, bool render, bool renderSound)
|
||||
{
|
||||
_controller = controller;
|
||||
FrameAdvancePre(controller, render, renderSound);
|
||||
|
||||
/* if the input poll callback is called, it will set this to false
|
||||
* this has to be done before we save the per-frame state in deterministic
|
||||
* mode, because in there, the core actually advances, and might advance
|
||||
* through the point in time where IsLagFrame gets set to false. makes sense?
|
||||
*/
|
||||
IsLagFrame = true;
|
||||
|
||||
bool resetSignal = controller.IsPressed("Reset");
|
||||
|
@ -31,6 +26,22 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
|||
Api.core.snes_power();
|
||||
}
|
||||
|
||||
// run the core for one frame
|
||||
Api.core.snes_run(false);
|
||||
Frame++;
|
||||
|
||||
if (IsLagFrame)
|
||||
{
|
||||
LagCount++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal void FrameAdvancePre(IController controller, bool render, bool renderSound)
|
||||
{
|
||||
_controller = controller;
|
||||
|
||||
var enables = new BsnesApi.LayerEnables
|
||||
{
|
||||
BG1_Prio0 = _settings.ShowBG1_0,
|
||||
|
@ -52,20 +63,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
|||
Api.core.snes_set_trace_enabled(_tracer.IsEnabled());
|
||||
Api.core.snes_set_video_enabled(render);
|
||||
Api.core.snes_set_audio_enabled(renderSound);
|
||||
|
||||
// run the core for one frame
|
||||
Api.core.snes_run();
|
||||
Frame++;
|
||||
|
||||
if (IsLagFrame)
|
||||
{
|
||||
LagCount++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int Frame { get; private set; }
|
||||
public int Frame { get; set; }
|
||||
|
||||
public string SystemId => VSystemID.Raw.SNES;
|
||||
|
||||
|
|
|
@ -14,7 +14,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
|||
{
|
||||
[CoreConstructor(VSystemID.Raw.SGB)]
|
||||
[CoreConstructor(VSystemID.Raw.SNES)]
|
||||
public BsnesCore(CoreLoadParameters<SnesSettings, SnesSyncSettings> loadParameters)
|
||||
public BsnesCore(CoreLoadParameters<SnesSettings, SnesSyncSettings> loadParameters) : this(loadParameters, false) { }
|
||||
public BsnesCore(CoreLoadParameters<SnesSettings, SnesSyncSettings> loadParameters, bool subframe = false)
|
||||
{
|
||||
var ser = new BasicServiceProvider(this);
|
||||
ServiceProvider = ser;
|
||||
|
@ -60,7 +61,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
|||
|
||||
Api = new BsnesApi(CoreComm.CoreFileProvider.DllPath(), CoreComm, callbacks.AllDelegatesInMemoryOrder());
|
||||
|
||||
_controllers = new BsnesControllers(_syncSettings);
|
||||
_controllers = new BsnesControllers(_syncSettings, subframe);
|
||||
|
||||
generate_palette();
|
||||
BsnesApi.SnesInitData snesInitData = new()
|
||||
|
@ -94,7 +95,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
|||
}
|
||||
|
||||
_region = Api.core.snes_get_region();
|
||||
|
||||
if (_region == BsnesApi.SNES_REGION.NTSC)
|
||||
{
|
||||
// taken from bsnes source
|
||||
|
@ -135,7 +135,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
|||
public string BoardName => "SGB";
|
||||
}
|
||||
|
||||
private BsnesApi Api { get; }
|
||||
internal BsnesApi Api { get; }
|
||||
|
||||
private string snes_path_request(int slot, string hint, bool required)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
||||
{
|
||||
[PortedCore(CoreNames.SubBsnes115, "")]
|
||||
[ServiceNotApplicable(new[] { typeof(IDriveLight) })]
|
||||
public class SubBsnesCore : IEmulator, ICycleTiming
|
||||
{
|
||||
[CoreConstructor(VSystemID.Raw.SGB)]
|
||||
[CoreConstructor(VSystemID.Raw.SNES)]
|
||||
public SubBsnesCore(CoreLoadParameters<BsnesCore.SnesSettings, BsnesCore.SnesSyncSettings> loadParameters)
|
||||
{
|
||||
_bsnesCore = new BsnesCore(loadParameters, true);
|
||||
if (_bsnesCore.Region == DisplayType.NTSC)
|
||||
ClockRate = 315.0 / 88.0 * 1000000.0 * 6.0;
|
||||
else
|
||||
ClockRate = (283.75 * 15625.0 + 25.0) * 4.8;
|
||||
|
||||
BasicServiceProvider ser = new(this);
|
||||
ser.Register(_bsnesCore.ServiceProvider.GetService<IDebuggable>());
|
||||
ser.Register(_bsnesCore.ServiceProvider.GetService<IVideoProvider>());
|
||||
ser.Register(_bsnesCore.ServiceProvider.GetService<ISaveRam>());
|
||||
ser.Register(_bsnesCore.ServiceProvider.GetService<IStatable>());
|
||||
ser.Register(_bsnesCore.ServiceProvider.GetService<IInputPollable>());
|
||||
ser.Register(_bsnesCore.ServiceProvider.GetService<IRegionable>());
|
||||
ser.Register(_bsnesCore.ServiceProvider.GetService<ISettable<BsnesCore.SnesSettings, BsnesCore.SnesSyncSettings>>());
|
||||
ser.Register(_bsnesCore.ServiceProvider.GetService<ISoundProvider>());
|
||||
ser.Register(_bsnesCore.ServiceProvider.GetService<IMemoryDomains>());
|
||||
ser.Register(_bsnesCore.ServiceProvider.GetService<IDisassemblable>());
|
||||
ser.Register(_bsnesCore.ServiceProvider.GetService<ITraceable>());
|
||||
if (IsSGB)
|
||||
{
|
||||
// board info is only set in SGB mode
|
||||
ser.Register(_bsnesCore.ServiceProvider.GetService<IBoardInfo>());
|
||||
}
|
||||
ServiceProvider = ser;
|
||||
}
|
||||
|
||||
private readonly BsnesCore _bsnesCore;
|
||||
|
||||
public bool IsSGB => _bsnesCore.IsSGB;
|
||||
|
||||
public IEmulatorServiceProvider ServiceProvider { get; }
|
||||
|
||||
public ControllerDefinition ControllerDefinition => _bsnesCore.ControllerDefinition;
|
||||
|
||||
public bool FrameAdvance(IController controller, bool render, bool renderSound = true)
|
||||
{
|
||||
_bsnesCore.FrameAdvancePre(controller, render, renderSound);
|
||||
|
||||
_bsnesCore.IsLagFrame = true;
|
||||
bool framePassed = false;
|
||||
|
||||
bool resetSignal = controller.IsPressed("Reset");
|
||||
bool powerSignal = controller.IsPressed("Power");
|
||||
|
||||
if (resetSignal || powerSignal)
|
||||
{
|
||||
int resetInstruction = controller.AxisValue("Reset Instruction");
|
||||
for (int i = 0; i < resetInstruction; i++)
|
||||
{
|
||||
framePassed = _bsnesCore.Api.core.snes_cpu_step();
|
||||
if (framePassed) break;
|
||||
}
|
||||
|
||||
if (resetSignal)
|
||||
{
|
||||
_bsnesCore.Api.core.snes_reset();
|
||||
}
|
||||
|
||||
if (powerSignal)
|
||||
{
|
||||
_bsnesCore.Api.core.snes_power();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// run the core for one (sub-)frame
|
||||
bool subFrameRequested = controller.IsPressed("Subframe");
|
||||
framePassed = _bsnesCore.Api.core.snes_run(subFrameRequested);
|
||||
}
|
||||
|
||||
_bsnesCore.Frame++;
|
||||
|
||||
if (framePassed && _bsnesCore.IsLagFrame)
|
||||
_bsnesCore.LagCount++;
|
||||
else
|
||||
_bsnesCore.IsLagFrame = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int Frame => _bsnesCore.Frame;
|
||||
|
||||
public string SystemId => _bsnesCore.SystemId;
|
||||
|
||||
public bool DeterministicEmulation => _bsnesCore.DeterministicEmulation;
|
||||
|
||||
public void ResetCounters()
|
||||
{
|
||||
_bsnesCore.ResetCounters();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_bsnesCore.Dispose();
|
||||
}
|
||||
|
||||
public long CycleCount => _bsnesCore.Api.core.snes_get_executed_cycles();
|
||||
|
||||
public double ClockRate { get; }
|
||||
}
|
||||
}
|
|
@ -50,6 +50,7 @@ namespace BizHawk.Emulation.Cores
|
|||
public const string Saturnus = "Saturnus";
|
||||
public const string SMSHawk = "SMSHawk";
|
||||
public const string Snes9X = "Snes9x";
|
||||
public const string SubBsnes115 = "SubBSNESv115+";
|
||||
public const string SubGbHawk = "SubGBHawk";
|
||||
public const string SubNesHawk = "SubNESHawk";
|
||||
public const string TI83Hawk = "TI83Hawk";
|
||||
|
|
|
@ -20,6 +20,7 @@ namespace BizHawk.Emulation.Cores
|
|||
{
|
||||
LibsnesCore libsnes => GetLibsnesPadSchemas(libsnes),
|
||||
BsnesCore bsnes => GetBsnesPadSchemas(bsnes),
|
||||
SubBsnesCore subBsnes => GetBsnesPadSchemas(subBsnes.ServiceProvider.GetService<ISettable<BsnesCore.SnesSettings, BsnesCore.SnesSyncSettings>>()),
|
||||
NymaCore nyma => GetFaustSchemas(nyma, showMessageBox),
|
||||
_ => GetSnes9xPadSchemas((Snes9x) core)
|
||||
};
|
||||
|
@ -112,9 +113,9 @@ namespace BizHawk.Emulation.Cores
|
|||
yield return ConsoleButtons();
|
||||
}
|
||||
|
||||
private IEnumerable<PadSchema> GetBsnesPadSchemas(BsnesCore core)
|
||||
private IEnumerable<PadSchema> GetBsnesPadSchemas(ISettable<BsnesCore.SnesSettings, BsnesCore.SnesSyncSettings> settingsProvider)
|
||||
{
|
||||
var syncSettings = core.GetSyncSettings();
|
||||
var syncSettings = settingsProvider.GetSyncSettings();
|
||||
|
||||
var ports = new[]
|
||||
{
|
||||
|
|
|
@ -58,6 +58,7 @@ auto SuperMultitap::latch(bool data) -> void {
|
|||
counter2 = 0;
|
||||
|
||||
if(latched == 0) {
|
||||
if (port == ID::Port::Controller1) platform->notify("LATCH");
|
||||
uint offset = isPayloadController ? 16 : 12;
|
||||
for(uint id : range(4)) {
|
||||
auto& gamepad = gamepads[id];
|
||||
|
|
|
@ -28,7 +28,10 @@ auto CPU::Enter() -> void {
|
|||
while(true) {
|
||||
scheduler.synchronize();
|
||||
cpu.main();
|
||||
if (scheduler.StepOnce) scheduler.leave(Scheduler::Event::Desynchronized);
|
||||
if (scheduler.StepOnce) {
|
||||
scheduler.StepOnce = false;
|
||||
scheduler.leave(Scheduler::Event::Desynchronized);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -76,6 +76,8 @@ struct CPU : Processor::WDC65816, Thread, PPUcounter {
|
|||
uint target = 0;
|
||||
} overclocking;
|
||||
|
||||
long TotalExecutedCycles;
|
||||
|
||||
private:
|
||||
uint version = 2; //allowed: 1, 2
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ auto CPU::joypadCounter() const -> uint {
|
|||
|
||||
auto CPU::stepOnce() -> void {
|
||||
counter.cpu += 2;
|
||||
TotalExecutedCycles += 2;
|
||||
tick();
|
||||
if(hcounter() & 2) nmiPoll(), irqPoll();
|
||||
if(joypadCounter() == 0) joypadEdge();
|
||||
|
|
|
@ -169,9 +169,11 @@ EXPORT void snes_reset(void)
|
|||
}
|
||||
|
||||
// note: run with runahead doesn't work yet, i suspect it's due to the serialize thing breaking (cause of libco)
|
||||
EXPORT void snes_run(void)
|
||||
EXPORT bool snes_run(bool breakOnLatch)
|
||||
{
|
||||
program->breakOnLatch = breakOnLatch;
|
||||
emulator->run();
|
||||
return scheduler.event == Scheduler::Event::Frame;
|
||||
}
|
||||
|
||||
// not used, but would probably be nice
|
||||
|
@ -449,10 +451,14 @@ EXPORT bool snes_cpu_step()
|
|||
{
|
||||
scheduler.StepOnce = true;
|
||||
emulator->run();
|
||||
scheduler.StepOnce = false;
|
||||
return scheduler.event == Scheduler::Event::Frame;
|
||||
}
|
||||
|
||||
EXPORT long snes_get_executed_cycles()
|
||||
{
|
||||
return SuperFamicom::cpu.TotalExecutedCycles;
|
||||
}
|
||||
|
||||
// should be called on savestate load, to get msu files loaded and in the correct state
|
||||
EXPORT void snes_msu_sync()
|
||||
{
|
||||
|
|
|
@ -43,6 +43,7 @@ struct Program : Emulator::Platform
|
|||
bool overscan = false;
|
||||
uint16_t backdropColor;
|
||||
int regionOverride = 0;
|
||||
bool breakOnLatch;
|
||||
|
||||
public:
|
||||
struct Game {
|
||||
|
@ -463,8 +464,13 @@ auto Program::notify(string message) -> void
|
|||
snesCallbacks.snes_no_lag(false);
|
||||
else if (message == "NO_LAG_SGB")
|
||||
snesCallbacks.snes_no_lag(true);
|
||||
else if (message == "LATCH")
|
||||
else if (message == "LATCH") {
|
||||
if (breakOnLatch) {
|
||||
scheduler.StepOnce = true;
|
||||
breakOnLatch = false;
|
||||
}
|
||||
snesCallbacks.snes_controller_latch();
|
||||
}
|
||||
}
|
||||
|
||||
auto Program::cpuTrace(vector<string> parts) -> void
|
||||
|
|
Loading…
Reference in New Issue