\r
#include <stdio.h>\r
#include <stdlib.h>\r
+#include <stdarg.h>\r
#ifndef NO_SYNC\r
#include <unistd.h>\r
#endif\r
char rom_fname_loaded[512] = { 0, };\r
int rom_loaded = 0;\r
int reset_timing = 0;\r
+static unsigned int notice_msg_time; /* when started showing */\r
+static char noticeMsg[40];\r
\r
unsigned char *movie_data = NULL;\r
static int movie_size = 0;\r
strlwr_(ext);\r
}\r
\r
+void emu_status_msg(const char *format, ...)\r
+{\r
+ va_list vl;\r
+\r
+ va_start(vl, format);\r
+ vsnprintf(noticeMsg, sizeof(noticeMsg), format, vl);\r
+ va_end(vl);\r
+\r
+ notice_msg_time = plat_get_ticks_ms();\r
+}\r
+\r
static const char *biosfiles_us[] = { "us_scd1_9210", "us_scd2_9306", "SegaCDBIOS9303" };\r
static const char *biosfiles_eu[] = { "eu_mcd1_9210", "eu_mcd2_9306", "eu_mcd2_9303" };\r
static const char *biosfiles_jp[] = { "jp_mcd1_9112", "jp_mcd1_9111" };\r
// TODO: bits 6 & 5\r
}\r
movie_data[0x18+30] = 0;\r
- plat_status_msg("MOVIE: %s", (char *) &movie_data[0x18]);\r
+ emu_status_msg("MOVIE: %s", (char *) &movie_data[0x18]);\r
}\r
else\r
{\r
PicoOpt &= ~POPT_DIS_VDP_FIFO;\r
- plat_status_msg(Pico.m.pal ? "PAL SYSTEM / 50 FPS" : "NTSC SYSTEM / 60 FPS");\r
+ emu_status_msg(Pico.m.pal ? "PAL SYSTEM / 50 FPS" : "NTSC SYSTEM / 60 FPS");\r
}\r
\r
// load SRAM for this ROM\r
if (offs+3 > movie_size) {\r
free(movie_data);\r
movie_data = 0;\r
- plat_status_msg("END OF MOVIE.");\r
+ emu_status_msg("END OF MOVIE.");\r
lprintf("END OF MOVIE.\n");\r
} else {\r
// MXYZ SACB RLDU\r
saveFname = emu_get_save_fname(load, sram, state_slot);\r
if (saveFname == NULL) {\r
if (!sram)\r
- plat_status_msg(load ? "LOAD FAILED (missing file)" : "SAVE FAILED");\r
+ emu_status_msg(load ? "LOAD FAILED (missing file)" : "SAVE FAILED");\r
return -1;\r
}\r
\r
}\r
else ret = -1;\r
if (!ret)\r
- plat_status_msg(load ? "GAME LOADED" : "GAME SAVED");\r
+ emu_status_msg(load ? "GAME LOADED" : "GAME SAVED");\r
else\r
{\r
- plat_status_msg(load ? "LOAD FAILED" : "SAVE FAILED");\r
+ emu_status_msg(load ? "LOAD FAILED" : "SAVE FAILED");\r
ret = -1;\r
}\r
\r
currentConfig.EmuOpt &= ~4;\r
currentConfig.EmuOpt |= 0x40000;\r
is_on = 1;\r
- plat_status_msg("FAST FORWARD");\r
+ emu_status_msg("FAST FORWARD");\r
}\r
else if (!set_on && is_on) {\r
PsndOut = set_PsndOut;\r
\r
static void emu_msg_tray_open(void)\r
{\r
- plat_status_msg("CD tray opened");\r
+ emu_status_msg("CD tray opened");\r
}\r
\r
void emu_reset_game(void)\r
if (pico_inp_mode > 2)\r
pico_inp_mode = 0;\r
switch (pico_inp_mode) {\r
- case 2: plat_status_msg("Input: Pen on Pad"); break;\r
- case 1: plat_status_msg("Input: Pen on Storyware"); break;\r
- case 0: plat_status_msg("Input: Joystick");\r
+ case 2: emu_status_msg("Input: Pen on Pad"); break;\r
+ case 1: emu_status_msg("Input: Pen on Storyware"); break;\r
+ case 0: emu_status_msg("Input: Joystick");\r
PicoPicohw.pen_pos[0] = PicoPicohw.pen_pos[1] = 0x8000;\r
break;\r
}\r
PicoPicohw.page--;\r
if (PicoPicohw.page < 0)\r
PicoPicohw.page = 0;\r
- plat_status_msg("Page %i", PicoPicohw.page);\r
+ emu_status_msg("Page %i", PicoPicohw.page);\r
}\r
if (events & PEV_PICO_PNEXT) {\r
PicoPicohw.page++;\r
if (PicoPicohw.page > 6)\r
PicoPicohw.page = 6;\r
- plat_status_msg("Page %i", PicoPicohw.page);\r
+ emu_status_msg("Page %i", PicoPicohw.page);\r
}\r
\r
if (pico_inp_mode == 0)\r
state_slot = 0;\r
}\r
\r
- plat_status_msg("SAVE SLOT %i [%s]", state_slot,\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
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 oldmodes, 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
+ oldmodes = ((Pico.video.reg[12]&1)<<2) ^ 0xc;\r
+ Pico.m.dirtyPal = 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
+\r
+ if (currentConfig.EmuOpt & EOPT_PSYNC)\r
+ plat_video_wait_vsync();\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
+ /* loop with resync every 1 sec. */\r
+ while (engineState == PGS_Running)\r
+ {\r
+ unsigned int timestamp;\r
+ int diff, diff_lim;\r
+ int modes;\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(2000)) {\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
+ // check for mode changes\r
+ modes = ((Pico.video.reg[12]&1)<<2) | (Pico.video.reg[1]&8);\r
+ if (modes != oldmodes) {\r
+ oldmodes = modes;\r
+ pemu_video_mode_change(!(modes & 4), (modes & 8));\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
+#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 (PsndOut == 0 && currentConfig.Frameskip >= 0)\r
+ pframes_done = 0;\r
+ else\r
+ pframes_done -= target_fps;\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 (PsndOut && !reset_timing) { // do framelimitting if sound is enabled\r
+ timestamp = get_ticks();\r
+ diff = timestamp - timestamp_base;\r
+ if (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
+ if (diff - diff_lim >= ms_to_ticks(300)) {\r
+ /* if too much behind, reset instead */\r
+ reset_timing = 1;\r
+ continue;\r
+ }\r
+ emu_update_input();\r
+ skip_frame(diff < diff_lim + target_frametime * 2);\r
+ pframes_done++; frames_done++;\r
+ continue;\r
+ }\r
+\r
+ emu_update_input();\r
+ PicoFrame();\r
+\r
+ /* frame limiter */\r
+ if (!reset_timing && (PsndOut != NULL || currentConfig.Frameskip < 0))\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
+ if (currentConfig.EmuOpt & EOPT_PSYNC) {\r
+ if (diff_lim - diff > target_frametime/2)\r
+ plat_wait_till_us(timestamp_base + target_frametime/4);\r
+ plat_video_wait_vsync();\r
+ } else\r
+ plat_wait_till_us(timestamp_base + diff_lim);\r
+ }\r
+ }\r
+\r
+ pemu_update_display(fpsbuff, notice_msg);\r
+\r
+ pframes_done++; frames_done++; frames_shown++;\r
+ }\r
+\r
+ emu_set_fastforward(0);\r
+\r
+ if (PicoAHW & PAHW_MCD)\r
+ PicoCDBufferFree();\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
+ // do menu background to be sure it's right\r
+ pemu_forced_frame(POPT_EN_SOFTSCALE);\r
+\r
+ pemu_loop_end();\r
+}\r
+\r
void emu_init(void);
void emu_finish(void);
+void emu_loop(void);
int emu_reload_rom(char *rom_fname);
int emu_save_load_game(int load, int sram);
void emu_get_game_name(char *str150);
void emu_set_fastforward(int set_on);
int emu_cd_check(int *pregion, char *fname_in);
+void emu_status_msg(const char *format, ...);
#ifdef __cplusplus
} // extern "C"
engineState = PGS_Running;\r
\r
case PGS_Running:\r
- pemu_loop();\r
+ emu_loop();\r
break;\r
\r
case PGS_Quit:\r
extern char cpu_clk_name[];
void pemu_prep_defconfig(void);
-void pemu_loop(void);
+void pemu_loop_prep(void);
+void pemu_loop_end(void);
void pemu_forced_frame(int opts);
+void pemu_video_mode_change(int is_32col, int is_240_lines);
+void pemu_update_display(const char *fps, const char *notice_msg);
+
void pemu_sound_start(void);
void pemu_sound_stop(void);
void pemu_sound_wait(void);
/* return the dir/ where configs, saves, bios, etc. are found */
int plat_get_root_dir(char *dst, int len);
-/* to be used while emulation is starting or running */
-void plat_status_msg(const char *format, ...);
-
/* used before things blocking for a while (these funcs redraw on return) */
void plat_status_msg_busy_first(const char *msg);
void plat_status_msg_busy_next(const char *msg);
+void plat_status_msg_clear(void);
/* menu: enter (switch bpp, etc), begin/end drawing */
void plat_video_menu_enter(int is_rom_loaded);
void plat_video_menu_begin(void);
void plat_video_menu_end(void);
+void plat_video_wait_vsync(void);
void plat_video_toggle_renderer(int is_next, int is_menu);
void plat_validate_config(void);
void plat_update_volume(int has_changed, int is_up);
int plat_wait_event(int *fds_hnds, int count, int timeout_ms);
void plat_sleep_ms(int ms);
-/* ms counter, to be used for time diff */
-unsigned int plat_get_ticks_ms(void);
+/* timers, to be used for time diff and must refet to the same clock */
+unsigned int plat_get_ticks_ms(void);
+unsigned int plat_get_ticks_us(void);
+void plat_wait_till_us(unsigned int us);
-const char *plat_get_credits(void);
+const char *plat_get_credits(void);
void plat_debug_cat(char *str);
#ifdef __cplusplus
unsigned char gfx_buffer[321*240*2*2];
unsigned char *PicoDraw2FB = gfx_buffer; // temporary buffer for alt renderer ( (8+320)*(8+240+8) )
-static DWORD noticeMsgTime = 0;
static short *snd_cbuff = NULL;
static int snd_cbuf_samples = 0, snd_all_samples = 0;
static void blit(const char *fps, const char *notice);
static void clearArea(int full);
-void plat_status_msg(const char *format, ...)
-{
- /* TODO */
- noticeMsgTime = GetTickCount();
-}
-
int plat_get_root_dir(char *dst, int len)
{
if (len > 0) *dst = 0;
\r
#include <stdio.h>\r
#include <stdlib.h>\r
-#include <sys/time.h>\r
-#include <stdarg.h>\r
\r
#include "plat_gp2x.h"\r
#include "soc.h"\r
extern int crashed_940;\r
\r
static short __attribute__((aligned(4))) sndBuffer[2*44100/50];\r
-static struct timeval noticeMsgTime = { 0, 0 }; // when started showing\r
-static char noticeMsg[40];\r
static unsigned char PicoDraw2FB_[(8+320) * (8+240+8)];\r
unsigned char *PicoDraw2FB = PicoDraw2FB_;\r
static int osd_fps_x;\r
\r
extern void *gp2x_screens[4];\r
\r
-void plat_status_msg(const char *format, ...)\r
-{\r
- va_list vl;\r
-\r
- va_start(vl, format);\r
- vsnprintf(noticeMsg, sizeof(noticeMsg), format, vl);\r
- va_end(vl);\r
-\r
- gettimeofday(¬iceMsgTime, 0);\r
-}\r
-\r
int plat_get_root_dir(char *dst, int len)\r
{\r
extern char **g_argv;\r
int localPal[0x100];\r
static void (*vidcpyM2)(void *dest, void *src, int m32col, int with_32c_border) = NULL;\r
\r
-static void blit(const char *fps, const char *notice)\r
+void pemu_update_display(const char *fps, const char *notice)\r
{\r
int emu_opt = currentConfig.EmuOpt;\r
\r
gp2x_video_flip();\r
}\r
\r
-// clears whole screen or just the notice area (in all buffers)\r
-static void clearArea(int full)\r
+/* XXX */\r
+#ifdef __GP2X__\r
+unsigned int plat_get_ticks_ms(void)\r
+{\r
+ return gp2x_get_ticks_ms();\r
+}\r
+\r
+unsigned int plat_get_ticks_us(void)\r
+{\r
+ return gp2x_get_ticks_us();\r
+}\r
+#endif\r
+\r
+void plat_wait_till_us(unsigned int us_to)\r
+{\r
+ unsigned int now;\r
+\r
+ spend_cycles(1024);\r
+ now = plat_get_ticks_us();\r
+\r
+ while ((signed int)(us_to - now) > 512)\r
+ {\r
+ spend_cycles(1024);\r
+ now = plat_get_ticks_us();\r
+ }\r
+}\r
+\r
+void plat_video_wait_vsync(void)\r
+{\r
+ gp2x_video_wait_vsync();\r
+}\r
+\r
+void plat_status_msg_clear(void)\r
{\r
int is_8bit = (PicoOpt & POPT_ALT_RENDERER) || !(currentConfig.EmuOpt & EOPT_16BPP);\r
- if (!full && (currentConfig.EmuOpt & EOPT_WIZ_TEAR_FIX)) {\r
+ if (currentConfig.EmuOpt & EOPT_WIZ_TEAR_FIX) {\r
/* ugh.. */\r
int i, u, *p;\r
if (is_8bit) {\r
return;\r
}\r
\r
- if (is_8bit) {\r
- // 8-bit renderers\r
- if (full) gp2x_memset_all_buffers(0, 0xe0, 320*240);\r
- else gp2x_memset_all_buffers(320*232, 0xe0, 320*8);\r
- } else {\r
- // 16bit accurate renderer\r
- if (full) gp2x_memset_all_buffers(0, 0, 320*240*2);\r
- else gp2x_memset_all_buffers(320*232*2, 0, 320*8*2);\r
- }\r
+ if (is_8bit)\r
+ gp2x_memset_all_buffers(320*232, 0xe0, 320*8);\r
+ else\r
+ gp2x_memset_all_buffers(320*232*2, 0, 320*8*2);\r
}\r
\r
void plat_status_msg_busy_next(const char *msg)\r
{\r
- clearArea(0);\r
- blit("", msg);\r
+ plat_status_msg_clear();\r
+ pemu_update_display("", msg);\r
\r
/* assumption: msg_busy_next gets called only when\r
* something slow is about to happen */\r
vidResetMode();\r
\r
if (PicoOpt & POPT_ALT_RENDERER) {\r
- plat_status_msg(" 8bit fast renderer");\r
+ emu_status_msg(" 8bit fast renderer");\r
} else if (currentConfig.EmuOpt & EOPT_16BPP) {\r
- plat_status_msg("16bit accurate renderer");\r
+ emu_status_msg("16bit accurate renderer");\r
} else {\r
- plat_status_msg(" 8bit accurate renderer");\r
+ emu_status_msg(" 8bit accurate renderer");\r
}\r
}\r
\r
sndout_oss_setvol(vol, vol);\r
currentConfig.volume = vol;\r
}\r
- plat_status_msg("VOL: %02i", vol);\r
+ emu_status_msg("VOL: %02i", vol);\r
prev_frame = Pico.m.frame_count;\r
}\r
\r
}\r
}\r
\r
-\r
static void updateSound(int len)\r
{\r
- if (PicoOpt&8) len<<=1;\r
+ if (PicoOpt & POPT_EN_STEREO)\r
+ len <<= 1;\r
\r
/* avoid writing audio when lagging behind to prevent audio lag */\r
if (PicoSkipFrame != 2)\r
}\r
\r
\r
-static void SkipFrame(int do_audio)\r
-{\r
- PicoSkipFrame=do_audio ? 1 : 2;\r
- PicoFrame();\r
- PicoSkipFrame=0;\r
-}\r
-\r
-\r
void pemu_forced_frame(int opts)\r
{\r
int po_old = PicoOpt;\r
{\r
}\r
\r
-static void simpleWait(int thissec, int lim_time)\r
+void pemu_video_mode_change(int is_32col, int is_240_lines)\r
{\r
- struct timeval tval;\r
-\r
- spend_cycles(1024);\r
- gettimeofday(&tval, 0);\r
- if (thissec != tval.tv_sec) tval.tv_usec+=1000000;\r
-\r
- while (tval.tv_usec < lim_time)\r
- {\r
- spend_cycles(1024);\r
- gettimeofday(&tval, 0);\r
- if (thissec != tval.tv_sec) tval.tv_usec+=1000000;\r
+ int scalex = 320;\r
+ osd_fps_x = OSD_FPS_X;\r
+ if (is_32col && (PicoOpt & POPT_DIS_32C_BORDER)) {\r
+ scalex = 256;\r
+ osd_fps_x = OSD_FPS_X - 64;\r
}\r
+ /* want vertical scaling and game is not in 240 line mode */\r
+ if (currentConfig.scaling == EOPT_SCALE_HW_HV && !is_240_lines)\r
+ gp2x_video_RGB_setscaling(8, scalex, 224);\r
+ else\r
+ gp2x_video_RGB_setscaling(0, scalex, 240);\r
+\r
+ // clear whole screen in all buffers\r
+ if ((PicoOpt & POPT_ALT_RENDERER) || !(currentConfig.EmuOpt & EOPT_16BPP))\r
+ gp2x_memset_all_buffers(0, 0xe0, 320*240);\r
+ else\r
+ gp2x_memset_all_buffers(0, 0, 320*240*2);\r
}\r
\r
-\r
#if 0\r
static void tga_dump(void)\r
{\r
}\r
#endif\r
\r
-\r
-void pemu_loop(void)\r
+void pemu_loop_prep(void)\r
{\r
static int gp2x_old_clock = -1, EmuOpt_old = 0, pal_old = 0;\r
static int gp2x_old_gamma = 100;\r
- char fpsbuff[24]; // fps count c string\r
- struct timeval tval; // timing\r
- int pframes_done, pframes_shown, pthissec; // "period" frames, used for sync\r
- int frames_done, frames_shown, thissec; // actual frames\r
- int oldmodes = 0, target_fps, target_frametime, lim_time, vsync_offset, i;\r
- char *notice = 0;\r
-\r
- printf("entered emu_Loop()\n");\r
\r
if ((EmuOpt_old ^ currentConfig.EmuOpt) & EOPT_RAM_TIMINGS) {\r
if (currentConfig.EmuOpt & EOPT_RAM_TIMINGS)\r
\r
EmuOpt_old = currentConfig.EmuOpt;\r
pal_old = Pico.m.pal;\r
- fpsbuff[0] = 0;\r
\r
// make sure we are in correct mode\r
vidResetMode();\r
scaling_update();\r
- Pico.m.dirtyPal = 1;\r
- oldmodes = ((Pico.video.reg[12]&1)<<2) ^ 0xc;\r
-\r
- // pal/ntsc might have changed, reset related stuff\r
- target_fps = Pico.m.pal ? 50 : 60;\r
- target_frametime = 1000000/target_fps;\r
- reset_timing = 1;\r
\r
pemu_sound_start();\r
+}\r
\r
- // prepare CD buffer\r
- if (PicoAHW & PAHW_MCD) PicoCDBufferInit();\r
-\r
- // calc vsync offset to sync timing code with vsync\r
- if (currentConfig.EmuOpt & EOPT_PSYNC) {\r
- gettimeofday(&tval, 0);\r
- gp2x_video_wait_vsync();\r
- gettimeofday(&tval, 0);\r
- vsync_offset = tval.tv_usec;\r
- while (vsync_offset >= target_frametime)\r
- vsync_offset -= target_frametime;\r
- if (!vsync_offset) vsync_offset++;\r
- printf("vsync_offset: %i\n", vsync_offset);\r
- } else\r
- vsync_offset = 0;\r
-\r
- frames_done = frames_shown = thissec =\r
- pframes_done = pframes_shown = pthissec = 0;\r
-\r
- // loop\r
- while (engineState == PGS_Running)\r
- {\r
- int modes;\r
-\r
- gettimeofday(&tval, 0);\r
- if (reset_timing) {\r
- reset_timing = 0;\r
- pthissec = tval.tv_sec;\r
- pframes_shown = pframes_done = tval.tv_usec/target_frametime;\r
- }\r
-\r
- // show notice message?\r
- if (noticeMsgTime.tv_sec)\r
- {\r
- static int noticeMsgSum;\r
- if((tval.tv_sec*1000000+tval.tv_usec) - (noticeMsgTime.tv_sec*1000000+noticeMsgTime.tv_usec) > 2000000) { // > 2.0 sec\r
- noticeMsgTime.tv_sec = noticeMsgTime.tv_usec = 0;\r
- clearArea(0);\r
- notice = 0;\r
- } else {\r
- int sum = noticeMsg[0]+noticeMsg[1]+noticeMsg[2];\r
- if (sum != noticeMsgSum) { clearArea(0); noticeMsgSum = sum; }\r
- notice = noticeMsg;\r
- }\r
- }\r
-\r
- // check for mode changes\r
- modes = ((Pico.video.reg[12]&1)<<2)|(Pico.video.reg[1]&8);\r
- if (modes != oldmodes)\r
- {\r
- int scalex = 320;\r
- osd_fps_x = OSD_FPS_X;\r
- if (!(modes & 4) && (PicoOpt & POPT_DIS_32C_BORDER)) {\r
- scalex = 256;\r
- osd_fps_x = OSD_FPS_X - 64;\r
- }\r
- /* want vertical scaling and game is not in 240 line mode */\r
- if (currentConfig.scaling == EOPT_SCALE_HW_HV && !(modes&8))\r
- gp2x_video_RGB_setscaling(8, scalex, 224);\r
- else gp2x_video_RGB_setscaling(0, scalex, 240);\r
- oldmodes = modes;\r
- clearArea(1);\r
- }\r
-\r
- // second changed?\r
- if (thissec != tval.tv_sec)\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
-#else\r
- if (currentConfig.EmuOpt & 2) {\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
- thissec = tval.tv_sec;\r
- }\r
-#ifdef PFRAMES\r
- sprintf(fpsbuff, "%i", Pico.m.frame_count);\r
-#endif\r
-\r
- if (pthissec != tval.tv_sec)\r
- {\r
- if (PsndOut == 0 && currentConfig.Frameskip >= 0) {\r
- pframes_done = pframes_shown = 0;\r
- } else {\r
- // it is quite common for this implementation to leave 1 fame unfinished\r
- // when second changes, but we don't want buffer to starve.\r
- if (PsndOut && pframes_done < target_fps && pframes_done > target_fps-5) {\r
- emu_update_input();\r
- SkipFrame(1); pframes_done++;\r
- }\r
-\r
- pframes_done -= target_fps; if (pframes_done < 0) pframes_done = 0;\r
- pframes_shown -= target_fps; if (pframes_shown < 0) pframes_shown = 0;\r
- if (pframes_shown > pframes_done) pframes_shown = pframes_done;\r
- }\r
- pthissec = tval.tv_sec;\r
- }\r
-\r
- lim_time = (pframes_done+1) * target_frametime + vsync_offset;\r
- if (currentConfig.Frameskip >= 0) // frameskip enabled\r
- {\r
- for(i = 0; i < currentConfig.Frameskip; i++) {\r
- emu_update_input();\r
- SkipFrame(1); pframes_done++; frames_done++;\r
- if (PsndOut && !reset_timing) { // do framelimitting if sound is enabled\r
- gettimeofday(&tval, 0);\r
- if (pthissec != tval.tv_sec) tval.tv_usec+=1000000;\r
- if (tval.tv_usec < lim_time) { // we are too fast\r
- simpleWait(pthissec, lim_time);\r
- }\r
- }\r
- lim_time += target_frametime;\r
- }\r
- }\r
- else if (tval.tv_usec > lim_time) // auto frameskip\r
- {\r
- // no time left for this frame - skip\r
- if (tval.tv_usec - lim_time >= 300000) {\r
- /* something caused a slowdown for us (disk access? cache flush?)\r
- * try to recover by resetting timing... */\r
- reset_timing = 1;\r
- continue;\r
- }\r
- emu_update_input();\r
- SkipFrame(tval.tv_usec < lim_time+target_frametime*2); pframes_done++; frames_done++;\r
- continue;\r
- }\r
-\r
- emu_update_input();\r
- PicoFrame();\r
-\r
- // check time\r
- gettimeofday(&tval, 0);\r
- if (pthissec != tval.tv_sec) tval.tv_usec+=1000000;\r
-\r
- if (currentConfig.Frameskip < 0 && tval.tv_usec - lim_time >= 300000) // slowdown detection\r
- reset_timing = 1;\r
- else if (PsndOut != NULL || currentConfig.Frameskip < 0)\r
- {\r
- // sleep or vsync if we are still too fast\r
- // usleep sleeps for ~20ms minimum, so it is not a solution here\r
- if (!reset_timing && tval.tv_usec < lim_time)\r
- {\r
- // we are too fast\r
- if (vsync_offset) {\r
- if (lim_time - tval.tv_usec > target_frametime/2)\r
- simpleWait(pthissec, lim_time - target_frametime/4);\r
- gp2x_video_wait_vsync();\r
- } else {\r
- simpleWait(pthissec, lim_time);\r
- }\r
- }\r
- }\r
-\r
- blit(fpsbuff, notice);\r
-\r
- pframes_done++; pframes_shown++;\r
- frames_done++; frames_shown++;\r
- }\r
-\r
- emu_set_fastforward(0);\r
-\r
- if (PicoAHW & PAHW_MCD)\r
- PicoCDBufferFree();\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
- // do menu background to be sure it's right\r
- pemu_forced_frame(POPT_EN_SOFTSCALE);\r
+void pemu_loop_end(void)\r
+{\r
}\r
\r
const char *plat_get_credits(void)\r
void (*unset_ram_timings)(void);
int (*gp2x_read_battery)(void);
+unsigned int (*gp2x_get_ticks_ms)(void);
+unsigned int (*gp2x_get_ticks_us)(void);
+
gp2x_soc_t soc_detect(void)
{
extern void (*unset_ram_timings)(void);
extern int (*gp2x_read_battery)(void);
+/* gettimeofday is not suitable for Wiz, at least fw 1.1 or lower */
+extern unsigned int (*gp2x_get_ticks_ms)(void);
+extern unsigned int (*gp2x_get_ticks_us)(void);
#include "soc_mmsp2.h"
#include "plat_gp2x.h"
#include "../common/emu.h"
+#include "../common/plat.h"
#include "../common/arm_utils.h"
#include "940ctl.h"
static unsigned short memtimex_old[2];
static unsigned short reg0910;
+extern unsigned int plat_get_ticks_ms_gtod(void);
+extern unsigned int plat_get_ticks_us_gtod(void);
/* video stuff */
static void gp2x_video_flip_(void)
set_ram_timings = set_ram_timings_;
unset_ram_timings = unset_ram_timings_;
gp2x_read_battery = gp2x_read_battery_;
+
+ gp2x_get_ticks_ms = plat_get_ticks_ms_gtod;
+ gp2x_get_ticks_us = plat_get_ticks_us_gtod;
}
void mmsp2_finish(void)
}
}
+#define TIMER_BASE3 0x1980
+#define TIMER_REG(x) memregl[(TIMER_BASE3 + x) >> 2]
+
+unsigned int gp2x_get_ticks_us_(void)
+{
+ TIMER_REG(0x08) = 0x4b; /* run timer, latch value */
+ return TIMER_REG(0);
+}
+
+unsigned int gp2x_get_ticks_ms_(void)
+{
+ unsigned long long v64;
+ v64 = (unsigned long long)gp2x_get_ticks_us_() * 4195;
+ return v64 >> 22;
+}
+
+static void timer_cleanup(void)
+{
+ TIMER_REG(0x40) = 0x0c; /* be sure clocks are on */
+ TIMER_REG(0x08) = 0x23; /* stop the timer, clear irq in case it's pending */
+ TIMER_REG(0x00) = 0; /* clear counter */
+ TIMER_REG(0x40) = 0; /* clocks off */
+ TIMER_REG(0x44) = 0; /* dividers back to default */
+}
+
void pollux_init(void)
{
struct fb_fix_screeninfo fbfix;
if (battdev < 0)
perror("Warning: could't open pollux_batt");
+ /* setup timer */
+ if (TIMER_REG(0x08) & 8)
+ timer_cleanup();
+
+ TIMER_REG(0x44) = 0x922; /* using PLL1, divider value 147 */
+ TIMER_REG(0x40) = 0x0c; /* clocks on */
+ TIMER_REG(0x08) = 0x6b; /* run timer, clear irq, latch value */
+
pllsetreg0 = memregl[0xf004>>2];
memtimex_old[0] = memregs[0x14802>>1];
memtimex_old[1] = memregs[0x14804>>1];
set_ram_timings = set_ram_timings_;
unset_ram_timings = unset_ram_timings_;
gp2x_read_battery = gp2x_read_battery_;
+
+ gp2x_get_ticks_ms = gp2x_get_ticks_ms_;
+ gp2x_get_ticks_us = gp2x_get_ticks_us_;
}
void pollux_finish(void)
return 0;
}
+#ifdef __GP2X__
+/* Wiz has a borked gettimeofday().. */
+#define plat_get_ticks_ms plat_get_ticks_ms_gtod
+#define plat_get_ticks_us plat_get_ticks_us_gtod
+#endif
+
unsigned int plat_get_ticks_ms(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
ret = (unsigned)tv.tv_sec * 1000;
- /* approximate division */
+ /* approximate /= 1000 */
ret += ((unsigned)tv.tv_usec * 4195) >> 22;
return ret;
}
+unsigned int plat_get_ticks_us(void)
+{
+ struct timeval tv;
+ unsigned int ret;
+
+ gettimeofday(&tv, NULL);
+
+ ret = (unsigned)tv.tv_sec * 1000000;
+ ret += (unsigned)tv.tv_usec;
+
+ return ret;
+}
+
void plat_sleep_ms(int ms)
{
usleep(ms * 1000);
\r
\r
static short __attribute__((aligned(4))) sndBuffer[2*44100/50];\r
-static struct timeval noticeMsgTime = { 0, 0 }; // when started showing\r
static int osd_fps_x;\r
unsigned char *PicoDraw2FB = NULL; // temporary buffer for alt renderer\r
\r
static int pico_pen_x = 0, pico_pen_y = 240/2;\r
\r
\r
-void plat_status_msg(const char *format, ...)\r
-{\r
- va_list vl;\r
-\r
- va_start(vl, format);\r
- vsnprintf(noticeMsg, sizeof(noticeMsg), fmt, vl);\r
- va_end(vl);\r
-\r
- gettimeofday(¬iceMsgTime, 0);\r
-}\r
-\r
int plat_get_root_dir(char *dst, int len)\r
{\r
extern char **g_argv;\r
unsigned char *PicoDraw2FB = (unsigned char *)VRAM_CACHED_STUFF + 8; // +8 to be able to skip border with 1 quadword..
int engineStateSuspend;
-static unsigned int noticeMsgTime = 0;
-
#define PICO_PEN_ADJUST_X 4
#define PICO_PEN_ADJUST_Y 2
static int pico_pen_x = 320/2, pico_pen_y = 240/2;
static void blit2(const char *fps, const char *notice, int lagging_behind);
static void clearArea(int full);
-void plat_status_msg(const char *format, ...)
-{
- va_list vl;
-
- va_start(vl, format);
- vsnprintf(noticeMsg, sizeof(noticeMsg), fmt, vl);
- va_end(vl);
-
- noticeMsgTime = sceKernelGetSystemTimeLow();
-}
-
int plat_get_root_dir(char *dst, int len)
{
if (len > 0) *dst = 0;
ret = sceAudio_38553111(samples_block/2, PsndRate, 2); // seems to not need that stupid 64byte alignment
if (ret < 0) {
lprintf("sceAudio_38553111() failed: %i\n", ret);
- plat_status_msg("sound init failed (%i), snd disabled", ret);
+ emu_status_msg("sound init failed (%i), snd disabled", ret);
currentConfig.EmuOpt &= ~EOPT_EN_SOUND;
} else {
PicoWriteSound = writeSound;
vidResetMode();
if (PicoOpt & POPT_ALT_RENDERER)
- plat_status_msg("fast renderer");
+ emu_status_msg("fast renderer");
else if (currentConfig.EmuOpt&0x80)
- plat_status_msg("accurate renderer");
+ emu_status_msg("accurate renderer");
}
if (which & 0x0300)
{
state_slot += 1;
if(state_slot > 9) state_slot = 0;
}
- plat_status_msg("SAVE SLOT %i [%s]", state_slot,
+ emu_status_msg("SAVE SLOT %i [%s]", state_slot,
emu_check_save_file(state_slot) ? "USED" : "FREE");
}
}