From 6f6bc6fa47b2888c4420eeb323d96be0982150de Mon Sep 17 00:00:00 2001
From: notaz <notasas@gmail.com>
Date: Sat, 2 Jun 2007 19:39:18 +0000
Subject: [PATCH] usb joys, custom pal

git-svn-id: file:///home/notaz/opt/svn/fceu@146 be3aeb3a-fb24-0410-a615-afba39da0efa
---
 Makefile.gp2x        |   3 +-
 Makefile.gp2x_test   |   3 +-
 drivers/gp2x/gp2x.c  |   4 +
 drivers/gp2x/input.c |  87 +++++++++++++++++----
 drivers/gp2x/main.c  |  24 +++---
 drivers/gp2x/menu.c  | 179 ++++++++++++++++++++++++++++---------------
 general.c            |   2 +-
 input.c              |   2 +-
 8 files changed, 212 insertions(+), 92 deletions(-)

diff --git a/Makefile.gp2x b/Makefile.gp2x
index 4af881d..c38f0ea 100644
--- a/Makefile.gp2x
+++ b/Makefile.gp2x
@@ -52,9 +52,8 @@ ncpu.o: ncpu.S ncpu.h
 include Makefile.base
 
 ${B}main.o:		${B}main.c ${B}main.h ${B}usage.h ${B}input.c
-${B}gp2x.o:		${B}gp2x.c ${B}gp2x.h
+${B}gp2x.o:		${B}gp2x.c ${B}gp2x.h ${B}rev.h
 ${B}throttle.o:         ${B}throttle.c ${B}main.h ${B}throttle.h
-${B}menu.o:		${B}rev.h
 ppu.o:			ppu.c ppu.h
 
 ${B}rev.h: FORCE
diff --git a/Makefile.gp2x_test b/Makefile.gp2x_test
index abb9545..bb6721f 100644
--- a/Makefile.gp2x_test
+++ b/Makefile.gp2x_test
@@ -39,9 +39,8 @@ x6502.o: x6502.c x6502.h ops.h fce.h sound.h dprintf.h
 include Makefile.base
 
 ${B}main.o:		${B}main.c ${B}main.h ${B}usage.h ${B}input.c
-${B}gp2x.o:		${B}gp2x.c ${B}gp2x.h
+${B}gp2x.o:		${B}gp2x.c ${B}gp2x.h ${B}rev.h
 ${B}throttle.o:         ${B}throttle.c ${B}main.h ${B}throttle.h
-${B}menu.o:		${B}rev.h
 ppu.o:			ppu.c ppu.h
 
 ${B}rev.h: FORCE
diff --git a/drivers/gp2x/gp2x.c b/drivers/gp2x/gp2x.c
index 58bf931..a4834b3 100644
--- a/drivers/gp2x/gp2x.c
+++ b/drivers/gp2x/gp2x.c
@@ -91,6 +91,7 @@ static void SetDefaults(void)
  Settings.sound_rate = 22050;
  Settings.turbo_rate_add = (8*2 << 24) / 60 + 1; // 8Hz turbofire
  Settings.gamma = 100;
+ Settings.sstate_confirm = 1;
  // default controls, RLDU SEBA
  Settings.KeyBinds[ 0] = 0x010; // GP2X_UP
  Settings.KeyBinds[ 4] = 0x020; // GP2X_DOWN
@@ -102,6 +103,9 @@ static void SetDefaults(void)
  Settings.KeyBinds[15] = 0x200; // GP2X_Y
  Settings.KeyBinds[ 8] = 0x008; // GP2X_START
  Settings.KeyBinds[ 9] = 0x004; // GP2X_SELECT
+ Settings.KeyBinds[10] = 0x80000000; // GP2X_L
+ Settings.KeyBinds[11] = 0x40000000; // GP2X_R
+ Settings.KeyBinds[27] = 0xc0000000; // GP2X_PUSH
 }
 
 void DoDriverArgs(void)
diff --git a/drivers/gp2x/input.c b/drivers/gp2x/input.c
index daadc34..7c33a96 100644
--- a/drivers/gp2x/input.c
+++ b/drivers/gp2x/input.c
@@ -18,6 +18,9 @@
 #include "../../state.h"
 #include "../../general.h"
 #include "../../input.h"
+#include "../../svga.h"
+#include "../../video.h"
+#include "usbjoy.h"
 
 /* UsrInputType[] is user-specified.  InputType[] is current
        (game loading can override user settings)
@@ -72,14 +75,42 @@ static void do_emu_acts(uint32 acts)
 
 	if (acts & (3 << 30))
 	{
+		unsigned long keys;
+		int do_it = 1;
 		if (acts & (1 << 30))
 		{
-			FCEUI_LoadState();
+			if (Settings.sstate_confirm & 2)
+			{
+				FCEU_DispMessage("LOAD STATE? (Y=yes, X=no)");
+				FCEU_PutImage();
+				FCEUD_Update(XBuf+8,NULL,0);
+				while( !((keys = gp2x_joystick_read(1)) & (GP2X_X|GP2X_Y)) ) usleep(50*1024);
+				if (keys & GP2X_X) do_it = 0;
+				FCEU_DispMessage("");
+			}
+			if (do_it) FCEUI_LoadState();
 		}
 		else
 		{
-			FCEUI_SaveState();
+			if (Settings.sstate_confirm & 1)
+			{
+				char *fname = FCEU_MakeFName(FCEUMKF_STATE,CurrentState,0);
+				FILE *st=fopen(fname,"rb");
+				free(fname);
+				if (st)
+				{
+					fclose(st);
+					FCEU_DispMessage("OVERWRITE SAVE? (Y=yes, X=no)");
+					FCEU_PutImage();
+					FCEUD_Update(XBuf+8,NULL,0);
+					while( !((keys = gp2x_joystick_read(1)) & (GP2X_X|GP2X_Y)) ) usleep(50*1024);
+					if (keys & GP2X_X) do_it = 0;
+					FCEU_DispMessage("");
+				}
+			}
+			if (do_it) FCEUI_SaveState();
 		}
+		RefreshThrottleFPS();
 	}
 	else if (acts & (3 << 28)) // state slot next/prev
 	{
@@ -156,9 +187,9 @@ static void do_fake_mouse(unsigned long keys)
 void FCEUD_UpdateInput(void)
 {
 	static int volpushed_frames = 0;
-	static int turbo_rate_cnt_a = 0, turbo_rate_cnt_b = 0;
+	static int turbo_rate_cnt_a[2] = {0,0}, turbo_rate_cnt_b[2] = {0,0};
 	unsigned long keys = gp2x_joystick_read(0);
-	uint32 all_acts = 0;
+	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))
@@ -219,21 +250,49 @@ void FCEUD_UpdateInput(void)
 			}
 			if (u != 32) acts &=  combo_acts; // other combo key pressed
 			else         acts &= ~combo_acts;
-			all_acts |= acts;
+			all_acts[(acts>>16)&1] |= acts;
+		}
+	}
+
+	// add joy inputs
+	if (num_of_joys > 0)
+	{
+		int joy;
+		gp2x_usbjoy_update();
+		for (joy = 0; joy < num_of_joys; joy++) {
+			int keys = gp2x_usbjoy_check2(joy);
+			for (i = 0; i < 32; i++) {
+				if (keys & (1 << i)) {
+					int acts = Settings.JoyBinds[joy][i];
+					all_acts[(acts>>16)&1] |= acts;
+				}
+			}
 		}
 	}
 
-	JSreturn |= all_acts & 0xff;
-	if (all_acts & 0x100) {		// A turbo
-		turbo_rate_cnt_a += Settings.turbo_rate_add;
-		JSreturn |= (turbo_rate_cnt_a >> 24) & 1;
+	// player 1
+	JSreturn |= all_acts[0] & 0xff;
+	if (all_acts[0] & 0x100) {		// A turbo
+		turbo_rate_cnt_a[0] += Settings.turbo_rate_add;
+		JSreturn |= (turbo_rate_cnt_a[0] >> 24) & 1;
 	}
-	if (all_acts & 0x200) {		// B turbo
-		turbo_rate_cnt_b += Settings.turbo_rate_add;
-		JSreturn |= (turbo_rate_cnt_b >> 23) & 2;
+	if (all_acts[0] & 0x200) {		// B turbo
+		turbo_rate_cnt_b[0] += Settings.turbo_rate_add;
+		JSreturn |= (turbo_rate_cnt_b[0] >> 23) & 2;
 	}
 
-	do_emu_acts(all_acts);
+	// player 2
+	JSreturn |= (all_acts[1] & 0xff) << 16;
+	if (all_acts[1] & 0x100) {		// A turbo
+		turbo_rate_cnt_a[1] += Settings.turbo_rate_add;
+		JSreturn |= (turbo_rate_cnt_a[1] >> 8) & 0x10000;
+	}
+	if (all_acts[1] & 0x200) {		// B turbo
+		turbo_rate_cnt_b[1] += Settings.turbo_rate_add;
+		JSreturn |= (turbo_rate_cnt_b[1] >> 7) & 0x20000;
+	}
+
+	do_emu_acts(all_acts[0]|all_acts[1]);
 }
 
 
@@ -301,6 +360,8 @@ static void PrepareOtherInput(void)
 		}
 	}
 
+	combo_acts &= ~0x00030000; // don't take player_id bits
+
 	// find combo_keys
 	for (act = 1; act; act <<= 1)
 	{
diff --git a/drivers/gp2x/main.c b/drivers/gp2x/main.c
index 3f4dff9..05724c6 100644
--- a/drivers/gp2x/main.c
+++ b/drivers/gp2x/main.c
@@ -91,8 +91,8 @@ void FCEUD_PrintError(char *s)
  puts(s);
 }
 
-static char *cpalette=0;
-static void LoadCPalette(void)
+char *cpalette=0;
+void LoadCPalette(void)
 {
  char tmpp[192];
  FILE *fp;
@@ -100,6 +100,8 @@ static void LoadCPalette(void)
  if(!(fp=fopen(cpalette,"rb")))
  {
   printf(" Error loading custom palette from file: %s\n",cpalette);
+  free(cpalette);
+  cpalette=0;
   return;
  }
  fread(tmpp,1,192,fp);
@@ -181,7 +183,7 @@ static void SaveLLGN(void)
 
 static void CreateDirs(void)
 {
- char *subs[]={"fcs","snaps","gameinfo","sav","cheats","cfg"};
+ char *subs[]={"fcs","snaps","gameinfo","sav","cheats","cfg","pal"};
  char tdir[2048];
  int x;
 
@@ -212,12 +214,9 @@ static void CloseStuff(int signum)
          case SIGHUP:printf("Reach out and hang-up on someone.\n");break;
          case SIGPIPE:printf("The pipe has broken!  Better watch out for floods...\n");break;
          case SIGSEGV:printf("Iyeeeeeeeee!!!  A segmentation fault has occurred.  Have a fluffy day.\n");break;
-	 /* So much SIGBUS evil. */
-	 #ifdef SIGBUS
 	 #if(SIGBUS!=SIGSEGV)
          case SIGBUS:printf("I told you to be nice to the driver.\n");break;
 	 #endif
-	 #endif
          case SIGFPE:printf("Those darn floating points.  Ne'er know when they'll bite!\n");break;
          case SIGALRM:printf("Don't throw your clock at the meowing cats!\n");break;
          case SIGABRT:printf("Abort, Retry, Ignore, Fail?\n");break;
@@ -251,8 +250,7 @@ static int DoArgs(int argc, char *argv[])
          {"-fcexp",0,&fcexp,0x4001},
 
          {"-gg",&docheckie[1],0,0},
-         {"-no8lim",0,&eoptions,0x8001},
-         {"-subase",0,&eoptions,0x8002},
+         {"-no8lim",0,&eoptions,0x8000|EO_NO8LIM},
          {"-snapname",0,&eoptions,0x8000|EO_SNAPNAME},
 	 {"-nofs",0,&eoptions,0x8000|EO_NOFOURSCORE},
          {"-clipsides",0,&eoptions,0x8000|EO_CLIPSIDES},
@@ -278,8 +276,7 @@ static int DoArgs(int argc, char *argv[])
 	 Settings.region_force=2;
 	if(docheckie[1])
 	 FCEUI_SetGameGenie(1);
-        FCEUI_DisableSpriteLimitation(1);
-        FCEUI_SaveExtraDataUnderBase(eoptions&2);
+        FCEUI_DisableSpriteLimitation(eoptions&EO_NO8LIM);
 	FCEUI_SetSnapName(eoptions&EO_SNAPNAME);
 
 	for(x=0;x<2;x++)
@@ -288,8 +285,6 @@ static int DoArgs(int argc, char *argv[])
          if(erendlinev[x]<srendlinev[x] || erendlinev[x]>239) erendlinev[x]=239;
 	}
 
-	printf("FCEUI_SetRenderedLines: %d, %d, %d, %d\n",srendlinev[0],erendlinev[0],srendlinev[1],erendlinev[1]);
-        printf("clip sides: %d\n", eoptions&EO_CLIPSIDES);
         FCEUI_SetRenderedLines(srendlinev[0],erendlinev[0],srendlinev[1],erendlinev[1]);
         FCEUI_SetSoundVolume(soundvol);
 	DoDriverArgs();
@@ -362,7 +357,7 @@ int CLImain(int argc, char *argv[])
 	LoadLLGN();
 	FCEUI_SetNTSCTH(ntsccol, ntsctint, ntschue);
 	if(cpalette)
-	 LoadCPalette(); // TODO
+	 LoadCPalette();
 	if(InitSound())
 	 inited|=1;
 
@@ -454,6 +449,9 @@ static void DriverKill(void)
  // SaveConfig(NULL); // done explicitly in menu now
  SetSignals(SIG_IGN);
 
+ if(cpalette) free(cpalette);
+ cpalette=0;
+
  if(inited&4)
   KillVideo();
  if(inited&1)
diff --git a/drivers/gp2x/menu.c b/drivers/gp2x/menu.c
index cdd06b2..b23837a 100644
--- a/drivers/gp2x/menu.c
+++ b/drivers/gp2x/menu.c
@@ -20,6 +20,7 @@
 
 #include "../../input.h"
 #include "../../state.h"
+#include "../../palette.h"
 
 #ifndef _DIRENT_HAVE_D_TYPE
 #error "need d_type for file browser
@@ -41,6 +42,9 @@ static char *gp2xKeyNames[] = {
 	"18???", "19???",  "1a???","PUSH",  "1c???","1d???", "1e???",    "1f???"
 };
 
+
+static char path_buffer[PATH_MAX];
+
 char menuErrorMsg[40] = {0, };
 
 // TODO
@@ -290,11 +294,11 @@ static int scandir_filter(const struct dirent *ent)
 	return 1;
 }
 
-static char *romsel_loop(char *curr_path)
+static char *filesel_loop(char *curr_path, char *final_dest)
 {
 	struct dirent **namelist;
 	DIR *dir;
-	int n, sel = 0;
+	int n, newlen, sel = 0;
 	unsigned long inp = 0;
 	char *ret = NULL, *fname = NULL;
 
@@ -343,15 +347,18 @@ static char *romsel_loop(char *curr_path)
 		if(inp & GP2X_R)     { sel+=24; if (sel > n-2) sel = n-2; }
 		if(inp & GP2X_B)     { // enter dir/select
 			again:
-			if (namelist[sel+1]->d_type == DT_REG) {
-				strcpy(lastLoadedGameName, curr_path);
-				strcat(lastLoadedGameName, "/");
-				strcat(lastLoadedGameName, namelist[sel+1]->d_name);
-				ret = lastLoadedGameName;
+			newlen = strlen(curr_path) + strlen(namelist[sel+1]->d_name) + 2;
+			if (namelist[sel+1]->d_type == DT_REG) { // file selected
+				if (final_dest == NULL) final_dest = malloc(newlen);
+				if (final_dest == NULL) break;
+				strcpy(final_dest, curr_path);
+				strcat(final_dest, "/");
+				strcat(final_dest, namelist[sel+1]->d_name);
+				ret = final_dest;
 				break;
 			} else if (namelist[sel+1]->d_type == DT_DIR) {
-				int newlen = strlen(curr_path) + strlen(namelist[sel+1]->d_name) + 2;
 				char *p, *newdir = malloc(newlen);
+				if (newdir == NULL) break;
 				if (strcmp(namelist[sel+1]->d_name, "..") == 0) {
 					char *start = curr_path;
 					p = start + strlen(start) - 1;
@@ -366,16 +373,19 @@ static char *romsel_loop(char *curr_path)
 					strcat(newdir, "/");
 					strcat(newdir, namelist[sel+1]->d_name);
 				}
-				ret = romsel_loop(newdir);
+				ret = filesel_loop(newdir, final_dest);
 				free(newdir);
 				break;
 			} else {
 				// unknown file type, happens on NTFS mounts. Try to guess.
-				FILE *tstf; int tmp;
-				strcpy(lastLoadedGameName, curr_path);
-				strcat(lastLoadedGameName, "/");
-				strcat(lastLoadedGameName, namelist[sel+1]->d_name);
-				tstf = fopen(lastLoadedGameName, "rb");
+				char *tstfn; FILE *tstf; int tmp;
+				tstfn = malloc(newlen);
+				if (tstfn == NULL) break;
+				strcpy(tstfn, curr_path);
+				strcat(tstfn, "/");
+				strcat(tstfn, namelist[sel+1]->d_name);
+				tstf = fopen(tstfn, "rb");
+				free(tstfn);
 				if (tstf != NULL)
 				{
 					if (fread(&tmp, 1, 1, tstf) > 0 || ferror(tstf) == 0)
@@ -617,7 +627,7 @@ static char *action_binds(int player_idx, int action_mask)
 		{
 			if (Settings.JoyBinds[joy][i] & action_mask)
 			{
-				if (player_idx >= 0 && ((Settings.KeyBinds[i] >> 16) & 3) != player_idx) continue;
+				if (player_idx >= 0 && ((Settings.JoyBinds[joy][i] >> 16) & 3) != player_idx) continue;
 				if (strkeys[0]) {
 					strcat(strkeys, ", "); strcat(strkeys, usb_joy_key_name(joy + 1, i));
 					break;
@@ -685,6 +695,8 @@ static void draw_key_config(const bind_action_t *opts, int opt_cnt, int player_i
 		gp2x_text_out15(30, 210, "To bind UP/DOWN, hold VOL-");
 		gp2x_text_out15(30, 220, "Select \"Done\" to exit");
 	} else {
+		gp2x_text_out15(30, 200, "Use Options -> Save cfg");
+		gp2x_text_out15(30, 210, "to save controls");
 		gp2x_text_out15(30, 220, "Press B or X to exit");
 	}
 	gp2x_video_flip();
@@ -723,7 +735,9 @@ static void key_config_loop(const bind_action_t *opts, int opt_cnt, int player_i
 						Settings.KeyBinds[i] |= player_idx << 16;
 					}
 				}
-		} else if (sel < opt_cnt) {
+		}
+		else if (sel < opt_cnt)
+		{
 			for (i = 0; i < 32; i++)
 				if (inp & (1 << i)) {
 					if (count_bound_keys(opts[sel].mask, 1) >= 1) // disallow combos for usbjoy
@@ -810,6 +824,7 @@ static void kc_sel_loop(void)
 				case 1: key_config_loop(ctrl_actions,  8, 1); return;
 				case 2: key_config_loop(emuctrl_actions,
 						sizeof(emuctrl_actions)/sizeof(emuctrl_actions[0]), -1); return;
+				case 3: if (!fceugi) SaveConfig(NULL); return;
 				default: return;
 			}
 		}
@@ -824,6 +839,8 @@ extern int ntsccol,ntschue,ntsctint;
 extern int srendlinev[2];
 extern int erendlinev[2];
 extern int eoptions;
+extern char *cpalette;
+extern void LoadCPalette(void);
 
 
 static void int_incdec(int *p, int inc, int min, int max)
@@ -836,20 +853,37 @@ static void int_incdec(int *p, int inc, int min, int max)
 static void draw_fcemenu_options(int menu_sel)
 {
 	int tl_x = 25, tl_y = 60, y;
+	char cpal[32];
+
+	if (cpalette != NULL)
+	{
+		char *p = cpalette + strlen(cpalette) - 1;
+		while (*p != '/' && p > cpalette) p--;
+		if (*p == '/') p++;
+		strncpy(cpal, p, 16);
+		cpal[16] = 0;
+	}
+	else strcpy(cpal, "           OFF");
 
 	y = tl_y;
 	gp2x_fceu_copy_bg();
 
-	gp2x_text_out15(tl_x,  y,      "NTSC Color Emulation       %s", ntsccol?"ON":"OFF");	// 0
+	gp2x_text_out15(tl_x,  y,      "Custom palette: %s", cpal);				// 0
+	gp2x_text_out15(tl_x, (y+=10), "NTSC Color Emulation       %s", ntsccol?"ON":"OFF");
 	gp2x_text_out15(tl_x, (y+=10), "  Tint (default: 56)       %i", ntsctint);
 	gp2x_text_out15(tl_x, (y+=10), "  Hue  (default: 72)       %i", ntschue);
 	gp2x_text_out15(tl_x, (y+=10), "First visible line (NTSC)  %i", srendlinev[0]);
-	gp2x_text_out15(tl_x, (y+=10), "Last visible line (NTSC)   %i", erendlinev[0]);
-	gp2x_text_out15(tl_x, (y+=10), "First visible line (PAL)   %i", srendlinev[1]);		// 5
+	gp2x_text_out15(tl_x, (y+=10), "Last visible line (NTSC)   %i", erendlinev[0]);		// 5
+	gp2x_text_out15(tl_x, (y+=10), "First visible line (PAL)   %i", srendlinev[1]);
 	gp2x_text_out15(tl_x, (y+=10), "Last visible line (PAL)    %i", erendlinev[1]);
 	gp2x_text_out15(tl_x, (y+=10), "Clip 8 left/right columns  %s", (eoptions&EO_CLIPSIDES)?"ON":"OFF");
-	gp2x_text_out15(tl_x, (y+=10), "Disable 8 sprite limit     %s", "TODO");
-	gp2x_text_out15(tl_x, (y+=10), "Done");							// 9
+	gp2x_text_out15(tl_x, (y+=10), "Disable 8 sprite limit     %s", (eoptions&EO_NO8LIM)?"ON":"OFF");
+	gp2x_text_out15(tl_x, (y+=10), "Done");							// 10
+
+	if (menu_sel == 0) {
+		gp2x_text_out15(30, 210, "Press B to browse,");
+		gp2x_text_out15(30, 220, "START to use default");
+	}
 
 	// draw cursor
 	gp2x_text_out15(tl_x - 16, tl_y + menu_sel*10, ">");
@@ -859,7 +893,7 @@ static void draw_fcemenu_options(int menu_sel)
 
 static void fcemenu_loop_options(void)
 {
-	int menu_sel = 0, menu_sel_max = 9, i;
+	int menu_sel = 0, menu_sel_max = 10, i;
 	unsigned long inp = 0;
 
 	FCEUI_GetNTSCTH(&ntsctint, &ntschue);
@@ -867,14 +901,15 @@ static void fcemenu_loop_options(void)
 	for(;;)
 	{
 		draw_fcemenu_options(menu_sel);
-		inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_B|GP2X_X|GP2X_A);
+		inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_B|GP2X_X|GP2X_A|GP2X_START);
 		if(inp & GP2X_UP  ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }
 		if(inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }
 		if((inp& GP2X_B)||(inp&GP2X_LEFT)||(inp&GP2X_RIGHT)) { // toggleable options
 			switch (menu_sel) {
-				case  0: ntsccol = !ntsccol; break;
-				case  7: eoptions^=EO_CLIPSIDES; break;
-				case  9: return;
+				case  1: ntsccol = !ntsccol; break;
+				case  8: eoptions^=EO_CLIPSIDES; break;
+				case  9: eoptions^=EO_NO8LIM; break;
+				case 10: return;
 			}
 		}
 		if(inp & (GP2X_X|GP2X_A)) {
@@ -885,16 +920,38 @@ static void fcemenu_loop_options(void)
 			}
 			FCEUI_SetNTSCTH(ntsccol, ntsctint, ntschue);
 			FCEUI_SetRenderedLines(srendlinev[0],erendlinev[0],srendlinev[1],erendlinev[1]);
+			FCEUI_DisableSpriteLimitation(eoptions&EO_NO8LIM);
+			if (cpalette) LoadCPalette();
+			else FCEUI_SetPaletteArray(0); // set to default
+			FCEU_ResetPalette();
 			return;
 		}
 		if(inp & (GP2X_LEFT|GP2X_RIGHT)) { // multi choise
 			switch (menu_sel) {
-				case  1: int_incdec(&ntsctint,      (inp & GP2X_LEFT) ? -1 : 1, 0, 128); break;
-				case  2: int_incdec(&ntschue,       (inp & GP2X_LEFT) ? -1 : 1, 0, 128); break;
-				case  3: int_incdec(&srendlinev[0], (inp & GP2X_LEFT) ? -1 : 1, 0, 239); break;
-				case  4: int_incdec(&erendlinev[0], (inp & GP2X_LEFT) ? -1 : 1, 0, 239); break;
-				case  5: int_incdec(&srendlinev[1], (inp & GP2X_LEFT) ? -1 : 1, 0, 239); break;
-				case  6: int_incdec(&erendlinev[1], (inp & GP2X_LEFT) ? -1 : 1, 0, 239); break;
+				case  2: int_incdec(&ntsctint,      (inp & GP2X_LEFT) ? -1 : 1, 0, 128); break;
+				case  3: int_incdec(&ntschue,       (inp & GP2X_LEFT) ? -1 : 1, 0, 128); break;
+				case  4: int_incdec(&srendlinev[0], (inp & GP2X_LEFT) ? -1 : 1, 0, 239); break;
+				case  5: int_incdec(&erendlinev[0], (inp & GP2X_LEFT) ? -1 : 1, 0, 239); break;
+				case  6: int_incdec(&srendlinev[1], (inp & GP2X_LEFT) ? -1 : 1, 0, 239); break;
+				case  7: int_incdec(&erendlinev[1], (inp & GP2X_LEFT) ? -1 : 1, 0, 239); break;
+			}
+		}
+		if(menu_sel == 0 && (inp & (GP2X_START|GP2X_B))) { // custom palette
+			if ((inp & GP2X_START) && cpalette) {
+				free(cpalette);
+				cpalette=NULL;
+			}
+			else if (inp & GP2X_B) {
+				char *selfname;
+				if (cpalette) strncpy(path_buffer, cpalette, sizeof(path_buffer));
+				else getcwd(path_buffer, PATH_MAX);
+				path_buffer[sizeof(path_buffer)-1] = 0;
+
+				selfname = filesel_loop(path_buffer, NULL);
+				if (selfname) {
+					if (cpalette) free(cpalette);
+					cpalette = selfname;
+				}
 			}
 		}
 	}
@@ -934,14 +991,13 @@ static void draw_menu_options(int menu_sel)
 	gp2x_text_out15(tl_x, (y+=10), "Sound Rate:           %5iHz", Settings.sound_rate);		// 4
 	gp2x_text_out15(tl_x, (y+=10), "Force Region:              %s",
 		Settings.region_force == 2 ? "PAL" : Settings.region_force == 1 ? "NTSC" : "OFF");	// 5
-	gp2x_text_out15(tl_x, (y+=10), "Use SRAM savestates        %s", "OFF");
 	gp2x_text_out15(tl_x, (y+=10), "Turbo rate                 %iHz", (Settings.turbo_rate_add*60/2) >> 24);
-	gp2x_text_out15(tl_x, (y+=10), "Confirm savestate          %s", strssconfirm);			// 8
+	gp2x_text_out15(tl_x, (y+=10), "Confirm savestate          %s", strssconfirm);			// 7
 	gp2x_text_out15(tl_x, (y+=10), "Save slot                  %i", CurrentState);
 	gp2x_text_out15(tl_x, (y+=10), "Faster RAM timings         %s", Settings.ramtimings?"ON":"OFF");
-	gp2x_text_out15(tl_x, (y+=10), "squidgehack (now %s %s",   mms, Settings.mmuhack?"ON":"OFF");	// 11
+	gp2x_text_out15(tl_x, (y+=10), "squidgehack (now %s %s",   mms, Settings.mmuhack?"ON":"OFF");	// 10
 	gp2x_text_out15(tl_x, (y+=10), "Gamma correction           %i.%02i", Settings.gamma / 100, Settings.gamma%100);
-	gp2x_text_out15(tl_x, (y+=10), "GP2X CPU clock             %iMhz", Settings.cpuclock);		// 13
+	gp2x_text_out15(tl_x, (y+=10), "GP2X CPU clock             %iMhz", Settings.cpuclock);		// 12
 	gp2x_text_out15(tl_x, (y+=10), "[FCE Ultra options]");
 	gp2x_text_out15(tl_x, (y+=10), "Save cfg as default");
 	if (fceugi)
@@ -991,14 +1047,14 @@ static int menu_loop_options(void)
 			switch (menu_sel) {
 				case  1: Settings.showfps    = !Settings.showfps; break;
 				case  3: soundvol = soundvol ? 0 : 100; break;
-				case 10: Settings.ramtimings = !Settings.ramtimings; break;
-				case 11: Settings.mmuhack    = !Settings.mmuhack; break;
-				case 14: fcemenu_loop_options(); break;
-				case 15: // done (update and write)
+				case  9: Settings.ramtimings = !Settings.ramtimings; break;
+				case 10: Settings.mmuhack    = !Settings.mmuhack; break;
+				case 13: fcemenu_loop_options(); break;
+				case 14: // done (update and write)
 					config_commit();
 					SaveConfig(NULL);
 					return 1;
-				case 16: // done (update and write for current game)
+				case 15: // done (update and write for current game)
 					config_commit();
 					if (lastLoadedGameName[0])
 						SaveConfig(lastLoadedGameName);
@@ -1018,16 +1074,16 @@ static int menu_loop_options(void)
 					InitSound();
 					break;
 				case  5: int_incdec(&Settings.region_force,   (inp & GP2X_LEFT) ? -1 : 1, 0, 2); break;
-				case  7: {
+				case  6: {
 					int hz = Settings.turbo_rate_add*60/2 >> 24;
 					int_incdec(&hz, (inp & GP2X_LEFT) ? -1 : 1, 1, 30);
 					Settings.turbo_rate_add = (hz*2 << 24) / 60 + 1;
 					break;
 				}
-				case  8: int_incdec(&Settings.sstate_confirm, (inp & GP2X_LEFT) ? -1 : 1, 0, 3); break;
-				case  9: int_incdec(&CurrentState,            (inp & GP2X_LEFT) ? -1 : 1, 0, 9); break;
-				case 12: int_incdec(&Settings.gamma,          (inp & GP2X_LEFT) ? -1 : 1, 0, 300); break;
-				case 13:
+				case  7: int_incdec(&Settings.sstate_confirm, (inp & GP2X_LEFT) ? -1 : 1, 0, 3); break;
+				case  8: int_incdec(&CurrentState,            (inp & GP2X_LEFT) ? -1 : 1, 0, 9); break;
+				case 11: int_incdec(&Settings.gamma,          (inp & GP2X_LEFT) ? -1 : 1, 0, 300); break;
+				case 12:
 					while ((inp = gp2x_joystick_read(1)) & (GP2X_LEFT|GP2X_RIGHT)) {
 						Settings.cpuclock += (inp & GP2X_LEFT) ? -1 : 1;
 						if (Settings.cpuclock < 0) Settings.cpuclock = 0; // 0 ~ do not change
@@ -1112,19 +1168,6 @@ static int menu_loop_root(void)
 	int ret, menu_sel_max = 8, menu_sel_min = 4;
 	static int menu_sel = 4;
 	unsigned long inp = 0;
-	char curr_path[PATH_MAX], *selfname;
-	FILE *tstf;
-
-	if ( (tstf = fopen(lastLoadedGameName, "rb")) )
-	{
-		fclose(tstf);
-		strncpy(curr_path, lastLoadedGameName, sizeof(curr_path));
-		curr_path[sizeof(curr_path)-1] = 0;
-	}
-	else
-	{
-		getcwd(curr_path, PATH_MAX);
-	}
 
 	if (fceugi) menu_sel_min = 0;
 // TODO	if (PicoPatches) menu_sel_max = 9;
@@ -1185,13 +1228,29 @@ static int menu_loop_root(void)
 					}
 					break;
 				case 4: // select rom
-					selfname = romsel_loop(curr_path);
+				{
+					FILE *tstf;
+					char *selfname;
+
+					if ( (tstf = fopen(lastLoadedGameName, "rb")) )
+					{
+						fclose(tstf);
+						strncpy(path_buffer, lastLoadedGameName, sizeof(path_buffer));
+						path_buffer[sizeof(path_buffer)-1] = 0;
+					}
+					else
+					{
+						getcwd(path_buffer, PATH_MAX);
+					}
+
+					selfname = filesel_loop(path_buffer, lastLoadedGameName);
 					if (selfname) {
 						printf("selected file: %s\n", selfname);
 						while (gp2x_joystick_read(1) & GP2X_B) usleep(50*1000);
 						return 2;
 					}
 					break;
+				}
 				case 5: // options
 					ret = menu_loop_options();
 					if (ret == 1) continue; // status update
diff --git a/general.c b/general.c
index 46383c2..ab1af60 100644
--- a/general.c
+++ b/general.c
@@ -217,7 +217,7 @@ char *FCEU_MakeFName(int type, int id1, char *cd1)
                        if(odirs[FCEUIOD_MISC])
                         asprintf(&ret,"%s"PSS"%s.pal",odirs[FCEUIOD_MISC],FileBase);
                        else
-                        asprintf(&ret,"%s"PSS"%s.pal",BaseDirectory,FileBase);
+                        asprintf(&ret,"%s"PSS"pal"PSS"%s.pal",BaseDirectory,FileBase);
                        break;
   case FCEUMKF_MOVIEGLOB:
                      if(odirs[FCEUIOD_MISC])
diff --git a/input.c b/input.c
index 0d4a9af..b625583 100644
--- a/input.c
+++ b/input.c
@@ -117,7 +117,7 @@ static DECLFR(JPRead)
 	  ret=FCExp->Read(A&1,ret);
 
 	ret|=X.DB&0xC0;
-	dprintf("JPRead %02x", ret);
+	dprintf("JPRead %i %02x", A&1, ret);
 	return(ret);
 }
 
-- 
2.39.5