diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.ISaveRam.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.ISaveRam.cs
index 3776eb00f7..218d2bf3ec 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.ISaveRam.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.ISaveRam.cs
@@ -41,31 +41,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
break;
default:
throw new ArgumentException("Size of saveram data does not match expected!");
- case 44:
- data = FixRTC(data, 44);
- break;
- case 40:
- data = FixRTC(data, 40);
- break;
}
LibGambatte.gambatte_loadsavedata(GambatteState, data);
}
-
- private byte[] FixRTC(byte[] data, int offset)
- {
- // length - offset is the start of the VBA-only data; so
- // length - offset - 4 is the start of the RTC block
- int idx = data.Length - offset - 4;
-
- byte[] ret = new byte[idx + 4];
- Buffer.BlockCopy(data, 0, ret, 0, idx);
- data[idx] = (byte)zerotime;
- data[idx + 1] = (byte)(zerotime >> 8);
- data[idx + 2] = (byte)(zerotime >> 16);
- data[idx + 3] = (byte)(zerotime >> 24);
-
- return ret;
- }
}
}
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.ISettable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.ISettable.cs
index 297b029f11..3681c532d3 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.ISettable.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.ISettable.cs
@@ -116,18 +116,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
[DefaultValue(false)]
public bool RealTimeRTC { get; set; }
- [DisplayName("RTC Initial Time")]
- [Description("Set the initial RTC time in terms of elapsed seconds. Only used when RealTimeRTC is false.")]
- [DefaultValue(0)]
- public int RTCInitialTime
- {
- get { return _RTCInitialTime; }
- set { _RTCInitialTime = Math.Max(0, Math.Min(1024 * 24 * 60 * 60, value)); }
- }
-
- [JsonIgnore]
- private int _RTCInitialTime;
-
[DisplayName("Equal Length Frames")]
[Description("When false, emulation frames sync to vblank. Only useful for high level TASing.")]
[DefaultValue(false)]
@@ -141,11 +129,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
[DeepEqualsIgnore]
private bool _equalLengthFrames;
- [DisplayName("Initial DIV offset")]
- [Description("Internal. Probably doesn't work. Leave this set to 0. Accepts values from 0 to 65532 in steps of 4")]
- [DefaultValue(0)]
- public int InitialDiv { get; set; }
-
public GambatteSyncSettings()
{
SettingsUtil.SetDefaultValues(this);
@@ -160,11 +143,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
{
return !DeepEquality.DeepEquals(x, y);
}
-
- public uint GetInitialDivInternal()
- {
- return (uint)(InitialDiv & 0xfffc);
- }
}
}
}
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
index 1790f04703..3b837f5b78 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
@@ -58,13 +58,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
{
_syncSettings = (GambatteSyncSettings)syncSettings ?? new GambatteSyncSettings();
- // copy over non-loadflag syncsettings now; they won't take effect if changed later
- zerotime = (uint)_syncSettings.RTCInitialTime;
-
- real_rtc_time = !DeterministicEmulation && _syncSettings.RealTimeRTC;
-
- DivInternal = _syncSettings.GetInitialDivInternal();
-
LibGambatte.LoadFlags flags = 0;
switch (_syncSettings.ConsoleMode)
@@ -90,7 +83,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
flags |= LibGambatte.LoadFlags.MULTICART_COMPAT;
}
- if (LibGambatte.gambatte_load(GambatteState, file, (uint)file.Length, GetCurrentTime(), flags, DivInternal) != 0)
+ if (LibGambatte.gambatte_load(GambatteState, file, (uint)file.Length, flags) != 0)
{
throw new InvalidOperationException($"{nameof(LibGambatte.gambatte_load)}() returned non-zero (is this not a gb or gbc rom?)");
}
@@ -133,8 +126,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
string romname = System.Text.Encoding.ASCII.GetString(buff);
Console.WriteLine("Core reported rom name: {0}", romname);
- TimeCallback = new LibGambatte.RTCCallback(GetCurrentTime);
- LibGambatte.gambatte_setrtccallback(GambatteState, TimeCallback);
+ if (!DeterministicEmulation && _syncSettings.RealTimeRTC)
+ {
+ LibGambatte.gambatte_settimemode(GambatteState, false);
+ }
_cdCallback = new LibGambatte.CDCallback(CDCallbackProc);
@@ -167,59 +162,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
///
private LibGambatte.Buttons CurrentButtons = 0;
- private uint DivInternal = 0;
-
- #region RTC
-
- ///
- /// RTC time when emulation begins.
- ///
- private readonly uint zerotime = 0;
-
- ///
- /// if true, RTC will run off of real elapsed time
- ///
- private bool real_rtc_time = false;
-
- private LibGambatte.RTCCallback TimeCallback;
-
- private static long GetUnixNow()
- {
- // because internally the RTC works off of relative time, we don't need to base
- // this off of any particular canonical epoch.
- return DateTime.UtcNow.Ticks / 10000000L - 60000000000L;
- }
-
- private uint GetCurrentTime()
- {
- if (real_rtc_time)
- {
- return (uint)GetUnixNow();
- }
-
- ulong fn = (ulong)Frame;
-
- // as we're exactly tracking cpu cycles, this can be pretty accurate
- fn *= 4389;
- fn /= 262144;
- fn += zerotime;
- return (uint)fn;
- }
-
- private uint GetInitialTime()
- {
- if (real_rtc_time)
- {
- return (uint)GetUnixNow();
- }
-
- // setting the initial boot time to 0 will cause our zerotime
- // to function as an initial offset, which is what we want
- return 0;
- }
-
- #endregion
-
#region ALL SAVESTATEABLE STATE GOES HERE
///
@@ -320,7 +262,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
if (controller.IsPressed("Power"))
{
- LibGambatte.gambatte_reset(GambatteState, GetCurrentTime(), DivInternal);
+ LibGambatte.gambatte_reset(GambatteState);
}
if (Tracer.Enabled)
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibGambatte.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibGambatte.cs
index 06cb95ece3..038ff62021 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibGambatte.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibGambatte.cs
@@ -53,11 +53,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
/// opaque state pointer
/// the rom data, can be disposed of once this function returns
/// length of romdata in bytes
- /// RTC time when the rom is loaded
/// ORed combination of LoadFlags.
/// 0 on success, negative value on failure.
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
- public static extern int gambatte_load(IntPtr core, byte[] romdata, uint length, long now, LoadFlags flags, uint div);
+ public static extern int gambatte_load(IntPtr core, byte[] romdata, uint length, LoadFlags flags);
///
/// Load GB(C) BIOS image.
@@ -114,9 +113,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
/// Equivalent to reloading a ROM image, or turning a Game Boy Color off and on again.
///
/// opaque state pointer
- /// RTC time when the reset occurs
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
- public static extern void gambatte_reset(IntPtr core, long now, uint div);
+ public static extern void gambatte_reset(IntPtr core);
///
/// palette type for gambatte_setdmgpalettecolor
@@ -259,21 +257,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
/// 0-153 inclusive
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void gambatte_setscanlinecallback(IntPtr core, ScanlineCallback callback, int sl);
-
- ///
- /// type of the RTC callback
- ///
- /// what time is it, unixy
- [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate uint RTCCallback();
-
- ///
- /// sets RTC callback. probably mandatory.
- ///
- /// opaque state pointer
- /// the callback
- [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
- public static extern void gambatte_setrtccallback(IntPtr core, RTCCallback callback);
///
/// type of the link data sent callback
@@ -289,6 +272,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void gambatte_setlinkcallback(IntPtr core, LinkCallback callback);
+ ///
+ /// Changes between cycle-based and real-time RTC. Defaults to cycle-based.
+ ///
+ /// opaque state pointer
+ /// use cycle-based RTC
+ [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void gambatte_settimemode(IntPtr core, bool useCycles);
+
///
/// Returns true if the currently loaded ROM image is treated as having CGB support.
///
diff --git a/libgambatte/include/gambatte.h b/libgambatte/include/gambatte.h
index 8bebff11bc..d86187c0fd 100644
--- a/libgambatte/include/gambatte.h
+++ b/libgambatte/include/gambatte.h
@@ -64,7 +64,7 @@ public:
* @param flags ORed combination of LoadFlags.
* @return 0 on success, negative value on failure.
*/
- LoadRes load(char const *romfiledata, unsigned romfilelength, std::uint32_t now, unsigned flags, unsigned div);
+ LoadRes load(char const *romfiledata, unsigned romfilelength, unsigned flags);
int loadBios(char const *biosfiledata, std::size_t size);
@@ -106,7 +106,7 @@ public:
* Reset to initial state.
* Equivalent to reloading a ROM image, or turning a Game Boy Color off and on again.
*/
- void reset(std::uint32_t now, unsigned div);
+ void reset();
/**
* @param palNum 0 <= palNum < 3. One of BG_PALETTE, SP1_PALETTE and SP2_PALETTE.
@@ -128,6 +128,9 @@ public:
void setRTCCallback(std::uint32_t (*callback)());
void setLinkCallback(void(*callback)());
+ /** Use cycle-based RTC instead of real-time. */
+ void setTimeMode(bool useCycles);
+
/** Returns true if the currently loaded ROM image is treated as having CGB support. */
bool isCgb() const;
diff --git a/libgambatte/libgambatte.vcxproj b/libgambatte/libgambatte.vcxproj
index 33e0eb0aee..6612bff667 100644
--- a/libgambatte/libgambatte.vcxproj
+++ b/libgambatte/libgambatte.vcxproj
@@ -170,6 +170,7 @@
+
@@ -202,6 +203,7 @@
+
diff --git a/libgambatte/libgambatte.vcxproj.filters b/libgambatte/libgambatte.vcxproj.filters
index 38cbfcdb7d..f096a22f6b 100644
--- a/libgambatte/libgambatte.vcxproj.filters
+++ b/libgambatte/libgambatte.vcxproj.filters
@@ -126,6 +126,9 @@
Header Files
+
+ Header Files
+
@@ -203,5 +206,8 @@
Source Files
+
+ Source Files
+
\ No newline at end of file
diff --git a/libgambatte/src/cinterface.cpp b/libgambatte/src/cinterface.cpp
index c342d81418..51c4730ae1 100644
--- a/libgambatte/src/cinterface.cpp
+++ b/libgambatte/src/cinterface.cpp
@@ -45,8 +45,8 @@ GBEXPORT void gambatte_destroy(GB *g) {
delete g;
}
-GBEXPORT int gambatte_load(GB *g, char const *romfiledata, unsigned romfilelength, long long now, unsigned flags, unsigned div) {
- return g->load(romfiledata, romfilelength, now, flags, div);
+GBEXPORT int gambatte_load(GB *g, char const *romfiledata, unsigned romfilelength, unsigned flags) {
+ return g->load(romfiledata, romfilelength, flags);
}
GBEXPORT int gambatte_loadbios(GB *g, char const *biosfiledata, unsigned size) {
@@ -68,8 +68,12 @@ GBEXPORT void gambatte_setlayers(GB *g, unsigned mask) {
g->setLayers(mask);
}
-GBEXPORT void gambatte_reset(GB *g, long long now, unsigned div) {
- g->reset(now, div);
+GBEXPORT void gambatte_setTimeMode(GB *g, bool useCycles) {
+ g->setTimeMode(useCycles);
+}
+
+GBEXPORT void gambatte_reset(GB *g) {
+ g->reset();
}
GBEXPORT void gambatte_setdmgpalettecolor(GB *g, unsigned palnum, unsigned colornum, unsigned rgb32) {
@@ -109,10 +113,6 @@ GBEXPORT void gambatte_setscanlinecallback(GB *g, void (*callback)(), int sl) {
g->setScanlineCallback(callback, sl);
}
-GBEXPORT void gambatte_setrtccallback(GB *g, unsigned int (*callback)()) {
- g->setRTCCallback(callback);
-}
-
GBEXPORT void gambatte_setlinkcallback(GB *g, void(*callback)()) {
g->setLinkCallback(callback);
}
diff --git a/libgambatte/src/cpu.h b/libgambatte/src/cpu.h
index 5349514e05..6059b0fad4 100644
--- a/libgambatte/src/cpu.h
+++ b/libgambatte/src/cpu.h
@@ -31,9 +31,9 @@ public:
void setStatePtrs(SaveState &state);
void loadState(SaveState const &state);
void setLayers(unsigned mask) { mem_.setLayers(mask); }
- void loadSavedata(char const *data) { mem_.loadSavedata(data); }
+ void loadSavedata(char const *data) { mem_.loadSavedata(data, cycleCounter_); }
int saveSavedataLength() {return mem_.saveSavedataLength(); }
- void saveSavedata(char *dest) { mem_.saveSavedata(dest); }
+ void saveSavedata(char *dest) { mem_.saveSavedata(dest, cycleCounter_); }
bool getMemoryArea(int which, unsigned char **data, int *length) { return mem_.getMemoryArea(which, data, length); }
@@ -69,10 +69,6 @@ public:
mem_.setScanlineCallback(callback, sl);
}
- void setRTCCallback(std::uint32_t (*callback)()) {
- mem_.setRTCCallback(callback);
- }
-
void setLinkCallback(void(*callback)()) {
mem_.setLinkCallback(callback);
}
@@ -94,6 +90,7 @@ public:
void setCgbPalette(unsigned *lut) {
mem_.setCgbPalette(lut);
}
+ void setTimeMode(bool useCycles) { mem_.setTimeMode(useCycles, cycleCounter_); }
void setBios(char const *buffer, std::size_t size) { mem_.setBios(buffer, size); }
bool gbIsCgb() { return mem_.gbIsCgb(); }
diff --git a/libgambatte/src/gambatte.cpp b/libgambatte/src/gambatte.cpp
index d4beddafce..d222874ac6 100644
--- a/libgambatte/src/gambatte.cpp
+++ b/libgambatte/src/gambatte.cpp
@@ -75,7 +75,7 @@ void GB::blitTo(gambatte::uint_least32_t *videoBuf, std::ptrdiff_t pitch) {
}
}
-void GB::reset(const std::uint32_t now, const unsigned div) {
+void GB::reset() {
if (p_->cpu.loaded()) {
int length = p_->cpu.saveSavedataLength();
@@ -88,7 +88,7 @@ void GB::reset(const std::uint32_t now, const unsigned div) {
SaveState state;
p_->cpu.setStatePtrs(state);
- setInitState(state, !(p_->loadflags & FORCE_DMG), p_->loadflags & GBA_CGB, now, div);
+ setInitState(state, !(p_->loadflags & FORCE_DMG), p_->loadflags & GBA_CGB);
p_->cpu.loadState(state);
if (length > 0)
{
@@ -126,22 +126,22 @@ void GB::setScanlineCallback(void (*callback)(), int sl) {
p_->cpu.setScanlineCallback(callback, sl);
}
-void GB::setRTCCallback(std::uint32_t (*callback)()) {
- p_->cpu.setRTCCallback(callback);
-}
-
void GB::setLinkCallback(void(*callback)()) {
p_->cpu.setLinkCallback(callback);
}
-LoadRes GB::load(char const *romfiledata, unsigned romfilelength, const std::uint32_t now, unsigned const flags, const unsigned div) {
+void GB::setTimeMode(bool useCycles) {
+ p_->cpu.setTimeMode(useCycles);
+}
+
+LoadRes GB::load(char const *romfiledata, unsigned romfilelength, unsigned const flags) {
LoadRes const loadres = p_->cpu.load(romfiledata, romfilelength, flags & FORCE_DMG, flags & MULTICART_COMPAT);
if (loadres == LOADRES_OK) {
SaveState state;
p_->cpu.setStatePtrs(state);
p_->loadflags = flags;
- setInitState(state, !(flags & FORCE_DMG), flags & GBA_CGB, now, div);
+ setInitState(state, !(flags & FORCE_DMG), flags & GBA_CGB);
p_->cpu.loadState(state);
}
diff --git a/libgambatte/src/initstate.cpp b/libgambatte/src/initstate.cpp
index d147eb03d6..72e26c6f85 100644
--- a/libgambatte/src/initstate.cpp
+++ b/libgambatte/src/initstate.cpp
@@ -20,6 +20,7 @@
#include "counterdef.h"
#include "savestate.h"
#include "sound/sound_unit.h"
+#include "mem/time.h"
#include
#include
@@ -1146,7 +1147,7 @@ static void setInitialDmgIoamhram(unsigned char ioamhram[]) {
} // anon namespace
-void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbMode, const std::uint32_t now, const unsigned div) {
+void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbMode) {
static unsigned char const cgbObjpDump[0x40] = {
0x00, 0x00, 0xF2, 0xAB,
0x61, 0xC2, 0xD9, 0xBA,
@@ -1198,7 +1199,7 @@ void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbM
state.mem.ioamhram.ptr[0x140] = 0;
state.mem.ioamhram.ptr[0x144] = 0x00;
- state.mem.divLastUpdate = 0 - div;
+ state.mem.divLastUpdate = 0;
state.mem.timaBasetime = 0;
state.mem.timaLastUpdate = 0;
state.mem.tmatime = disabled_time;
@@ -1315,8 +1316,12 @@ void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbM
state.spu.ch4.nr4 = 0;
state.spu.ch4.master = false;
- state.rtc.baseTime = now;
- state.rtc.haltTime = state.rtc.baseTime;
+ state.time.seconds = 0;
+ state.time.lastTimeSec = Time::now().tv_sec;
+ state.time.lastTimeUsec = Time::now().tv_usec;
+ state.time.lastCycles = state.cpu.cycleCounter;
+
+ state.rtc.haltTime = state.time.seconds;
state.rtc.dataDh = 0;
state.rtc.dataDl = 0;
state.rtc.dataH = 0;
diff --git a/libgambatte/src/initstate.h b/libgambatte/src/initstate.h
index 02363941d8..0e31dd35bb 100644
--- a/libgambatte/src/initstate.h
+++ b/libgambatte/src/initstate.h
@@ -23,7 +23,7 @@
namespace gambatte {
-void setInitState(struct SaveState &state, bool cgb, bool gbaCgbMode, std::uint32_t now, unsigned div);
+void setInitState(struct SaveState &state, bool cgb, bool gbaCgbMode);
}
#endif
diff --git a/libgambatte/src/mem/cartridge.cpp b/libgambatte/src/mem/cartridge.cpp
index 5465548f22..0d6539af68 100644
--- a/libgambatte/src/mem/cartridge.cpp
+++ b/libgambatte/src/mem/cartridge.cpp
@@ -50,7 +50,7 @@ public:
{
}
- virtual void romWrite(unsigned const p, unsigned const data) {
+ virtual void romWrite(unsigned const p, unsigned const data, unsigned long const /*cc*/) {
if (p < 0x2000) {
enableRam_ = (data & 0xF) == 0xA;
memptrs_.setRambank(enableRam_ ? MemPtrs::read_en | MemPtrs::write_en : 0, 0);
@@ -92,7 +92,7 @@ public:
{
}
- virtual void romWrite(unsigned const p, unsigned const data) {
+ virtual void romWrite(unsigned const p, unsigned const data, unsigned long const /*cc*/) {
switch (p >> 13 & 3) {
case 0:
enableRam_ = (data & 0xF) == 0xA;
@@ -166,7 +166,7 @@ public:
{
}
- virtual void romWrite(unsigned const p, unsigned const data) {
+ virtual void romWrite(unsigned const p, unsigned const data, unsigned long const /*cc*/) {
switch (p >> 13 & 3) {
case 0:
enableRam_ = (data & 0xF) == 0xA;
@@ -238,7 +238,7 @@ public:
{
}
- virtual void romWrite(unsigned const p, unsigned const data) {
+ virtual void romWrite(unsigned const p, unsigned const data, unsigned long const /*cc*/) {
switch (p & 0x6100) {
case 0x0000:
enableRam_ = (data & 0xF) == 0xA;
@@ -282,7 +282,7 @@ public:
{
}
- virtual void romWrite(unsigned const p, unsigned const data) {
+ virtual void romWrite(unsigned const p, unsigned const data, unsigned long const cc) {
switch (p >> 13 & 3) {
case 0:
enableRam_ = (data & 0xF) == 0xA;
@@ -298,7 +298,7 @@ public:
break;
case 3:
if (rtc_)
- rtc_->latch(data);
+ rtc_->latch(data, cc);
break;
}
@@ -356,7 +356,7 @@ public:
{
}
- virtual void romWrite(unsigned const p, unsigned const data) {
+ virtual void romWrite(unsigned const p, unsigned const data, unsigned long const /*cc*/) {
switch (p >> 13 & 3) {
case 0:
enableRam_ = (data & 0xF) == 0xA;
@@ -424,7 +424,7 @@ public:
{
}
- virtual void romWrite(unsigned const p, unsigned const data) {
+ virtual void romWrite(unsigned const p, unsigned const data, unsigned long const /*cc*/) {
switch (p >> 13 & 3) {
case 0:
enableRam_ = (data & 0xF) == 0xA;
@@ -487,6 +487,11 @@ static bool hasRtc(unsigned headerByte0x147) {
}
+Cartridge::Cartridge()
+: rtc_(time_)
+{
+}
+
void Cartridge::setStatePtrs(SaveState &state) {
state.mem.vram.set(memptrs_.vramdata(), memptrs_.vramdataend() - memptrs_.vramdata());
state.mem.sram.set(memptrs_.rambankdata(), memptrs_.rambankdataend() - memptrs_.rambankdata());
@@ -652,7 +657,7 @@ static bool hasBattery(unsigned char headerByte0x147) {
}
}
-void Cartridge::loadSavedata(char const *data) {
+void Cartridge::loadSavedata(char const *data, unsigned long const cc) {
if (hasBattery(memptrs_.romdata()[0x147])) {
int length = memptrs_.rambankdataend() - memptrs_.rambankdata();
std::memcpy(memptrs_.rambankdata(), data, length);
@@ -661,9 +666,17 @@ void Cartridge::loadSavedata(char const *data) {
}
if (hasRtc(memptrs_.romdata()[0x147])) {
- unsigned long basetime;
- std::memcpy(&basetime, data, 4);
- rtc_.setBaseTime(basetime);
+ timeval basetime;
+ basetime.tv_sec = (*data++);
+ basetime.tv_sec = basetime.tv_sec << 8 | (*data++);
+ basetime.tv_sec = basetime.tv_sec << 8 | (*data++);
+ basetime.tv_sec = basetime.tv_sec << 8 | (*data++);
+ basetime.tv_usec = (*data++);
+ basetime.tv_usec = basetime.tv_usec << 8 | (*data++);
+ basetime.tv_usec = basetime.tv_usec << 8 | (*data++);
+ basetime.tv_usec = basetime.tv_usec << 8 | (*data++);
+
+ time_.setBaseTime(basetime, cc);
}
}
@@ -673,12 +686,12 @@ int Cartridge::saveSavedataLength() {
ret = memptrs_.rambankdataend() - memptrs_.rambankdata();
}
if (hasRtc(memptrs_.romdata()[0x147])) {
- ret += 4;
+ ret += 8;
}
return ret;
}
-void Cartridge::saveSavedata(char *dest) {
+void Cartridge::saveSavedata(char *dest, unsigned long const cc) {
if (hasBattery(memptrs_.romdata()[0x147])) {
int length = memptrs_.rambankdataend() - memptrs_.rambankdata();
std::memcpy(dest, memptrs_.rambankdata(), length);
@@ -686,8 +699,15 @@ void Cartridge::saveSavedata(char *dest) {
}
if (hasRtc(memptrs_.romdata()[0x147])) {
- const unsigned long basetime = rtc_.getBaseTime();
- std::memcpy(dest, &basetime, 4);
+ timeval basetime = time_.baseTime(cc);
+ *dest++ = (basetime.tv_sec >> 24 & 0xFF);
+ *dest++ = (basetime.tv_sec >> 16 & 0xFF);
+ *dest++ = (basetime.tv_sec >> 8 & 0xFF);
+ *dest++ = (basetime.tv_sec & 0xFF);
+ *dest++ = (basetime.tv_usec >> 24 & 0xFF);
+ *dest++ = (basetime.tv_usec >> 16 & 0xFF);
+ *dest++ = (basetime.tv_usec >> 8 & 0xFF);
+ *dest++ = (basetime.tv_usec & 0xFF);
}
}
@@ -723,6 +743,7 @@ bool Cartridge::getMemoryArea(int which, unsigned char **data, int *length) cons
SYNCFUNC(Cartridge)
{
SSS(memptrs_);
+ SSS(time_);
SSS(rtc_);
TSS(mbc_);
}
diff --git a/libgambatte/src/mem/cartridge.h b/libgambatte/src/mem/cartridge.h
index 245bf537aa..db46afb262 100644
--- a/libgambatte/src/mem/cartridge.h
+++ b/libgambatte/src/mem/cartridge.h
@@ -21,6 +21,7 @@
#include "loadres.h"
#include "memptrs.h"
+#include "time.h"
#include "rtc.h"
#include "savestate.h"
#include
@@ -33,7 +34,7 @@ namespace gambatte {
class Mbc {
public:
virtual ~Mbc() {}
- virtual void romWrite(unsigned P, unsigned data) = 0;
+ virtual void romWrite(unsigned P, unsigned data, unsigned long cycleCounter) = 0;
virtual void loadState(SaveState::Mem const &ss) = 0;
virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned address, unsigned rombank) const = 0;
@@ -47,6 +48,7 @@ public:
class Cartridge {
public:
+ Cartridge();
void setStatePtrs(SaveState &);
void loadState(SaveState const &);
bool loaded() const { return mbc_.get(); }
@@ -64,23 +66,23 @@ public:
void setWrambank(unsigned bank) { memptrs_.setWrambank(bank); }
void setOamDmaSrc(OamDmaSrc oamDmaSrc) { memptrs_.setOamDmaSrc(oamDmaSrc); }
unsigned curRomBank() const { return memptrs_.curRomBank(); }
- void mbcWrite(unsigned addr, unsigned data) { mbc_->romWrite(addr, data); }
+ void mbcWrite(unsigned addr, unsigned data, unsigned long const cc) { mbc_->romWrite(addr, data, cc); }
bool isCgb() const { return gambatte::isCgb(memptrs_); }
- void rtcWrite(unsigned data) { rtc_.write(data); }
+ void resetCc(unsigned long const oldCc, unsigned long const newCc) { time_.resetCc(oldCc, newCc); }
+ void speedChange(unsigned long const cc) { time_.speedChange(cc); }
+ void setTimeMode(bool useCycles, unsigned long const cc) { time_.setTimeMode(useCycles, cc); }
+ void rtcWrite(unsigned data, unsigned long const cc) { rtc_.write(data, cc); }
unsigned char rtcRead() const { return *rtc_.activeData(); }
- void loadSavedata(char const *data);
+ void loadSavedata(char const *data, unsigned long cycleCounter);
int saveSavedataLength();
- void saveSavedata(char *dest);
+ void saveSavedata(char *dest, unsigned long cycleCounter);
bool getMemoryArea(int which, unsigned char **data, int *length) const;
LoadRes loadROM(char const *romfiledata, unsigned romfilelength, bool forceDmg, bool multicartCompat);
char const * romTitle() const { return reinterpret_cast(memptrs_.romdata() + 0x134); }
- void setRTCCallback(std::uint32_t (*callback)()) {
- rtc_.setRTCCallback(callback);
- }
-
private:
MemPtrs memptrs_;
+ Time time_;
Rtc rtc_;
std::unique_ptr mbc_;
diff --git a/libgambatte/src/mem/rtc.cpp b/libgambatte/src/mem/rtc.cpp
index 5495201c4c..5b79c04d7b 100644
--- a/libgambatte/src/mem/rtc.cpp
+++ b/libgambatte/src/mem/rtc.cpp
@@ -22,10 +22,10 @@
namespace gambatte {
-Rtc::Rtc()
-: activeData_(0)
+Rtc::Rtc(Time &time)
+: time_(time)
+, activeData_(0)
, activeSet_(0)
-, baseTime_(0)
, haltTime_(0)
, index_(5)
, dataDh_(0)
@@ -35,16 +35,15 @@ Rtc::Rtc()
, dataS_(0)
, enabled_(false)
, lastLatchData_(false)
-, timeCB(0)
{
}
-void Rtc::doLatch() {
- std::uint32_t tmp = ((dataDh_ & 0x40) ? haltTime_ : timeCB()) - baseTime_;
+void Rtc::doLatch(unsigned long const cc) {
+ std::uint32_t tmp = time(cc);
- while (tmp > 0x1FF * 86400) {
- baseTime_ += 0x1FF * 86400;
- tmp -= 0x1FF * 86400;
+ if (tmp >= 0x200 * 86400) {
+ tmp %= 0x200 * 86400;
+ time_.set(tmp, cc);
dataDh_ |= 0x80;
}
@@ -91,7 +90,6 @@ void Rtc::doSwapActive() {
}
void Rtc::loadState(SaveState const &state) {
- baseTime_ = state.rtc.baseTime;
haltTime_ = state.rtc.haltTime;
dataDh_ = state.rtc.dataDh;
dataDl_ = state.rtc.dataDl;
@@ -102,45 +100,50 @@ void Rtc::loadState(SaveState const &state) {
doSwapActive();
}
-void Rtc::setDh(unsigned const newDh) {
- const std::uint32_t unixtime = (dataDh_ & 0x40) ? haltTime_ : timeCB();
- const std::uint32_t oldHighdays = ((unixtime - baseTime_) / 86400) & 0x100;
- baseTime_ += oldHighdays * 86400;
- baseTime_ -= ((newDh & 0x1) << 8) * 86400;
+void Rtc::setDh(unsigned const newDh, unsigned const long cc) {
+ std::uint32_t seconds = time(cc);
+ std::uint32_t const oldHighdays = (seconds / 86400) & 0x100;
+ seconds -= oldHighdays * 86400;
+ seconds += ((newDh & 0x1) << 8) * 86400;
+ time_.set(seconds, cc);
if ((dataDh_ ^ newDh) & 0x40) {
if (newDh & 0x40)
- haltTime_ = timeCB();
+ haltTime_ = seconds;
else
- baseTime_ += timeCB() - haltTime_;
+ time_.set(haltTime_, cc);
}
}
-void Rtc::setDl(unsigned const newLowdays) {
- const std::uint32_t unixtime = (dataDh_ & 0x40) ? haltTime_ : timeCB();
- const std::uint32_t oldLowdays = ((unixtime - baseTime_) / 86400) & 0xFF;
- baseTime_ += oldLowdays * 86400;
- baseTime_ -= newLowdays * 86400;
+void Rtc::setDl(unsigned const newLowdays, unsigned const long cc) {
+ std::uint32_t seconds = time(cc);
+ std::uint32_t const oldLowdays = (seconds / 86400) & 0xFF;
+ seconds -= oldLowdays * 86400;
+ seconds += newLowdays * 86400;
+ time_.set(seconds, cc);
}
-void Rtc::setH(unsigned const newHours) {
- const std::uint32_t unixtime = (dataDh_ & 0x40) ? haltTime_ : timeCB();
- const std::uint32_t oldHours = ((unixtime - baseTime_) / 3600) % 24;
- baseTime_ += oldHours * 3600;
- baseTime_ -= newHours * 3600;
+void Rtc::setH(unsigned const newHours, unsigned const long cc) {
+ std::uint32_t seconds = time(cc);
+ std::uint32_t const oldHours = (seconds / 3600) % 24;
+ seconds -= oldHours * 3600;
+ seconds += newHours * 3600;
+ time_.set(seconds, cc);
}
-void Rtc::setM(unsigned const newMinutes) {
- const std::uint32_t unixtime = (dataDh_ & 0x40) ? haltTime_ : timeCB();
- const std::uint32_t oldMinutes = ((unixtime - baseTime_) / 60) % 60;
- baseTime_ += oldMinutes * 60;
- baseTime_ -= newMinutes * 60;
+void Rtc::setM(unsigned const newMinutes, unsigned const long cc) {
+ std::uint32_t seconds = time(cc);
+ std::uint32_t const oldMinutes = (seconds / 60) % 60;
+ seconds -= oldMinutes * 60;
+ seconds += newMinutes * 60;
+ time_.set(seconds, cc);
}
-void Rtc::setS(unsigned const newSeconds) {
- const std::uint32_t unixtime = (dataDh_ & 0x40) ? haltTime_ : timeCB();
- baseTime_ += (unixtime - baseTime_) % 60;
- baseTime_ -= newSeconds;
+void Rtc::setS(unsigned const newSeconds, unsigned const long cc) {
+ std::uint32_t seconds = time(cc);
+ seconds -= seconds % 60;
+ seconds += newSeconds;
+ time_.reset(seconds, cc);
}
SYNCFUNC(Rtc)
@@ -161,7 +164,6 @@ SYNCFUNC(Rtc)
EVS(activeSet_, &Rtc::setDh, 5);
EES(activeSet_, NULL);
- NSS(baseTime_);
NSS(haltTime_);
NSS(index_);
NSS(dataDh_);
diff --git a/libgambatte/src/mem/rtc.h b/libgambatte/src/mem/rtc.h
index f7594e2eec..853027ed58 100644
--- a/libgambatte/src/mem/rtc.h
+++ b/libgambatte/src/mem/rtc.h
@@ -20,6 +20,7 @@
#define RTC_H
#include
+#include "time.h"
#include "newstate.h"
namespace gambatte {
@@ -28,18 +29,12 @@ struct SaveState;
class Rtc {
public:
- Rtc();
-
+ Rtc(Time &time);
unsigned char const * activeData() const { return activeData_; }
- std::uint32_t getBaseTime() const { return baseTime_; }
- void setBaseTime(const std::uint32_t baseTime) {
- this->baseTime_ = baseTime;
- }
-
- void latch(unsigned data) {
+ void latch(unsigned data, unsigned long const cc) {
if (!lastLatchData_ && data == 1)
- doLatch();
+ doLatch(cc);
lastLatchData_ = data;
}
@@ -55,19 +50,15 @@ public:
doSwapActive();
}
- void write(unsigned data) {
- (this->*activeSet_)(data);
+ void write(unsigned data, unsigned long const cc) {
+ (this->*activeSet_)(data, cc);
*activeData_ = data;
}
- void setRTCCallback(std::uint32_t (*callback)()) {
- timeCB = callback;
- }
-
private:
+ Time &time_;
unsigned char *activeData_;
- void (Rtc::*activeSet_)(unsigned);
- std::uint32_t baseTime_;
+ void (Rtc::*activeSet_)(unsigned, unsigned long);
std::uint32_t haltTime_;
unsigned char index_;
unsigned char dataDh_;
@@ -77,16 +68,18 @@ private:
unsigned char dataS_;
bool enabled_;
bool lastLatchData_;
- std::uint32_t (*timeCB)();
- void doLatch();
+ void doLatch(unsigned long cycleCounter);
void doSwapActive();
- void setDh(unsigned newDh);
- void setDl(unsigned newLowdays);
- void setH(unsigned newHours);
- void setM(unsigned newMinutes);
- void setS(unsigned newSeconds);
+ void setDh(unsigned newDh, unsigned long cycleCounter);
+ void setDl(unsigned newLowdays, unsigned long cycleCounter);
+ void setH(unsigned newHours, unsigned long cycleCounter);
+ void setM(unsigned newMinutes, unsigned long cycleCounter);
+ void setS(unsigned newSeconds, unsigned long cycleCounter);
+ std::uint32_t time(unsigned long const cc) {
+ return dataDh_ & 0x40 ? haltTime_ : time_.get(cc);
+ }
public:
templatevoid SyncState(NewState *ns);
};
diff --git a/libgambatte/src/mem/time.cpp b/libgambatte/src/mem/time.cpp
new file mode 100644
index 0000000000..71e92d1356
--- /dev/null
+++ b/libgambatte/src/mem/time.cpp
@@ -0,0 +1,144 @@
+//
+// Copyright (C) 2007 by sinamas
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License version 2 for more details.
+//
+// You should have received a copy of the GNU General Public License
+// version 2 along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+
+#include "time.h"
+#include "../savestate.h"
+
+namespace gambatte {
+
+static timeval operator-(timeval l, timeval r) {
+ timeval t;
+ t.tv_sec = l.tv_sec - r.tv_sec;
+ t.tv_usec = l.tv_usec - r.tv_usec;
+ if (t.tv_usec < 0) {
+ t.tv_sec--;
+ t.tv_usec += 1000000;
+ }
+ return t;
+}
+
+Time::Time()
+: useCycles_(true)
+{
+}
+
+void Time::loadState(SaveState const &state) {
+ seconds_ = state.time.seconds;
+ lastTime_.tv_sec = state.time.lastTimeSec;
+ lastTime_.tv_usec = state.time.lastTimeUsec;
+ lastCycles_ = state.time.lastCycles;
+ ds_ = state.ppu.isCgb & state.mem.ioamhram.get()[0x14D] >> 7;
+}
+
+std::uint32_t Time::get(unsigned long const cc) {
+ update(cc);
+ return seconds_;
+}
+
+void Time::set(std::uint32_t seconds, unsigned long const cc) {
+ update(cc);
+ seconds_ = seconds;
+}
+
+void Time::reset(std::uint32_t seconds, unsigned long const cc) {
+ set(seconds, cc);
+ lastTime_ = now();
+ lastCycles_ = cc;
+}
+
+void Time::resetCc(unsigned long const oldCc, unsigned long const newCc) {
+ update(oldCc);
+ lastCycles_ -= oldCc - newCc;
+}
+
+void Time::speedChange(unsigned long const cc) {
+ update(cc);
+
+ if (useCycles_) {
+ unsigned long diff = cc - lastCycles_;
+ lastCycles_ = cc - (ds_ ? diff >> 1 : diff << 1);
+ }
+
+ ds_ = !ds_;
+}
+
+timeval Time::baseTime(unsigned long const cc) {
+ if (useCycles_)
+ timeFromCycles(cc);
+
+ timeval baseTime = lastTime_;
+ baseTime.tv_sec -= seconds_;
+ return baseTime;
+}
+
+void Time::setBaseTime(timeval baseTime, unsigned long const cc) {
+ seconds_ = (now() - baseTime).tv_sec;
+ lastTime_ = baseTime;
+ lastTime_.tv_sec += seconds_;
+
+ if (useCycles_)
+ cyclesFromTime(cc);
+}
+
+void Time::setTimeMode(bool useCycles, unsigned long const cc) {
+ if (useCycles != useCycles_) {
+ if (useCycles_)
+ timeFromCycles(cc);
+ else
+ cyclesFromTime(cc);
+
+ useCycles_ = useCycles;
+ }
+}
+
+void Time::update(unsigned long const cc) {
+ if (useCycles_) {
+ std::uint32_t diff = (cc - lastCycles_) / (0x400000 << ds_);
+ seconds_ += diff;
+ lastCycles_ += diff * (0x400000 << ds_);
+ } else {
+ std::uint32_t diff = (now() - lastTime_).tv_sec;
+ seconds_ += diff;
+ lastTime_.tv_sec += diff;
+ }
+}
+
+void Time::cyclesFromTime(unsigned long const cc) {
+ update(cc);
+ timeval diff = now() - lastTime_;
+ lastCycles_ = cc - diff.tv_usec * ((0x400000 << ds_) / 1000000.0f);
+}
+
+void Time::timeFromCycles(unsigned long const cc) {
+ update(cc);
+ unsigned long diff = cc - lastCycles_;
+ timeval usec = { 0, (long)(diff / ((0x400000 << ds_) / 1000000.0f)) };
+ lastTime_ = now() - usec;
+}
+
+SYNCFUNC(Time)
+{
+ NSS(seconds_);
+ NSS(lastTime_.tv_sec);
+ NSS(lastTime_.tv_usec);
+ NSS(lastCycles_);
+ NSS(useCycles_);
+ NSS(ds_);
+}
+
+}
diff --git a/libgambatte/src/mem/time.h b/libgambatte/src/mem/time.h
new file mode 100644
index 0000000000..aa8e49b5e3
--- /dev/null
+++ b/libgambatte/src/mem/time.h
@@ -0,0 +1,78 @@
+//
+// Copyright (C) 2007 by sinamas
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License version 2 for more details.
+//
+// You should have received a copy of the GNU General Public License
+// version 2 along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+
+#ifndef TIME_H
+#define TIME_H
+
+#include
+#include
+#include
+#include "newstate.h"
+
+namespace gambatte {
+
+struct SaveState;
+
+struct timeval {
+ std::uint32_t tv_sec;
+ std::uint32_t tv_usec;
+};
+
+class Time {
+public:
+ static timeval now() {
+ long long micros = std::chrono::duration_cast(
+ std::chrono::high_resolution_clock::now().time_since_epoch())
+ .count();
+ timeval t;
+ t.tv_usec = micros % 1000000;
+ t.tv_sec = micros / 1000000;
+ return t;
+ }
+
+ Time();
+ void loadState(SaveState const &state);
+
+ std::uint32_t get(unsigned long cycleCounter);
+ void set(std::uint32_t seconds, unsigned long cycleCounter);
+ void reset(std::uint32_t seconds, unsigned long cycleCounter);
+ void resetCc(unsigned long oldCc, unsigned long newCc);
+ void speedChange(unsigned long cycleCounter);
+
+ timeval baseTime(unsigned long cycleCounter);
+ void setBaseTime(timeval baseTime, unsigned long cycleCounter);
+ void setTimeMode(bool useCycles, unsigned long cycleCounter);
+
+private:
+ std::uint32_t seconds_;
+ timeval lastTime_;
+ unsigned long lastCycles_;
+ bool useCycles_;
+ bool ds_;
+
+ void update(unsigned long cycleCounter);
+ void cyclesFromTime(unsigned long cycleCounter);
+ void timeFromCycles(unsigned long cycleCounter);
+
+public:
+ templatevoid SyncState(NewState *ns);
+};
+
+}
+
+#endif
diff --git a/libgambatte/src/memory.cpp b/libgambatte/src/memory.cpp
index 2e39855eda..6ddce9da05 100644
--- a/libgambatte/src/memory.cpp
+++ b/libgambatte/src/memory.cpp
@@ -345,6 +345,7 @@ unsigned long Memory::stop(unsigned long cc) {
if (ioamhram_[0x14D] & isCgb()) {
psg_.generateSamples(cc + 4, isDoubleSpeed());
lcd_.speedChange((cc + 7) & ~7);
+ cart_.speedChange(cc);
ioamhram_[0x14D] ^= 0x81;
intreq_.setEventTime(ioamhram_[0x140] & lcdc_en
? lcd_.nextMode1IrqTime()
@@ -403,6 +404,7 @@ unsigned long Memory::resetCounters(unsigned long cc) {
unsigned long const oldCC = cc;
cc -= dec;
intreq_.resetCc(oldCC, cc);
+ cart_.resetCc(oldCC, cc);
tima_.resetCc(oldCC, cc, TimaInterruptRequester(intreq_));
lcd_.resetCc(oldCC, cc);
psg_.resetCounter(cc, oldCC, isDoubleSpeed());
@@ -1099,7 +1101,7 @@ void Memory::nontrivial_write(unsigned const p, unsigned const data, unsigned lo
if (p < 0xFE00) {
if (p < 0xA000) {
if (p < 0x8000) {
- cart_.mbcWrite(p, data);
+ cart_.mbcWrite(p, data, cc);
} else if (lcd_.vramAccessible(cc)) {
lcd_.vramChange(cc);
cart_.vrambankptr()[p] = data;
@@ -1108,7 +1110,7 @@ void Memory::nontrivial_write(unsigned const p, unsigned const data, unsigned lo
if (cart_.wsrambankptr())
cart_.wsrambankptr()[p] = data;
else
- cart_.rtcWrite(data);
+ cart_.rtcWrite(data, cc);
} else
cart_.wramdata(p >> 12 & 1)[p & 0xFFF] = data;
} else if (p - 0xFF80u >= 0x7Fu) {
diff --git a/libgambatte/src/memory.h b/libgambatte/src/memory.h
index 051a5ea904..f00e28ac24 100644
--- a/libgambatte/src/memory.h
+++ b/libgambatte/src/memory.h
@@ -29,6 +29,7 @@ static unsigned char const agbOverride[0xD] = { 0xFF, 0x00, 0xCD, 0x03, 0x35, 0x
#include "gambatte.h"
namespace gambatte {
+
class FilterInfo;
class Memory {
@@ -42,9 +43,9 @@ public:
int debugGetLY() const { return lcd_.debugGetLY(); }
void setStatePtrs(SaveState &state);
void loadState(SaveState const &state);
- void loadSavedata(char const *data) { cart_.loadSavedata(data); }
+ void loadSavedata(char const *data, unsigned long const cc) { cart_.loadSavedata(data, cc); }
int saveSavedataLength() {return cart_.saveSavedataLength(); }
- void saveSavedata(char *dest) { cart_.saveSavedata(dest); }
+ void saveSavedata(char *dest, unsigned long const cc) { cart_.saveSavedata(dest, cc); }
void updateInput();
void setBios(char const *buffer, std::size_t size) {
@@ -243,10 +244,6 @@ public:
lcd_.setScanlineCallback(callback, sl);
}
- void setRTCCallback(std::uint32_t (*callback)()) {
- cart_.setRTCCallback(callback);
- }
-
void setLinkCallback(void(*callback)()) {
this->linkCallback_ = callback;
}
@@ -266,6 +263,9 @@ public:
}
void setCgbPalette(unsigned *lut);
+ void setTimeMode(bool useCycles, unsigned long const cc) {
+ cart_.setTimeMode(useCycles, cc);
+ }
int linkStatus(int which);
diff --git a/libgambatte/src/savestate.h b/libgambatte/src/savestate.h
index e56290685d..c130ab5ecb 100644
--- a/libgambatte/src/savestate.h
+++ b/libgambatte/src/savestate.h
@@ -36,7 +36,7 @@ struct SaveState {
void set(T *p, std::size_t size) { ptr = p; size_ = size; }
friend class SaverList;
- friend void setInitState(SaveState &, bool, bool, std::uint32_t, unsigned);
+ friend void setInitState(SaveState &, bool, bool);
private:
T *ptr;
std::size_t size_;
@@ -190,8 +190,14 @@ struct SaveState {
unsigned long cycleCounter;
} spu;
+ struct Time {
+ unsigned long seconds;
+ unsigned long lastTimeSec;
+ unsigned long lastTimeUsec;
+ unsigned long lastCycles;
+ } time;
+
struct RTC {
- unsigned long baseTime;
unsigned long haltTime;
unsigned char dataDh;
unsigned char dataDl;
diff --git a/output/dll/libgambatte.dll b/output/dll/libgambatte.dll
index 2d96928fd0..17b09b4e0a 100644
Binary files a/output/dll/libgambatte.dll and b/output/dll/libgambatte.dll differ