[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:
CasualPokePlayer 2021-05-05 18:40:36 -07:00 committed by GitHub
parent 7a7522f282
commit 3372556ef0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 199 additions and 10 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -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);
}
}
}

View File

@ -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)]

View File

@ -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);

View File

@ -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