aboutsummaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/nds/entry.cpp244
-rw-r--r--source/nds/entry.h2
-rw-r--r--source/nds/gui.c22
-rw-r--r--source/nds/gui.h23
-rw-r--r--source/nds/message.h7
5 files changed, 185 insertions, 113 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)
diff --git a/source/nds/entry.h b/source/nds/entry.h
index a6bd350..2d3f7db 100644
--- a/source/nds/entry.h
+++ b/source/nds/entry.h
@@ -8,6 +8,8 @@ extern "C" {
void game_restart(void);
int load_gamepak(char* file);
+
+ extern unsigned int AutoCPUFrequency;
#ifdef __cplusplus
}
#endif
diff --git a/source/nds/gui.c b/source/nds/gui.c
index 4b5955a..2dad9c8 100644
--- a/source/nds/gui.c
+++ b/source/nds/gui.c
@@ -289,7 +289,6 @@ u32 game_enable_audio = 1;
/******************************************************************************
******************************************************************************/
static u32 menu_cheat_page = 0;
-u32 clock_speed_number = 5;
u32 gamepad_config_menu;
/******************************************************************************
@@ -1665,8 +1664,10 @@ void GameFrequencyCPU()
{
u32 clock_speed_table[6] = {6, 9, 10, 11, 12, 13}; //240, 300, 336, 360, 384, 396
- if(clock_speed_number <= 5)
- ds2_setCPUclocklevel(clock_speed_table[clock_speed_number]);
+ if (game_config.clock_speed_number == 0)
+ ds2_setCPUclocklevel(clock_speed_table[AutoCPUFrequency]);
+ else if(game_config.clock_speed_number <= 6)
+ ds2_setCPUclocklevel(clock_speed_table[game_config.clock_speed_number - 1]);
}
void savefast_int(void)
@@ -1776,8 +1777,6 @@ u32 menu(u16 *screen, bool8 FirstInvocation)
HighFrequencyCPU(); // Crank it up, leave quickly
if(gamepak_name[0] != 0)
{
- game_config.clock_speed_number = clock_speed_number;
-
reorder_latest_file();
S9xAutoSaveSRAM ();
save_game_config_file();
@@ -2828,6 +2827,8 @@ u32 menu(u16 *screen, bool8 FirstInvocation)
char *frameskip_options[] = { (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_AUTOMATIC], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_2], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_3], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_4], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_5], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_6], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_7], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_8], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_9], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_10] };
+ char *cpu_frequency_options[] = { (char*)&msg[MSG_OPTIONS_CPU_FREQUENCY_AUTOMATIC], (char*)&msg[MSG_OPTIONS_CPU_FREQUENCY_0], (char*)&msg[MSG_OPTIONS_CPU_FREQUENCY_1], (char*)&msg[MSG_OPTIONS_CPU_FREQUENCY_2], (char*)&msg[MSG_OPTIONS_CPU_FREQUENCY_3], (char*)&msg[MSG_OPTIONS_CPU_FREQUENCY_4], (char*)&msg[MSG_OPTIONS_CPU_FREQUENCY_5] };
+
char *fluidity_options[] = { (char*)&msg[MSG_VIDEO_AUDIO_FLUIDITY_PREFER_VIDEO], (char*)&msg[MSG_VIDEO_AUDIO_FLUIDITY_PREFER_AUDIO] };
char *on_off_options[] = { (char*)&msg[MSG_GENERAL_OFF], (char*)&msg[MSG_GENERAL_ON] };
@@ -3002,8 +3003,9 @@ u32 menu(u16 *screen, bool8 FirstInvocation)
{
/* 00 */ SUBMENU_OPTION(NULL, &msg[MSG_MAIN_MENU_OPTIONS], NULL, 0),
- //CPU speed
- /* 01 */ NUMERIC_SELECTION_OPTION(NULL, &msg[FMT_OPTIONS_CPU_FREQUENCY], &clock_speed_number, 6, NULL, 1),
+ //CPU speed (string: shows MHz)
+ /* 01 */ STRING_SELECTION_OPTION(NULL, NULL, &msg[FMT_OPTIONS_CPU_FREQUENCY], cpu_frequency_options,
+ &game_config.clock_speed_number, 7, NULL, PASSIVE_TYPE, 1),
/* 02 */ STRING_SELECTION_OPTION(language_set, NULL, &msg[FMT_OPTIONS_LANGUAGE], language_options,
&emu_config.language, sizeof(language_options) / sizeof(language_options[0]) /* number of possible languages */, NULL, ACTION_TYPE, 2),
@@ -4113,8 +4115,6 @@ u32 menu(u16 *screen, bool8 FirstInvocation)
if(gamepak_name[0] != 0)
{
- game_config.clock_speed_number = clock_speed_number;
-
reorder_latest_file();
S9xAutoSaveSRAM ();
save_game_config_file();
@@ -4284,8 +4284,7 @@ u32 load_font()
--------------------------------------------------------*/
void init_game_config(void)
{
- game_config.clock_speed_number = 5; // 396 MHz by default
- clock_speed_number = 5;
+ game_config.clock_speed_number = 0; // "Auto" by default
game_config.graphic = 3; // By default, have a good-looking aspect ratio
game_config.frameskip_value = 0; // Automatic frame skipping
game_config.SoundSync = 0; // Prefer fluid images by default
@@ -4341,7 +4340,6 @@ void load_game_config_file(void)
{
fread(&game_config, 1, sizeof(GAME_CONFIG), fp);
- clock_speed_number = game_config.clock_speed_number;
game_set_frameskip();
game_set_fluidity();
}
diff --git a/source/nds/gui.h b/source/nds/gui.h
index b390b69..df1bff9 100644
--- a/source/nds/gui.h
+++ b/source/nds/gui.h
@@ -48,7 +48,25 @@ struct _EMU_CONFIG
struct _GAME_CONFIG
{
- u32 clock_speed_number;
+ /*
+ * PreviouslyUsed_20130205_2 was formerly known as
+ * 'clock_speed_number'; its values were in [0, 5]. [0, 5] were mapped
+ * to 240, 300, 336, 360, 384 and 394 MHz respectively.
+ * Version 1.29 changes the value range for 'clock_speed_number' to
+ * [0, 6], with 0 as an automatic CPU speed setting.
+ * Change rationale: The default value becomes 0 instead of 5.
+ * If this variable were to be used as is, the meaning of the default
+ * value would change. Games which had a configuration file before
+ * 1.29 would be using the older default of 5 (394 MHz), the meaning
+ * of which would become 384 MHz instead of "staying the default".
+ * Games which did not have a configuration file before 1.29 would be
+ * using the correct default.
+ * This would confuse users or cause undue hassle.
+ * THIS VALUE IS NOT GUARANTEED TO BE RESERVED AND SET TO 0.
+ * DO NOT USE THIS VALUE FOR ANY PURPOSE OTHER THAN EXACTLY THE ONE
+ * FOR WHICH IT WAS INTENDED.
+ */
+ u32 PreviouslyUsed_20130205_2;
u32 Reserved0;
/*
* PreviouslyUsed_20130205_1 was formerly known as 'frameskip_value';
@@ -78,7 +96,8 @@ struct _GAME_CONFIG
u32 HotkeyToggleSound;
u32 SoundSync;
u32 frameskip_value;
- u32 Reserved2[43];
+ u32 clock_speed_number;
+ u32 Reserved2[42];
};
typedef enum
diff --git a/source/nds/message.h b/source/nds/message.h
index 86389b1..e58d7b8 100644
--- a/source/nds/message.h
+++ b/source/nds/message.h
@@ -48,6 +48,13 @@ enum MSG
MSG_TOOLS_GAME_HOTKEY_GENERAL,
FMT_OPTIONS_LANGUAGE,
FMT_OPTIONS_CPU_FREQUENCY,
+ MSG_OPTIONS_CPU_FREQUENCY_AUTOMATIC,
+ MSG_OPTIONS_CPU_FREQUENCY_0,
+ MSG_OPTIONS_CPU_FREQUENCY_1,
+ MSG_OPTIONS_CPU_FREQUENCY_2,
+ MSG_OPTIONS_CPU_FREQUENCY_3,
+ MSG_OPTIONS_CPU_FREQUENCY_4,
+ MSG_OPTIONS_CPU_FREQUENCY_5,
MSG_OPTIONS_CARD_CAPACITY /* unused if !defined(ENABLE_FREE_SPACE) */,
MSG_OPTIONS_RESET,
MSG_OPTIONS_VERSION,