+static void run_events_ui(unsigned int which)\r
+{\r
+ if (which & (PEV_STATE_LOAD|PEV_STATE_SAVE))\r
+ {\r
+ int do_it = 1;\r
+ if ( emu_check_save_file(state_slot) &&\r
+ (((which & PEV_STATE_LOAD) && (currentConfig.confirm_save & EOPT_CONFIRM_LOAD)) ||\r
+ ((which & PEV_STATE_SAVE) && (currentConfig.confirm_save & EOPT_CONFIRM_SAVE))) )\r
+ {\r
+ const char *nm;\r
+ char tmp[64];\r
+ int keys, len;\r
+\r
+ strcpy(tmp, (which & PEV_STATE_LOAD) ? "LOAD STATE?" : "OVERWRITE SAVE?");\r
+ len = strlen(tmp);\r
+ nm = in_get_key_name(-1, -PBTN_MA3);\r
+ snprintf(tmp + len, sizeof(tmp) - len, "(%s=yes, ", nm);\r
+ len = strlen(tmp);\r
+ nm = in_get_key_name(-1, -PBTN_MBACK);\r
+ snprintf(tmp + len, sizeof(tmp) - len, "%s=no)", nm);\r
+\r
+ plat_status_msg_busy_first(tmp);\r
+\r
+ in_set_blocking(1);\r
+ while (in_menu_wait_any(50) & (PBTN_MA3|PBTN_MBACK))\r
+ ;\r
+ while ( !((keys = in_menu_wait_any(50)) & (PBTN_MA3|PBTN_MBACK)) )\r
+ ;\r
+ if (keys & PBTN_MBACK)\r
+ do_it = 0;\r
+ while (in_menu_wait_any(50) & (PBTN_MA3|PBTN_MBACK))\r
+ ;\r
+ in_set_blocking(0);\r
+ }\r
+ if (do_it) {\r
+ plat_status_msg_busy_first((which & PEV_STATE_LOAD) ? "LOADING STATE" : "SAVING STATE");\r
+ PicoStateProgressCB = plat_status_msg_busy_next;\r
+ emu_save_load_game((which & PEV_STATE_LOAD) ? 1 : 0, 0);\r
+ PicoStateProgressCB = NULL;\r
+ }\r
+ }\r
+ if (which & PEV_SWITCH_RND)\r
+ {\r
+ plat_video_toggle_renderer(1, 0);\r
+ }\r
+ if (which & (PEV_SSLOT_PREV|PEV_SSLOT_NEXT))\r
+ {\r
+ if (which & PEV_SSLOT_PREV) {\r
+ state_slot -= 1;\r
+ if (state_slot < 0)\r
+ state_slot = 9;\r
+ } else {\r
+ state_slot += 1;\r
+ if (state_slot > 9)\r
+ state_slot = 0;\r
+ }\r
+\r
+ emu_status_msg("SAVE SLOT %i [%s]", state_slot,\r
+ emu_check_save_file(state_slot) ? "USED" : "FREE");\r
+ }\r
+ if (which & PEV_MENU)\r
+ engineState = PGS_Menu;\r
+}\r
+\r
+void emu_update_input(void)\r
+{\r
+ static int prev_events = 0;\r
+ int actions[IN_BINDTYPE_COUNT] = { 0, };\r
+ int pl_actions[2];\r
+ int events;\r
+\r
+ in_update(actions);\r
+\r
+ pl_actions[0] = actions[IN_BINDTYPE_PLAYER12];\r
+ pl_actions[1] = actions[IN_BINDTYPE_PLAYER12] >> 16;\r
+\r
+ PicoPad[0] = pl_actions[0] & 0xfff;\r
+ PicoPad[1] = pl_actions[1] & 0xfff;\r
+\r
+ if (pl_actions[0] & 0x7000)\r
+ do_turbo(&PicoPad[0], pl_actions[0]);\r
+ if (pl_actions[1] & 0x7000)\r
+ do_turbo(&PicoPad[1], pl_actions[1]);\r
+\r
+ events = actions[IN_BINDTYPE_EMU] & PEV_MASK;\r
+\r
+ // volume is treated in special way and triggered every frame\r
+ if (events & (PEV_VOL_DOWN|PEV_VOL_UP))\r
+ plat_update_volume(1, events & PEV_VOL_UP);\r
+\r
+ if ((events ^ prev_events) & PEV_FF) {\r
+ emu_set_fastforward(events & PEV_FF);\r
+ plat_update_volume(0, 0);\r
+ reset_timing = 1;\r
+ }\r
+\r
+ events &= ~prev_events;\r
+\r
+ if (PicoAHW == PAHW_PICO)\r
+ run_events_pico(events);\r
+ if (events)\r
+ run_events_ui(events);\r
+ if (movie_data)\r
+ update_movie();\r
+\r
+ prev_events = actions[IN_BINDTYPE_EMU] & PEV_MASK;\r
+}\r
+\r
+static void mkdir_path(char *path_with_reserve, int pos, const char *name)\r
+{\r
+ strcpy(path_with_reserve + pos, name);\r
+ if (plat_is_dir(path_with_reserve))\r
+ return;\r
+ if (mkdir(path_with_reserve, 0777) < 0)\r
+ lprintf("failed to create: %s\n", path_with_reserve);\r
+}\r
+\r
+void emu_init(void)\r
+{\r
+ char path[512];\r
+ int pos;\r
+\r
+#if 0\r
+ // FIXME: handle through menu, etc\r
+ FILE *f;\r
+ f = fopen("32X_M_BIOS.BIN", "rb");\r
+ p32x_bios_m = malloc(2048);\r
+ fread(p32x_bios_m, 1, 2048, f);\r
+ fclose(f);\r
+ f = fopen("32X_S_BIOS.BIN", "rb");\r
+ p32x_bios_s = malloc(1024);\r
+ fread(p32x_bios_s, 1, 1024, f);\r
+ fclose(f);\r
+#endif\r
+\r
+ /* make dirs for saves */\r
+ pos = plat_get_root_dir(path, sizeof(path) - 4);\r
+ mkdir_path(path, pos, "mds");\r
+ mkdir_path(path, pos, "srm");\r
+ mkdir_path(path, pos, "brm");\r
+\r
+ pprof_init();\r
+\r
+ make_config_cfg(path);\r
+ config_readlrom(path);\r
+\r
+ PicoInit();\r
+ PicoMessage = plat_status_msg_busy_next;\r
+ PicoMCDopenTray = emu_tray_open;\r
+ PicoMCDcloseTray = emu_tray_close;\r
+}\r
+\r
+void emu_finish(void)\r
+{\r
+ // save SRAM\r
+ if ((currentConfig.EmuOpt & EOPT_EN_SRAM) && SRam.changed) {\r
+ emu_save_load_game(0, 1);\r
+ SRam.changed = 0;\r
+ }\r
+\r
+ if (!(currentConfig.EmuOpt & EOPT_NO_AUTOSVCFG)) {\r
+ char cfg[512];\r
+ make_config_cfg(cfg);\r
+ config_writelrom(cfg);\r
+#ifndef NO_SYNC\r
+ sync();\r
+#endif\r
+ }\r
+\r
+ pprof_finish();\r
+\r
+ PicoExit();\r
+}\r
+\r
+static void skip_frame(int do_audio)\r
+{\r
+ PicoSkipFrame = do_audio ? 1 : 2;\r
+ PicoFrame();\r
+ PicoSkipFrame = 0;\r
+}\r
+\r
+/* our tick here is 1 us right now */\r
+#define ms_to_ticks(x) (unsigned int)(x * 1000)\r
+#define get_ticks() plat_get_ticks_us()\r
+\r
+void emu_loop(void)\r
+{\r
+ int pframes_done; /* "period" frames, used for sync */\r
+ int frames_done, frames_shown; /* actual frames for fps counter */\r
+ int target_fps, target_frametime;\r
+ unsigned int timestamp_base = 0, timestamp_fps;\r
+ char *notice_msg = NULL;\r
+ char fpsbuff[24];\r
+ int i;\r
+\r
+ fpsbuff[0] = 0;\r
+\r
+ /* make sure we are in correct mode */\r
+ Pico.m.dirtyPal = 1;\r
+ rendstatus_old = -1;\r
+\r
+ /* number of ticks per frame */\r
+ if (Pico.m.pal) {\r
+ target_fps = 50;\r
+ target_frametime = ms_to_ticks(1000) / 50;\r
+ } else {\r
+ target_fps = 60;\r
+ target_frametime = ms_to_ticks(1000) / 60 + 1;\r
+ }\r
+\r
+ // prepare CD buffer\r
+ if (PicoAHW & PAHW_MCD)\r
+ PicoCDBufferInit();\r
+ PicoLoopPrepare();\r
+\r
+ pemu_loop_prep();\r
+\r
+ timestamp_fps = get_ticks();\r
+ reset_timing = 1;\r
+\r
+ frames_done = frames_shown = pframes_done = 0;\r
+\r
+ plat_video_wait_vsync();\r
+\r
+ /* loop with resync every 1 sec. */\r
+ while (engineState == PGS_Running)\r
+ {\r
+ unsigned int timestamp;\r
+ int diff, diff_lim;\r
+\r
+ pprof_start(main);\r
+\r
+ timestamp = get_ticks();\r
+ if (reset_timing) {\r
+ reset_timing = 0;\r
+ timestamp_base = timestamp;\r
+ pframes_done = 0;\r
+ }\r
+\r
+ // show notice_msg message?\r
+ if (notice_msg_time != 0)\r
+ {\r
+ static int noticeMsgSum;\r
+ if (timestamp - ms_to_ticks(notice_msg_time) > ms_to_ticks(STATUS_MSG_TIMEOUT)) {\r
+ notice_msg_time = 0;\r
+ plat_status_msg_clear();\r
+ notice_msg = NULL;\r
+ } else {\r
+ int sum = noticeMsg[0] + noticeMsg[1] + noticeMsg[2];\r
+ if (sum != noticeMsgSum) {\r
+ plat_status_msg_clear();\r
+ noticeMsgSum = sum;\r
+ }\r
+ notice_msg = noticeMsg;\r
+ }\r
+ }\r
+\r
+ // second changed?\r
+ if (timestamp - timestamp_fps >= ms_to_ticks(1000))\r
+ {\r
+#ifdef BENCHMARK\r
+ static int bench = 0, bench_fps = 0, bench_fps_s = 0, bfp = 0, bf[4];\r
+ if (++bench == 10) {\r
+ bench = 0;\r
+ bench_fps_s = bench_fps;\r
+ bf[bfp++ & 3] = bench_fps;\r
+ bench_fps = 0;\r
+ }\r
+ bench_fps += frames_shown;\r
+ sprintf(fpsbuff, "%02i/%02i/%02i", frames_shown, bench_fps_s, (bf[0]+bf[1]+bf[2]+bf[3])>>2);\r
+ printf("%s\n", fpsbuff);\r
+#else\r
+ if (currentConfig.EmuOpt & EOPT_SHOW_FPS) {\r
+ sprintf(fpsbuff, "%02i/%02i", frames_shown, frames_done);\r
+ if (fpsbuff[5] == 0) { fpsbuff[5] = fpsbuff[6] = ' '; fpsbuff[7] = 0; }\r
+ }\r
+#endif\r
+ frames_shown = frames_done = 0;\r
+ timestamp_fps += ms_to_ticks(1000);\r
+ }\r
+#ifdef PFRAMES\r
+ sprintf(fpsbuff, "%i", Pico.m.frame_count);\r
+#endif\r
+\r
+ if (timestamp - timestamp_base >= ms_to_ticks(1000))\r
+ {\r
+ if ((currentConfig.EmuOpt & EOPT_NO_FRMLIMIT) && currentConfig.Frameskip >= 0)\r
+ pframes_done = 0;\r
+ else\r
+ pframes_done -= target_fps;\r
+ if (pframes_done < -2) {\r
+ /* don't drag more than 2 frames behind */\r
+ pframes_done = -2;\r
+ timestamp_base = timestamp - 2 * target_frametime;\r
+ }\r
+ else\r
+ timestamp_base += ms_to_ticks(1000);\r
+ }\r
+\r
+ diff = timestamp - timestamp_base;\r
+ diff_lim = (pframes_done + 1) * target_frametime;\r
+\r
+ if (currentConfig.Frameskip >= 0) // frameskip enabled\r
+ {\r
+ for (i = 0; i < currentConfig.Frameskip; i++) {\r
+ emu_update_input();\r
+ skip_frame(1);\r
+ pframes_done++; frames_done++;\r
+ diff_lim += target_frametime;\r
+\r
+ if (!(currentConfig.EmuOpt & (EOPT_NO_FRMLIMIT|EOPT_EXT_FRMLIMIT))) {\r
+ timestamp = get_ticks();\r
+ diff = timestamp - timestamp_base;\r
+ if (!reset_timing && diff < diff_lim) // we are too fast\r
+ plat_wait_till_us(timestamp_base + diff_lim);\r
+ }\r
+ }\r
+ }\r
+ else if (diff > diff_lim)\r
+ {\r
+ /* no time left for this frame - skip */\r
+ /* limit auto frameskip to 8 */\r
+ if (frames_done / 8 <= frames_shown) {\r
+ emu_update_input();\r
+ skip_frame(diff < diff_lim + target_frametime * 16);\r
+ pframes_done++; frames_done++;\r
+ continue;\r
+ }\r
+ }\r
+\r
+ emu_update_input();\r
+ PicoFrame();\r
+ pemu_finalize_frame(fpsbuff, notice_msg);\r
+\r
+ // plat_video_flip();\r
+\r
+ /* frame limiter */\r
+ if (!reset_timing && !(currentConfig.EmuOpt & (EOPT_NO_FRMLIMIT|EOPT_EXT_FRMLIMIT)))\r
+ {\r
+ timestamp = get_ticks();\r
+ diff = timestamp - timestamp_base;\r
+\r
+ // sleep or vsync if we are still too fast\r
+ if (diff < diff_lim)\r
+ {\r
+ // we are too fast\r
+ plat_wait_till_us(timestamp_base + diff_lim - target_frametime / 4);\r
+ if (currentConfig.EmuOpt & EOPT_VSYNC)\r
+ plat_video_wait_vsync();\r
+ }\r
+ }\r
+\r
+ // XXX: for some plats it might be better to flip before vsync\r
+ // (due to shadow registers in display hw)\r
+ plat_video_flip();\r
+\r
+ pframes_done++; frames_done++; frames_shown++;\r
+\r
+ pprof_end(main);\r
+ }\r
+\r
+ emu_set_fastforward(0);\r
+\r
+ // save SRAM\r
+ if ((currentConfig.EmuOpt & EOPT_EN_SRAM) && SRam.changed) {\r
+ plat_status_msg_busy_first("Writing SRAM/BRAM...");\r
+ emu_save_load_game(0, 1);\r
+ SRam.changed = 0;\r
+ }\r
+\r
+ pemu_loop_end();\r
+\r
+ // pemu_loop_end() might want to do 1 frame for bg image,\r
+ // so free CD buffer here\r
+ if (PicoAHW & PAHW_MCD)\r
+ PicoCDBufferFree();\r
+}\r
+\r