diff options
-rw-r--r-- | CATSFC/system/language.msg | 48 | ||||
-rw-r--r-- | source/nds/entry.cpp | 244 | ||||
-rw-r--r-- | source/nds/entry.h | 2 | ||||
-rw-r--r-- | source/nds/gui.c | 22 | ||||
-rw-r--r-- | source/nds/gui.h | 23 | ||||
-rw-r--r-- | source/nds/message.h | 7 |
6 files changed, 230 insertions, 116 deletions
diff --git a/CATSFC/system/language.msg b/CATSFC/system/language.msg index 4ae6ee6..410b9a6 100644 --- a/CATSFC/system/language.msg +++ b/CATSFC/system/language.msg @@ -66,7 +66,21 @@ Game-specific hotkey overrides... #FMT_OPTIONS_LANGUAGE Language %s #FMT_OPTIONS_CPU_FREQUENCY -CPU frequency %d +CPU frequency %s +#MSG_OPTIONS_CPU_FREQUENCY_AUTOMATIC +[-] Adjust as needed +#MSG_OPTIONS_CPU_FREQUENCY_0 +[0] 240 MHz +#MSG_OPTIONS_CPU_FREQUENCY_1 +[1] 300 MHz +#MSG_OPTIONS_CPU_FREQUENCY_2 +[2] 336 MHz +#MSG_OPTIONS_CPU_FREQUENCY_3 +[3] 360 MHz +#MSG_OPTIONS_CPU_FREQUENCY_4 +[4] 384 MHz +#MSG_OPTIONS_CPU_FREQUENCY_5 +[5] 396 MHz #MSG_OPTIONS_CARD_CAPACITY Card capacity #MSG_OPTIONS_RESET @@ -266,7 +280,21 @@ Game-specific hotkey overrides... #FMT_OPTIONS_LANGUAGE 语言 %s #FMT_OPTIONS_CPU_FREQUENCY -CPU主频 %d +CPU主频 %s +#MSG_OPTIONS_CPU_FREQUENCY_AUTOMATIC +[-] Adjust as needed +#MSG_OPTIONS_CPU_FREQUENCY_0 +[0] 240 MHz +#MSG_OPTIONS_CPU_FREQUENCY_1 +[1] 300 MHz +#MSG_OPTIONS_CPU_FREQUENCY_2 +[2] 336 MHz +#MSG_OPTIONS_CPU_FREQUENCY_3 +[3] 360 MHz +#MSG_OPTIONS_CPU_FREQUENCY_4 +[4] 384 MHz +#MSG_OPTIONS_CPU_FREQUENCY_5 +[5] 396 MHz #MSG_OPTIONS_CARD_CAPACITY 卡容量 #MSG_OPTIONS_RESET @@ -466,7 +494,21 @@ Raccourcis pour le jeu actuel... #FMT_OPTIONS_LANGUAGE Langue %s #FMT_OPTIONS_CPU_FREQUENCY -Fréquence CPU %d +Fréquence CPU %s +#MSG_OPTIONS_CPU_FREQUENCY_AUTOMATIC +[-] Selon le besoin +#MSG_OPTIONS_CPU_FREQUENCY_0 +[0] 240 MHz +#MSG_OPTIONS_CPU_FREQUENCY_1 +[1] 300 MHz +#MSG_OPTIONS_CPU_FREQUENCY_2 +[2] 336 MHz +#MSG_OPTIONS_CPU_FREQUENCY_3 +[3] 360 MHz +#MSG_OPTIONS_CPU_FREQUENCY_4 +[4] 384 MHz +#MSG_OPTIONS_CPU_FREQUENCY_5 +[5] 396 MHz #MSG_OPTIONS_CARD_CAPACITY Capacité de la carte #MSG_OPTIONS_RESET 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, |