[Gambatte] MBC3 RTC Refactor (And add a way to set initial RTC state) (#2724)
* slightly fix gambatte peeking * fix gambatte layer masking, move layer masking to sync settings (these settings affect sync, they shouldn't be normal settings) * block toggle layer hotkeys when movie recording * refactor Gambatte's RTC * add a way to set an inital RTC state during a movie recording * prevent Gambatte from saving RTC data when recording a movie, needed to create save-anchored movies
This commit is contained in:
parent
7a7522f282
commit
3372556ef0
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -9,7 +9,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
{
|
||||
get
|
||||
{
|
||||
if (LibGambatte.gambatte_savesavedatalength(GambatteState) == 0)
|
||||
if (LibGambatte.gambatte_savesavedatalength(GambatteState, DeterministicEmulation) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -20,12 +20,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
|
||||
public byte[] CloneSaveRam()
|
||||
{
|
||||
int length = LibGambatte.gambatte_savesavedatalength(GambatteState);
|
||||
int length = LibGambatte.gambatte_savesavedatalength(GambatteState, DeterministicEmulation);
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
byte[] ret = new byte[length];
|
||||
LibGambatte.gambatte_savesavedata(GambatteState, ret);
|
||||
LibGambatte.gambatte_savesavedata(GambatteState, ret, DeterministicEmulation);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
|
||||
public void StoreSaveRam(byte[] data)
|
||||
{
|
||||
int expected = LibGambatte.gambatte_savesavedatalength(GambatteState);
|
||||
int expected = LibGambatte.gambatte_savesavedatalength(GambatteState, DeterministicEmulation);
|
||||
switch (data.Length - expected)
|
||||
{
|
||||
case 0:
|
||||
|
@ -43,7 +43,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
throw new ArgumentException("Size of saveram data does not match expected!");
|
||||
}
|
||||
|
||||
LibGambatte.gambatte_loadsavedata(GambatteState, data);
|
||||
LibGambatte.gambatte_loadsavedata(GambatteState, data, DeterministicEmulation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.ComponentModel;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
@ -120,6 +121,134 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
[DefaultValue(0)]
|
||||
public int RTCDivisorOffset { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
private int _internalRTCDays;
|
||||
|
||||
[JsonIgnore]
|
||||
private int _internalRTCHours;
|
||||
|
||||
[JsonIgnore]
|
||||
private int _internalRTCMinutes;
|
||||
|
||||
[JsonIgnore]
|
||||
private int _internalRTCSeconds;
|
||||
|
||||
[JsonIgnore]
|
||||
private int _internalRTCCycles;
|
||||
|
||||
[JsonIgnore]
|
||||
private int _latchedRTCDays;
|
||||
|
||||
[JsonIgnore]
|
||||
private int _latchedRTCHours;
|
||||
|
||||
[JsonIgnore]
|
||||
private int _latchedRTCMinutes;
|
||||
|
||||
[JsonIgnore]
|
||||
private int _latchedRTCSeconds;
|
||||
|
||||
[DisplayName("RTC Overflow")]
|
||||
[Description("Sets whether the internal RTC day counter has overflowed.")]
|
||||
[DefaultValue(false)]
|
||||
public bool InternalRTCOverflow { get; set; }
|
||||
|
||||
[DisplayName("RTC Halt")]
|
||||
[Description("Sets whether the internal RTC has halted.")]
|
||||
[DefaultValue(false)]
|
||||
public bool InternalRTCHalt { get; set; }
|
||||
|
||||
[DisplayName("RTC Days")]
|
||||
[Description("Sets the internal RTC day counter. Ranges from 0 to 511.")]
|
||||
[DefaultValue(0)]
|
||||
public int InternalRTCDays
|
||||
{
|
||||
get => _internalRTCDays;
|
||||
set => _internalRTCDays = Math.Max(0, Math.Min(511, value));
|
||||
}
|
||||
|
||||
[DisplayName("RTC Hours")]
|
||||
[Description("Sets the internal RTC hour counter. Ranges from -8 to 23.")]
|
||||
[DefaultValue(0)]
|
||||
public int InternalRTCHours
|
||||
{
|
||||
get => _internalRTCHours;
|
||||
set => _internalRTCHours = Math.Max(-8, Math.Min(23, value));
|
||||
}
|
||||
|
||||
[DisplayName("RTC Minutes")]
|
||||
[Description("Sets the internal RTC minute counter. Ranges from -4 to 59.")]
|
||||
[DefaultValue(0)]
|
||||
public int InternalRTCMinutes
|
||||
{
|
||||
get => _internalRTCMinutes;
|
||||
set => _internalRTCMinutes = Math.Max(-4, Math.Min(59, value));
|
||||
}
|
||||
|
||||
[DisplayName("RTC Seconds")]
|
||||
[Description("Sets the internal RTC second counter. Ranges from -4 to 59.")]
|
||||
[DefaultValue(0)]
|
||||
public int InternalRTCSeconds
|
||||
{
|
||||
get => _internalRTCSeconds;
|
||||
set => _internalRTCSeconds = Math.Max(-4, Math.Min(59, value));
|
||||
}
|
||||
|
||||
[DisplayName("RTC Sub-Seconds")]
|
||||
[Description("Sets the internal RTC sub-second counter, expressed in CPU cycles. Ranges from 0 to 4194303 + the set RTC divisor offset.")]
|
||||
[DefaultValue(0)]
|
||||
public int InternalRTCCycles
|
||||
{
|
||||
get => _internalRTCCycles;
|
||||
set => _internalRTCCycles = Math.Max(0, Math.Min((4194303 + RTCDivisorOffset), value));
|
||||
}
|
||||
|
||||
[DisplayName("Latched RTC Overflow")]
|
||||
[Description("Sets whether the latched RTC shows an overflow.")]
|
||||
[DefaultValue(false)]
|
||||
public bool LatchedRTCOverflow { get; set; }
|
||||
|
||||
[DisplayName("Latched RTC Halt")]
|
||||
[Description("Sets whether the latched RTC shows a halt.")]
|
||||
[DefaultValue(false)]
|
||||
public bool LatchedRTCHalt { get; set; }
|
||||
|
||||
[DisplayName("Latched RTC Days")]
|
||||
[Description("Sets the latched RTC days. Ranges from 0 to 511.")]
|
||||
[DefaultValue(0)]
|
||||
public int LatchedRTCDays
|
||||
{
|
||||
get => _latchedRTCDays;
|
||||
set => _latchedRTCDays = Math.Max(0, Math.Min(511, value));
|
||||
}
|
||||
|
||||
[DisplayName("Latched RTC Hours")]
|
||||
[Description("Sets the latched RTC hours. Ranges from 0 to 31.")]
|
||||
[DefaultValue(0)]
|
||||
public int LatchedRTCHours
|
||||
{
|
||||
get => _latchedRTCHours;
|
||||
set => _latchedRTCHours = Math.Max(0, Math.Min(63, value));
|
||||
}
|
||||
|
||||
[DisplayName("Latched RTC Minutes")]
|
||||
[Description("Sets the latched RTC minutes. Ranges from 0 to 63.")]
|
||||
[DefaultValue(0)]
|
||||
public int LatchedRTCMinutes
|
||||
{
|
||||
get => _latchedRTCMinutes;
|
||||
set => _latchedRTCMinutes = Math.Max(0, Math.Min(63, value));
|
||||
}
|
||||
|
||||
[DisplayName("Latched RTC Seconds")]
|
||||
[Description("Sets the latched RTC seconds. Ranges from 0 to 63.")]
|
||||
[DefaultValue(0)]
|
||||
public int LatchedRTCSeconds
|
||||
{
|
||||
get => _latchedRTCSeconds;
|
||||
set => _latchedRTCSeconds = Math.Max(0, Math.Min(63, value));
|
||||
}
|
||||
|
||||
[DisplayName("Equal Length Frames")]
|
||||
[Description("When false, emulation frames sync to vblank. Only useful for high level TASing.")]
|
||||
[DefaultValue(false)]
|
||||
|
|
|
@ -145,6 +145,42 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
{
|
||||
LibGambatte.gambatte_settimemode(GambatteState, false);
|
||||
}
|
||||
|
||||
if (DeterministicEmulation)
|
||||
{
|
||||
int[] rtcRegs = new int[11];
|
||||
rtcRegs[(int)LibGambatte.RtcRegIndicies.Dh] = 0;
|
||||
if (_syncSettings.InternalRTCOverflow)
|
||||
{
|
||||
rtcRegs[(int)LibGambatte.RtcRegIndicies.Dh] |= 0x80;
|
||||
}
|
||||
if (_syncSettings.InternalRTCHalt)
|
||||
{
|
||||
rtcRegs[(int)LibGambatte.RtcRegIndicies.Dh] |= 0x40;
|
||||
}
|
||||
rtcRegs[(int)LibGambatte.RtcRegIndicies.Dh] |= _syncSettings.InternalRTCDays >> 8;
|
||||
rtcRegs[(int)LibGambatte.RtcRegIndicies.Dl] = _syncSettings.InternalRTCDays & 0xFF;
|
||||
rtcRegs[(int)LibGambatte.RtcRegIndicies.H] = (_syncSettings.InternalRTCHours < 0) ? (_syncSettings.InternalRTCHours + 0x20) : _syncSettings.InternalRTCHours;
|
||||
rtcRegs[(int)LibGambatte.RtcRegIndicies.M] = (_syncSettings.InternalRTCMinutes < 0) ? (_syncSettings.InternalRTCMinutes + 0x40) : _syncSettings.InternalRTCMinutes;
|
||||
rtcRegs[(int)LibGambatte.RtcRegIndicies.S] = (_syncSettings.InternalRTCSeconds < 0) ? (_syncSettings.InternalRTCSeconds + 0x40) : _syncSettings.InternalRTCSeconds;
|
||||
rtcRegs[(int)LibGambatte.RtcRegIndicies.C] = _syncSettings.InternalRTCCycles;
|
||||
rtcRegs[(int)LibGambatte.RtcRegIndicies.Dh_L] = 0;
|
||||
if (_syncSettings.LatchedRTCOverflow)
|
||||
{
|
||||
rtcRegs[(int)LibGambatte.RtcRegIndicies.Dh_L] |= 0x80;
|
||||
}
|
||||
if (_syncSettings.LatchedRTCHalt)
|
||||
{
|
||||
rtcRegs[(int)LibGambatte.RtcRegIndicies.Dh_L] |= 0x40;
|
||||
}
|
||||
rtcRegs[(int)LibGambatte.RtcRegIndicies.Dh_L] |= _syncSettings.LatchedRTCDays >> 8;
|
||||
rtcRegs[(int)LibGambatte.RtcRegIndicies.Dl_L] = _syncSettings.LatchedRTCDays & 0xFF;
|
||||
rtcRegs[(int)LibGambatte.RtcRegIndicies.H_L] = _syncSettings.LatchedRTCHours;
|
||||
rtcRegs[(int)LibGambatte.RtcRegIndicies.M_L] = _syncSettings.LatchedRTCMinutes;
|
||||
rtcRegs[(int)LibGambatte.RtcRegIndicies.S_L] = _syncSettings.LatchedRTCSeconds;
|
||||
LibGambatte.gambatte_setrtcregs(GambatteState, rtcRegs);
|
||||
}
|
||||
|
||||
LibGambatte.gambatte_setrtcdivisoroffset(GambatteState, _syncSettings.RTCDivisorOffset);
|
||||
|
||||
_cdCallback = new LibGambatte.CDCallback(CDCallbackProc);
|
||||
|
|
|
@ -296,24 +296,27 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
/// </summary>
|
||||
/// <param name="core">opaque state pointer</param>
|
||||
/// <param name="dest">byte buffer to write into. gambatte_savesavedatalength() bytes will be written</param>
|
||||
/// <param name="isDeterministic">determinism bool. RTC data is ignored if set </param>
|
||||
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void gambatte_savesavedata(IntPtr core, byte[] dest);
|
||||
public static extern void gambatte_savesavedata(IntPtr core, byte[] dest, bool isDeterministic);
|
||||
|
||||
/// <summary>
|
||||
/// restore persistant cart memory.
|
||||
/// </summary>
|
||||
/// <param name="core">opaque state pointer</param>
|
||||
/// <param name="data">byte buffer to read from. gambatte_savesavedatalength() bytes will be read</param>
|
||||
/// <param name="isDeterministic">determinism bool. RTC data is ignored if set </param>
|
||||
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void gambatte_loadsavedata(IntPtr core, byte[] data);
|
||||
public static extern void gambatte_loadsavedata(IntPtr core, byte[] data, bool isDeterministic);
|
||||
|
||||
/// <summary>
|
||||
/// get the size of the persistant cart memory block. this value DEPENDS ON THE PARTICULAR CART LOADED
|
||||
/// </summary>
|
||||
/// <param name="core">opaque state pointer</param>
|
||||
/// <param name="isDeterministic">determinism bool. RTC data is ignored if set </param>
|
||||
/// <returns>length in bytes. 0 means no internal persistant cart memory</returns>
|
||||
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int gambatte_savesavedatalength(IntPtr core);
|
||||
public static extern int gambatte_savesavedatalength(IntPtr core, bool isDeterministic);
|
||||
|
||||
/// <summary>
|
||||
/// new savestate method
|
||||
|
@ -416,5 +419,26 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
{
|
||||
PC, SP, A, B, C, D, E, F, H, L
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// get MBC3 RTC reg values
|
||||
/// </summary>
|
||||
/// <param name="core">opaque state pointer</param>
|
||||
/// <param name="dest">length of at least 11, please</param>
|
||||
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void gambatte_getrtcregs(IntPtr core, int[] dest);
|
||||
|
||||
/// <summary>
|
||||
/// set MBC3 RTC reg values
|
||||
/// </summary>
|
||||
/// <param name="core">opaque state pointer</param>
|
||||
/// <param name="src">length of at least 11, please</param>
|
||||
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void gambatte_setrtcregs(IntPtr core, int[] src);
|
||||
|
||||
public enum RtcRegIndicies : int
|
||||
{
|
||||
Dh, Dl, H, M, S, C, Dh_L, Dl_L, H_L, M_L, S_L
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 3ac46735febd8933f3be808db6b8759495932371
|
||||
Subproject commit 514af8f401a3619e98e4d20f03d691eba2e91aca
|
Loading…
Reference in New Issue