AppleII - make clock registers deterministic if needed

also don't state monochrome (non-sync setting? todo: verify)
This commit is contained in:
CasualPokePlayer 2022-06-27 18:33:31 -07:00
parent b730af7b73
commit 13456e51bf
7 changed files with 96 additions and 12 deletions

View File

@ -21,6 +21,8 @@ namespace Jellyfish.Virtu
private RingRegister _clockRegister;
private RingRegister _comparisonRegister;
public Func<DateTime> FrontendTimeCallback;
public NoSlotClock(Video video)
{
_video = video;
@ -117,7 +119,7 @@ namespace Jellyfish.Virtu
private void PopulateClockRegister()
{
// all values are in packed BCD format (4 bits per decimal digit)
var now = DateTime.Now;
var now = FrontendTimeCallback();
int centisecond = now.Millisecond / 10; // 00-99
_clockRegister.WriteNibble(centisecond % 10);

View File

@ -121,7 +121,8 @@ namespace Jellyfish.Virtu
ser.Sync(nameof(_vLineLeaveVBlank), ref _vLineLeaveVBlank);
ser.Sync(nameof(_charSet), ref _charSet, false);
ser.Sync(nameof(_isCellDirty), ref _isCellDirty, false);
ser.Sync(nameof(_isMonochrome), ref _isMonochrome);
//ser.Sync(nameof(_isMonochrome), ref _isMonochrome);
//TODO: does this affect sync?
}
// ReSharper disable once UnusedMember.Global

Binary file not shown.

View File

@ -13,7 +13,7 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII
public string SystemId => VSystemID.Raw.AppleII;
public bool DeterministicEmulation => true;
public bool DeterministicEmulation { get; }
public bool FrameAdvance(IController controller, bool render, bool renderSound)
{

View File

@ -1,24 +1,58 @@
using System.ComponentModel;
using System;
using System.ComponentModel;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Computers.AppleII
{
public partial class AppleII : ISettable<AppleII.Settings, object>
public partial class AppleII : ISettable<AppleII.Settings, AppleII.SyncSettings>
{
private Settings _settings;
private SyncSettings _syncSettings;
public class Settings
{
[DisplayName("Monochrome")]
[DefaultValue(false)]
[Description("Choose a monochrome monitor.")]
public bool Monochrome { get; set; }
public Settings Clone() => (Settings)MemberwiseClone();
public Settings()
=> SettingsUtil.SetDefaultValues(this);
public Settings Clone()
=> (Settings)MemberwiseClone();
}
public Settings GetSettings() => _settings.Clone();
public class SyncSettings
{
[DisplayName("Initial Time")]
[Description("Initial time of emulation.")]
[DefaultValue(typeof(DateTime), "2010-01-01")]
[TypeConverter(typeof(BizDateTimeConverter))]
public DateTime InitialTime { get; set; }
public object GetSyncSettings() => null;
[DisplayName("Use Real Time")]
[Description("If true, RTC clock will be based off of real time instead of emulated time. Ignored (set to false) when recording a movie.")]
[DefaultValue(false)]
public bool UseRealTime { get; set; }
public SyncSettings()
=> SettingsUtil.SetDefaultValues(this);
public SyncSettings Clone()
=> (SyncSettings)MemberwiseClone();
public static bool NeedsReboot(SyncSettings x, SyncSettings y)
=> !DeepEquality.DeepEquals(x, y);
}
public Settings GetSettings()
=> _settings.Clone();
public SyncSettings GetSyncSettings()
=> _syncSettings.Clone();
public PutSettingsDirtyBits PutSettings(Settings o)
{
@ -30,6 +64,11 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII
return PutSettingsDirtyBits.None;
}
public PutSettingsDirtyBits PutSyncSettings(object o) => PutSettingsDirtyBits.None;
public PutSettingsDirtyBits PutSyncSettings(SyncSettings o)
{
var ret = SyncSettings.NeedsReboot(_syncSettings, o);
_syncSettings = o;
return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None;
}
}
}

View File

@ -39,6 +39,8 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII
ser.Sync("CurrentDisk", ref _currentDisk);
ser.Sync("WhiteAppleDown", ref Keyboard.WhiteAppleDown);
ser.Sync("BlackAppleDown", ref Keyboard.BlackAppleDown);
ser.Sync("ClockTime", ref _clockTime);
ser.Sync("ClockRemainder", ref _clockRemainder);
ser.BeginSection("Events");
_machine.Events.Sync(ser);

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using BizHawk.Common.CollectionExtensions;
@ -20,7 +21,7 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII
}
[CoreConstructor(VSystemID.Raw.AppleII)]
public AppleII(CoreLoadParameters<Settings, object> lp)
public AppleII(CoreLoadParameters<Settings, SyncSettings> lp)
{
_romSet = lp.Roms.Select(r => r.RomData).ToList();
var ser = new BasicServiceProvider(this);
@ -35,7 +36,7 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII
_diskIIRom = lp.Comm.CoreFileProvider.GetFirmwareOrThrow(new(SystemId, "DiskII"), "The DiskII firmware is required");
_machine = new Components(_appleIIRom, _diskIIRom);
// make a writable memory stream cloned from the rom.
// for junk.dsk the .dsk is important because it determines the format from that
InitDisk();
@ -46,6 +47,10 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII
SetupMemoryDomains();
PutSettings(lp.Settings ?? new Settings());
_syncSettings = lp.SyncSettings ?? new SyncSettings();
DeterministicEmulation = lp.DeterministicEmulationRequested || !_syncSettings.UseRealTime;
InitializeRtc(DeterministicEmulation);
}
private static readonly ControllerDefinition AppleIIController;
@ -155,6 +160,8 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII
_prevPressed = false;
}
AdvanceRtc();
MachineAdvance(RealButtons.Where(controller.IsPressed));
if (IsLagFrame)
{
@ -211,5 +218,38 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII
};
_machine.Memory.InputCallback = InputCallbacks.Call;
}
private bool _useRealTime;
private long _clockTime;
private int _clockRemainder;
private const int TicksInSecond = 10000000; // DateTime.Ticks uses 100-nanosecond intervals
private DateTime GetFrontendTime()
{
if (_useRealTime && DeterministicEmulation)
throw new InvalidOperationException();
return _useRealTime
? DateTime.Now
: new DateTime(_clockTime * TicksInSecond + (_clockRemainder * TicksInSecond / VsyncNumerator));
}
private void InitializeRtc(bool useRealTime)
{
_useRealTime = useRealTime;
_clockTime = _syncSettings.InitialTime.Ticks / TicksInSecond;
_clockRemainder = (int)(_syncSettings.InitialTime.Ticks % TicksInSecond) * VsyncNumerator / TicksInSecond;
_machine.NoSlotClock.FrontendTimeCallback = GetFrontendTime;
}
private void AdvanceRtc()
{
_clockRemainder += VsyncDenominator;
if (_clockRemainder >= VsyncNumerator)
{
_clockRemainder -= VsyncNumerator;
_clockTime++;
}
}
}
}