move emu loop to common; redo timing; add pollux timer

git-svn-id: file:///home/notaz/opt/svn/PicoDrive@721 be3aeb3a-fb24-0410-a615-afba39da0efa
This commit is contained in:
notaz 2009-07-31 22:01:03 +00:00
parent bbc8ceb9c0
commit b24e0f6ce6
13 changed files with 385 additions and 319 deletions

View file

@ -5,6 +5,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h>
#ifndef NO_SYNC #ifndef NO_SYNC
#include <unistd.h> #include <unistd.h>
#endif #endif
@ -44,6 +45,8 @@ char rom_fname_reload[512] = { 0, };
char rom_fname_loaded[512] = { 0, }; char rom_fname_loaded[512] = { 0, };
int rom_loaded = 0; int rom_loaded = 0;
int reset_timing = 0; int reset_timing = 0;
static unsigned int notice_msg_time; /* when started showing */
static char noticeMsg[40];
unsigned char *movie_data = NULL; unsigned char *movie_data = NULL;
static int movie_size = 0; static int movie_size = 0;
@ -86,6 +89,17 @@ static void get_ext(char *file, char *ext)
strlwr_(ext); strlwr_(ext);
} }
void emu_status_msg(const char *format, ...)
{
va_list vl;
va_start(vl, format);
vsnprintf(noticeMsg, sizeof(noticeMsg), format, vl);
va_end(vl);
notice_msg_time = plat_get_ticks_ms();
}
static const char *biosfiles_us[] = { "us_scd1_9210", "us_scd2_9306", "SegaCDBIOS9303" }; static const char *biosfiles_us[] = { "us_scd1_9210", "us_scd2_9306", "SegaCDBIOS9303" };
static const char *biosfiles_eu[] = { "eu_mcd1_9210", "eu_mcd2_9306", "eu_mcd2_9303" }; static const char *biosfiles_eu[] = { "eu_mcd1_9210", "eu_mcd2_9306", "eu_mcd2_9303" };
static const char *biosfiles_jp[] = { "jp_mcd1_9112", "jp_mcd1_9111" }; static const char *biosfiles_jp[] = { "jp_mcd1_9112", "jp_mcd1_9111" };
@ -485,12 +499,12 @@ int emu_reload_rom(char *rom_fname)
// TODO: bits 6 & 5 // TODO: bits 6 & 5
} }
movie_data[0x18+30] = 0; movie_data[0x18+30] = 0;
plat_status_msg("MOVIE: %s", (char *) &movie_data[0x18]); emu_status_msg("MOVIE: %s", (char *) &movie_data[0x18]);
} }
else else
{ {
PicoOpt &= ~POPT_DIS_VDP_FIFO; PicoOpt &= ~POPT_DIS_VDP_FIFO;
plat_status_msg(Pico.m.pal ? "PAL SYSTEM / 50 FPS" : "NTSC SYSTEM / 60 FPS"); emu_status_msg(Pico.m.pal ? "PAL SYSTEM / 50 FPS" : "NTSC SYSTEM / 60 FPS");
} }
// load SRAM for this ROM // load SRAM for this ROM
@ -702,7 +716,7 @@ void update_movie(void)
if (offs+3 > movie_size) { if (offs+3 > movie_size) {
free(movie_data); free(movie_data);
movie_data = 0; movie_data = 0;
plat_status_msg("END OF MOVIE."); emu_status_msg("END OF MOVIE.");
lprintf("END OF MOVIE.\n"); lprintf("END OF MOVIE.\n");
} else { } else {
// MXYZ SACB RLDU // MXYZ SACB RLDU
@ -824,7 +838,7 @@ int emu_save_load_game(int load, int sram)
saveFname = emu_get_save_fname(load, sram, state_slot); saveFname = emu_get_save_fname(load, sram, state_slot);
if (saveFname == NULL) { if (saveFname == NULL) {
if (!sram) if (!sram)
plat_status_msg(load ? "LOAD FAILED (missing file)" : "SAVE FAILED"); emu_status_msg(load ? "LOAD FAILED (missing file)" : "SAVE FAILED");
return -1; return -1;
} }
@ -910,10 +924,10 @@ int emu_save_load_game(int load, int sram)
} }
else ret = -1; else ret = -1;
if (!ret) if (!ret)
plat_status_msg(load ? "GAME LOADED" : "GAME SAVED"); emu_status_msg(load ? "GAME LOADED" : "GAME SAVED");
else else
{ {
plat_status_msg(load ? "LOAD FAILED" : "SAVE FAILED"); emu_status_msg(load ? "LOAD FAILED" : "SAVE FAILED");
ret = -1; ret = -1;
} }
@ -935,7 +949,7 @@ void emu_set_fastforward(int set_on)
currentConfig.EmuOpt &= ~4; currentConfig.EmuOpt &= ~4;
currentConfig.EmuOpt |= 0x40000; currentConfig.EmuOpt |= 0x40000;
is_on = 1; is_on = 1;
plat_status_msg("FAST FORWARD"); emu_status_msg("FAST FORWARD");
} }
else if (!set_on && is_on) { else if (!set_on && is_on) {
PsndOut = set_PsndOut; PsndOut = set_PsndOut;
@ -948,7 +962,7 @@ void emu_set_fastforward(int set_on)
static void emu_msg_tray_open(void) static void emu_msg_tray_open(void)
{ {
plat_status_msg("CD tray opened"); emu_status_msg("CD tray opened");
} }
void emu_reset_game(void) void emu_reset_game(void)
@ -966,9 +980,9 @@ void run_events_pico(unsigned int events)
if (pico_inp_mode > 2) if (pico_inp_mode > 2)
pico_inp_mode = 0; pico_inp_mode = 0;
switch (pico_inp_mode) { switch (pico_inp_mode) {
case 2: plat_status_msg("Input: Pen on Pad"); break; case 2: emu_status_msg("Input: Pen on Pad"); break;
case 1: plat_status_msg("Input: Pen on Storyware"); break; case 1: emu_status_msg("Input: Pen on Storyware"); break;
case 0: plat_status_msg("Input: Joystick"); case 0: emu_status_msg("Input: Joystick");
PicoPicohw.pen_pos[0] = PicoPicohw.pen_pos[1] = 0x8000; PicoPicohw.pen_pos[0] = PicoPicohw.pen_pos[1] = 0x8000;
break; break;
} }
@ -977,13 +991,13 @@ void run_events_pico(unsigned int events)
PicoPicohw.page--; PicoPicohw.page--;
if (PicoPicohw.page < 0) if (PicoPicohw.page < 0)
PicoPicohw.page = 0; PicoPicohw.page = 0;
plat_status_msg("Page %i", PicoPicohw.page); emu_status_msg("Page %i", PicoPicohw.page);
} }
if (events & PEV_PICO_PNEXT) { if (events & PEV_PICO_PNEXT) {
PicoPicohw.page++; PicoPicohw.page++;
if (PicoPicohw.page > 6) if (PicoPicohw.page > 6)
PicoPicohw.page = 6; PicoPicohw.page = 6;
plat_status_msg("Page %i", PicoPicohw.page); emu_status_msg("Page %i", PicoPicohw.page);
} }
if (pico_inp_mode == 0) if (pico_inp_mode == 0)
@ -1094,7 +1108,7 @@ static void run_events_ui(unsigned int which)
state_slot = 0; 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"); emu_check_save_file(state_slot) ? "USED" : "FREE");
} }
if (which & PEV_MENU) if (which & PEV_MENU)
@ -1194,3 +1208,205 @@ void emu_finish(void)
PicoExit(); PicoExit();
} }
static void skip_frame(int do_audio)
{
PicoSkipFrame = do_audio ? 1 : 2;
PicoFrame();
PicoSkipFrame = 0;
}
/* our tick here is 1 us right now */
#define ms_to_ticks(x) (unsigned int)(x * 1000)
#define get_ticks() plat_get_ticks_us()
void emu_loop(void)
{
int pframes_done; /* "period" frames, used for sync */
int frames_done, frames_shown; /* actual frames for fps counter */
int oldmodes, target_fps, target_frametime;
unsigned int timestamp_base = 0, timestamp_fps;
char *notice_msg = NULL;
char fpsbuff[24];
int i;
fpsbuff[0] = 0;
/* make sure we are in correct mode */
oldmodes = ((Pico.video.reg[12]&1)<<2) ^ 0xc;
Pico.m.dirtyPal = 1;
/* number of ticks per frame */
if (Pico.m.pal) {
target_fps = 50;
target_frametime = ms_to_ticks(1000) / 50;
} else {
target_fps = 60;
target_frametime = ms_to_ticks(1000) / 60 + 1;
}
// prepare CD buffer
if (PicoAHW & PAHW_MCD)
PicoCDBufferInit();
if (currentConfig.EmuOpt & EOPT_PSYNC)
plat_video_wait_vsync();
pemu_loop_prep();
timestamp_fps = get_ticks();
reset_timing = 1;
frames_done = frames_shown = pframes_done = 0;
/* loop with resync every 1 sec. */
while (engineState == PGS_Running)
{
unsigned int timestamp;
int diff, diff_lim;
int modes;
timestamp = get_ticks();
if (reset_timing) {
reset_timing = 0;
timestamp_base = timestamp;
pframes_done = 0;
}
// show notice_msg message?
if (notice_msg_time != 0)
{
static int noticeMsgSum;
if (timestamp - ms_to_ticks(notice_msg_time) > ms_to_ticks(2000)) {
notice_msg_time = 0;
plat_status_msg_clear();
notice_msg = NULL;
} else {
int sum = noticeMsg[0] + noticeMsg[1] + noticeMsg[2];
if (sum != noticeMsgSum) {
plat_status_msg_clear();
noticeMsgSum = sum;
}
notice_msg = noticeMsg;
}
}
// check for mode changes
modes = ((Pico.video.reg[12]&1)<<2) | (Pico.video.reg[1]&8);
if (modes != oldmodes) {
oldmodes = modes;
pemu_video_mode_change(!(modes & 4), (modes & 8));
}
// second changed?
if (timestamp - timestamp_fps >= ms_to_ticks(1000))
{
#ifdef BENCHMARK
static int bench = 0, bench_fps = 0, bench_fps_s = 0, bfp = 0, bf[4];
if (++bench == 10) {
bench = 0;
bench_fps_s = bench_fps;
bf[bfp++ & 3] = bench_fps;
bench_fps = 0;
}
bench_fps += frames_shown;
sprintf(fpsbuff, "%02i/%02i/%02i", frames_shown, bench_fps_s, (bf[0]+bf[1]+bf[2]+bf[3])>>2);
#else
if (currentConfig.EmuOpt & EOPT_SHOW_FPS) {
sprintf(fpsbuff, "%02i/%02i", frames_shown, frames_done);
if (fpsbuff[5] == 0) { fpsbuff[5] = fpsbuff[6] = ' '; fpsbuff[7] = 0; }
}
#endif
frames_shown = frames_done = 0;
timestamp_fps += ms_to_ticks(1000);
}
#ifdef PFRAMES
sprintf(fpsbuff, "%i", Pico.m.frame_count);
#endif
if (timestamp - timestamp_base >= ms_to_ticks(1000))
{
if (PsndOut == 0 && currentConfig.Frameskip >= 0)
pframes_done = 0;
else
pframes_done -= target_fps;
timestamp_base += ms_to_ticks(1000);
}
diff = timestamp - timestamp_base;
diff_lim = (pframes_done + 1) * target_frametime;
if (currentConfig.Frameskip >= 0) // frameskip enabled
{
for (i = 0; i < currentConfig.Frameskip; i++) {
emu_update_input();
skip_frame(1);
pframes_done++; frames_done++;
diff_lim += target_frametime;
if (PsndOut && !reset_timing) { // do framelimitting if sound is enabled
timestamp = get_ticks();
diff = timestamp - timestamp_base;
if (diff < diff_lim) // we are too fast
plat_wait_till_us(timestamp_base + diff_lim);
}
}
}
else if (diff > diff_lim)
{
/* no time left for this frame - skip */
if (diff - diff_lim >= ms_to_ticks(300)) {
/* if too much behind, reset instead */
reset_timing = 1;
continue;
}
emu_update_input();
skip_frame(diff < diff_lim + target_frametime * 2);
pframes_done++; frames_done++;
continue;
}
emu_update_input();
PicoFrame();
/* frame limiter */
if (!reset_timing && (PsndOut != NULL || currentConfig.Frameskip < 0))
{
timestamp = get_ticks();
diff = timestamp - timestamp_base;
// sleep or vsync if we are still too fast
if (diff < diff_lim)
{
// we are too fast
if (currentConfig.EmuOpt & EOPT_PSYNC) {
if (diff_lim - diff > target_frametime/2)
plat_wait_till_us(timestamp_base + target_frametime/4);
plat_video_wait_vsync();
} else
plat_wait_till_us(timestamp_base + diff_lim);
}
}
pemu_update_display(fpsbuff, notice_msg);
pframes_done++; frames_done++; frames_shown++;
}
emu_set_fastforward(0);
if (PicoAHW & PAHW_MCD)
PicoCDBufferFree();
// save SRAM
if ((currentConfig.EmuOpt & EOPT_EN_SRAM) && SRam.changed) {
plat_status_msg_busy_first("Writing SRAM/BRAM...");
emu_save_load_game(0, 1);
SRam.changed = 0;
}
// do menu background to be sure it's right
pemu_forced_frame(POPT_EN_SOFTSCALE);
pemu_loop_end();
}

