1: /* unofficial gameplaySP kai
2: *
3: * Copyright (C) 2006 Exophase <exophase@gmail.com>
4: * Copyright (C) 2007 takka <takka@tfact.net>
5: * Copyright (C) 2007 NJ
6: * Copyright (C) 2007 ????? <?????>
7: *
8: * This program is free software; you can redistribute it and/or
9: * modify it under the terms of the GNU General Public License as
10: * published by the Free Software Foundation; either version 2 of
11: * the License, or (at your option) any later version.
12: *
13: * This program is distributed in the hope that it will be useful,
14: * but WITHOUT ANY WARRANTY; without even the implied warranty of
15: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16: * General Public License for more details.
17: *
18: * You should have received a copy of the GNU General Public License
19: * along with this program; if not, write to the Free Software
20: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21: */
22:
23: /******************************************************************************
24: * ヘッダファイルの読込み
25: ******************************************************************************/
26: #include "common.h"
27:
28: PSP_MODULE_INFO("gpSP", PSP_MODULE_USER, VERSION_MAJOR, VERSION_MINOR);
29: PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER|PSP_THREAD_ATTR_VFPU);
30: PSP_MAIN_THREAD_PRIORITY(0x11);
31: PSP_MAIN_THREAD_STACK_SIZE_KB(300);
32:
33: /******************************************************************************
34: * 変数の定義
35: ******************************************************************************/
36:
37: TIMER_TYPE timer[4]; // タイマー
38:
39: u32 global_cycles_per_instruction = 1;
40: u64 frame_count_initial_timestamp = 0;
41: u64 last_frame_interval_timestamp;
42: u32 psp_fps_debug = 0;
43: u32 skip_next_frame_flag = 0;
44: u32 frameskip_counter = 0;
45:
46: u32 cpu_ticks = 0;
47: u32 frame_ticks = 0;
48:
49: u32 execute_cycles = 960;
50: s32 video_count = 960;
51: u32 ticks;
52:
53: u32 arm_frame = 0;
54: u32 thumb_frame = 0;
55: u32 last_frame = 0;
56:
57: u32 cycle_memory_access = 0;
58: u32 cycle_pc_relative_access = 0;
59: u32 cycle_sp_relative_access = 0;
60: u32 cycle_block_memory_access = 0;
61: u32 cycle_block_memory_sp_access = 0;
62: u32 cycle_block_memory_words = 0;
63: u32 cycle_dma16_words = 0;
64: u32 cycle_dma32_words = 0;
65:
66: u32 synchronize_flag = 1;
67:
68: u32 hold_state = 0;
69:
70: char main_path[MAX_PATH];
71: char rom_path[MAX_PATH];
72:
73: vu32 quit_flag;
74: vu32 power_flag;
75:
76: char *lang[12] =
77: { "japanese", // 0
78: "english", // 1
79: "french", // 2
80: "spanish", // 3
81: "german", // 4
82: "italian", // 5
83: "dutch", // 6
84: "portuguese", // 7
85: "russian", // 8
86: "korean", // 9
87: "chinese_traditional", // 10
88: "chinese_simplified" // 11
89: };
90:
91: #define MAX_LANG_NUM 11
92:
93: int lang_num;
94: int date_format;
95:
96: u32 prescale_table[] = { 0, 6, 8, 10 };
97:
98: char *file_ext[] = { ".gba", ".bin", ".zip", NULL };
99:
100: // PSPの種類
101: MODEL_TYPE psp_model;
102:
103: /******************************************************************************
104: * マクロ等の定義
105: ******************************************************************************/
106:
107: // エミュレーション サイクルの決定
108: #define CHECK_COUNT(count_var) \
109: if((count_var) < execute_cycles) \
110: execute_cycles = count_var; \
111:
112: #define CHECK_TIMER(timer_number) \
113: if(timer[timer_number].status == TIMER_PRESCALE) \
114: CHECK_COUNT(timer[timer_number].count); \
115:
116: // タイマーのアップデート
117: // 実機では0~0xFFFFだが、gpSP内部では (0x10000~1)<<prescale(0,6,8,10)の値をとる
118: #define update_timer(timer_number) \
119: if(timer[timer_number].status != TIMER_INACTIVE) \
120: { \
121: /* タイマーがアクティブだった場合 */ \
122: if(timer[timer_number].status != TIMER_CASCADE) \
123: { \
124: /* タイマーがプリスケールモードだった場合 */ \
125: /* タイマー変更 */ \
126: timer[timer_number].count -= execute_cycles; \
127: /* レジスタに書込 */ \
128: io_registers[REG_TM##timer_number##D] = \
129: 0x10000 - (timer[timer_number].count >> timer[timer_number].prescale); \
130: } \
131: \
132: if(timer[timer_number].count <= 0) \
133: { \
134: /* タイマーがオーバーフローした場合 */ \
135: /* IRQのトリガをON */ \
136: if(timer[timer_number].irq == TIMER_TRIGGER_IRQ) \
137: irq_raised |= IRQ_TIMER##timer_number; \
138: \
139: if((timer_number != 3) && \
140: (timer[timer_number + 1].status == TIMER_CASCADE)) \
141: { \
142: /* タイマー0~2 かつ 次のタイマーがカスケードモードの場合 */ \
143: /* カウンタを変更 */ \
144: timer[timer_number + 1].count--; \
145: /* レジスタに書込 */ \
146: io_registers[REG_TM0D + (timer_number + 1) * 2] = \
147: 0x10000 - (timer[timer_number + 1].count); \
148: } \
149: \
150: if(timer_number < 2) \
151: { \
152: if(timer[timer_number].direct_sound_channels & 0x01) \
153: sound_timer(timer[timer_number].frequency_step, 0); \
154: \
155: if(timer[timer_number].direct_sound_channels & 0x02) \
156: sound_timer(timer[timer_number].frequency_step, 1); \
157: } \
158: \
159: /* タイマーのリロード */ \
160: timer[timer_number].count += \
161: (timer[timer_number].reload << timer[timer_number].prescale); \
162: io_registers[REG_TM##timer_number##D] = \
163: 0x10000 - (timer[timer_number].count >> timer[timer_number].prescale); \
164: } \
165: } \
166:
167: // ローカル関数の宣言
168: void vblank_interrupt_handler(u32 sub, u32 *parg);
169: void init_main();
170: int main(int argc, char *argv[]);
171: void print_memory_stats(u32 *counter, u32 *region_stats, u8 *stats_str);
172: u32 check_power();
173: int exit_callback(int arg1, int arg2, void *common);
174: SceKernelCallbackFunction power_callback(int unknown, int powerInfo, void *common);
175: int CallbackThread(SceSize args, void *argp);
176: int SetupCallbacks();
177: int user_main(SceSize args, char *argp[]);
178: void psp_exception_handler(PspDebugRegBlock *regs);
179:
180: // クロックの変更
181: void set_cpu_clock(u32 num)
182: {
183: const u32 clock_speed_table[11] = {33, 66, 100, 133, 166, 200, 233, 266, 300, 333, 222};
184: num = num % 11;
185: scePowerSetClockFrequency(clock_speed_table[num], clock_speed_table[num], clock_speed_table[num] / 2);
186: }
187:
188: void init_main()
189: {
190: u32 i;
191:
192: skip_next_frame_flag = 0;
193:
194: for(i = 0; i < 4; i++)
195: {
196: dma[i].start_type = DMA_INACTIVE;
197: dma[i].direct_sound_channel = DMA_NO_DIRECT_SOUND;
198: timer[i].status = TIMER_INACTIVE;
199: timer[i].reload = 0x10000;
200: }
201:
202: timer[0].direct_sound_channels = TIMER_DS_CHANNEL_BOTH;
203: timer[1].direct_sound_channels = TIMER_DS_CHANNEL_NONE;
204:
205: cpu_ticks = 0;
206: frame_ticks = 0;
207:
208: execute_cycles = 960;
209: video_count = 960;
210:
211: bios_mode = USE_BIOS;
212:
213: flush_translation_cache_rom();
214: flush_translation_cache_ram();
215: flush_translation_cache_bios();
216: }
217:
218: int exit_callback(int arg1, int arg2, void *common)
219: {
220: quit_flag = 1;
221: return 0;
222: }
223:
224: // サスペンド/復旧時の処理
225: SceKernelCallbackFunction power_callback(int unknown, int powerInfo, void *common)
226: {
227: if (powerInfo & PSP_POWER_CB_POWER_SWITCH)
228: {
229: // サスペンド時の処理
230: power_flag = 1;
231:
232: // 新型PSPの場合、増設メモリの一部をメインメモリに待避
233: if(psp_model == psp_2000_new)
234: {
235: memcpy(gamepak_rom_resume,(void *)(PSP2K_MEM_TOP + 0x1c00000), 0x400000);
236: }
237: }
238: else if (powerInfo & PSP_POWER_CB_RESUME_COMPLETE)
239: {
240: power_flag = 0;
241:
242: // 新型PSPの場合、メインメモリから増設メモリへ内容を復旧
243: if(psp_model == psp_2000_new)
244: {
245: memcpy((void *)(PSP2K_MEM_TOP + 0x1c00000),gamepak_rom_resume, 0x400000);
246: }
247: }
248: return 0;
249: }
250:
251: int CallbackThread(SceSize args, void *argp)
252: {
253: int id;
254:
255: // 終了周りのコールバック
256: id = sceKernelCreateCallback("Exit Callback", (void *)exit_callback, NULL);
257: sceKernelRegisterExitCallback(id);
258:
259: // 電源周りのコールバック
260: id = sceKernelCreateCallback("Power Callback", (void *)power_callback, NULL);
261: scePowerRegisterCallback(0, id);
262:
263: sceKernelSleepThreadCB();
264:
265: return 0;
266: }
267:
268: int SetupCallbacks()
269: {
270: int callback_thread_id = 0;
271:
272: callback_thread_id = sceKernelCreateThread("update_thread", CallbackThread, 0x11, 0xFA0, 0, 0);
273: if (callback_thread_id >= 0)
274: {
275: sceKernelStartThread(callback_thread_id, 0, 0);
276: }
277:
278: return callback_thread_id;
279: }
280:
281: void quit()
282: {
283: save_game_config_file();
284: save_config_file();
285:
286: update_backup_force();
287:
288: sound_exit();
289: fbm_freeall();
290:
291: fclose(dbg_file);
292:
293: set_cpu_clock(222);
294: sceKernelExitGame();
295: }
296:
297: int main(int argc, char *argv[])
298: {
299: char load_filename[MAX_FILE];
300: char filename[MAX_FILE];
301:
302: sceDisplaySetMode(0, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT);
303: pspDebugScreenInit();
304:
305: psp_model = get_model();
306:
307: // HOMEボタンを読取り可能にする
308: if(pspSdkLoadStartModule("homehook.prx", PSP_MEMORY_PARTITION_KERNEL) < 0)
309: {
310: error_msg("Error in load/start homehook module.\n");
311: quit();
312: }
313:
314: // PSP-2000(CFW3.71)なら、外部出力用のモジュールを読込む
315: if(psp_model == psp_2000_new)
316: {
317: if(pspSdkLoadStartModule("dvemgr.prx", PSP_MEMORY_PARTITION_KERNEL) < 0)
318: error_msg("Error in load/start TV OUT module.\n");
319: }
320:
321: quit_flag = 0;
322: power_flag = 0;
323: SetupCallbacks();
324:
325: sceKernelRegisterSubIntrHandler(PSP_VBLANK_INT, 0, vblank_interrupt_handler, NULL);
326: sceKernelEnableSubIntr(PSP_VBLANK_INT, 0);
327:
328: // デバッグ出力ファイルのオープン
329: dbg_file = fopen(DBG_FILE_NAME, "awb");
330:
331: getcwd(main_path, 512);
332:
333: #ifdef ADHOC_MODE
334: // adhoc用モジュールのロード
335: if (pspSdkLoadAdhocModules() != 0)
336: error_msg("not load adhoc modules!!\n");
337: #endif
338:
339: // Copy the directory path of the executable into main_path
340: chdir(main_path);
341:
342: sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_LANGUAGE, &lang_num);
343: // 言語が設定外の場合英語に設定
344: if(lang_num > MAX_LANG_NUM) lang_num = 1;
345: sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_DATE_FORMAT,&date_format);
346:
347: // 設定ファイルの読込み
348: load_config_file();
349: init_game_config();
350:
351: init_main();
352: init_sound();
353:
354: init_video();
355: init_input();
356:
357: video_resolution(FRAME_MENU);
358: video_resolution(FRAME_GAME);
359: video_resolution(FRAME_MENU);
360: clear_screen(COLOR_BG);
361: flip_screen();
362: clear_screen(COLOR_BG);
363: flip_screen();
364:
365: // 初期設定用のプログレスバー
366: init_progress(7, "");
367:
368: // ディレクトリ設定の読込み
369: if (load_dircfg("settings/dir.cfg") != 0)
370: {
371: pspDebugScreenInit();
372: error_msg("dir.cfg Error!!");
373: quit();
374: }
375: update_progress();
376:
377: // フォント設定の読込み
378: sprintf(filename,"settings/%s.fnt",lang[lang_num]);
379: if (load_fontcfg(filename) != 0)
380: {
381: pspDebugScreenInit();
382: error_msg("font.cfg Error!!");
383: quit();
384: }
385: update_progress();
386:
387: // メッセージファイルの読込み
388: sprintf(filename,"settings/%s.msg",lang[lang_num]);
389: if (load_msgcfg(filename) != 0)
390: {
391: pspDebugScreenInit();
392: error_msg("message.cfg Error!!");
393: quit();
394: }
395: update_progress();
396:
397: // フォントの読込み
398: if (load_font() != 0)
399: {
400: pspDebugScreenInit();
401: error_msg("font init Error!!");
402: quit();
403: }
404: update_progress();
405:
406: // ROMバッファの初期化
407: init_gamepak_buffer();
408: update_progress();
409:
410: sceImposeSetHomePopup(gpsp_config.enable_home);
411:
412: // ROMファイル名の初期化
413: gamepak_filename[0] = 0;
414:
415: // BIOSの読込み
416: u32 bios_ret = load_bios("gba_bios.bin");
417: if(bios_ret == -1) // 読込めない場合
418: {
419: PRINT_STRING_BG(msg[MSG_ERR_BIOS_1], 0xFFFF, 0x0000, 0, 0);
420: PRINT_STRING_BG(msg[MSG_ERR_BIOS_2], 0xFFFF, 0x0000, 0, 60);
421: flip_screen();
422: error_msg("");
423: quit();
424: }
425: update_progress();
426: if(bios_ret == -2) // MD5が違う場合
427: {
428: PRINT_STRING_BG(msg[MSG_ERR_BIOS_MD5], 0xFFFF, 0x0000, 0, 0);
429: flip_screen();
430: delay_us(5000000);
431: }
432: update_progress();
433:
434: show_progress(msg[MSG_INIT_END]);
435:
436: #ifdef ADHOC_MODE
437: // WLANのスイッチがONならばadhoc接続のテスト
438: if (sceWlanDevIsPowerOn() == 1)
439: {
440: adhocInit("adhoc test");
441: adhocTerm();
442: }
443: #endif
444:
445: if(argc > 1)
446: {
447: if(load_gamepak((char *)argv[1]) == -1)
448: {
449: printf("Failed to load gamepak %s, exiting.\n", load_filename);
450: exit(-1);
451: }
452:
453: clear_screen(0);
454: flip_screen();
455: clear_screen(0);
456: flip_screen();
457: video_resolution(FRAME_GAME);
458:
459: init_cpu();
460: init_memory();
461: reset_sound();
462: }
463: else
464: {
465: if(load_file(file_ext, load_filename, DEFAULT_ROM_DIR) == -1)
466: {
467: u16 *screen_copy = copy_screen();
468: menu(screen_copy);
469: free(screen_copy);
470: }
471: else
472: {
473: if(load_gamepak(load_filename) == -1)
474: {
475: video_resolution(FRAME_MENU);
476: printf("Failed to load gamepak %s, exiting.\n", load_filename);
477: delay_us(5000000);
478: quit();
479: }
480:
481: clear_screen(0);
482: flip_screen();
483: clear_screen(0);
484: flip_screen();
485: video_resolution(FRAME_GAME);
486:
487: init_cpu();
488: init_memory();
489: reset_sound();
490: }
491: }
492:
493: last_frame = 0;
494: set_cpu_clock(game_config.clock_speed_number);
495:
496: pause_sound(0);
497: real_frame_count = 0;
498: virtual_frame_count = 0;
499:
500: // エミュレートの開始
501: execute_arm_translate(execute_cycles);
502: return 0;
503: }
504:
505: u32 check_power()
506: {
507: if (power_flag == 0) return 0;
508: FILE_CLOSE(gamepak_file_large);
509: u16 *screen_copy = copy_screen();
510: u32 ret_val = menu(screen_copy);
511: free(screen_copy);
512: FILE_OPEN(gamepak_file_large, gamepak_filename_raw, READ);
513: return ret_val;
514: }
515:
516: u32 sync_flag = 0;
517:
518: u32 update_gba()
519: {
520: IRQ_TYPE irq_raised = IRQ_NONE;
521:
522: do {
523: cpu_ticks += execute_cycles;
524:
525: reg[CHANGED_PC_STATUS] = 0;
526:
527: if(gbc_sound_update) {
528: update_gbc_sound(cpu_ticks);
529: gbc_sound_update = 0;
530: }
531:
532: update_timer(0);
533: update_timer(1);
534: update_timer(2);
535: update_timer(3);
536:
537: video_count -= execute_cycles;
538:
539: if(video_count <= 0) {
540: u32 vcount = io_registers[REG_VCOUNT];
541: u32 dispstat = io_registers[REG_DISPSTAT];
542:
543: if((dispstat & 0x02) == 0)
544: {
545: // Transition from hrefresh to hblank
546: video_count += 272;
547: dispstat |= 0x02;
548:
549: if((dispstat & 0x01) == 0)
550: {
551: // フレームスキップ時は描画しない
552: if(!skip_next_frame_flag)
553: update_scanline();
554:
555: // If in visible area also fire HDMA
556: if(dma[0].start_type == DMA_START_HBLANK)
557: dma_transfer(dma);
558: if(dma[1].start_type == DMA_START_HBLANK)
559: dma_transfer(dma + 1);
560: if(dma[2].start_type == DMA_START_HBLANK)
561: dma_transfer(dma + 2);
562: if(dma[3].start_type == DMA_START_HBLANK)
563: dma_transfer(dma + 3);
564: }
565:
566: if(dispstat & 0x10)
567: irq_raised |= IRQ_HBLANK;
568: }
569: else
570: {
571: // Transition from hblank to next line
572: video_count += 960;
573: dispstat &= ~0x02;
574:
575: vcount++;
576:
577: if(vcount == 160)
578: {
579: // Transition from vrefresh to vblank
580:
581: dispstat |= 0x01;
582: if(dispstat & 0x8)
583: {
584: irq_raised |= IRQ_VBLANK;
585: }
586:
587: affine_reference_x[0] = (s32)(ADDRESS32(io_registers, 0x28) << 4) >> 4;
588: affine_reference_y[0] = (s32)(ADDRESS32(io_registers, 0x2C) << 4) >> 4;
589: affine_reference_x[1] = (s32)(ADDRESS32(io_registers, 0x38) << 4) >> 4;
590: affine_reference_y[1] = (s32)(ADDRESS32(io_registers, 0x3C) << 4) >> 4;
591:
592: if(dma[0].start_type == DMA_START_VBLANK)
593: dma_transfer(dma);
594: if(dma[1].start_type == DMA_START_VBLANK)
595: dma_transfer(dma + 1);
596: if(dma[2].start_type == DMA_START_VBLANK)
597: dma_transfer(dma + 2);
598: if(dma[3].start_type == DMA_START_VBLANK)
599: dma_transfer(dma + 3);
600: }
601: else
602:
603: if(vcount == 228) {
604: // Transition from vblank to next screen
605: dispstat &= ~0x01;
606: frame_ticks++;
607:
608: sceKernelDelayThread(10);
609:
610: if (update_input())
611: continue;
612:
613: if (check_power())
614: continue;
615:
616: if (quit_flag == 1)
617: quit();
618:
619: update_gbc_sound(cpu_ticks);
620:
621: //TODO 調整必要
622: if((gpsp_config.screen_interlace == PROGRESSIVE)||(video_out_mode == 0))
623: synchronize();
624: else
625: {
626: if(sync_flag == 0)
627: synchronize();
628: sync_flag ^= 1;
629: }
630:
631: update_screen();
632:
633: if(game_config.update_backup_flag)
634: update_backup();
635:
636: process_cheats();
637:
638: vcount = 0;
639: }
640:
641: if(vcount == (dispstat >> 8)) {
642: // vcount trigger
643: dispstat |= 0x04;
644: if(dispstat & 0x20)
645: {
646: irq_raised |= IRQ_VCOUNT;
647: }
648: }
649: else
650: {
651: dispstat &= ~0x04;
652: }
653:
654: io_registers[REG_VCOUNT] = vcount;
655: }
656: io_registers[REG_DISPSTAT] = dispstat;
657: }
658:
659: if(irq_raised)
660: raise_interrupt(irq_raised);
661:
662: execute_cycles = video_count;
663:
664: CHECK_TIMER(0);
665: CHECK_TIMER(1);
666: CHECK_TIMER(2);
667: CHECK_TIMER(3);
668:
669: } while(reg[CPU_HALT_STATE] != CPU_ACTIVE);
670:
671: return execute_cycles;
672: }
673:
674: u64 last_screen_timestamp = 0;
675: u32 frame_speed = 15000;
676:
677: volatile u32 real_frame_count = 0;
678: u32 virtual_frame_count = 0;
679: volatile u32 vblank_count = 0;
680: u32 num_skipped_frames = 0;
681: u32 interval_skipped_frames;
682: u32 frames;
683: u32 skipped_frames = 0;
684: u32 ticks_needed_total = 0;
685: const u32 frame_interval = 60;
686:
687: void vblank_interrupt_handler(u32 sub, u32 *parg)
688: {
689: real_frame_count++;
690: vblank_count++;
691: }
692:
693: // TODO:最適化/タイマー使った方が良いかも
694: void synchronize()
695: {
696: // char char_buffer[64];
697: static u32 fps = 60;
698: static u32 frames_drawn = 0;
699: static u32 frames_drawn_count = 0;
700:
701: // FPS等の表示
702: if(psp_fps_debug)
703: {
704: char print_buffer[256];
705: sprintf(print_buffer, "FPS:%02d DRAW:(%02d) S_BUF:%02d", (int)fps, (int)frames_drawn, (int)left_buffer);
706: PRINT_STRING_BG(print_buffer, 0xFFFF, 0x000, 0, 0);
707: // dump_translation_cache();
708: }
709:
710: // フレームスキップ フラグの初期化
711: skip_next_frame_flag = 0;
712: // 内部フレーム値の増加
713: frames++;
714:
715: switch(game_config.frameskip_type)
716: {
717: // オートフレームスキップ時
718: case auto_frameskip:
719: virtual_frame_count++;
720:
721: // 内部フレーム数に遅れが出ている場合
722: if(real_frame_count > virtual_frame_count)
723: {
724: if(num_skipped_frames < game_config.frameskip_value) // スキップしたフレームが設定より小さい
725: {
726: // 次のフレームはスキップ
727: skip_next_frame_flag = 1;
728: // スキップしたフレーム数を増加
729: num_skipped_frames++;
730: }
731: else
732: {
733: // 設定の上限に達した場合
734: // real_frame_count = virtual_frame_count;
735: // スキップしたフレーム数は0に初期化
736: num_skipped_frames = 0;
737: frames_drawn_count++;
738: }
739: }
740:
741: // 内部フレーム数が同じ場合
742: if(real_frame_count == virtual_frame_count)
743: {
744: // スキップしたフレーム数は0に初期化
745: num_skipped_frames = 0;
746: frames_drawn_count++;
747: }
748:
749: // 内部フレーム数が実機を上回る場合
750: if(real_frame_count < virtual_frame_count)
751: {
752: num_skipped_frames = 0;
753: frames_drawn_count++;
754: }
755:
756: // 内部フレーム数が実機を上回る場合
757: if((real_frame_count < virtual_frame_count) && (synchronize_flag) && (skip_next_frame_flag == 0))
758: {
759: // VBANK待ち
760: synchronize_sound();
761: sceDisplayWaitVblankStart();
762: real_frame_count = 0;
763: virtual_frame_count = 0;
764: }
765: break;
766:
767: // マニュアルフレームスキップ時
768: case manual_frameskip:
769: virtual_frame_count++;
770: // フレームスキップ数増加
771: num_skipped_frames = (num_skipped_frames + 1) % (game_config.frameskip_value + 1);
772: if(game_config.random_skip)
773: {
774: if(num_skipped_frames != (rand() % (game_config.frameskip_value + 1)))
775: skip_next_frame_flag = 1;
776: else
777: frames_drawn_count++;
778: }
779: else
780: {
781: // フレームスキップ数=0の時だけ画面更新
782: if(num_skipped_frames != 0)
783: skip_next_frame_flag = 1;
784: else
785: frames_drawn_count++;
786: }
787:
788: // 内部フレーム数が実機を上回る場合
789: if((real_frame_count < virtual_frame_count) && (synchronize_flag) && (skip_next_frame_flag == 0))
790: {
791: // VBANK待ち
792: synchronize_sound();
793: sceDisplayWaitVblankStart();
794: }
795: real_frame_count = 0;
796: virtual_frame_count = 0;
797: break;
798:
799: // フレームスキップなし時
800: case no_frameskip:
801: frames_drawn_count++;
802: virtual_frame_count++;
803: if((real_frame_count < virtual_frame_count) && (synchronize_flag))
804: {
805: // 内部フレーム数が実機を上回る場合
806: // VBANK待ち
807: synchronize_sound();
808: sceDisplayWaitVblankStart();
809: }
810: real_frame_count = 0;
811: virtual_frame_count = 0;
812: break;
813: }
814:
815: // FPSのカウント
816: // 1/60秒のVBLANK割込みがあるので、タイマは使用しないようにした
817: if(frames == 60)
818: {
819: frames = 0;
820: fps = 3600 / vblank_count;
821: vblank_count = 0;
822: frames_drawn = frames_drawn_count;
823: frames_drawn_count = 0;
824: }
825:
826: if(!synchronize_flag)
827: PRINT_STRING_BG("--FF--", 0xFFFF, 0x000, 0, 10);
828: }
829:
830: void reset_gba()
831: {
832: init_main();
833: init_memory();
834: init_cpu();
835: reset_sound();
836: }
837:
838: u32 file_length(char *filename, s32 dummy)
839: {
840: SceIoStat stats;
841: sceIoGetstat(filename, &stats);
842: return stats.st_size;
843: }
844:
845: void delay_us(u32 us_count)
846: {
847: sceKernelDelayThread(us_count);
848: }
849:
850: void get_ticks_us(u64 *tick_return)
851: {
852: u64 ticks;
853: sceRtcGetCurrentTick(&ticks);
854: *tick_return = ticks;
855: }
856:
857: void change_ext(char *src, char *buffer, char *extension)
858: {
859: char *dot_position;
860: strcpy(buffer, src);
861: dot_position = strrchr(buffer, '.');
862:
863: if(dot_position)
864: strcpy(dot_position, extension);
865: }
866:
867: // type = READ / WRITE_MEM
868: #define MAIN_SAVESTATE_BODY(type) \
869: { \
870: FILE_##type##_VARIABLE(cpu_ticks); \
871: FILE_##type##_VARIABLE(execute_cycles); \
872: FILE_##type##_VARIABLE(video_count); \
873: FILE_##type##_ARRAY(timer); \
874: } \
875:
876: void main_read_mem_savestate()
877: MAIN_SAVESTATE_BODY(READ_MEM);
878:
879: void main_write_mem_savestate()
880: MAIN_SAVESTATE_BODY(WRITE_MEM);
881:
882: void error_msg(char *text)
883: {
884: gui_action_type gui_action = CURSOR_NONE;
885:
886: printf(text);
887:
888: while(gui_action == CURSOR_NONE)
889: {
890: gui_action = get_gui_input();
891: delay_us(15000); /* 0.0015s */
892: }
893: }
894:
895: void set_cpu_mode(CPU_MODE_TYPE new_mode)
896: {
897: u32 i;
898: CPU_MODE_TYPE cpu_mode = reg[CPU_MODE];
899:
900: if(cpu_mode != new_mode)
901: {
902: if(new_mode == MODE_FIQ)
903: {
904: for(i = 8; i < 15; i++)
905: {
906: reg_mode[cpu_mode][i - 8] = reg[i];
907: }
908: }
909: else
910: {
911: reg_mode[cpu_mode][5] = reg[REG_SP];
912: reg_mode[cpu_mode][6] = reg[REG_LR];
913: }
914:
915: if(cpu_mode == MODE_FIQ)
916: {
917: for(i = 8; i < 15; i++)
918: {
919: reg[i] = reg_mode[new_mode][i - 8];
920: }
921: }
922: else
923: {
924: reg[REG_SP] = reg_mode[new_mode][5];
925: reg[REG_LR] = reg_mode[new_mode][6];
926: }
927:
928: reg[CPU_MODE] = new_mode;
929: }
930: }
931:
932: void raise_interrupt(IRQ_TYPE irq_raised)
933: {
934: // The specific IRQ must be enabled in IE, master IRQ enable must be on,
935: // and it must be on in the flags.
936: io_registers[REG_IF] |= irq_raised;
937:
938: if((io_registers[REG_IE] & irq_raised) && io_registers[REG_IME] &&
939: ((reg[REG_CPSR] & 0x80) == 0))
940: {
941: bios_read_protect = 0xe55ec002;
942:
943: // Interrupt handler in BIOS
944: reg_mode[MODE_IRQ][6] = reg[REG_PC] + 4;
945: spsr[MODE_IRQ] = reg[REG_CPSR];
946: reg[REG_CPSR] = 0xD2;
947: reg[REG_PC] = 0x00000018;
948: bios_region_read_allow();
949: set_cpu_mode(MODE_IRQ);
950: reg[CPU_HALT_STATE] = CPU_ACTIVE;
951: reg[CHANGED_PC_STATUS] = 1;
952: }
953: }
954:
955: MODEL_TYPE get_model()
956: {
957: if(kuKernelGetModel() != PSP_MODEL_SLIM_AND_LITE)
958: {
959: return psp_1000;
960: }
961: else
962: if(sceKernelDevkitVersion() < 0x03070110)
963: {
964: return psp_2000_old;
965: }
966: else
967: {
968: return psp_2000_new;
969: }
970: }
971: