include Makefile.common
up: fceu
- cp -v fceu /mnt/gp2x/mnt/sd/emus/gpfce/gpfce
+ cp -v fceu /mnt/gp2x/mnt/sd/emus/gpfce/gpfce.gpe
# ----------- release -----------
ifneq ($(findstring rel,$(MAKECMDGOALS)),)
/* cpuctrl for GP2X
- Copyright (C) 2005 Hermes/PS2Reality
+ Copyright (C) 2005 Hermes/PS2Reality
the gamma-routine was provided by theoddbot
- parts (c) Rlyehs Work & (C) 2006 god_at_hell
+ parts (c) Rlyehs Work & (C) 2006 god_at_hell
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
*/
-#include <sys/mman.h>
+#include <stdio.h>
#include <math.h>
#include "cpuctrl.h"
/* system registers */
-static struct
+static struct
{
- unsigned short SYSCLKENREG,SYSCSETREG,FPLLVSETREG,DUALINT920,DUALINT940,DUALCTRL940,MEMTIMEX0,MEMTIMEX1;
+ unsigned short SYSCLKENREG,SYSCSETREG,UPLLVSETREG,FPLLVSETREG,
+ DUALINT920,DUALINT940,DUALCTRL940,MEMTIMEX0,MEMTIMEX1,DISPCSETREG,
+ DPC_HS_WIDTH,DPC_HS_STR,DPC_HS_END,DPC_VS_END,DPC_DE;
}
system_reg;
-static unsigned short dispclockdiv;
-
static volatile unsigned short *MEM_REG;
#define SYS_CLK_FREQ 7372800
+// Fout = (m * Fin) / (p * 2^s)
+// m = MDIV+8, p = PDIV+2, s = SDIV
+
+// m = (Fout * p * 2^s) / Fin
void cpuctrl_init(void)
{
extern volatile unsigned short *gp2x_memregs; /* from minimal library rlyeh */
MEM_REG=&gp2x_memregs[0];
- system_reg.SYSCSETREG=MEM_REG[0x91c>>1];
+ system_reg.DISPCSETREG=MEM_REG[0x924>>1];
+ system_reg.UPLLVSETREG=MEM_REG[0x916>>1];
system_reg.FPLLVSETREG=MEM_REG[0x912>>1];
+ system_reg.SYSCSETREG=MEM_REG[0x91c>>1];
system_reg.SYSCLKENREG=MEM_REG[0x904>>1];
system_reg.DUALINT920=MEM_REG[0x3B40>>1];
system_reg.DUALINT940=MEM_REG[0x3B42>>1];
system_reg.DUALCTRL940=MEM_REG[0x3B48>>1];
system_reg.MEMTIMEX0=MEM_REG[0x3802>>1];
system_reg.MEMTIMEX1=MEM_REG[0x3804>>1];
- dispclockdiv=MEM_REG[0x924>>1];
+ system_reg.DPC_HS_WIDTH=MEM_REG[0x281A>>1];
+ system_reg.DPC_HS_STR=MEM_REG[0x281C>>1];
+ system_reg.DPC_HS_END=MEM_REG[0x281E>>1];
+ system_reg.DPC_VS_END=MEM_REG[0x2822>>1];
+ system_reg.DPC_DE=MEM_REG[0x2826>>1];
}
void cpuctrl_deinit(void)
{
- MEM_REG[0x91c>>1]=system_reg.SYSCSETREG;
MEM_REG[0x910>>1]=system_reg.FPLLVSETREG;
+ MEM_REG[0x91c>>1]=system_reg.SYSCSETREG;
MEM_REG[0x3B40>>1]=system_reg.DUALINT920;
MEM_REG[0x3B42>>1]=system_reg.DUALINT940;
MEM_REG[0x3B48>>1]=system_reg.DUALCTRL940;
MEM_REG[0x904>>1]=system_reg.SYSCLKENREG;
- MEM_REG[0x924>>1]=dispclockdiv;
MEM_REG[0x3802>>1]=system_reg.MEMTIMEX0;
MEM_REG[0x3804>>1]=system_reg.MEMTIMEX1 /*| 0x9000*/;
+ unset_LCD_custom_rate();
}
{
unsigned short v;
v = MEM_REG[0x91c>>1] & (~0x3);
- MEM_REG[0x91c>>1] = (div & 0x7) | v;
+ MEM_REG[0x91c>>1] = (div & 0x7) | v;
}
{
unsigned short v;
v = (unsigned short)( MEM_REG[0x91c>>1] & (~(0x7 << 6)) );
- MEM_REG[0x91c>>1] = ((div & 0x7) << 6) | v;
+ MEM_REG[0x91c>>1] = ((div & 0x7) << 6) | v;
}
/*
{
MEM_REG[0x3B42>>1];
MEM_REG[0x3B42>>1]=0;
- MEM_REG[0x3B46>>1]=0xffff;
+ MEM_REG[0x3B46>>1]=0xffff;
MEM_REG[0x3B48>>1]|= (1 << 7);
MEM_REG[0x904>>1]&=0xfffe;
}
*/
+
+typedef struct
+{
+ unsigned short reg, valmask, val;
+}
+reg_setting;
+
+// ~59.998, couldn't figure closer values
+static reg_setting rate_almost60[] =
+{
+ { 0x0914, 0xffff, (212<<8)|(2<<2)|1 }, /* UPLLSETVREG */
+ { 0x0924, 0xff00, (2<<14)|(36<<8) }, /* DISPCSETREG */
+ { 0x281A, 0x00ff, 1 }, /* .HSWID(T2) */
+ { 0x281C, 0x00ff, 0 }, /* .HSSTR(T8) */
+ { 0x281E, 0x00ff, 2 }, /* .HSEND(T7) */
+ { 0x2822, 0x01ff, 12 }, /* .VSEND (T9) */
+ { 0x2826, 0x0ff0, 34<<4 }, /* .DESTR(T3) */
+ { 0, 0, 0 }
+};
+
+// perfect 50Hz?
+static reg_setting rate_50[] =
+{
+ { 0x0914, 0xffff, (39<<8)|(0<<2)|2 }, /* UPLLSETVREG */
+ { 0x0924, 0xff00, (2<<14)|(7<<8) }, /* DISPCSETREG */
+ { 0x281A, 0x00ff, 31 }, /* .HSWID(T2) */
+ { 0x281C, 0x00ff, 16 }, /* .HSSTR(T8) */
+ { 0x281E, 0x00ff, 15 }, /* .HSEND(T7) */
+ { 0x2822, 0x01ff, 15 }, /* .VSEND (T9) */
+ { 0x2826, 0x0ff0, 37<<4 }, /* .DESTR(T3) */
+ { 0, 0, 0 }
+};
+
+// 16639/2 ~120.20
+static reg_setting rate_120_20[] =
+{
+ { 0x0914, 0xffff, (203<<8)|(2<<2)|1 }, /* UPLLSETVREG */
+ { 0x0924, 0xff00, (2<<14)|(14<<8) }, /* DISPCSETREG */
+ { 0x281A, 0x00ff, 29 }, /* .HSWID(T2) */
+ { 0x281C, 0x00ff, 19 }, /* .HSSTR(T8) */
+ { 0x281E, 0x00ff, 19 }, /* .HSEND(T7) */
+ { 0x2822, 0x01ff, 11 }, /* .VSEND (T9) */
+ { 0x2826, 0x0ff0, 37<<4 }, /* .DESTR(T3) */
+ { 0, 0, 0 }
+};
+
+// 19997/2 ~100.02
+static reg_setting rate_100_02[] =
+{
+ { 0x0914, 0xffff, (63<<8)|(1<<2)|1 }, /* UPLLSETVREG */
+ { 0x0924, 0xff00, (2<<14)|(7<<8) }, /* DISPCSETREG */
+ { 0x281A, 0x00ff, 29 }, /* .HSWID(T2) */
+ { 0x281C, 0x00ff, 21 }, /* .HSSTR(T8) */
+ { 0x281E, 0x00ff, 20 }, /* .HSEND(T7) */
+ { 0x2822, 0x01ff, 12 }, /* .VSEND (T9) */
+ { 0x2826, 0x0ff0, 37<<4 }, /* .DESTR(T3) */
+ { 0, 0, 0 }
+};
+
+
+
+static reg_setting *possible_rates[] = { rate_almost60, rate_50, rate_120_20, rate_100_02 };
+
+void set_LCD_custom_rate(lcd_rate_t rate)
+{
+ reg_setting *set;
+
+ printf("setting custom LCD refresh, mode=%i... ", rate); fflush(stdout);
+ for (set = possible_rates[rate]; set->reg; set++)
+ {
+ unsigned short val = MEM_REG[set->reg >> 1];
+ val &= ~set->valmask;
+ val |= set->val;
+ MEM_REG[set->reg >> 1] = val;
+ }
+ printf("done.\n");
+}
+
+void unset_LCD_custom_rate(void)
+{
+ printf("reset to prev LCD refresh.\n");
+ MEM_REG[0x914>>1]=system_reg.UPLLVSETREG;
+ MEM_REG[0x924>>1]=system_reg.DISPCSETREG;
+ MEM_REG[0x281A>>1]=system_reg.DPC_HS_WIDTH;
+ MEM_REG[0x281C>>1]=system_reg.DPC_HS_STR;
+ MEM_REG[0x281E>>1]=system_reg.DPC_HS_END;
+ MEM_REG[0x2822>>1]=system_reg.DPC_VS_END;
+ MEM_REG[0x2826>>1]=system_reg.DPC_DE;
+}
+
void set_RAM_Timings(int tRC, int tRAS, int tWR, int tMRD, int tRFC, int tRP, int tRCD)
{
tRC -= 1; tRAS -= 1; tWR -= 1; tMRD -= 1; tRFC -= 1; tRP -= 1; tRCD -= 1; // ???
}
-/*
-void gp2x_video_wait_vsync(void)
-{
- MEM_REG[0x2846>>1]=(MEM_REG[0x2846>>1] | 0x20) & ~2;
- while(!(MEM_REG[0x2846>>1] & 2));
-}
-*/
-
void set_gamma(int g100)
{
float gamma = (float) g100 / 100;
extern void set_920_Div(unsigned short div); /* 0 to 7 divider (freq=FCLK/(1+div)) */
extern void set_DCLK_Div(unsigned short div); /* 0 to 7 divider (freq=FCLK/(1+div)) */
//extern void Disable_940(void); /* 940t down */
-//extern void gp2x_video_wait_vsync(void);
+
extern void set_RAM_Timings(int tRC, int tRAS, int tWR, int tMRD, int tRFC, int tRP, int tRCD);
extern void set_gamma(int g100);
+typedef enum
+{
+ LCDR_60 = 0, /* as close as possible to 60.00Hz, currently only managed to set to ~59.998Hz, has interlacing problems */
+ LCDR_50, /* 50Hz, has interlacing problems */
+ LCDR_120_20, /* ~60.10*2Hz, used by FCE Ultra */
+ LCDR_100_02, /* ~50.01*2Hz, used by FCE Ultra */
+} lcd_rate_t;
+
+extern void set_LCD_custom_rate(lcd_rate_t rate);
+extern void unset_LCD_custom_rate(void);
+
#endif
void WriteSound(int16 *Buffer, int Count);
void KillSound(void);
-void SilenceSound(int s); /* DOS and SDL */
+void SilenceSound(int s);
int InitVideo(void);
void KillVideo(void);
-void BlitScreen(uint8 *buf);
+void BlitPrepare(int skip);
+void BlitScreen(int skip);
void LockConsole(void);
void UnlockConsole(void);
-void ToggleFS(); /* SDL */
+void ToggleFS();
}
-void BlitScreen(uint8 *buf)
+void BlitPrepare(int skip)
{
framesEmulated++;
- if (!buf) {
+ if (skip) {
printFps(0);
return;
}
memset32((int *)((char *)gp2x_screen + 32), 0, srendline*320*2/4);
}
- gp2x_video_flip();
- XBuf = gp2x_screen;
+ /* at this point we should be done with the frame */
+ gp2x_video_flush_cache();
+}
+
+
+void BlitScreen(int skip)
+{
+ if (!skip)
+ {
+ gp2x_video_flip();
+ XBuf = gp2x_screen;
+ }
}
#include "rev.h"
;
+extern uint8 PAL;
+
int CLImain(int argc, char *argv[]);
DSETTINGS Settings;
ret = CLImain(argc,argv);
- // unscale the screen, in case this is bad.
- gp2x_video_RGB_setscaling(0, 320, 240);
+ // unscale the screen, in case it is bad.
+ gp2x_video_RGB_setscaling(320, 240);
if (mmuhack_status > 0)
mmuunhack();
}
}
-void gp2x_cpuclock_gamma_update(void)
+void gp2x_opt_update(void)
{
- static int prev_cpuclock = 200, prev_gamma = 100;
+ static int prev_cpuclock = 200, prev_gamma = 100, prev_vsync = 0, prev_pal = 0;
if (Settings.cpuclock != 0 && Settings.cpuclock != prev_cpuclock)
{
set_FCLK(Settings.cpuclock);
set_gamma(Settings.gamma);
prev_gamma = Settings.gamma;
}
+
+ if (Settings.perfect_vsync != prev_vsync || (Settings.perfect_vsync && prev_pal != PAL))
+ {
+ if (Settings.perfect_vsync)
+ {
+ set_LCD_custom_rate(PAL ? LCDR_100_02 : LCDR_120_20);
+ prev_pal = PAL;
+ }
+ else
+ {
+ unset_LCD_custom_rate();
+ }
+ prev_vsync = Settings.perfect_vsync;
+ }
}
int mmuhack;
int ramtimings;
int gamma;
+ int perfect_vsync;
} DSETTINGS;
extern DSETTINGS Settings;
void gp2x_opt_setup(void);
-void gp2x_cpuclock_gamma_update(void);
+void gp2x_opt_update(void);
#include "../../video.h"
#include "usbjoy.h"
-extern int FSkip;
-
/* UsrInputType[] is user-specified. InputType[] is current
(game loading can override user settings)
*/
{
int soundvolIndex;
static char soundvolmeter[24];
+ static int prev_snd_on = 0;
+
+ if ((!!soundvolume) ^ prev_snd_on)
+ {
+ FCEUI_Sound(Settings.sound_rate);
+ prev_snd_on = !!soundvolume;
+ }
// draw on screen :D
gp2x_sound_volume(soundvolume, soundvolume);
uint32 all_acts[2] = {0,0};
int i;
- if ((down(VOL_DOWN) && down(VOL_UP)) || (keys & (GP2X_L|GP2X_L|GP2X_START)) == (GP2X_L|GP2X_L|GP2X_START))
+ if ((down(VOL_DOWN) && down(VOL_UP)) || (keys & (GP2X_L|GP2X_START)) == (GP2X_L|GP2X_START))
{
Exit = 1;
- FSkip = 0; /* force rendering the last frame for menu */
return;
}
else if (down(VOL_UP))
// internals
extern char lastLoadedGameName[2048];
extern uint8 Exit; // exit emu loop flag
+extern int FSkip;
void CloseGame(void);
FCEUGI *fceugi = NULL;
static void SaveLLGN(void)
{
// save last loaded game name
- if (lastLoadedGameName[0])
+ if (lastLoadedGameName[0] && !(eoptions&EO_NOAUTOWRITE))
{
char tdir[2048];
FILE *f;
{"-nofs",0,&eoptions,0x8000|EO_NOFOURSCORE},
{"-clipsides",0,&eoptions,0x8000|EO_CLIPSIDES},
{"-nothrottle",0,&eoptions,0x8000|EO_NOTHROTTLE},
+ {"-noautowrite",0,&eoptions,0x8000|EO_NOAUTOWRITE},
{"-slstart",0,&srendlinev[0],0},{"-slend",0,&erendlinev[0],0},
{"-slstartp",0,&srendlinev[1],0},{"-slendp",0,&erendlinev[1],0},
{0,(void *)DriverArgs,0,0},
}
FCEUI_SetRenderedLines(srendlinev[0],erendlinev[0],srendlinev[1],erendlinev[1]);
- FCEUI_SetSoundVolume(soundvol);
+ FCEUI_SetSoundVolume(80);
DoDriverArgs();
if(fcexp)
LoadConfig(NULL);
last_arg_parsed=DoArgs(argc-1,&argv[1]);
gp2x_opt_setup();
- gp2x_cpuclock_gamma_update();
LoadLLGN();
FCEUI_SetNTSCTH(ntsccol, ntsctint, ntschue);
if(cpalette)
}
}
+ gp2x_opt_update();
PrepareOtherInput();
- RefreshThrottleFPS();
FCEUI_GetCurrentVidSystem(&srendline,&erendline);
gp2x_video_changemode(Settings.scaling == 3 ? 15 : 8);
switch (Settings.scaling & 3) {
- case 0: gp2x_video_set_offs(0); gp2x_video_RGB_setscaling(0, 320, 240); break;
- case 1: gp2x_video_set_offs(32); gp2x_video_RGB_setscaling(0, 256, 240); break;
- case 2: gp2x_video_set_offs(32); gp2x_video_RGB_setscaling(srendline, 256, erendline-srendline); break;
- case 3: gp2x_video_set_offs(32); gp2x_video_RGB_setscaling(0, 320, 240); break;
+ case 0: gp2x_video_set_offs(0); gp2x_video_RGB_setscaling(320, 240); break;
+ case 1: gp2x_video_set_offs(32); gp2x_video_RGB_setscaling(256, 240); break;
+ case 2: gp2x_video_set_offs(32+srendline*320); gp2x_video_RGB_setscaling(256, erendline-srendline); break;
+ case 3: gp2x_video_set_offs(32); gp2x_video_RGB_setscaling(320, 240); break;
}
CleanSurface();
gp2x_start_sound(Settings.sound_rate, 16, 0);
+ RefreshThrottleFPS();
FCEUI_Emulate();
}
void FCEUD_Update(uint8 *xbuf, int16 *Buffer, int Count)
{
+ FCEUD_UpdateInput(); // must update input before blitting because of save confirmation stuff
+ BlitPrepare(xbuf == NULL);
if(!(eoptions&EO_NOTHROTTLE))
{
if(Count)
WriteSound(Buffer,Count);
SpeedThrottle();
}
- FCEUD_UpdateInput(); // must update input before blitting because of save confirmation stuff
- BlitScreen(xbuf);
+ BlitScreen(xbuf == NULL);
+ // make sure last frame won't get skipped, because we need it for menu bg
+ if (Exit) FSkip=0;
}
#define EO_NOFOURSCORE 32
#define EO_NOTHROTTLE 64
#define EO_GG 128
+#define EO_NOAUTOWRITE 256
extern int srendline,erendline,srendlinev[2],erendlinev[2];
extern int NoWaiting;
\r
char menuErrorMsg[40] = {0, };\r
\r
-static void gp2x_fceu_darken_reset(void)\r
+static void menu_flip(void)\r
+{\r
+ gp2x_video_flush_cache();\r
+ gp2x_video_flip();\r
+}\r
+\r
+static void menu_darken_reset(void)\r
{\r
txt_xmin = 320; txt_xmax = 0;\r
txt_ymin = 240; txt_ymax = 0;\r
if (menu_bg)\r
memcpy(gp2x_screen, menu_bg, 320*240*2);\r
else memset(gp2x_screen, 0, 320*240*2);\r
- gp2x_fceu_darken_reset();\r
+ menu_darken_reset();\r
}\r
\r
-static void gp2x_fceu_darken_text_bg(void)\r
+static void menu_darken_text_bg(void)\r
{\r
int x, y, xmin, xmax, ymax;\r
unsigned short *screen = gp2x_screen;\r
}\r
}\r
gp2x_text_out15(5, 120, ">");\r
- gp2x_video_flip();\r
+ menu_flip();\r
}\r
\r
static int scandir_cmp(const void *p1, const void *p2)\r
if (pos < 24) gp2x_smalltext16_lim(14, pos*10, "done", 4);\r
\r
gp2x_text_out15(5, 120, ">");\r
- gp2x_video_flip();\r
+ menu_flip();\r
}\r
\r
void patches_menu_loop(void)\r
// draw cursor\r
gp2x_text_out15(tl_x - 16, tl_y + menu_sel*10, ">");\r
\r
- gp2x_video_flip();\r
+ menu_flip();\r
}\r
\r
static int savestate_menu_loop(int is_loading)\r
// draw cursor\r
gp2x_text_out15(x - 16, tl_y + sel*10, ">");\r
\r
- gp2x_fceu_darken_text_bg();\r
- gp2x_fceu_darken_reset();\r
+ menu_darken_text_bg();\r
+ menu_darken_reset();\r
\r
if (sel < opt_cnt) {\r
gp2x_text_out15(30, 190, "Press a button to bind/unbind");\r
gp2x_text_out15(30, 210, "to save controls");\r
gp2x_text_out15(30, 220, "Press B or X to exit");\r
}\r
- gp2x_fceu_darken_text_bg();\r
- gp2x_video_flip();\r
+ menu_darken_text_bg();\r
+ menu_flip();\r
}\r
\r
static void key_config_loop(const bind_action_t *opts, int opt_cnt, int player_idx)\r
gp2x_text_out15(tl_x, (y+=10), "none");\r
}\r
\r
- gp2x_fceu_darken_text_bg();\r
- gp2x_video_flip();\r
+ menu_darken_text_bg();\r
+ menu_flip();\r
}\r
\r
// b_turbo,a_turbo RLDU SEBA\r
gp2x_text_out15(tl_x - 16, tl_y + menu_sel*10, ">");\r
\r
if (menu_sel == 0) {\r
- gp2x_fceu_darken_text_bg();\r
- gp2x_fceu_darken_reset();\r
+ menu_darken_text_bg();\r
+ menu_darken_reset();\r
\r
gp2x_text_out15(30, 210, "Press B to browse,");\r
gp2x_text_out15(30, 220, "START to use default");\r
}\r
\r
- gp2x_fceu_darken_text_bg();\r
- gp2x_video_flip();\r
+ menu_darken_text_bg();\r
+ menu_flip();\r
}\r
\r
static void fcemenu_loop_options(void)\r
gp2x_text_out15(tl_x, (y+=10), "Faster RAM timings %s", Settings.ramtimings?"ON":"OFF");\r
gp2x_text_out15(tl_x, (y+=10), "squidgehack (now %s %s", mms, Settings.mmuhack?"ON":"OFF"); // 10\r
gp2x_text_out15(tl_x, (y+=10), "Gamma correction %i.%02i", Settings.gamma / 100, Settings.gamma%100);\r
- gp2x_text_out15(tl_x, (y+=10), "GP2X CPU clock %iMhz", Settings.cpuclock); // 12\r
+ gp2x_text_out15(tl_x, (y+=10), "Perfect VSYNC %s", Settings.perfect_vsync?"ON":"OFF");\r
+ gp2x_text_out15(tl_x, (y+=10), "GP2X CPU clock %iMhz", Settings.cpuclock); // 13\r
gp2x_text_out15(tl_x, (y+=10), "[FCE Ultra options]");\r
- gp2x_text_out15(tl_x, (y+=10), "Save cfg as default");\r
+ gp2x_text_out15(tl_x, (y+=10), "Save cfg as default"); // 15\r
if (fceugi)\r
gp2x_text_out15(tl_x, (y+=10), "Save cfg for current game only");\r
\r
// draw cursor\r
gp2x_text_out15(tl_x - 16, tl_y + menu_sel*10, ">");\r
\r
- gp2x_fceu_darken_text_bg();\r
- gp2x_video_flip();\r
+ menu_darken_text_bg();\r
+ menu_flip();\r
}\r
\r
static int sndrate_prevnext(int rate, int dir)\r
\r
static void config_commit(void)\r
{\r
- gp2x_cpuclock_gamma_update();\r
if (Settings.region_force)\r
FCEUI_SetVidSystem(Settings.region_force - 1);\r
}\r
static int menu_loop_options(void)\r
{\r
static int menu_sel = 0;\r
- int menu_sel_max = 14;\r
+ int menu_sel_max = 15;\r
unsigned long inp = 0;\r
\r
if (fceugi) menu_sel_max++;\r
if((inp& GP2X_B)||(inp&GP2X_LEFT)||(inp&GP2X_RIGHT)) { // toggleable options\r
switch (menu_sel) {\r
case 1: Settings.showfps = !Settings.showfps; break;\r
- case 3: soundvol = soundvol ? 0 : 100; break;\r
+ case 3: soundvol = soundvol ? 0 : 50; break;\r
case 9: Settings.ramtimings = !Settings.ramtimings; break;\r
case 10: Settings.mmuhack = !Settings.mmuhack; break;\r
- case 13: fcemenu_loop_options(); break;\r
- case 14: // done (update and write)\r
+ case 12: Settings.perfect_vsync = !Settings.perfect_vsync; break;\r
+ case 14: fcemenu_loop_options(); break;\r
+ case 15: // done (update and write)\r
config_commit();\r
SaveConfig(NULL);\r
return 1;\r
- case 15: // done (update and write for current game)\r
+ case 16: // done (update and write for current game)\r
config_commit();\r
if (lastLoadedGameName[0])\r
SaveConfig(lastLoadedGameName);\r
case 7: int_incdec(&Settings.sstate_confirm, (inp & GP2X_LEFT) ? -1 : 1, 0, 3); break;\r
case 8: int_incdec(&CurrentState, (inp & GP2X_LEFT) ? -1 : 1, 0, 9); break;\r
case 11: int_incdec(&Settings.gamma, (inp & GP2X_LEFT) ? -1 : 1, 0, 300); break;\r
- case 12:\r
+ case 13:\r
while ((inp = gp2x_joystick_read(1)) & (GP2X_LEFT|GP2X_RIGHT)) {\r
Settings.cpuclock += (inp & GP2X_LEFT) ? -1 : 1;\r
if (Settings.cpuclock < 0) Settings.cpuclock = 0; // 0 ~ do not change\r
gp2x_text_out15(20, 180, " cpuctrl, gamma libs");\r
gp2x_text_out15(20, 190, "Squidge: squidgehack");\r
\r
- gp2x_fceu_darken_text_bg();\r
- gp2x_video_flip();\r
+ menu_darken_text_bg();\r
+ menu_flip();\r
}\r
\r
\r
// draw cursor\r
gp2x_text_out15(tl_x - 16, tl_y + menu_sel*10, ">");\r
\r
- gp2x_fceu_darken_text_bg();\r
- gp2x_fceu_darken_reset();\r
+ menu_darken_text_bg();\r
+ menu_darken_reset();\r
\r
// error / version\r
if (menuErrorMsg[0]) gp2x_text_out15(1, 229, menuErrorMsg);\r
sprintf(vstr, "v" GP2X_PORT_VERSION " r%i", GP2X_PORT_REV);\r
gp2x_text_out15(320-strlen(vstr)*8-1, 228, vstr);\r
}\r
- gp2x_fceu_darken_text_bg();\r
- gp2x_video_flip();\r
+ menu_darken_text_bg();\r
+ menu_flip();\r
}\r
\r
\r
// switch bpp\r
gp2x_video_changemode(16);\r
gp2x_video_set_offs(0);\r
- gp2x_video_RGB_setscaling(0, 320, 240);\r
- gp2x_video_flip();\r
+ gp2x_video_RGB_setscaling(320, 240);\r
+ menu_flip();\r
}\r
\r
\r
#define FRAMEBUFF_ADDR3 (FRAMEBUFF_ADDR2+0x30000)\r
\r
static const int gp2x_screenaddrs[4] = { FRAMEBUFF_ADDR0, FRAMEBUFF_ADDR1, FRAMEBUFF_ADDR2, FRAMEBUFF_ADDR3 };\r
-static int gp2x_screenaddrs_use[4];\r
static unsigned short gp2x_screenaddr_old[4];\r
\r
\r
void gp2x_video_flip(void)\r
{\r
unsigned short lsw, msw;\r
- int addr = gp2x_screenaddrs_use[screensel&3];\r
+ int addr = gp2x_screenaddrs[screensel&3];\r
\r
addr += gp2x_screen_offs;\r
\r
- // since we are using the mmu hack, we must flush the cache first\r
- // (the params are most likely wrong, but they seem to work somehow)\r
- //flushcache(addr, addr + 320*240*2, 0);\r
- flushcache(gp2x_screen, (char *)gp2x_screen + 320*240*2, 0);\r
-\r
lsw = (unsigned short) addr;\r
msw = (unsigned short)(addr >> 16);\r
\r
/* doulblebuffered flip */\r
void gp2x_video_flip2(void)\r
{\r
- unsigned short msw = (unsigned short)(gp2x_screenaddrs_use[screensel&1] >> 16);\r
+ unsigned short msw = (unsigned short)(gp2x_screenaddrs[screensel&1] >> 16);\r
\r
gp2x_memregs[0x2910>>1] = msw;\r
gp2x_memregs[0x2914>>1] = msw;\r
\r
\r
// TV Compatible function //\r
-void gp2x_video_RGB_setscaling(int ln_offs, int W, int H)\r
+void gp2x_video_RGB_setscaling(int W, int H)\r
{\r
float escalaw, escalah;\r
int bpp = (gp2x_memregs[0x28DA>>1]>>9)&0x3;\r
unsigned short scalw;\r
\r
- // set offset\r
- gp2x_screenaddrs_use[0] = gp2x_screenaddrs[0] + ln_offs * 320 * bpp;\r
- gp2x_screenaddrs_use[1] = gp2x_screenaddrs[1] + ln_offs * 320 * bpp;\r
- gp2x_screenaddrs_use[2] = gp2x_screenaddrs[2] + ln_offs * 320 * bpp;\r
- gp2x_screenaddrs_use[3] = gp2x_screenaddrs[3] + ln_offs * 320 * bpp;\r
-\r
escalaw = 1024.0; // RGB Horiz LCD\r
escalah = 320.0; // RGB Vert LCD\r
\r
gp2x_screen_offs = offs;\r
}\r
\r
+void gp2x_video_wait_vsync(void)\r
+{\r
+ unsigned short v = gp2x_memregs[0x1182>>1];\r
+ while (!((v ^ gp2x_memregs[0x1182>>1]) & 0x10));\r
+}\r
+\r
+void gp2x_video_flush_cache(void)\r
+{\r
+ // since we are using the mmu hack, we must flush the cache first\r
+ // (the params are most likely wrong, but they seem to work somehow)\r
+ //flushcache(addr, addr + 320*240*2, 0);\r
+ flushcache(gp2x_screen, (char *)gp2x_screen + 320*240*2, 0);\r
+}\r
+\r
void gp2x_memcpy_buffers(int buffers, void *data, int offset, int len)\r
{\r
if (buffers & (1<<0)) memcpy((char *)gp2x_screens[0] + offset, data, len);\r
gp2x_screenaddr_old[2] = gp2x_memregs[0x2912>>1];\r
gp2x_screenaddr_old[3] = gp2x_memregs[0x2914>>1];\r
\r
- memcpy(gp2x_screenaddrs_use, gp2x_screenaddrs, sizeof(gp2x_screenaddrs));\r
gp2x_memset_all_buffers(0, 0, 320*240*2);\r
\r
// snd\r
void gp2x_video_changemode(int bpp);\r
void gp2x_video_changemode2(int bpp);\r
void gp2x_video_setpalette(int *pal, int len);\r
-void gp2x_video_RGB_setscaling(int ln_offs, int W, int H);\r
+void gp2x_video_RGB_setscaling(int W, int H);\r
void gp2x_video_set_offs(int offs);\r
+void gp2x_video_wait_vsync(void);\r
+void gp2x_video_flush_cache(void);\r
void gp2x_memcpy_buffers(int buffers, void *data, int offset, int len);\r
void gp2x_memcpy_all_buffers(void *data, int offset, int len);\r
void gp2x_memset_all_buffers(int offset, int byte, int len);\r
#include <sys/time.h>
#include "main.h"
#include "gp2x.h"
+#include "minimal.h"
#include "throttle.h"
extern uint8 PAL;
extern int FSkip;
-static int usec_aim = 0, usec_done = 0;
static int skip_count = 0;
+static struct timeval tv_prev;
void RefreshThrottleFPS(void)
{
- usec_aim = usec_done = skip_count = 0;
+ skip_count = 0;
+ if (Settings.perfect_vsync)
+ {
+ gp2x_video_wait_vsync();
+ }
+ gettimeofday(&tv_prev, 0);
}
-void SpeedThrottle(void)
+#define tvdiff(tv1, tv2) \
+ ((tv1.tv_sec - tv2.tv_sec) * 1000000 + tv1.tv_usec - tv2.tv_usec)
+
+#define tvadd(tv, usec) { \
+ tv.tv_usec += usec; \
+ if (tv.tv_usec >= 1000000) { \
+ tv.tv_sec += 1; \
+ tv.tv_usec -= 1000000; \
+ } \
+}
+
+#define tvsub(tv, usec) { \
+ tv.tv_usec -= usec; \
+ if (tv.tv_usec < 0) { \
+ tv.tv_sec -= 1; \
+ tv.tv_usec += 1000000; \
+ } \
+}
+
+static void wait_to(struct timeval *tv_aim)
{
- static struct timeval tv_prev;
struct timeval tv_now;
- int delta_nom = PAL ? 19997 : 16639; // ~50.007, 19.997 ms/frame : ~60.1, 16.639 ms/frame
+ int diff;
-
- if (usec_done == 0) { // first time
- usec_done = 1;
- gettimeofday(&tv_prev, 0);
- return;
+ do
+ {
+ gettimeofday(&tv_now, 0);
+ diff = tvdiff((*tv_aim), tv_now);
}
+ while (diff > 0);
+}
- gettimeofday(&tv_now, 0);
+#include <stdio.h>
+void SpeedThrottle(void)
+{
+ struct timeval tv_now, tv_aim;
+ int tdiff;
+
+ tv_aim = tv_prev;
+ tvadd(tv_aim, PAL ? 19997 : 16639); // ~50.007, 19.997 ms/frame : ~60.1, 16.639 ms/frame
- usec_aim += delta_nom;
- if (tv_now.tv_sec != tv_prev.tv_sec)
- usec_done += 1000000;
- usec_done += tv_now.tv_usec - tv_prev.tv_usec;
+ gettimeofday(&tv_now, 0);
+ tdiff = tvdiff(tv_now, tv_aim);
#ifdef FRAMESKIP
if (Settings.frameskip >= 0)
FSkip = 1;
}
}
- else if (usec_done > usec_aim + 1024*4)
+ else if (tdiff > 0)
{
/* auto frameskip */
- if (usec_done - usec_aim > 1024*32)
- usec_done = usec_aim = 1; // too much behind, try to recover..
- else
- FSkip = 1;
tv_prev = tv_now;
+ if (tdiff < 1024*16) // limit frameskip
+ {
+ FSkip = 1;
+ tvsub(tv_prev, tdiff);
+ }
return;
}
#endif
- tv_prev = tv_now;
- while (usec_done < usec_aim)
+ /* throttle */
+ if (tdiff < 0)
{
- gettimeofday(&tv_now, 0);
-
- if (tv_now.tv_sec != tv_prev.tv_sec)
- usec_done += 1000000;
- usec_done += tv_now.tv_usec - tv_prev.tv_usec;
- tv_prev = tv_now;
+ if (Settings.perfect_vsync)
+ {
+ if (tdiff <= (PAL ? 19997/2 : 16639/2))
+ {
+ struct timeval tv_tmp = tv_aim;
+ tvsub(tv_tmp, 5000);
+ wait_to(&tv_tmp);
+ }
+ gp2x_video_wait_vsync();
+ gettimeofday(&tv_prev, 0);
+ return;
+ }
+ else
+ {
+ wait_to(&tv_aim);
+ }
}
- usec_done = usec_done - usec_aim + 1; // reset to prevent overflows
- usec_aim = 0;
+
+ tv_prev = tv_aim;
}
}
-void gp2x_video_RGB_setscaling(int ln_offs, int W, int H)
+void gp2x_video_RGB_setscaling(int W, int H)
{
}
- Fixed an issue of MapIRQHook getting lost after loading a savestate\r
(glitched Akumajou Densetsu and other games after savestate load).\r
- A bug, which prevented configuring multiple USB pads fixed.\r
+ - Fixed sound breaking bug after switching it on/off multiple times.\r
+ - Added "Perfect VSYNC" option, which changes GP2X refresh rate and\r
+ syncs emu timing to LCD vsync.\r
rev 153\r
- Lots of work on the asm core. Timing fixed for some instructions.\r
Some missing undocumented instruction handlers added. Lots of\r
int32 lowp; // 0 through 65536, 65536 = max low pass(total attenuation)
// 65536 = no low pass
+static int32 flt_acc=0, flt_acc2=0;
+
static void FilterSound(uint32 *in, int16 *outMono, int count)
{
- static int32 acc=0, acc2=0;
// static int min=0, max=0;
for(;count;count--,in++,outMono++)
{
int32 diff;
- diff = *in - acc;
+ diff = *in - flt_acc;
- acc += (diff*highp)>>16;
- acc2+= (int32) (((int64)((diff-acc2)*lowp))>>16);
+ flt_acc += (diff*highp)>>16;
+ flt_acc2+= (int32) (((int64)((diff-flt_acc2)*lowp))>>16);
*in=0;
- *outMono = acc2*7 >> 2; // * 1.75
+ *outMono = flt_acc2*7 >> 2; // * 1.75
// if (acc2 < min) { printf("min: %i %04x\n", acc2, acc2); min = acc2; }
// if (acc2 > max) { printf("max: %i %04x\n", acc2, acc2); max = acc2; }
}
if(highp>(1<<16)) highp=1<<16;
if(lowp>(1<<16)) lowp=1<<16;
+
+ flt_acc=flt_acc2=0;
}
void FixOldSaveStateSFreq(void)