View file

@ -99,6 +99,7 @@ enum TPicoGameState {
void emu_init(void); void emu_init(void);
void emu_finish(void); void emu_finish(void);
void emu_loop(void);
int emu_reload_rom(char *rom_fname); int emu_reload_rom(char *rom_fname);
int emu_save_load_game(int load, int sram); int emu_save_load_game(int load, int sram);
@ -122,6 +123,7 @@ void emu_update_input(void);
void emu_get_game_name(char *str150); void emu_get_game_name(char *str150);
void emu_set_fastforward(int set_on); void emu_set_fastforward(int set_on);
int emu_cd_check(int *pregion, char *fname_in); int emu_cd_check(int *pregion, char *fname_in);
void emu_status_msg(const char *format, ...);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"

View file

@ -117,7 +117,7 @@ int main(int argc, char *argv[])
engineState = PGS_Running; engineState = PGS_Running;
case PGS_Running: case PGS_Running:
pemu_loop(); emu_loop();
break; break;
case PGS_Quit: case PGS_Quit:

View file

@ -6,8 +6,12 @@ extern "C" {
extern char cpu_clk_name[]; extern char cpu_clk_name[];
void pemu_prep_defconfig(void); 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_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_start(void);
void pemu_sound_stop(void); void pemu_sound_stop(void);
void pemu_sound_wait(void); void pemu_sound_wait(void);
@ -22,18 +26,17 @@ void plat_finish(void);
/* return the dir/ where configs, saves, bios, etc. are found */ /* return the dir/ where configs, saves, bios, etc. are found */
int plat_get_root_dir(char *dst, int len); 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) */ /* 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_first(const char *msg);
void plat_status_msg_busy_next(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 */ /* menu: enter (switch bpp, etc), begin/end drawing */
void plat_video_menu_enter(int is_rom_loaded); void plat_video_menu_enter(int is_rom_loaded);
void plat_video_menu_begin(void); void plat_video_menu_begin(void);
void plat_video_menu_end(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_video_toggle_renderer(int is_next, int is_menu);
void plat_validate_config(void); void plat_validate_config(void);
void plat_update_volume(int has_changed, int is_up); void plat_update_volume(int has_changed, int is_up);
@ -42,8 +45,10 @@ int plat_is_dir(const char *path);
int plat_wait_event(int *fds_hnds, int count, int timeout_ms); int plat_wait_event(int *fds_hnds, int count, int timeout_ms);
void plat_sleep_ms(int ms); void plat_sleep_ms(int ms);
/* ms counter, to be used for time diff */ /* 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_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); void plat_debug_cat(char *str);

View file

@ -28,7 +28,6 @@
unsigned char gfx_buffer[321*240*2*2]; unsigned char gfx_buffer[321*240*2*2];
unsigned char *PicoDraw2FB = gfx_buffer; // temporary buffer for alt renderer ( (8+320)*(8+240+8) ) 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 short *snd_cbuff = NULL;
static int snd_cbuf_samples = 0, snd_all_samples = 0; static int snd_cbuf_samples = 0, snd_all_samples = 0;
@ -36,12 +35,6 @@ static int snd_cbuf_samples = 0, snd_all_samples = 0;
static void blit(const char *fps, const char *notice); static void blit(const char *fps, const char *notice);
static void clearArea(int full); static void clearArea(int full);
void plat_status_msg(const char *format, ...)
{
/* TODO */
noticeMsgTime = GetTickCount();
}
int plat_get_root_dir(char *dst, int len) int plat_get_root_dir(char *dst, int len)
{ {
if (len > 0) *dst = 0; if (len > 0) *dst = 0;

View file

@ -5,8 +5,6 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/time.h>
#include <stdarg.h>
#include "plat_gp2x.h" #include "plat_gp2x.h"
#include "soc.h" #include "soc.h"
@ -36,25 +34,12 @@
extern int crashed_940; extern int crashed_940;
static short __attribute__((aligned(4))) sndBuffer[2*44100/50]; static short __attribute__((aligned(4))) sndBuffer[2*44100/50];
static struct timeval noticeMsgTime = { 0, 0 }; // when started showing
static char noticeMsg[40];
static unsigned char PicoDraw2FB_[(8+320) * (8+240+8)]; static unsigned char PicoDraw2FB_[(8+320) * (8+240+8)];
unsigned char *PicoDraw2FB = PicoDraw2FB_; unsigned char *PicoDraw2FB = PicoDraw2FB_;
static int osd_fps_x; static int osd_fps_x;
extern void *gp2x_screens[4]; extern void *gp2x_screens[4];
void plat_status_msg(const char *format, ...)
{
va_list vl;
va_start(vl, format);
vsnprintf(noticeMsg, sizeof(noticeMsg), format, vl);
va_end(vl);
gettimeofday(&noticeMsgTime, 0);
}
int plat_get_root_dir(char *dst, int len) int plat_get_root_dir(char *dst, int len)
{ {
extern char **g_argv; extern char **g_argv;
@ -289,7 +274,7 @@ static int EmuScanEnd8_rot(unsigned int num)
int localPal[0x100]; int localPal[0x100];
static void (*vidcpyM2)(void *dest, void *src, int m32col, int with_32c_border) = NULL; static void (*vidcpyM2)(void *dest, void *src, int m32col, int with_32c_border) = NULL;
static void blit(const char *fps, const char *notice) void pemu_update_display(const char *fps, const char *notice)
{ {
int emu_opt = currentConfig.EmuOpt; int emu_opt = currentConfig.EmuOpt;
@ -360,11 +345,42 @@ static void blit(const char *fps, const char *notice)
gp2x_video_flip(); gp2x_video_flip();
} }
// clears whole screen or just the notice area (in all buffers) /* XXX */
static void clearArea(int full) #ifdef __GP2X__
unsigned int plat_get_ticks_ms(void)
{
return gp2x_get_ticks_ms();
}
unsigned int plat_get_ticks_us(void)
{
return gp2x_get_ticks_us();
}
#endif
void plat_wait_till_us(unsigned int us_to)
{
unsigned int now;
spend_cycles(1024);
now = plat_get_ticks_us();
while ((signed int)(us_to - now) > 512)
{
spend_cycles(1024);
now = plat_get_ticks_us();
}
}
void plat_video_wait_vsync(void)
{
gp2x_video_wait_vsync();
}
void plat_status_msg_clear(void)
{ {
int is_8bit = (PicoOpt & POPT_ALT_RENDERER) || !(currentConfig.EmuOpt & EOPT_16BPP); int is_8bit = (PicoOpt & POPT_ALT_RENDERER) || !(currentConfig.EmuOpt & EOPT_16BPP);
if (!full && (currentConfig.EmuOpt & EOPT_WIZ_TEAR_FIX)) { if (currentConfig.EmuOpt & EOPT_WIZ_TEAR_FIX) {
/* ugh.. */ /* ugh.. */
int i, u, *p; int i, u, *p;
if (is_8bit) { if (is_8bit) {
@ -383,21 +399,16 @@ static void clearArea(int full)
return; return;
} }
if (is_8bit) { if (is_8bit)
// 8-bit renderers gp2x_memset_all_buffers(320*232, 0xe0, 320*8);
if (full) gp2x_memset_all_buffers(0, 0xe0, 320*240); else
else gp2x_memset_all_buffers(320*232, 0xe0, 320*8); gp2x_memset_all_buffers(320*232*2, 0, 320*8*2);
} else {
// 16bit accurate renderer
if (full) gp2x_memset_all_buffers(0, 0, 320*240*2);
else gp2x_memset_all_buffers(320*232*2, 0, 320*8*2);
}
} }
void plat_status_msg_busy_next(const char *msg) void plat_status_msg_busy_next(const char *msg)
{ {
clearArea(0); plat_status_msg_clear();
blit("", msg); pemu_update_display("", msg);
/* assumption: msg_busy_next gets called only when /* assumption: msg_busy_next gets called only when
* something slow is about to happen */ * something slow is about to happen */
@ -494,11 +505,11 @@ void plat_video_toggle_renderer(int is_next, int is_menu)
vidResetMode(); vidResetMode();
if (PicoOpt & POPT_ALT_RENDERER) { if (PicoOpt & POPT_ALT_RENDERER) {
plat_status_msg(" 8bit fast renderer"); emu_status_msg(" 8bit fast renderer");
} else if (currentConfig.EmuOpt & EOPT_16BPP) { } else if (currentConfig.EmuOpt & EOPT_16BPP) {
plat_status_msg("16bit accurate renderer"); emu_status_msg("16bit accurate renderer");
} else { } else {
plat_status_msg(" 8bit accurate renderer"); emu_status_msg(" 8bit accurate renderer");
} }
} }
@ -560,7 +571,7 @@ void plat_update_volume(int has_changed, int is_up)
sndout_oss_setvol(vol, vol); sndout_oss_setvol(vol, vol);
currentConfig.volume = vol; currentConfig.volume = vol;
} }
plat_status_msg("VOL: %02i", vol); emu_status_msg("VOL: %02i", vol);
prev_frame = Pico.m.frame_count; prev_frame = Pico.m.frame_count;
} }
@ -576,10 +587,10 @@ void plat_update_volume(int has_changed, int is_up)
} }
} }
static void updateSound(int len) static void updateSound(int len)
{ {
if (PicoOpt&8) len<<=1; if (PicoOpt & POPT_EN_STEREO)
len <<= 1;
/* avoid writing audio when lagging behind to prevent audio lag */ /* avoid writing audio when lagging behind to prevent audio lag */
if (PicoSkipFrame != 2) if (PicoSkipFrame != 2)
@ -626,14 +637,6 @@ void pemu_sound_wait(void)
} }
static void SkipFrame(int do_audio)
{
PicoSkipFrame=do_audio ? 1 : 2;
PicoFrame();
PicoSkipFrame=0;
}
void pemu_forced_frame(int opts) void pemu_forced_frame(int opts)
{ {
int po_old = PicoOpt; int po_old = PicoOpt;
@ -657,22 +660,26 @@ void plat_debug_cat(char *str)
{ {
} }
static void simpleWait(int thissec, int lim_time) void pemu_video_mode_change(int is_32col, int is_240_lines)
{ {
struct timeval tval; int scalex = 320;
osd_fps_x = OSD_FPS_X;
spend_cycles(1024); if (is_32col && (PicoOpt & POPT_DIS_32C_BORDER)) {
gettimeofday(&tval, 0); scalex = 256;
if (thissec != tval.tv_sec) tval.tv_usec+=1000000; osd_fps_x = OSD_FPS_X - 64;
while (tval.tv_usec < lim_time)
{
spend_cycles(1024);
gettimeofday(&tval, 0);
if (thissec != tval.tv_sec) tval.tv_usec+=1000000;
} }
} /* want vertical scaling and game is not in 240 line mode */
if (currentConfig.scaling == EOPT_SCALE_HW_HV && !is_240_lines)
gp2x_video_RGB_setscaling(8, scalex, 224);
else
gp2x_video_RGB_setscaling(0, scalex, 240);
// clear whole screen in all buffers
if ((PicoOpt & POPT_ALT_RENDERER) || !(currentConfig.EmuOpt & EOPT_16BPP))
gp2x_memset_all_buffers(0, 0xe0, 320*240);
else
gp2x_memset_all_buffers(0, 0, 320*240*2);
}
#if 0 #if 0
static void tga_dump(void) static void tga_dump(void)
@ -722,19 +729,10 @@ static void tga_dump(void)
} }
#endif #endif
void pemu_loop_prep(void)
void pemu_loop(void)
{ {
static int gp2x_old_clock = -1, EmuOpt_old = 0, pal_old = 0; static int gp2x_old_clock = -1, EmuOpt_old = 0, pal_old = 0;
static int gp2x_old_gamma = 100; static int gp2x_old_gamma = 100;
char fpsbuff[24]; // fps count c string
struct timeval tval; // timing
int pframes_done, pframes_shown, pthissec; // "period" frames, used for sync
int frames_done, frames_shown, thissec; // actual frames
int oldmodes = 0, target_fps, target_frametime, lim_time, vsync_offset, i;
char *notice = 0;
printf("entered emu_Loop()\n");
if ((EmuOpt_old ^ currentConfig.EmuOpt) & EOPT_RAM_TIMINGS) { if ((EmuOpt_old ^ currentConfig.EmuOpt) & EOPT_RAM_TIMINGS) {
if (currentConfig.EmuOpt & EOPT_RAM_TIMINGS) if (currentConfig.EmuOpt & EOPT_RAM_TIMINGS)
@ -770,206 +768,16 @@ void pemu_loop(void)
EmuOpt_old = currentConfig.EmuOpt; EmuOpt_old = currentConfig.EmuOpt;
pal_old = Pico.m.pal; pal_old = Pico.m.pal;
fpsbuff[0] = 0;
// make sure we are in correct mode // make sure we are in correct mode
vidResetMode(); vidResetMode();
scaling_update(); scaling_update();
Pico.m.dirtyPal = 1;
oldmodes = ((Pico.video.reg[12]&1)<<2) ^ 0xc;
// pal/ntsc might have changed, reset related stuff
target_fps = Pico.m.pal ? 50 : 60;
target_frametime = 1000000/target_fps;
reset_timing = 1;
pemu_sound_start(); pemu_sound_start();
}
// prepare CD buffer void pemu_loop_end(void)
if (PicoAHW & PAHW_MCD) PicoCDBufferInit(); {
// calc vsync offset to sync timing code with vsync
if (currentConfig.EmuOpt & EOPT_PSYNC) {
gettimeofday(&tval, 0);
gp2x_video_wait_vsync();
gettimeofday(&tval, 0);
vsync_offset = tval.tv_usec;
while (vsync_offset >= target_frametime)
vsync_offset -= target_frametime;
if (!vsync_offset) vsync_offset++;
printf("vsync_offset: %i\n", vsync_offset);
} else
vsync_offset = 0;
frames_done = frames_shown = thissec =
pframes_done = pframes_shown = pthissec = 0;
// loop
while (engineState == PGS_Running)
{
int modes;
gettimeofday(&tval, 0);
if (reset_timing) {
reset_timing = 0;
pthissec = tval.tv_sec;
pframes_shown = pframes_done = tval.tv_usec/target_frametime;
}
// show notice message?
if (noticeMsgTime.tv_sec)
{
static int noticeMsgSum;
if((tval.tv_sec*1000000+tval.tv_usec) - (noticeMsgTime.tv_sec*1000000+noticeMsgTime.tv_usec) > 2000000) { // > 2.0 sec
noticeMsgTime.tv_sec = noticeMsgTime.tv_usec = 0;
clearArea(0);
notice = 0;
} else {
int sum = noticeMsg[0]+noticeMsg[1]+noticeMsg[2];
if (sum != noticeMsgSum) { clearArea(0); noticeMsgSum = sum; }
notice = noticeMsg;
}
}
// check for mode changes
modes = ((Pico.video.reg[12]&1)<<2)|(Pico.video.reg[1]&8);
if (modes != oldmodes)
{
int scalex = 320;
osd_fps_x = OSD_FPS_X;
if (!(modes & 4) && (PicoOpt & POPT_DIS_32C_BORDER)) {
scalex = 256;
osd_fps_x = OSD_FPS_X - 64;
}
/* want vertical scaling and game is not in 240 line mode */
if (currentConfig.scaling == EOPT_SCALE_HW_HV && !(modes&8))
gp2x_video_RGB_setscaling(8, scalex, 224);
else gp2x_video_RGB_setscaling(0, scalex, 240);
oldmodes = modes;
clearArea(1);
}
// second changed?
if (thissec != tval.tv_sec)
{
#ifdef BENCHMARK
static int bench = 0, bench_fps = 0, bench_fps_s = 0, bfp = 0, bf[4];
if (++bench == 10) {
bench = 0;
bench_fps_s = bench_fps;
bf[bfp++ & 3] = bench_fps;
bench_fps = 0;
}
bench_fps += frames_shown;
sprintf(fpsbuff, "%02i/%02i/%02i", frames_shown, bench_fps_s, (bf[0]+bf[1]+bf[2]+bf[3])>>2);
#else
if (currentConfig.EmuOpt & 2) {
sprintf(fpsbuff, "%02i/%02i", frames_shown, frames_done);
if (fpsbuff[5] == 0) { fpsbuff[5] = fpsbuff[6] = ' '; fpsbuff[7] = 0; }
}
#endif
frames_shown = frames_done = 0;
thissec = tval.tv_sec;
}
#ifdef PFRAMES
sprintf(fpsbuff, "%i", Pico.m.frame_count);
#endif
if (pthissec != tval.tv_sec)
{
if (PsndOut == 0 && currentConfig.Frameskip >= 0) {
pframes_done = pframes_shown = 0;
} else {
// it is quite common for this implementation to leave 1 fame unfinished
// when second changes, but we don't want buffer to starve.
if (PsndOut && pframes_done < target_fps && pframes_done > target_fps-5) {
emu_update_input();
SkipFrame(1); pframes_done++;
}
pframes_done -= target_fps; if (pframes_done < 0) pframes_done = 0;
pframes_shown -= target_fps; if (pframes_shown < 0) pframes_shown = 0;
if (pframes_shown > pframes_done) pframes_shown = pframes_done;
}
pthissec = tval.tv_sec;
}
lim_time = (pframes_done+1) * target_frametime + vsync_offset;
if (currentConfig.Frameskip >= 0) // frameskip enabled
{
for(i = 0; i < currentConfig.Frameskip; i++) {
emu_update_input();
SkipFrame(1); pframes_done++; frames_done++;
if (PsndOut && !reset_timing) { // do framelimitting if sound is enabled
gettimeofday(&tval, 0);
if (pthissec != tval.tv_sec) tval.tv_usec+=1000000;
if (tval.tv_usec < lim_time) { // we are too fast
simpleWait(pthissec, lim_time);
}
}
lim_time += target_frametime;
}
}
else if (tval.tv_usec > lim_time) // auto frameskip
{
// no time left for this frame - skip
if (tval.tv_usec - lim_time >= 300000) {
/* something caused a slowdown for us (disk access? cache flush?)
* try to recover by resetting timing... */
reset_timing = 1;
continue;
}
emu_update_input();
SkipFrame(tval.tv_usec < lim_time+target_frametime*2); pframes_done++; frames_done++;
continue;
}
emu_update_input();
PicoFrame();
// check time
gettimeofday(&tval, 0);
if (pthissec != tval.tv_sec) tval.tv_usec+=1000000;
if (currentConfig.Frameskip < 0 && tval.tv_usec - lim_time >= 300000) // slowdown detection
reset_timing = 1;
else if (PsndOut != NULL || currentConfig.Frameskip < 0)
{
// sleep or vsync if we are still too fast
// usleep sleeps for ~20ms minimum, so it is not a solution here
if (!reset_timing && tval.tv_usec < lim_time)
{
// we are too fast
if (vsync_offset) {
if (lim_time - tval.tv_usec > target_frametime/2)
simpleWait(pthissec, lim_time - target_frametime/4);
gp2x_video_wait_vsync();
} else {
simpleWait(pthissec, lim_time);
}
}
}
blit(fpsbuff, notice);
pframes_done++; pframes_shown++;
frames_done++; frames_shown++;
}
emu_set_fastforward(0);
if (PicoAHW & PAHW_MCD)
PicoCDBufferFree();
// save SRAM
if ((currentConfig.EmuOpt & EOPT_EN_SRAM) && SRam.changed) {
plat_status_msg_busy_first("Writing SRAM/BRAM...");
emu_save_load_game(0, 1);
SRam.changed = 0;
}
// do menu background to be sure it's right
pemu_forced_frame(POPT_EN_SOFTSCALE);
} }
const char *plat_get_credits(void) const char *plat_get_credits(void)

View file

@ -25,6 +25,9 @@ void (*set_ram_timings)(void);
void (*unset_ram_timings)(void); void (*unset_ram_timings)(void);
int (*gp2x_read_battery)(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) gp2x_soc_t soc_detect(void)
{ {

View file

@ -30,3 +30,6 @@ extern void (*set_ram_timings)(void);
extern void (*unset_ram_timings)(void); extern void (*unset_ram_timings)(void);
extern int (*gp2x_read_battery)(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);

View file

@ -12,6 +12,7 @@
#include "soc_mmsp2.h" #include "soc_mmsp2.h"
#include "plat_gp2x.h" #include "plat_gp2x.h"
#include "../common/emu.h" #include "../common/emu.h"
#include "../common/plat.h"
#include "../common/arm_utils.h" #include "../common/arm_utils.h"
#include "940ctl.h" #include "940ctl.h"
@ -40,6 +41,8 @@ static unsigned short gp2x_screenaddr_old[4];
static unsigned short memtimex_old[2]; static unsigned short memtimex_old[2];
static unsigned short reg0910; static unsigned short reg0910;
extern unsigned int plat_get_ticks_ms_gtod(void);
extern unsigned int plat_get_ticks_us_gtod(void);
/* video stuff */ /* video stuff */
static void gp2x_video_flip_(void) static void gp2x_video_flip_(void)
@ -508,6 +511,9 @@ void mmsp2_init(void)
set_ram_timings = set_ram_timings_; set_ram_timings = set_ram_timings_;
unset_ram_timings = unset_ram_timings_; unset_ram_timings = unset_ram_timings_;
gp2x_read_battery = gp2x_read_battery_; 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) void mmsp2_finish(void)

View file

@ -208,6 +208,31 @@ static int gp2x_read_battery_(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) void pollux_init(void)
{ {
struct fb_fix_screeninfo fbfix; struct fb_fix_screeninfo fbfix;
@ -264,6 +289,14 @@ void pollux_init(void)
if (battdev < 0) if (battdev < 0)
perror("Warning: could't open pollux_batt"); 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]; pllsetreg0 = memregl[0xf004>>2];
memtimex_old[0] = memregs[0x14802>>1]; memtimex_old[0] = memregs[0x14802>>1];
memtimex_old[1] = memregs[0x14804>>1]; memtimex_old[1] = memregs[0x14804>>1];
@ -284,6 +317,9 @@ void pollux_init(void)
set_ram_timings = set_ram_timings_; set_ram_timings = set_ram_timings_;
unset_ram_timings = unset_ram_timings_; unset_ram_timings = unset_ram_timings_;
gp2x_read_battery = gp2x_read_battery_; 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) void pollux_finish(void)

View file

@ -17,6 +17,12 @@ int plat_is_dir(const char *path)
return 0; 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) unsigned int plat_get_ticks_ms(void)
{ {
struct timeval tv; struct timeval tv;
@ -25,12 +31,25 @@ unsigned int plat_get_ticks_ms(void)
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
ret = (unsigned)tv.tv_sec * 1000; ret = (unsigned)tv.tv_sec * 1000;
/* approximate division */ /* approximate /= 1000 */
ret += ((unsigned)tv.tv_usec * 4195) >> 22; ret += ((unsigned)tv.tv_usec * 4195) >> 22;
return ret; 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) void plat_sleep_ms(int ms)
{ {
usleep(ms * 1000); usleep(ms * 1000);

View file

@ -34,7 +34,6 @@
static short __attribute__((aligned(4))) sndBuffer[2*44100/50]; static short __attribute__((aligned(4))) sndBuffer[2*44100/50];
static struct timeval noticeMsgTime = { 0, 0 }; // when started showing
static int osd_fps_x; static int osd_fps_x;
unsigned char *PicoDraw2FB = NULL; // temporary buffer for alt renderer unsigned char *PicoDraw2FB = NULL; // temporary buffer for alt renderer
@ -43,17 +42,6 @@ unsigned char *PicoDraw2FB = NULL; // temporary buffer for alt renderer
static int pico_pen_x = 0, pico_pen_y = 240/2; static int pico_pen_x = 0, pico_pen_y = 240/2;
void plat_status_msg(const char *format, ...)
{
va_list vl;
va_start(vl, format);
vsnprintf(noticeMsg, sizeof(noticeMsg), fmt, vl);
va_end(vl);
gettimeofday(&noticeMsgTime, 0);
}
int plat_get_root_dir(char *dst, int len) int plat_get_root_dir(char *dst, int len)
{ {
extern char **g_argv; extern char **g_argv;

View file

@ -36,8 +36,6 @@ int sceAudioOutput2GetRestSample();
unsigned char *PicoDraw2FB = (unsigned char *)VRAM_CACHED_STUFF + 8; // +8 to be able to skip border with 1 quadword.. unsigned char *PicoDraw2FB = (unsigned char *)VRAM_CACHED_STUFF + 8; // +8 to be able to skip border with 1 quadword..
int engineStateSuspend; int engineStateSuspend;
static unsigned int noticeMsgTime = 0;
#define PICO_PEN_ADJUST_X 4 #define PICO_PEN_ADJUST_X 4
#define PICO_PEN_ADJUST_Y 2 #define PICO_PEN_ADJUST_Y 2
static int pico_pen_x = 320/2, pico_pen_y = 240/2; static int pico_pen_x = 320/2, pico_pen_y = 240/2;
@ -47,17 +45,6 @@ static void sound_deinit(void);
static void blit2(const char *fps, const char *notice, int lagging_behind); static void blit2(const char *fps, const char *notice, int lagging_behind);
static void clearArea(int full); 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) int plat_get_root_dir(char *dst, int len)
{ {
if (len > 0) *dst = 0; if (len > 0) *dst = 0;
@ -610,7 +597,7 @@ void pemu_sound_start(void)
ret = sceAudio_38553111(samples_block/2, PsndRate, 2); // seems to not need that stupid 64byte alignment ret = sceAudio_38553111(samples_block/2, PsndRate, 2); // seems to not need that stupid 64byte alignment
if (ret < 0) { if (ret < 0) {
lprintf("sceAudio_38553111() failed: %i\n", ret); 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; currentConfig.EmuOpt &= ~EOPT_EN_SOUND;
} else { } else {
PicoWriteSound = writeSound; PicoWriteSound = writeSound;
@ -782,9 +769,9 @@ static void RunEvents(unsigned int which)
vidResetMode(); vidResetMode();
if (PicoOpt & POPT_ALT_RENDERER) if (PicoOpt & POPT_ALT_RENDERER)
plat_status_msg("fast renderer"); emu_status_msg("fast renderer");
else if (currentConfig.EmuOpt&0x80) else if (currentConfig.EmuOpt&0x80)
plat_status_msg("accurate renderer"); emu_status_msg("accurate renderer");
} }
if (which & 0x0300) if (which & 0x0300)
{ {
@ -795,7 +782,7 @@ static void RunEvents(unsigned int which)
state_slot += 1; state_slot += 1;
if(state_slot > 9) state_slot = 0; 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"); emu_check_save_file(state_slot) ? "USED" : "FREE");
} }
} }