aboutsummaryrefslogtreecommitdiff
path: root/source/nds/entry.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/nds/entry.cpp')
-rw-r--r--source/nds/entry.cpp244
1 files changed, 145 insertions, 99 deletions
diff --git a/source/nds/entry.cpp b/source/nds/entry.cpp
index 6cbf3ef..08e95cb 100644
--- a/source/nds/entry.cpp
+++ b/source/nds/entry.cpp
@@ -642,10 +642,19 @@ static unsigned int sync_next = 0;
static unsigned int skip_rate= 0;
+#define CPU_DOWNCLOCK_EARLY_TIME 293 /* 1 = 42.667 us. 391 = 16.67 ms */
+#define CPU_DOWNCLOCK_DETERMINATION_INTERVAL 46874 /* 23437 = 1 s */
+
+static unsigned int LastAutoCPUTime = 0;
+unsigned int AutoCPUFrequency = 5;
+static bool8 ConsistentlyEarly = FALSE;
+static bool8 FastForwardLastFrame = FALSE;
+
void S9xSyncSpeed ()
{
uint32 syncnow;
int32 syncdif;
+ unsigned int LastAutoCPUFrequency = AutoCPUFrequency;
#if 0
if (Settings.SoundSync == 2)
@@ -657,8 +666,19 @@ void S9xSyncSpeed ()
#endif
syncnow = getSysTime();
- if (game_fast_forward || temporary_fast_forward /* hotkey is held */)
+ bool8 FastForward = game_fast_forward || temporary_fast_forward /* hotkey is held */;
+
+ if (game_config.clock_speed_number == 0)
+ if (FastForward && !FastForwardLastFrame)
+ HighFrequencyCPU ();
+ else if (!FastForward && FastForwardLastFrame)
+ GameFrequencyCPU ();
+
+ FastForwardLastFrame = FastForward;
+
+ if (FastForward)
{
+ ConsistentlyEarly = FALSE; // don't use fast-forward to lower CPU
sync_last = syncnow;
sync_next = syncnow;
@@ -670,137 +690,149 @@ void S9xSyncSpeed ()
IPPU.RenderThisFrame = true;
}
}
- else if (Settings.SkipFrames == AUTO_FRAMERATE /* && !game_fast_forward && !temporary_fast_forward */)
+ else
{
- // frame_time is in getSysTime units: 42.667 microseconds.
- int32 frame_time = Settings.PAL ? 468 /* = 20.0 ms */ : 391 /* = 16.67 ms */;
- if (sync_last > syncnow) // Overflow occurred! (every 50 hrs)
+ // Manual or automatic frame skipping, no fast-forward.
+ if (Settings.SkipFrames == AUTO_FRAMERATE)
{
- // Render this frame regardless, set the
- // sync_next, and get the hell out.
- IPPU.RenderThisFrame = TRUE;
+ // frame_time is in getSysTime units: 42.667 microseconds.
+ int32 frame_time = Settings.PAL ? 468 /* = 20.0 ms */ : 391 /* = 16.67 ms */;
+ if (sync_last > syncnow) // Overflow occurred! (every 50 hrs)
+ {
+ // Render this frame regardless, set the
+ // sync_next, and get the hell out.
+ ConsistentlyEarly = FALSE;
+ AutoCPUFrequency = 5;
+ LastAutoCPUTime = syncnow;
+
+ IPPU.RenderThisFrame = TRUE;
+ sync_last = syncnow;
+ sync_next = syncnow + frame_time;
+ goto finalise;
+ }
sync_last = syncnow;
- sync_next = syncnow + frame_time;
- return;
- }
- sync_last = syncnow;
- // If this is positive, we have syncdif*42.66 microseconds to
- // spare.
- // If this is negative, we're late by syncdif*42.66
- // microseconds.
- syncdif = sync_next - syncnow;
- if(skip_rate < 2 /* did not skip 2 frames yet */)
- {
- // Skip a minimum of 2 frames between rendered frames.
- // This prevents the DSTwo-DS link from being too busy
- // to return button statuses.
- ++skip_rate;
- IPPU.RenderThisFrame = FALSE;
- sync_next += frame_time;
- }
- else if (syncdif < 0 && syncdif >= -(frame_time / 2))
- {
- // We're late, but by less than half a frame. Draw it
- // anyway. If the next frame is too late, it'll be
- // skipped.
- skip_rate = 0;
- IPPU.RenderThisFrame = true;
- sync_next += frame_time;
- }
- else if(syncdif < 0)
- {
- /*
- * If we're consistently late, delay up to 8 frames.
- *
- * That really helps with certain games, such as
- * Super Mario RPG and Yoshi's Island.
- */
- if(++skip_rate < 10)
+ // If this is positive, we have syncdif*42.66 microseconds to
+ // spare.
+ // If this is negative, we're late by syncdif*42.66
+ // microseconds.
+ syncdif = sync_next - syncnow;
+ if(skip_rate < 2 /* did not skip 2 frames yet */)
{
- if(syncdif >= -11719 /* not more than 500.0 ms late */)
+ // Skip a minimum of 2 frames between rendered frames.
+ // This prevents the DSTwo-DS link from being too busy
+ // to return button statuses.
+ ++skip_rate;
+ IPPU.RenderThisFrame = FALSE;
+ sync_next += frame_time;
+ }
+ else if(syncdif < 0)
+ {
+ ConsistentlyEarly = FALSE;
+ AutoCPUFrequency = 5;
+ LastAutoCPUTime = syncnow;
+
+ /*
+ * If we're consistently late, delay up to 8 frames.
+ *
+ * That really helps with certain games, such as
+ * Super Mario RPG and Yoshi's Island.
+ */
+ if(++skip_rate < 10)
{
- IPPU.RenderThisFrame = FALSE;
- sync_next += frame_time;
+ if(syncdif >= -11719 /* not more than 500.0 ms late */)
+ {
+ IPPU.RenderThisFrame = FALSE;
+ sync_next += frame_time;
+ }
+ else
+ { //lag more than 0.5s, maybe paused
+ IPPU.RenderThisFrame = TRUE;
+ sync_next = syncnow + frame_time;
+ }
}
else
- { //lag more than 0.5s, maybe paused
+ {
+ skip_rate = 0;
IPPU.RenderThisFrame = TRUE;
sync_next = syncnow + frame_time;
}
}
- else
+ else // Early
{
+ ConsistentlyEarly = ConsistentlyEarly && syncdif >= CPU_DOWNCLOCK_EARLY_TIME;
skip_rate = 0;
- IPPU.RenderThisFrame = TRUE;
- sync_next = syncnow + frame_time;
- }
- }
- else // Early
- {
- skip_rate = 0;
- if (syncdif > 0)
- {
- do {
- S9xProcessSound (0);
+ if (syncdif > 0)
+ {
+ do {
+ S9xProcessSound (0);
#ifdef ACCUMULATE_JOYPAD
/*
* This call allows NDSSFC to synchronise the DS controller more often.
* If porting a later version of Snes9x into NDSSFC, it is essential to
* preserve it.
*/
- NDSSFCAccumulateJoypad ();
+ NDSSFCAccumulateJoypad ();
#endif
- syncdif = sync_next - getSysTime();
- } while (syncdif > 0);
- }
+ syncdif = sync_next - getSysTime();
+ } while (syncdif > 0);
+ }
- IPPU.RenderThisFrame = TRUE;
- sync_next += frame_time;
- }
+ IPPU.RenderThisFrame = TRUE;
+ sync_next += frame_time;
+ }
#if 0
- if(++framenum >= 60)
- {
- syncdif = syncnow - sync_last;
- sync_last = syncnow;
- framenum = 0;
- //printf("T %d %d\n", syncdif*42667/1000, realframe);
- realframe = 0;
- }
+ if(++framenum >= 60)
+ {
+ syncdif = syncnow - sync_last;
+ sync_last = syncnow;
+ framenum = 0;
+ //printf("T %d %d\n", syncdif*42667/1000, realframe);
+ realframe = 0;
+ }
#endif
- }
- else /* if (Settings.SkipFrames != AUTO_FRAMERATE && !game_fast_forward && !temporary_fast_forward) */
- {
- // frame_time is in getSysTime units: 42.667 microseconds.
- uint32 frame_time = Settings.PAL ? 468 /* = 20.0 ms */ : 391 /* = 16.67 ms */;
- sync_last = syncnow;
- if (++skip_rate > Settings.SkipFrames)
+ }
+ else /* if (Settings.SkipFrames != AUTO_FRAMERATE) */
{
- skip_rate = 0;
- IPPU.RenderThisFrame = TRUE;
- // Are we early?
- syncdif = sync_next - syncnow;
- if (syncdif > 0)
+ // frame_time is in getSysTime units: 42.667 microseconds.
+ uint32 frame_time = Settings.PAL ? 468 /* = 20.0 ms */ : 391 /* = 16.67 ms */;
+ sync_last = syncnow;
+ if (++skip_rate > Settings.SkipFrames)
{
- do {
- S9xProcessSound (0);
+ skip_rate = 0;
+ IPPU.RenderThisFrame = TRUE;
+ // Are we early?
+ syncdif = sync_next - syncnow;
+ if (syncdif > 0)
+ {
+ ConsistentlyEarly = ConsistentlyEarly && syncdif >= CPU_DOWNCLOCK_EARLY_TIME;
+ do {
+ S9xProcessSound (0);
#ifdef ACCUMULATE_JOYPAD
/*
* This call allows NDSSFC to synchronise the DS controller more often.
* If porting a later version of Snes9x into NDSSFC, it is essential to
* preserve it.
*/
- NDSSFCAccumulateJoypad ();
+ NDSSFCAccumulateJoypad ();
#endif
- syncdif = sync_next - getSysTime();
- } while (syncdif > 0);
- // After that little delay, what time is it?
- syncnow = getSysTime();
+ syncdif = sync_next - getSysTime();
+ } while (syncdif > 0);
+ // After that little delay, what time is it?
+ syncnow = getSysTime();
+ }
+ else
+ {
+ // Nope, we're late.
+ ConsistentlyEarly = FALSE;
+ AutoCPUFrequency = 5;
+ LastAutoCPUTime = syncnow;
+ }
+ sync_next = syncnow + frame_time * (Settings.SkipFrames + 1);
+ }
+ else
+ {
+ IPPU.RenderThisFrame = FALSE;
}
- sync_next = syncnow + frame_time * (Settings.SkipFrames + 1);
- }
- else
- {
- IPPU.RenderThisFrame = FALSE;
}
}
@@ -887,6 +919,20 @@ void S9xSyncSpeed ()
next1.tv_usec %= 1000000;
}
#endif
+
+finalise: ;
+
+ if (syncnow - LastAutoCPUTime >= CPU_DOWNCLOCK_DETERMINATION_INTERVAL) {
+ if (ConsistentlyEarly && AutoCPUFrequency > 0)
+ AutoCPUFrequency--;
+
+ LastAutoCPUTime = syncnow;
+ ConsistentlyEarly = TRUE;
+ // will get unset if the CPU should stay the same at next check
+ }
+
+ if (game_config.clock_speed_number == 0 && LastAutoCPUFrequency != AutoCPUFrequency)
+ GameFrequencyCPU ();
}
bool8 S9xOpenSoundDevice (int mode, bool8 stereo, int buffer_size)