gpsp-kai 

File Info

Rev. 359
Size 27,084 bytes
Time 2007-11-08 10:22:11
Author takka
Log Message

(empty log message)

Content

  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: 
旧リポジトリブラウザで表示