cdrom: change pause timing again
[pcsx_rearmed.git] / frontend / menu.c
index 301a10d..58efd21 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * (C) Gražvydas "notaz" Ignotas, 2010-2011
+ * (C) Gražvydas "notaz" Ignotas, 2010-2015
  *
  * This work is licensed under the terms of any of these licenses
  * (at your option):
  *
  * This work is licensed under the terms of any of these licenses
  * (at your option):
@@ -8,6 +8,12 @@
  * See the COPYING file in the top-level directory.
  */
 
  * See the COPYING file in the top-level directory.
  */
 
+#define _GNU_SOURCE 1
+#ifdef __FreeBSD__
+#define STAT stat
+#else
+#define STAT stat64
+#endif
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
@@ -16,6 +22,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <dirent.h>
 
 #include "main.h"
 #include "menu.h"
 
 #include "main.h"
 #include "menu.h"
 #include "plugin_lib.h"
 #include "plat.h"
 #include "pcnt.h"
 #include "plugin_lib.h"
 #include "plat.h"
 #include "pcnt.h"
-#include "common/plat.h"
-#include "common/input.h"
-#include "linux/in_evdev.h"
+#include "cspace.h"
+#include "libpicofe/plat.h"
+#include "libpicofe/input.h"
+#include "libpicofe/linux/in_evdev.h"
+#include "libpicofe/plat.h"
 #include "../libpcsxcore/misc.h"
 #include "../libpcsxcore/cdrom.h"
 #include "../libpcsxcore/cdriso.h"
 #include "../libpcsxcore/cheat.h"
 #include "../libpcsxcore/misc.h"
 #include "../libpcsxcore/cdrom.h"
 #include "../libpcsxcore/cdriso.h"
 #include "../libpcsxcore/cheat.h"
-#include "../libpcsxcore/psemu_plugin_defs.h"
 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
-#include "../plugins/dfinput/main.h"
-#include "../plugins/gpulib/cspace.h"
+#include "../plugins/dfsound/spu_config.h"
+#include "psemu_plugin_defs.h"
+#include "arm_features.h"
 #include "revision.h"
 
 #define REARMED_BIRTHDAY_TIME 1293306830       /* 25 Dec 2010 */
 #include "revision.h"
 
 #define REARMED_BIRTHDAY_TIME 1293306830       /* 25 Dec 2010 */
@@ -71,52 +80,60 @@ typedef enum
        MA_OPT_SAVECFG,
        MA_OPT_SAVECFG_GAME,
        MA_OPT_CPU_CLOCKS,
        MA_OPT_SAVECFG,
        MA_OPT_SAVECFG_GAME,
        MA_OPT_CPU_CLOCKS,
+       MA_OPT_SPU_THREAD,
        MA_OPT_DISP_OPTS,
        MA_OPT_DISP_OPTS,
-       MA_OPT_SCALER,
+       MA_OPT_VARSCALER,
+       MA_OPT_VARSCALER_C,
        MA_OPT_SCALER2,
        MA_OPT_SCALER2,
-       MA_OPT_FILTERING,
-       MA_OPT_SCALER_C,
+       MA_OPT_HWFILTER,
+       MA_OPT_SWFILTER,
+       MA_OPT_GAMMA,
+       MA_OPT_VOUT_MODE,
+       MA_OPT_SCANLINES,
+       MA_OPT_SCANLINE_LEVEL,
+       MA_OPT_CENTERING,
 } menu_id;
 
 } menu_id;
 
-enum {
-       SCALE_1_1,
-       SCALE_4_3,
-       SCALE_4_3v2,
-       SCALE_FULLSCREEN,
-       SCALE_CUSTOM,
-};
-
-static int last_psx_w, last_psx_h, last_psx_bpp;
-static int scaling, cpu_clock, cpu_clock_st, volume_boost, frameskip;
-static char rom_fname_reload[MAXPATHLEN];
+static int last_vout_w, last_vout_h, last_vout_bpp;
+static int cpu_clock, cpu_clock_st, volume_boost;
+static int frameskip = 1; // 0 - auto, 1 - off
 static char last_selected_fname[MAXPATHLEN];
 static char last_selected_fname[MAXPATHLEN];
-static int warned_about_bios, region, in_type_sel1, in_type_sel2;
+static int config_save_counter, region, in_type_sel1, in_type_sel2;
 static int psx_clock;
 static int psx_clock;
-static int memcard1_sel, memcard2_sel;
-int g_opts;
+static int memcard1_sel = -1, memcard2_sel = -1;
+extern int g_autostateld_opt;
+static int menu_iopts[8];
+int g_opts, g_scaler, g_gamma = 100;
+int scanlines, scanline_level = 20;
 int soft_scaling, analog_deadzone; // for Caanoo
 int soft_scaling, analog_deadzone; // for Caanoo
-int filter;
+int soft_filter;
 
 
-#ifdef __ARM_ARCH_7A__
-#define DEFAULT_PSX_CLOCK 57
+#ifndef HAVE_PRE_ARMV7
+#define DEFAULT_PSX_CLOCK (10000 / CYCLE_MULT_DEFAULT)
 #define DEFAULT_PSX_CLOCK_S "57"
 #else
 #define DEFAULT_PSX_CLOCK 50
 #define DEFAULT_PSX_CLOCK_S "50"
 #endif
 
 #define DEFAULT_PSX_CLOCK_S "57"
 #else
 #define DEFAULT_PSX_CLOCK 50
 #define DEFAULT_PSX_CLOCK_S "50"
 #endif
 
-// sound plugin
-extern int iUseReverb;
-extern int iUseInterpolation;
-extern int iXAPitch;
-extern int iVolume;
-
-static const char *bioses[24];
+static const char *bioses[32];
 static const char *gpu_plugins[16];
 static const char *spu_plugins[16];
 static const char *memcards[32];
 static int bios_sel, gpu_plugsel, spu_plugsel;
 
 static const char *gpu_plugins[16];
 static const char *spu_plugins[16];
 static const char *memcards[32];
 static int bios_sel, gpu_plugsel, spu_plugsel;
 
+#ifndef UI_FEATURES_H
+#define MENU_BIOS_PATH "bios/"
+#define MENU_SHOW_VARSCALER 0
+#define MENU_SHOW_VOUTMODE 1
+#define MENU_SHOW_SCALER2 0
+#define MENU_SHOW_NUBS_BTNS 0
+#define MENU_SHOW_VIBRATION 0
+#define MENU_SHOW_DEADZONE 0
+#define MENU_SHOW_MINIMIZE 0
+#define MENU_SHOW_FULLSCREEN 1
+#define MENU_SHOW_VOLUME 0
+#endif
 
 static int min(int x, int y) { return x < y ? x : y; }
 static int max(int x, int y) { return x > y ? x : y; }
 
 static int min(int x, int y) { return x < y ? x : y; }
 static int max(int x, int y) { return x > y ? x : y; }
@@ -179,6 +196,112 @@ static int emu_save_load_game(int load, int unused)
        return ret;
 }
 
        return ret;
 }
 
+static void rm_namelist_entry(struct dirent **namelist,
+       int count, const char *name)
+{
+       int i;
+
+       for (i = 1; i < count; i++) {
+               if (namelist[i] == NULL || namelist[i]->d_type == DT_DIR)
+                       continue;
+
+               if (strcmp(name, namelist[i]->d_name) == 0) {
+                       free(namelist[i]);
+                       namelist[i] = NULL;
+                       break;
+               }
+       }
+}
+
+static int optional_cdimg_filter(struct dirent **namelist, int count,
+       const char *basedir)
+{
+       const char *ext, *p;
+       char buf[256], buf2[257];
+       int i, d, ret, good_cue;
+       struct STAT statf;
+       FILE *f;
+
+       if (count <= 1)
+               return count;
+
+       for (i = 1; i < count; i++) {
+               if (namelist[i] == NULL || namelist[i]->d_type == DT_DIR)
+                       continue;
+
+               ext = strrchr(namelist[i]->d_name, '.');
+               if (ext == NULL) {
+                       // should not happen but whatever
+                       free(namelist[i]);
+                       namelist[i] = NULL;
+                       continue;
+               }
+               ext++;
+
+               // first find .cue files and remove files they reference
+               if (strcasecmp(ext, "cue") == 0)
+               {
+                       snprintf(buf, sizeof(buf), "%s/%s", basedir,
+                               namelist[i]->d_name);
+
+                       f = fopen(buf, "r");
+                       if (f == NULL) {
+                               free(namelist[i]);
+                               namelist[i] = NULL;
+                               continue;
+                       }
+
+                       good_cue = 0;
+                       while (fgets(buf, sizeof(buf), f)) {
+                               ret = sscanf(buf, " FILE \"%256[^\"]\"", buf2);
+                               if (ret != 1)
+                                       ret = sscanf(buf, " FILE %256s", buf2);
+                               if (ret != 1)
+                                       continue;
+
+                               p = strrchr(buf2, '/');
+                               if (p == NULL)
+                                       p = strrchr(buf2, '\\');
+                               if (p != NULL)
+                                       p++;
+                               else
+                                       p = buf2;
+
+                               snprintf(buf, sizeof(buf), "%s/%s", basedir, p);
+                               ret = STAT(buf, &statf);
+                               if (ret == 0) {
+                                       rm_namelist_entry(namelist, count, p);
+                                       good_cue = 1;
+                               }
+                       }
+                       fclose(f);
+
+                       if (!good_cue) {
+                               free(namelist[i]);
+                               namelist[i] = NULL;
+                       }
+                       continue;
+               }
+
+               p = strcasestr(namelist[i]->d_name, "track");
+               if (p != NULL) {
+                       ret = strtoul(p + 5, NULL, 10);
+                       if (ret > 1) {
+                               free(namelist[i]);
+                               namelist[i] = NULL;
+                               continue;
+                       }
+               }
+       }
+
+       // compact namelist
+       for (i = d = 1; i < count; i++)
+               if (namelist[i] != NULL)
+                       namelist[d++] = namelist[i];
+
+       return d;
+}
+
 // propagate menu settings to the emu vars
 static void menu_sync_config(void)
 {
 // propagate menu settings to the emu vars
 static void menu_sync_config(void)
 {
@@ -189,24 +312,28 @@ static void menu_sync_config(void)
                Config.PsxAuto = 0;
                Config.PsxType = region - 1;
        }
                Config.PsxAuto = 0;
                Config.PsxType = region - 1;
        }
-       cycle_multiplier = 10000 / psx_clock;
+       Config.cycle_multiplier = 10000 / psx_clock;
 
        switch (in_type_sel1) {
 
        switch (in_type_sel1) {
-       case 1:  in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
-       case 2:  in_type1 = PSE_PAD_TYPE_GUNCON;    break;
-       default: in_type1 = PSE_PAD_TYPE_STANDARD;
+       case 1:  in_type[0] = PSE_PAD_TYPE_ANALOGPAD; break;
+       case 2:  in_type[0] = PSE_PAD_TYPE_GUNCON;    break;
+       case 3:  in_type[0] = PSE_PAD_TYPE_GUN;       break;
+       case 4:  in_type[0] = PSE_PAD_TYPE_NONE;      break;
+       default: in_type[0] = PSE_PAD_TYPE_STANDARD;
        }
        switch (in_type_sel2) {
        }
        switch (in_type_sel2) {
-       case 1:  in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
-       case 2:  in_type2 = PSE_PAD_TYPE_GUNCON;    break;
-       default: in_type2 = PSE_PAD_TYPE_STANDARD;
+       case 1:  in_type[1] = PSE_PAD_TYPE_ANALOGPAD; break;
+       case 2:  in_type[1] = PSE_PAD_TYPE_GUNCON;    break;
+       case 3:  in_type[1] = PSE_PAD_TYPE_GUN;       break;
+       case 4:  in_type[1] = PSE_PAD_TYPE_NONE;      break;
+       default: in_type[1] = PSE_PAD_TYPE_STANDARD;
        }
        if (in_evdev_allow_abs_only != allow_abs_only_old) {
                in_probe();
                allow_abs_only_old = in_evdev_allow_abs_only;
        }
 
        }
        if (in_evdev_allow_abs_only != allow_abs_only_old) {
                in_probe();
                allow_abs_only_old = in_evdev_allow_abs_only;
        }
 
-       iVolume = 768 + 128 * volume_boost;
+       spu_config.iVolume = 768 + 128 * volume_boost;
        pl_rearmed_cbs.frameskip = frameskip - 1;
        pl_timing_prepare(Config.PsxType);
 }
        pl_rearmed_cbs.frameskip = frameskip - 1;
        pl_timing_prepare(Config.PsxType);
 }
@@ -216,11 +343,16 @@ static void menu_set_defconfig(void)
        emu_set_default_config();
 
        g_opts = 0;
        emu_set_default_config();
 
        g_opts = 0;
-       scaling = SCALE_4_3;
+       g_scaler = SCALE_4_3;
+       g_gamma = 100;
        volume_boost = 0;
        volume_boost = 0;
-       frameskip = 0;
+       frameskip = 1; // 1 - off
        analog_deadzone = 50;
        soft_scaling = 1;
        analog_deadzone = 50;
        soft_scaling = 1;
+       soft_filter = 0;
+       scanlines = 0;
+       scanline_level = 20;
+       plat_target.vout_fullscreen = 0;
        psx_clock = DEFAULT_PSX_CLOCK;
 
        region = 0;
        psx_clock = DEFAULT_PSX_CLOCK;
 
        region = 0;
@@ -242,6 +374,9 @@ static void menu_set_defconfig(void)
 #define CE_INTVAL(val) \
        { #val, sizeof(val), &val }
 
 #define CE_INTVAL(val) \
        { #val, sizeof(val), &val }
 
+#define CE_INTVAL_N(name, val) \
+       { name, sizeof(val), &val }
+
 #define CE_INTVAL_P(val) \
        { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
 
 #define CE_INTVAL_P(val) \
        { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
 
@@ -261,41 +396,62 @@ static const struct {
        void *val;
 } config_data[] = {
        CE_CONFIG_STR(Bios),
        void *val;
 } config_data[] = {
        CE_CONFIG_STR(Bios),
-       CE_CONFIG_STR_V(Gpu, 2),
+       CE_CONFIG_STR_V(Gpu, 3),
        CE_CONFIG_STR(Spu),
 //     CE_CONFIG_STR(Cdr),
        CE_CONFIG_VAL(Xa),
        CE_CONFIG_STR(Spu),
 //     CE_CONFIG_STR(Cdr),
        CE_CONFIG_VAL(Xa),
-       CE_CONFIG_VAL(Sio),
        CE_CONFIG_VAL(Mdec),
        CE_CONFIG_VAL(Cdda),
        CE_CONFIG_VAL(Debug),
        CE_CONFIG_VAL(PsxOut),
        CE_CONFIG_VAL(Mdec),
        CE_CONFIG_VAL(Cdda),
        CE_CONFIG_VAL(Debug),
        CE_CONFIG_VAL(PsxOut),
-       CE_CONFIG_VAL(SpuIrq),
-       CE_CONFIG_VAL(RCntFix),
-       CE_CONFIG_VAL(VSyncWA),
+       CE_CONFIG_VAL(icache_emulation),
+       CE_CONFIG_VAL(DisableStalls),
        CE_CONFIG_VAL(Cpu),
        CE_CONFIG_VAL(Cpu),
-       CE_CONFIG_VAL(CdrReschedule),
+       CE_CONFIG_VAL(GpuListWalking),
+       CE_CONFIG_VAL(FractionalFramerate),
+       CE_CONFIG_VAL(PreciseExceptions),
        CE_INTVAL(region),
        CE_INTVAL(region),
-       CE_INTVAL_V(scaling, 2),
+       CE_INTVAL_V(g_scaler, 3),
+       CE_INTVAL(g_gamma),
        CE_INTVAL(g_layer_x),
        CE_INTVAL(g_layer_y),
        CE_INTVAL(g_layer_w),
        CE_INTVAL(g_layer_h),
        CE_INTVAL(g_layer_x),
        CE_INTVAL(g_layer_y),
        CE_INTVAL(g_layer_w),
        CE_INTVAL(g_layer_h),
-       CE_INTVAL(filter),
+       CE_INTVAL(soft_filter),
+       CE_INTVAL(scanlines),
+       CE_INTVAL(scanline_level),
+       CE_INTVAL(plat_target.vout_method),
+       CE_INTVAL(plat_target.hwfilter),
+       CE_INTVAL(plat_target.vout_fullscreen),
        CE_INTVAL(state_slot),
        CE_INTVAL(cpu_clock),
        CE_INTVAL(g_opts),
        CE_INTVAL(in_type_sel1),
        CE_INTVAL(in_type_sel2),
        CE_INTVAL(analog_deadzone),
        CE_INTVAL(state_slot),
        CE_INTVAL(cpu_clock),
        CE_INTVAL(g_opts),
        CE_INTVAL(in_type_sel1),
        CE_INTVAL(in_type_sel2),
        CE_INTVAL(analog_deadzone),
-       CE_INTVAL_V(frameskip, 3),
+       CE_INTVAL(memcard1_sel),
+       CE_INTVAL(memcard2_sel),
+       CE_INTVAL(g_autostateld_opt),
+       CE_INTVAL_N("adev0_is_nublike", in_adev_is_nublike[0]),
+       CE_INTVAL_N("adev1_is_nublike", in_adev_is_nublike[1]),
+       CE_INTVAL_V(frameskip, 4),
        CE_INTVAL_P(gpu_peops.iUseDither),
        CE_INTVAL_P(gpu_peops.dwActFixes),
        CE_INTVAL_P(gpu_peops.iUseDither),
        CE_INTVAL_P(gpu_peops.dwActFixes),
-       CE_INTVAL_P(gpu_unai.lineskip),
-       CE_INTVAL_P(gpu_unai.abe_hack),
-       CE_INTVAL_P(gpu_unai.no_light),
-       CE_INTVAL_P(gpu_unai.no_blend),
+       CE_INTVAL_P(gpu_unai_old.lineskip),
+       CE_INTVAL_P(gpu_unai_old.abe_hack),
+       CE_INTVAL_P(gpu_unai_old.no_light),
+       CE_INTVAL_P(gpu_unai_old.no_blend),
+       CE_INTVAL_P(gpu_unai.ilace_force),
+       CE_INTVAL_P(gpu_unai.pixel_skip),
+       CE_INTVAL_P(gpu_unai.lighting),
+       CE_INTVAL_P(gpu_unai.fast_lighting),
+       CE_INTVAL_P(gpu_unai.blending),
+       CE_INTVAL_P(gpu_unai.dithering),
+       CE_INTVAL_P(gpu_unai.scale_hires),
        CE_INTVAL_P(gpu_neon.allow_interlace),
        CE_INTVAL_P(gpu_neon.allow_interlace),
+       CE_INTVAL_P(gpu_neon.enhancement_enable),
+       CE_INTVAL_P(gpu_neon.enhancement_no_main),
+       CE_INTVAL_P(gpu_neon.enhancement_tex_adj),
        CE_INTVAL_P(gpu_peopsgl.bDrawDither),
        CE_INTVAL_P(gpu_peopsgl.iFilterType),
        CE_INTVAL_P(gpu_peopsgl.iFrameTexType),
        CE_INTVAL_P(gpu_peopsgl.bDrawDither),
        CE_INTVAL_P(gpu_peopsgl.iFilterType),
        CE_INTVAL_P(gpu_peopsgl.iFrameTexType),
@@ -306,10 +462,15 @@ static const struct {
        CE_INTVAL_P(gpu_peopsgl.iVRamSize),
        CE_INTVAL_P(gpu_peopsgl.iTexGarbageCollection),
        CE_INTVAL_P(gpu_peopsgl.dwActFixes),
        CE_INTVAL_P(gpu_peopsgl.iVRamSize),
        CE_INTVAL_P(gpu_peopsgl.iTexGarbageCollection),
        CE_INTVAL_P(gpu_peopsgl.dwActFixes),
-       CE_INTVAL_V(iUseReverb, 3),
-       CE_INTVAL_V(iXAPitch, 3),
-       CE_INTVAL_V(iUseInterpolation, 3),
-       CE_INTVAL(warned_about_bios),
+       CE_INTVAL_P(screen_centering_type),
+       CE_INTVAL_P(screen_centering_x),
+       CE_INTVAL_P(screen_centering_y),
+       CE_INTVAL(spu_config.iUseReverb),
+       CE_INTVAL(spu_config.iXAPitch),
+       CE_INTVAL(spu_config.iUseInterpolation),
+       CE_INTVAL(spu_config.iTempo),
+       CE_INTVAL(spu_config.iUseThread),
+       CE_INTVAL(config_save_counter),
        CE_INTVAL(in_evdev_allow_abs_only),
        CE_INTVAL(volume_boost),
        CE_INTVAL(psx_clock),
        CE_INTVAL(in_evdev_allow_abs_only),
        CE_INTVAL(volume_boost),
        CE_INTVAL(psx_clock),
@@ -340,6 +501,14 @@ static void make_cfg_fname(char *buf, size_t size, int is_game)
 }
 
 static void keys_write_all(FILE *f);
 }
 
 static void keys_write_all(FILE *f);
+static char *mystrip(char *str);
+
+static void write_u32_value(FILE *f, u32 v)
+{
+       if (v > 7)
+               fprintf(f, "0x");
+       fprintf(f, "%x\n", v);
+}
 
 static int menu_write_config(int is_game)
 {
 
 static int menu_write_config(int is_game)
 {
@@ -347,6 +516,8 @@ static int menu_write_config(int is_game)
        FILE *f;
        int i;
 
        FILE *f;
        int i;
 
+       config_save_counter++;
+
        make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
        f = fopen(cfgfile, "w");
        if (f == NULL) {
        make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
        f = fopen(cfgfile, "w");
        if (f == NULL) {
@@ -361,17 +532,17 @@ static int menu_write_config(int is_game)
                        fprintf(f, "%s\n", (char *)config_data[i].val);
                        break;
                case 1:
                        fprintf(f, "%s\n", (char *)config_data[i].val);
                        break;
                case 1:
-                       fprintf(f, "%x\n", *(u8 *)config_data[i].val);
+                       write_u32_value(f, *(u8 *)config_data[i].val);
                        break;
                case 2:
                        break;
                case 2:
-                       fprintf(f, "%x\n", *(u16 *)config_data[i].val);
+                       write_u32_value(f, *(u16 *)config_data[i].val);
                        break;
                case 4:
                        break;
                case 4:
-                       fprintf(f, "%x\n", *(u32 *)config_data[i].val);
+                       write_u32_value(f, *(u32 *)config_data[i].val);
                        break;
                default:
                        printf("menu_write_config: unhandled len %d for %s\n",
                        break;
                default:
                        printf("menu_write_config: unhandled len %d for %s\n",
-                                config_data[i].len, config_data[i].name);
+                                (int)config_data[i].len, config_data[i].name);
                        break;
                }
        }
                        break;
                }
        }
@@ -384,20 +555,39 @@ static int menu_write_config(int is_game)
 
 static int menu_do_last_cd_img(int is_get)
 {
 
 static int menu_do_last_cd_img(int is_get)
 {
+       static const char *defaults[] = { "/media", "/mnt/sd", "/mnt" };
        char path[256];
        char path[256];
+       struct STAT st;
        FILE *f;
        FILE *f;
+       int i, ret = -1;
 
        snprintf(path, sizeof(path), "." PCSX_DOT_DIR "lastcdimg.txt");
        f = fopen(path, is_get ? "r" : "w");
 
        snprintf(path, sizeof(path), "." PCSX_DOT_DIR "lastcdimg.txt");
        f = fopen(path, is_get ? "r" : "w");
-       if (f == NULL)
-               return -1;
+       if (f == NULL) {
+               ret = -1;
+               goto out;
+       }
 
 
-       if (is_get)
-               fscanf(f, "%255s", last_selected_fname);
+       if (is_get) {
+               ret = fread(last_selected_fname, 1, sizeof(last_selected_fname) - 1, f);
+               last_selected_fname[ret] = 0;
+               mystrip(last_selected_fname);
+       }
        else
                fprintf(f, "%s\n", last_selected_fname);
        fclose(f);
 
        else
                fprintf(f, "%s\n", last_selected_fname);
        fclose(f);
 
+out:
+       if (is_get) {
+               for (i = 0; last_selected_fname[0] == 0
+                      || STAT(last_selected_fname, &st) != 0; i++)
+               {
+                       if (i >= ARRAY_SIZE(defaults))
+                               break;
+                       strcpy(last_selected_fname, defaults[i]);
+               }
+       }
+
        return 0;
 }
 
        return 0;
 }
 
@@ -415,7 +605,7 @@ static void parse_str_val(char *cval, const char *src)
 
 static void keys_load_all(const char *cfg);
 
 
 static void keys_load_all(const char *cfg);
 
-static int menu_load_config(int is_game)
+int menu_load_config(int is_game)
 {
        char cfgfile[MAXPATHLEN];
        int i, ret = -1;
 {
        char cfgfile[MAXPATHLEN];
        int i, ret = -1;
@@ -482,7 +672,7 @@ static int menu_load_config(int is_game)
                        break;
                default:
                        printf("menu_load_config: unhandled len %d for %s\n",
                        break;
                default:
                        printf("menu_load_config: unhandled len %d for %s\n",
-                                config_data[i].len, config_data[i].name);
+                                (int)config_data[i].len, config_data[i].name);
                        break;
                }
        }
                        break;
                }
        }
@@ -505,10 +695,6 @@ fail:
 
        menu_sync_config();
 
 
        menu_sync_config();
 
-       // caanoo old config compat hack
-       if (strcmp(Config.Gpu, "gpuPCSX4ALL.so") == 0)
-               strcpy(Config.Gpu, "gpu_unai.so");
-
        // sync plugins
        for (i = bios_sel = 0; bioses[i] != NULL; i++)
                if (strcmp(Config.Bios, bioses[i]) == 0)
        // sync plugins
        for (i = bios_sel = 0; bioses[i] != NULL; i++)
                if (strcmp(Config.Bios, bioses[i]) == 0)
@@ -522,23 +708,54 @@ fail:
                if (strcmp(Config.Spu, spu_plugins[i]) == 0)
                        { spu_plugsel = i; break; }
 
                if (strcmp(Config.Spu, spu_plugins[i]) == 0)
                        { spu_plugsel = i; break; }
 
+       // memcard selections
+       char mcd1_old[sizeof(Config.Mcd1)];
+       char mcd2_old[sizeof(Config.Mcd2)];
+       strcpy(mcd1_old, Config.Mcd1);
+       strcpy(mcd2_old, Config.Mcd2);
+
+       if ((unsigned int)memcard1_sel < ARRAY_SIZE(memcards)) {
+               if (memcard1_sel == 0)
+                       strcpy(Config.Mcd1, "none");
+               else if (memcards[memcard1_sel] != NULL)
+                       snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s",
+                               MEMCARD_DIR, memcards[memcard1_sel]);
+       }
+       if ((unsigned int)memcard2_sel < ARRAY_SIZE(memcards)) {
+               if (memcard2_sel == 0)
+                       strcpy(Config.Mcd2, "none");
+               else if (memcards[memcard2_sel] != NULL)
+                       snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s",
+                               MEMCARD_DIR, memcards[memcard2_sel]);
+       }
+       if (strcmp(mcd1_old, Config.Mcd1) || strcmp(mcd2_old, Config.Mcd2))
+               LoadMcds(Config.Mcd1, Config.Mcd2);
+
        return ret;
 }
 
        return ret;
 }
 
+static const char *filter_exts[] = {
+       "bin", "img", "mdf", "iso", "cue", "z",
+       #ifdef HAVE_CHD
+       "chd",
+       #endif
+       "bz",  "znx", "pbp", "cbn", NULL
+};
+
 // rrrr rggg gggb bbbb
 static unsigned short fname2color(const char *fname)
 {
 // rrrr rggg gggb bbbb
 static unsigned short fname2color(const char *fname)
 {
-       static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
-                                           ".bz", ".znx", ".pbp", ".cbn" };
-       static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
-                                           ".table", ".index", ".sbi" };
+       static const char *other_exts[] = {
+               "ccd", "toc", "mds", "sub", "table", "index", "sbi"
+       };
        const char *ext = strrchr(fname, '.');
        int i;
 
        if (ext == NULL)
                return 0xffff;
        const char *ext = strrchr(fname, '.');
        int i;
 
        if (ext == NULL)
                return 0xffff;
-       for (i = 0; i < array_size(cdimg_exts); i++)
-               if (strcasecmp(ext, cdimg_exts[i]) == 0)
+       ext++;
+       for (i = 0; filter_exts[i] != NULL; i++)
+               if (strcasecmp(ext, filter_exts[i]) == 0)
                        return 0x7bff;
        for (i = 0; i < array_size(other_exts); i++)
                if (strcasecmp(ext, other_exts[i]) == 0)
                        return 0x7bff;
        for (i = 0; i < array_size(other_exts); i++)
                if (strcasecmp(ext, other_exts[i]) == 0)
@@ -548,20 +765,14 @@ static unsigned short fname2color(const char *fname)
 
 static void draw_savestate_bg(int slot);
 
 
 static void draw_savestate_bg(int slot);
 
-static const char *filter_exts[] = {
-       ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
-};
-
 #define MENU_ALIGN_LEFT
 #define MENU_ALIGN_LEFT
-#ifdef __ARM_ARCH_7A__ // assume hires device
+#ifndef HAVE_PRE_ARMV7 // assume hires device
 #define MENU_X2 1
 #else
 #define MENU_X2 0
 #endif
 
 #define MENU_X2 1
 #else
 #define MENU_X2 0
 #endif
 
-#define menu_init menu_init_common
-#include "common/menu.c"
-#undef menu_init
+#include "libpicofe/menu.c"
 
 // a bit of black magic here
 static void draw_savestate_bg(int slot)
 
 // a bit of black magic here
 static void draw_savestate_bg(int slot)
@@ -583,8 +794,8 @@ static void draw_savestate_bg(int slot)
        if (f == NULL)
                return;
 
        if (f == NULL)
                return;
 
-       if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
-               fprintf(stderr, "gzseek failed\n");
+       if ((ret = (int)gzseek(f, 0x29933d, SEEK_SET)) != 0x29933d) {
+               fprintf(stderr, "gzseek failed: %d\n", ret);
                gzclose(f);
                return;
        }
                gzclose(f);
                return;
        }
@@ -609,12 +820,18 @@ static void draw_savestate_bg(int slot)
 
        x = gpu->ulControl[5] & 0x3ff;
        y = (gpu->ulControl[5] >> 10) & 0x1ff;
 
        x = gpu->ulControl[5] & 0x3ff;
        y = (gpu->ulControl[5] >> 10) & 0x1ff;
-       s = (u16 *)gpu->psxVRam + y * 1024 + x;
        w = psx_widths[(gpu->ulStatus >> 16) & 7];
        tmp = gpu->ulControl[7];
        h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
        if (gpu->ulStatus & 0x80000) // doubleheight
                h *= 2;
        w = psx_widths[(gpu->ulStatus >> 16) & 7];
        tmp = gpu->ulControl[7];
        h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
        if (gpu->ulStatus & 0x80000) // doubleheight
                h *= 2;
+       if (h <= 0 || h > 512)
+               goto out;
+       if (y > 512 - 64)
+               y = 0;
+       if (y + h > 512)
+               h = 512 - y;
+       s = (u16 *)gpu->psxVRam + y * 1024 + x;
 
        x = max(0, g_menuscreen_w - w) & ~3;
        y = max(0, g_menuscreen_h / 2 - h / 2);
 
        x = max(0, g_menuscreen_w - w) & ~3;
        y = max(0, g_menuscreen_h / 2 - h / 2);
@@ -630,7 +847,7 @@ static void draw_savestate_bg(int slot)
 
                // darken this so that menu text is visible
                if (g_menuscreen_w - w < 320)
 
                // darken this so that menu text is visible
                if (g_menuscreen_w - w < 320)
-                       menu_darken_bg(d, d, w * 2, 0);
+                       menu_darken_bg(d, d, w, 0);
        }
 
 out:
        }
 
 out:
@@ -668,18 +885,27 @@ me_bind_action emuctrl_actions[] =
        { "Next Save Slot   ", 1 << SACTION_NEXT_SSLOT },
        { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
        { "Take Screenshot  ", 1 << SACTION_SCREENSHOT },
        { "Next Save Slot   ", 1 << SACTION_NEXT_SSLOT },
        { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
        { "Take Screenshot  ", 1 << SACTION_SCREENSHOT },
-       { "Enter Menu       ", 1 << SACTION_ENTER_MENU },
-#ifdef __ARM_ARCH_7A__ /* XXX */
+       { "Show/Hide FPS    ", 1 << SACTION_TOGGLE_FPS },
+#ifndef HAVE_PRE_ARMV7
+       { "Switch Renderer  ", 1 << SACTION_SWITCH_DISPMODE },
+#endif
+       { "Fast Forward     ", 1 << SACTION_FAST_FORWARD },
+#if MENU_SHOW_MINIMIZE
        { "Minimize         ", 1 << SACTION_MINIMIZE },
 #endif
        { "Minimize         ", 1 << SACTION_MINIMIZE },
 #endif
+#if MENU_SHOW_FULLSCREEN
+       { "Toggle fullscreen", 1 << SACTION_TOGGLE_FULLSCREEN },
+#endif
+       { "Enter Menu       ", 1 << SACTION_ENTER_MENU },
        { "Gun Trigger      ", 1 << SACTION_GUN_TRIGGER },
        { "Gun A button     ", 1 << SACTION_GUN_A },
        { "Gun B button     ", 1 << SACTION_GUN_B },
        { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
        { "Gun Trigger      ", 1 << SACTION_GUN_TRIGGER },
        { "Gun A button     ", 1 << SACTION_GUN_A },
        { "Gun B button     ", 1 << SACTION_GUN_B },
        { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
-#ifndef __ARM_ARCH_7A__ /* XXX */
+#if MENU_SHOW_VOLUME
        { "Volume Up        ", 1 << SACTION_VOLUME_UP },
        { "Volume Down      ", 1 << SACTION_VOLUME_DOWN },
 #endif
        { "Volume Up        ", 1 << SACTION_VOLUME_UP },
        { "Volume Down      ", 1 << SACTION_VOLUME_DOWN },
 #endif
+       { "Analog toggle    ", 1 << SACTION_ANALOG_TOGGLE },
        { NULL,                0 }
 };
 
        { NULL,                0 }
 };
 
@@ -694,7 +920,7 @@ static char *mystrip(char *str)
 
        len = strlen(str);
        for (i = len - 1; i >= 0; i--)
 
        len = strlen(str);
        for (i = len - 1; i >= 0; i--)
-               if (str[i] != ' ') break;
+               if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n') break;
        str[i+1] = 0;
 
        return str;
        str[i+1] = 0;
 
        return str;
@@ -712,8 +938,6 @@ static void get_line(char *d, size_t size, const char *s)
                len = size - 1;
        strncpy(d, s, len);
        d[len] = 0;
                len = size - 1;
        strncpy(d, s, len);
        d[len] = 0;
-
-       mystrip(d);
 }
 
 static void keys_write_all(FILE *f)
 }
 
 static void keys_write_all(FILE *f)
@@ -820,7 +1044,10 @@ static void keys_load_all(const char *cfg)
        while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
                p += 10;
 
        while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
                p += 10;
 
+               // don't strip 'dev' because there are weird devices
+               // with names with space at the end
                get_line(dev, sizeof(dev), p);
                get_line(dev, sizeof(dev), p);
+
                dev_id = in_config_parse_dev(dev);
                if (dev_id < 0) {
                        printf("input: can't handle dev: %s\n", dev);
                dev_id = in_config_parse_dev(dev);
                if (dev_id < 0) {
                        printf("input: can't handle dev: %s\n", dev);
@@ -894,17 +1121,21 @@ static int key_config_loop_wrap(int id, int keys)
        return 0;
 }
 
        return 0;
 }
 
+static const char h_nubmode[] = "Maps nub-like analog controls to PSX ones better\n"
+                               "Might cause problems with real analog sticks";
 static const char *adevnames[IN_MAX_DEVS + 2];
 static int stick_sel[2];
 
 static menu_entry e_menu_keyconfig_analog[] =
 {
 static const char *adevnames[IN_MAX_DEVS + 2];
 static int stick_sel[2];
 
 static menu_entry e_menu_keyconfig_analog[] =
 {
-       mee_enum ("Left stick (L3)",  0, stick_sel[0], adevnames),
-       mee_range("  X axis",    0, in_adev_axis[0][0], 0, 7),
-       mee_range("  Y axis",    0, in_adev_axis[0][1], 0, 7),
-       mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
-       mee_range("  X axis",    0, in_adev_axis[1][0], 0, 7),
-       mee_range("  Y axis",    0, in_adev_axis[1][1], 0, 7),
+       mee_enum   ("Left stick (L3)",  0, stick_sel[0], adevnames),
+       mee_range  ("  X axis",    0, in_adev_axis[0][0], 0, 7),
+       mee_range  ("  Y axis",    0, in_adev_axis[0][1], 0, 7),
+       mee_onoff_h("  nub mode",  0, in_adev_is_nublike[0], 1, h_nubmode),
+       mee_enum   ("Right stick (R3)", 0, stick_sel[1], adevnames),
+       mee_range  ("  X axis",    0, in_adev_axis[1][0], 0, 7),
+       mee_range  ("  Y axis",    0, in_adev_axis[1][1], 0, 7),
+       mee_onoff_h("  nub mode",  0, in_adev_is_nublike[1], 1, h_nubmode),
        mee_end,
 };
 
        mee_end,
 };
 
@@ -971,9 +1202,9 @@ static const char *mgn_saveloadcfg(int id, int *offs)
 static int mh_savecfg(int id, int keys)
 {
        if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
 static int mh_savecfg(int id, int keys)
 {
        if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
-               me_update_msg("config saved");
+               menu_update_msg("config saved");
        else
        else
-               me_update_msg("failed to write config");
+               menu_update_msg("failed to write config");
 
        return 1;
 }
 
        return 1;
 }
@@ -982,7 +1213,7 @@ static int mh_input_rescan(int id, int keys)
 {
        //menu_sync_config();
        in_probe();
 {
        //menu_sync_config();
        in_probe();
-       me_update_msg("rescan complete.");
+       menu_update_msg("rescan complete.");
 
        return 0;
 }
 
        return 0;
 }
@@ -991,6 +1222,8 @@ static const char *men_in_type_sel[] = {
        "Standard (SCPH-1080)",
        "Analog (SCPH-1150)",
        "GunCon",
        "Standard (SCPH-1080)",
        "Analog (SCPH-1150)",
        "GunCon",
+       "Konami Gun",
+       "None",
        NULL
 };
 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
        NULL
 };
 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
@@ -1035,26 +1268,64 @@ static int menu_loop_keyconfig(int id, int keys)
 
 // ------------ gfx options menu ------------
 
 
 // ------------ gfx options menu ------------
 
-static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
+static const char *men_scaler[] = {
+       "1x1", "integer scaled 2x", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL
+};
+static const char *men_soft_filter[] = { "None",
+#ifdef __ARM_NEON__
+       "scale2x", "eagle2x",
+#endif
+       NULL };
+static const char *men_dummy[] = { NULL };
+static const char *men_centering[] = { "Auto", "Ingame", "Borderless", "Force", NULL };
+static const char h_scaler[]    = "int. 2x  - scales w. or h. 2x if it fits on screen\n"
+                                 "int. 4:3 - uses integer if possible, else fractional";
 static const char h_cscaler[]   = "Displays the scaler layer, you can resize it\n"
                                  "using d-pad or move it using R+d-pad";
 static const char h_cscaler[]   = "Displays the scaler layer, you can resize it\n"
                                  "using d-pad or move it using R+d-pad";
-static const char *men_dummy[] = { NULL };
+static const char h_soft_filter[] = "Works only if game uses low resolution modes";
+static const char h_gamma[]     = "Gamma/brightness adjustment (default 100)";
+#ifdef __ARM_NEON__
+static const char *men_scanlines[] = { "OFF", "1", "2", "3", NULL };
+static const char h_scanline_l[]  = "Scanline brightness, 0-100%";
+#endif
 
 static int menu_loop_cscaler(int id, int keys)
 {
 
 static int menu_loop_cscaler(int id, int keys)
 {
+       void *saved_layer = NULL;
+       size_t saved_layer_size = 0;
+       int was_layer_clipped = 0;
        unsigned int inp;
 
        unsigned int inp;
 
-       scaling = SCALE_CUSTOM;
+       if (!pl_vout_buf)
+               return -1;
+
+       g_scaler = SCALE_CUSTOM;
+       saved_layer_size = last_vout_w * last_vout_h * last_vout_bpp / 8;
+       saved_layer = malloc(saved_layer_size);
+       if (saved_layer)
+               memcpy(saved_layer, pl_vout_buf, saved_layer_size);
 
        plat_gvideo_open(Config.PsxType);
 
 
        plat_gvideo_open(Config.PsxType);
 
+       menu_draw_begin(0, 1);
+       memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
+       menu_draw_end();
+
        for (;;)
        {
        for (;;)
        {
-               menu_draw_begin(0);
-               memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
-               text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
-               text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
-               menu_draw_end();
+               if (saved_layer && last_vout_bpp == 16) {
+                       int top_x = max(0, -g_layer_x * last_vout_w / 800) + 1;
+                       int top_y = max(0, -g_layer_y * last_vout_h / 480) + 1;
+                       char text[128];
+                       memcpy(pl_vout_buf, saved_layer, saved_layer_size);
+                       snprintf(text, sizeof(text), "%d,%d %dx%d",
+                               g_layer_x, g_layer_y, g_layer_w, g_layer_h);
+                       basic_text_out16_nf(pl_vout_buf, last_vout_w,
+                               top_x, top_y, text);
+                       basic_text_out16_nf(pl_vout_buf, last_vout_w, 2,
+                               last_vout_h - 20, "d-pad: resize, R+d-pad: move");
+                       pl_vout_buf = plat_gvideo_flip();
+               }
 
                inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT
                                |PBTN_R|PBTN_MOK|PBTN_MBACK, NULL, 40);
 
                inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT
                                |PBTN_R|PBTN_MOK|PBTN_MBACK, NULL, 40);
@@ -1072,33 +1343,49 @@ static int menu_loop_cscaler(int id, int keys)
                        break;
 
                if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
                        break;
 
                if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
-                       if (g_layer_x < 0)   g_layer_x = 0;
-                       if (g_layer_x > 640) g_layer_x = 640;
-                       if (g_layer_y < 0)   g_layer_y = 0;
-                       if (g_layer_y > 420) g_layer_y = 420;
-                       if (g_layer_w < 160) g_layer_w = 160;
-                       if (g_layer_h < 60)  g_layer_h = 60;
-                       if (g_layer_x + g_layer_w > 800)
-                               g_layer_w = 800 - g_layer_x;
-                       if (g_layer_y + g_layer_h > 480)
-                               g_layer_h = 480 - g_layer_y;
+                       int layer_clipped = 0;
+                       g_layer_x = max(-320, min(g_layer_x, 640));
+                       g_layer_y = max(-240, min(g_layer_y, 400));
+                       g_layer_w = max(160, g_layer_w);
+                       g_layer_h = max( 60, g_layer_h);
+                       if (g_layer_x < 0 || g_layer_x + g_layer_w > 800)
+                               layer_clipped = 1;
+                       if (g_layer_w > 800+400)
+                               g_layer_w = 800+400;
+                       if (g_layer_y < 0 || g_layer_y + g_layer_h > 480)
+                               layer_clipped = 1;
+                       if (g_layer_h > 480+360)
+                               g_layer_h = 480+360;
                        // resize the layer
                        plat_gvideo_open(Config.PsxType);
                        // resize the layer
                        plat_gvideo_open(Config.PsxType);
+                       if (layer_clipped || was_layer_clipped)
+                               pl_vout_buf = plat_gvideo_set_mode(&last_vout_w,
+                                       &last_vout_h, &last_vout_bpp);
+                       was_layer_clipped = layer_clipped;
                }
        }
 
        plat_gvideo_close();
                }
        }
 
        plat_gvideo_close();
+       free(saved_layer);
 
        return 0;
 }
 
 static menu_entry e_menu_gfx_options[] =
 {
 
        return 0;
 }
 
 static menu_entry e_menu_gfx_options[] =
 {
-       mee_enum      ("Scaler",                   MA_OPT_SCALER, scaling, men_scaler),
+       mee_enum      ("Screen centering",         MA_OPT_CENTERING, pl_rearmed_cbs.screen_centering_type, men_centering),
+       mee_enum_h    ("Scaler",                   MA_OPT_VARSCALER, g_scaler, men_scaler, h_scaler),
+       mee_enum      ("Video output mode",        MA_OPT_VOUT_MODE, plat_target.vout_method, men_dummy),
        mee_onoff     ("Software Scaling",         MA_OPT_SCALER2, soft_scaling, 1),
        mee_onoff     ("Software Scaling",         MA_OPT_SCALER2, soft_scaling, 1),
-       mee_enum      ("Filter",                   MA_OPT_FILTERING, filter, men_dummy),
+       mee_enum      ("Hardware Filter",          MA_OPT_HWFILTER, plat_target.hwfilter, men_dummy),
+       mee_enum_h    ("Software Filter",          MA_OPT_SWFILTER, soft_filter, men_soft_filter, h_soft_filter),
+#ifdef __ARM_NEON__
+       mee_enum      ("Scanlines",                MA_OPT_SCANLINES, scanlines, men_scanlines),
+       mee_range_h   ("Scanline brightness",      MA_OPT_SCANLINE_LEVEL, scanline_level, 0, 100, h_scanline_l),
+#endif
+       mee_range_h   ("Gamma adjustment",         MA_OPT_GAMMA, g_gamma, 1, 200, h_gamma),
 //     mee_onoff     ("Vsync",                    0, vsync, 1),
 //     mee_onoff     ("Vsync",                    0, vsync, 1),
-       mee_cust_h    ("Setup custom scaler",      MA_OPT_SCALER_C, menu_loop_cscaler, NULL, h_cscaler),
+       mee_cust_h    ("Setup custom scaler",      MA_OPT_VARSCALER_C, menu_loop_cscaler, NULL, h_cscaler),
        mee_end,
 };
 
        mee_end,
 };
 
@@ -1111,44 +1398,61 @@ static int menu_loop_gfx_options(int id, int keys)
        return 0;
 }
 
        return 0;
 }
 
-// XXX
-void menu_set_filter_list(void *filters)
-{
-       int i;
-
-       i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
-       e_menu_gfx_options[i].data = filters;
-       me_enable(e_menu_gfx_options, MA_OPT_FILTERING, filters != NULL);
-}
-
 // ------------ bios/plugins ------------
 
 // ------------ bios/plugins ------------
 
-#ifdef __ARM_NEON__
+#ifdef BUILTIN_GPU_NEON
 
 
-static const char h_gpu_neon[] = "Configure built-in NEON GPU plugin";
+static const char h_gpu_neon[] =
+       "Configure built-in NEON GPU plugin";
+static const char h_gpu_neon_enhanced[] =
+       "Renders in double resolution at the cost of lower performance\n"
+       "(not available for high resolution games)";
+static const char h_gpu_neon_enhanced_hack[] =
+       "Speed hack for above option (glitches some games)";
 static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
 
 static menu_entry e_menu_plugin_gpu_neon[] =
 {
        mee_enum      ("Enable interlace mode",      0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
 static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
 
 static menu_entry e_menu_plugin_gpu_neon[] =
 {
        mee_enum      ("Enable interlace mode",      0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
+       mee_onoff_h   ("Enhanced resolution",        0, pl_rearmed_cbs.gpu_neon.enhancement_enable, 1, h_gpu_neon_enhanced),
+       mee_onoff_h   ("Enhanced res. speed hack",   0, pl_rearmed_cbs.gpu_neon.enhancement_no_main, 1, h_gpu_neon_enhanced_hack),
+       mee_onoff     ("Enh. res. texture adjust",   0, pl_rearmed_cbs.gpu_neon.enhancement_tex_adj, 1),
        mee_end,
 };
 
 static int menu_loop_plugin_gpu_neon(int id, int keys)
 {
        mee_end,
 };
 
 static int menu_loop_plugin_gpu_neon(int id, int keys)
 {
-       int sel = 0;
+       static int sel = 0;
        me_loop(e_menu_plugin_gpu_neon, &sel);
        return 0;
 }
 
 #endif
 
        me_loop(e_menu_plugin_gpu_neon, &sel);
        return 0;
 }
 
 #endif
 
+static menu_entry e_menu_plugin_gpu_unai_old[] =
+{
+       mee_onoff     ("Skip every 2nd line",        0, pl_rearmed_cbs.gpu_unai_old.lineskip, 1),
+       mee_onoff     ("Abe's Odyssey hack",         0, pl_rearmed_cbs.gpu_unai_old.abe_hack, 1),
+       mee_onoff     ("Disable lighting",           0, pl_rearmed_cbs.gpu_unai_old.no_light, 1),
+       mee_onoff     ("Disable blending",           0, pl_rearmed_cbs.gpu_unai_old.no_blend, 1),
+       mee_end,
+};
+
+static int menu_loop_plugin_gpu_unai_old(int id, int keys)
+{
+       int sel = 0;
+       me_loop(e_menu_plugin_gpu_unai_old, &sel);
+       return 0;
+}
+
 static menu_entry e_menu_plugin_gpu_unai[] =
 {
 static menu_entry e_menu_plugin_gpu_unai[] =
 {
-       mee_onoff     ("Skip every 2nd line",        0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
-       mee_onoff     ("Abe's Odyssey hack",         0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
-       mee_onoff     ("Disable lighting",           0, pl_rearmed_cbs.gpu_unai.no_light, 1),
-       mee_onoff     ("Disable blending",           0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
+       mee_onoff     ("Interlace",                  0, pl_rearmed_cbs.gpu_unai.ilace_force, 1),
+       mee_onoff     ("Dithering",                  0, pl_rearmed_cbs.gpu_unai.dithering, 1),
+       mee_onoff     ("Lighting",                   0, pl_rearmed_cbs.gpu_unai.lighting, 1),
+       mee_onoff     ("Fast lighting",              0, pl_rearmed_cbs.gpu_unai.fast_lighting, 1),
+       mee_onoff     ("Blending",                   0, pl_rearmed_cbs.gpu_unai.blending, 1),
+       mee_onoff     ("Pixel skip",                 0, pl_rearmed_cbs.gpu_unai.pixel_skip, 1),
        mee_end,
 };
 
        mee_end,
 };
 
@@ -1159,6 +1463,7 @@ static int menu_loop_plugin_gpu_unai(int id, int keys)
        return 0;
 }
 
        return 0;
 }
 
+
 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
 //static const char h_gpu_0[]            = "Needed for Chrono Cross";
 static const char h_gpu_1[]            = "Capcom fighting games";
 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
 //static const char h_gpu_0[]            = "Needed for Chrono Cross";
 static const char h_gpu_1[]            = "Capcom fighting games";
@@ -1231,13 +1536,16 @@ static int menu_loop_plugin_gpu_peopsgl(int id, int keys)
 
 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
 static const char h_spu_volboost[]  = "Large values cause distortion";
 
 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
 static const char h_spu_volboost[]  = "Large values cause distortion";
+static const char h_spu_tempo[]     = "Slows down audio if emu is too slow\n"
+                                     "This is inaccurate and breaks games";
 
 static menu_entry e_menu_plugin_spu[] =
 {
        mee_range_h   ("Volume boost",              0, volume_boost, -5, 30, h_spu_volboost),
 
 static menu_entry e_menu_plugin_spu[] =
 {
        mee_range_h   ("Volume boost",              0, volume_boost, -5, 30, h_spu_volboost),
-       mee_onoff     ("Reverb",                    0, iUseReverb, 2),
-       mee_enum      ("Interpolation",             0, iUseInterpolation, men_spu_interp),
-       mee_onoff     ("Adjust XA pitch",           0, iXAPitch, 1),
+       mee_onoff     ("Reverb",                    0, spu_config.iUseReverb, 1),
+       mee_enum      ("Interpolation",             0, spu_config.iUseInterpolation, men_spu_interp),
+       //mee_onoff     ("Adjust XA pitch",           0, spu_config.iXAPitch, 1),
+       mee_onoff_h   ("Adjust tempo",              0, spu_config.iTempo, 1, h_spu_tempo),
        mee_end,
 };
 
        mee_end,
 };
 
@@ -1252,21 +1560,20 @@ static const char h_bios[]       = "HLE is simulated BIOS. BIOS selection is sav
                                   "savestates and can't be changed there. Must save\n"
                                   "config and reload the game for change to take effect";
 static const char h_plugin_gpu[] = 
                                   "savestates and can't be changed there. Must save\n"
                                   "config and reload the game for change to take effect";
 static const char h_plugin_gpu[] = 
-#ifdef __ARM_NEON__
+#ifdef BUILTIN_GPU_NEON
                                   "builtin_gpu is the NEON GPU, very fast and accurate\n"
                                   "builtin_gpu is the NEON GPU, very fast and accurate\n"
-                                  "gpuPEOPS "
-#else
-                                  "builtin_gpu "
 #endif
 #endif
-                                               "is Pete's soft GPU, slow but accurate\n"
-                                  "gpuPCSX4ALL is GPU from PCSX4ALL, fast but glitchy\n"
-                                  "gpuGLES Pete's hw GPU, uses 3D chip but is glitchy\n"
+                                  "gpu_peops is Pete's soft GPU, slow but accurate\n"
+                                  "gpu_unai_old is from old PCSX4ALL, fast but glitchy\n"
+                                  "gpu_unai is newer, more accurate but slower\n"
+                                  "gpu_gles Pete's hw GPU, uses 3D chip but is glitchy\n"
                                   "must save config and reload the game if changed";
 static const char h_plugin_spu[] = "spunull effectively disables sound\n"
                                   "must save config and reload the game if changed";
 static const char h_gpu_peops[]  = "Configure P.E.Op.S. SoftGL Driver V1.17";
 static const char h_gpu_peopsgl[]= "Configure P.E.Op.S. MesaGL Driver V1.78";
                                   "must save config and reload the game if changed";
 static const char h_plugin_spu[] = "spunull effectively disables sound\n"
                                   "must save config and reload the game if changed";
 static const char h_gpu_peops[]  = "Configure P.E.Op.S. SoftGL Driver V1.17";
 static const char h_gpu_peopsgl[]= "Configure P.E.Op.S. MesaGL Driver V1.78";
-static const char h_gpu_unai[]   = "Configure Unai/PCSX4ALL Team GPU plugin";
+static const char h_gpu_unai_old[] = "Configure Unai/PCSX4ALL Team GPU plugin (old)";
+static const char h_gpu_unai[]   = "Configure Unai/PCSX4ALL Team plugin (new)";
 static const char h_spu[]        = "Configure built-in P.E.Op.S. Sound Driver V1.7";
 
 static menu_entry e_menu_plugin_options[] =
 static const char h_spu[]        = "Configure built-in P.E.Op.S. Sound Driver V1.7";
 
 static menu_entry e_menu_plugin_options[] =
@@ -1274,12 +1581,13 @@ static menu_entry e_menu_plugin_options[] =
        mee_enum_h    ("BIOS",                          0, bios_sel, bioses, h_bios),
        mee_enum_h    ("GPU plugin",                    0, gpu_plugsel, gpu_plugins, h_plugin_gpu),
        mee_enum_h    ("SPU plugin",                    0, spu_plugsel, spu_plugins, h_plugin_spu),
        mee_enum_h    ("BIOS",                          0, bios_sel, bioses, h_bios),
        mee_enum_h    ("GPU plugin",                    0, gpu_plugsel, gpu_plugins, h_plugin_gpu),
        mee_enum_h    ("SPU plugin",                    0, spu_plugsel, spu_plugins, h_plugin_spu),
-#ifdef __ARM_NEON__
+#ifdef BUILTIN_GPU_NEON
        mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu_neon, h_gpu_neon),
 #endif
        mee_handler_h ("Configure gpu_peops plugin",    menu_loop_plugin_gpu_peops, h_gpu_peops),
        mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu_neon, h_gpu_neon),
 #endif
        mee_handler_h ("Configure gpu_peops plugin",    menu_loop_plugin_gpu_peops, h_gpu_peops),
-       mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
-       mee_handler_h ("Configure GLES GPU plugin",     menu_loop_plugin_gpu_peopsgl, h_gpu_peopsgl),
+       mee_handler_h ("Configure gpu_unai_old GPU plugin", menu_loop_plugin_gpu_unai_old, h_gpu_unai_old),
+       mee_handler_h ("Configure gpu_unai GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
+       mee_handler_h ("Configure gpu_gles GPU plugin", menu_loop_plugin_gpu_peopsgl, h_gpu_peopsgl),
        mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
        mee_end,
 };
        mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
        mee_end,
 };
@@ -1302,29 +1610,37 @@ static int menu_loop_plugin_options(int id, int keys)
 
 // ------------ adv options menu ------------
 
 
 // ------------ adv options menu ------------
 
-static const char h_cfg_psxclk[]  = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
-                                   "(lower value - less work for the emu, may be faster)";
+#ifndef DRC_DISABLE
+static const char h_cfg_noch[]    = "Disables game-specific compatibility hacks";
 static const char h_cfg_nosmc[]   = "Will cause crashes when loading, break memcards";
 static const char h_cfg_gteunn[]  = "May cause graphical glitches";
 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
 static const char h_cfg_nosmc[]   = "Will cause crashes when loading, break memcards";
 static const char h_cfg_gteunn[]  = "May cause graphical glitches";
 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
+#endif
+static const char h_cfg_stalls[]  = "Will cause some games to run too fast";
 
 static menu_entry e_menu_speed_hacks[] =
 {
 
 static menu_entry e_menu_speed_hacks[] =
 {
-       mee_range_h   ("PSX CPU clock, %%",        0, psx_clock, 1, 500, h_cfg_psxclk),
+#ifndef DRC_DISABLE
+       mee_onoff_h   ("Disable compat hacks",     0, new_dynarec_hacks, NDHACK_NO_COMPAT_HACKS, h_cfg_noch),
        mee_onoff_h   ("Disable SMC checks",       0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
        mee_onoff_h   ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
        mee_onoff_h   ("Disable GTE flags",        0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
        mee_onoff_h   ("Disable SMC checks",       0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
        mee_onoff_h   ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
        mee_onoff_h   ("Disable GTE flags",        0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
+#endif
+       mee_onoff_h   ("Disable CPU/GTE stalls",   0, menu_iopts[0], 1, h_cfg_stalls),
        mee_end,
 };
 
 static int menu_loop_speed_hacks(int id, int keys)
 {
        static int sel = 0;
        mee_end,
 };
 
 static int menu_loop_speed_hacks(int id, int keys)
 {
        static int sel = 0;
+       menu_iopts[0] = Config.DisableStalls;
        me_loop(e_menu_speed_hacks, &sel);
        me_loop(e_menu_speed_hacks, &sel);
+       Config.DisableStalls = menu_iopts[0];
        return 0;
 }
 
        return 0;
 }
 
-static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
+static const char *men_autooo[]  = { "Auto", "Off", "On", NULL };
+
 static const char h_cfg_cpul[]   = "Shows CPU usage in %";
 static const char h_cfg_spu[]    = "Shows active SPU channels\n"
                                   "(green: normal, red: fmod, blue: noise)";
 static const char h_cfg_cpul[]   = "Shows CPU usage in %";
 static const char h_cfg_spu[]    = "Shows active SPU channels\n"
                                   "(green: normal, red: fmod, blue: noise)";
@@ -1332,31 +1648,38 @@ static const char h_cfg_fl[]     = "Frame Limiter keeps the game from running to
 static const char h_cfg_xa[]     = "Disables XA sound, which can sometimes improve performance";
 static const char h_cfg_cdda[]   = "Disable CD Audio for a performance boost\n"
                                   "(proper .cue/.bin dump is needed otherwise)";
 static const char h_cfg_xa[]     = "Disables XA sound, which can sometimes improve performance";
 static const char h_cfg_cdda[]   = "Disable CD Audio for a performance boost\n"
                                   "(proper .cue/.bin dump is needed otherwise)";
-static const char h_cfg_sio[]    = "You should not need this, breaks games";
-static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
-static const char h_cfg_rcnt1[]  = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
-                                  "(timing hack, breaks other games)";
-static const char h_cfg_rcnt2[]  = "InuYasha Sengoku Battle Fix\n"
-                                  "(timing hack, breaks other games)";
-static const char h_cfg_cdrr[]   = "Compatibility tweak (CD timing hack, breaks FMVs)";
+#ifndef DRC_DISABLE
 static const char h_cfg_nodrc[]  = "Disable dynamic recompiler and use interpreter\n"
                                   "Might be useful to overcome some dynarec bugs";
 static const char h_cfg_nodrc[]  = "Disable dynamic recompiler and use interpreter\n"
                                   "Might be useful to overcome some dynarec bugs";
-static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
-                                  "must reload game for any change to take effect";
+#endif
+static const char h_cfg_shacks[] = "Breaks games but may give better performance";
+static const char h_cfg_icache[] = "Support F1 games (only when dynarec is off)";
+static const char h_cfg_exc[]    = "Emulate some PSX's debug hw like breakpoints\n"
+                                  "and exceptions (slow, interpreter only, keep off)";
+static const char h_cfg_gpul[]   = "Try enabling this if the game misses some graphics\n"
+                                  "causes a performance hit";
+static const char h_cfg_ffps[]   = "Instead of 50/60fps for PAL/NTSC use ~49.75/59.81\n"
+                                  "Closer to real hw but doesn't match modern displays.";
+static const char h_cfg_psxclk[]  = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
+                                   "(adjust this if the game is too slow/too fast/hangs)";
+
+enum { AMO_XA, AMO_CDDA, AMO_IC, AMO_BP, AMO_CPU, AMO_GPUL, AMO_FFPS };
 
 static menu_entry e_menu_adv_options[] =
 {
        mee_onoff_h   ("Show CPU load",          0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
        mee_onoff_h   ("Show SPU channels",      0, g_opts, OPT_SHOWSPU, h_cfg_spu),
        mee_onoff_h   ("Disable Frame Limiter",  0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
 
 static menu_entry e_menu_adv_options[] =
 {
        mee_onoff_h   ("Show CPU load",          0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
        mee_onoff_h   ("Show SPU channels",      0, g_opts, OPT_SHOWSPU, h_cfg_spu),
        mee_onoff_h   ("Disable Frame Limiter",  0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
-       mee_onoff_h   ("Disable XA Decoding",    0, Config.Xa, 1, h_cfg_xa),
-       mee_onoff_h   ("Disable CD Audio",       0, Config.Cdda, 1, h_cfg_cdda),
-       mee_onoff_h   ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
-       mee_onoff_h   ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
-       //mee_onoff_h   ("Rootcounter hack",       0, Config.RCntFix, 1, h_cfg_rcnt1),
-       mee_onoff_h   ("Rootcounter hack 2",     0, Config.VSyncWA, 1, h_cfg_rcnt2),
-       mee_enum_h    ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
-       mee_onoff_h   ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
+       mee_onoff_h   ("Disable XA Decoding",    0, menu_iopts[AMO_XA],   1, h_cfg_xa),
+       mee_onoff_h   ("Disable CD Audio",       0, menu_iopts[AMO_CDDA], 1, h_cfg_cdda),
+       mee_onoff_h   ("ICache emulation",       0, menu_iopts[AMO_IC],   1, h_cfg_icache),
+       mee_onoff_h   ("BP exception emulation", 0, menu_iopts[AMO_BP],   1, h_cfg_exc),
+       mee_enum_h    ("GPU l-list slow walking",0, menu_iopts[AMO_GPUL], men_autooo, h_cfg_gpul),
+       mee_enum_h    ("Fractional framerate",   0, menu_iopts[AMO_FFPS], men_autooo, h_cfg_ffps),
+#if !defined(DRC_DISABLE) || defined(LIGHTREC)
+       mee_onoff_h   ("Disable dynarec (slow!)",0, menu_iopts[AMO_CPU],  1, h_cfg_nodrc),
+#endif
+       mee_range_h   ("PSX CPU clock, %",       0, psx_clock, 1, 500, h_cfg_psxclk),
        mee_handler_h ("[Speed hacks]",             menu_loop_speed_hacks, h_cfg_shacks),
        mee_end,
 };
        mee_handler_h ("[Speed hacks]",             menu_loop_speed_hacks, h_cfg_shacks),
        mee_end,
 };
@@ -1364,7 +1687,29 @@ static menu_entry e_menu_adv_options[] =
 static int menu_loop_adv_options(int id, int keys)
 {
        static int sel = 0;
 static int menu_loop_adv_options(int id, int keys)
 {
        static int sel = 0;
+       static struct {
+               boolean *opt;
+               int *mopt;
+       } opts[] = {
+               { &Config.Xa,      &menu_iopts[AMO_XA] },
+               { &Config.Cdda,    &menu_iopts[AMO_CDDA] },
+               { &Config.icache_emulation, &menu_iopts[AMO_IC] },
+               { &Config.PreciseExceptions, &menu_iopts[AMO_BP] },
+               { &Config.Cpu,     &menu_iopts[AMO_CPU] },
+       };
+       int i;
+       for (i = 0; i < ARRAY_SIZE(opts); i++)
+               *opts[i].mopt = *opts[i].opt;
+       menu_iopts[AMO_GPUL] = Config.GpuListWalking + 1;
+       menu_iopts[AMO_FFPS] = Config.FractionalFramerate + 1;
+
        me_loop(e_menu_adv_options, &sel);
        me_loop(e_menu_adv_options, &sel);
+
+       for (i = 0; i < ARRAY_SIZE(opts); i++)
+               *opts[i].opt = *opts[i].mopt;
+       Config.GpuListWalking = menu_iopts[AMO_GPUL] - 1;
+       Config.FractionalFramerate = menu_iopts[AMO_FFPS] - 1;
+
        return 0;
 }
 
        return 0;
 }
 
@@ -1373,7 +1718,7 @@ static int menu_loop_adv_options(int id, int keys)
 static int mh_restore_defaults(int id, int keys)
 {
        menu_set_defconfig();
 static int mh_restore_defaults(int id, int keys)
 {
        menu_set_defconfig();
-       me_update_msg("defaults restored");
+       menu_update_msg("defaults restored");
        return 1;
 }
 
        return 1;
 }
 
@@ -1387,6 +1732,7 @@ static const char h_confirm_save[]    = "Ask for confirmation when overwriting s
 static const char h_restore_def[]     = "Switches back to default / recommended\n"
                                        "configuration";
 static const char h_frameskip[]       = "Warning: frameskip sometimes causes glitches\n";
 static const char h_restore_def[]     = "Switches back to default / recommended\n"
                                        "configuration";
 static const char h_frameskip[]       = "Warning: frameskip sometimes causes glitches\n";
+static const char h_sputhr[]          = "Warning: has some known bugs\n";
 
 static menu_entry e_menu_options[] =
 {
 
 static menu_entry e_menu_options[] =
 {
@@ -1396,6 +1742,11 @@ static menu_entry e_menu_options[] =
        mee_onoff     ("Show FPS",                 0, g_opts, OPT_SHOWFPS),
        mee_enum      ("Region",                   0, region, men_region),
        mee_range     ("CPU clock",                MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
        mee_onoff     ("Show FPS",                 0, g_opts, OPT_SHOWFPS),
        mee_enum      ("Region",                   0, region, men_region),
        mee_range     ("CPU clock",                MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
+#ifdef C64X_DSP
+       mee_onoff_h   ("Use C64x DSP for sound",   MA_OPT_SPU_THREAD, spu_config.iUseThread, 1, h_sputhr),
+#else
+       mee_onoff_h   ("Threaded SPU",             MA_OPT_SPU_THREAD, spu_config.iUseThread, 1, h_sputhr),
+#endif
        mee_handler_id("[Display]",                MA_OPT_DISP_OPTS, menu_loop_gfx_options),
        mee_handler   ("[BIOS/Plugins]",           menu_loop_plugin_options),
        mee_handler   ("[Advanced]",               menu_loop_adv_options),
        mee_handler_id("[Display]",                MA_OPT_DISP_OPTS, menu_loop_gfx_options),
        mee_handler   ("[BIOS/Plugins]",           menu_loop_plugin_options),
        mee_handler   ("[Advanced]",               menu_loop_adv_options),
@@ -1408,10 +1759,9 @@ static menu_entry e_menu_options[] =
 static int menu_loop_options(int id, int keys)
 {
        static int sel = 0;
 static int menu_loop_options(int id, int keys)
 {
        static int sel = 0;
-       int i;
 
 
-       i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
-       e_menu_options[i].enabled = cpu_clock_st > 0 ? 1 : 0;
+       me_enable(e_menu_options, MA_OPT_CPU_CLOCKS, cpu_clock_st > 0);
+       me_enable(e_menu_options, MA_OPT_SPU_THREAD, spu_config.iThreadAvail);
        me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
 
        me_loop(e_menu_options, &sel);
        me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
 
        me_loop(e_menu_options, &sel);
@@ -1455,7 +1805,7 @@ static void debug_menu_loop(void)
 
        while (1)
        {
 
        while (1)
        {
-               menu_draw_begin(0);
+               menu_draw_begin(0, 1);
                draw_frame_debug(gpuf, df_x, df_y);
                menu_draw_end();
 
                draw_frame_debug(gpuf, df_x, df_y);
                menu_draw_end();
 
@@ -1507,7 +1857,7 @@ static void draw_mc_bg(void)
                GetMcdBlockInfo(2, i + 1, &blocks2[i]);
        }
 
                GetMcdBlockInfo(2, i + 1, &blocks2[i]);
        }
 
-       menu_draw_begin(1);
+       menu_draw_begin(1, 1);
 
        memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
 
 
        memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
 
@@ -1537,10 +1887,10 @@ out:
 
 static void handle_memcard_sel(void)
 {
 
 static void handle_memcard_sel(void)
 {
-       Config.Mcd1[0] = 0;
+       strcpy(Config.Mcd1, "none");
        if (memcard1_sel != 0)
                snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
        if (memcard1_sel != 0)
                snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
-       Config.Mcd2[0] = 0;
+       strcpy(Config.Mcd2, "none");
        if (memcard2_sel != 0)
                snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
        LoadMcds(Config.Mcd1, Config.Mcd2);
        if (memcard2_sel != 0)
                snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
        LoadMcds(Config.Mcd1, Config.Mcd2);
@@ -1588,7 +1938,7 @@ static void draw_cheatlist(int sel)
        max_cnt = g_menuscreen_h / me_sfont_h;
        start = max_cnt / 2 - sel;
 
        max_cnt = g_menuscreen_h / me_sfont_h;
        start = max_cnt / 2 - sel;
 
-       menu_draw_begin(1);
+       menu_draw_begin(1, 1);
 
        for (i = 0; i < NumCheats; i++) {
                pos = start + i;
 
        for (i = 0; i < NumCheats; i++) {
                pos = start + i;
@@ -1640,11 +1990,8 @@ static void menu_bios_warn(void)
        static const char msg[] =
                "You don't seem to have copied any BIOS\n"
                "files to\n"
        static const char msg[] =
                "You don't seem to have copied any BIOS\n"
                "files to\n"
-#ifdef __ARM_ARCH_7A__ // XXX
-               "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
-#else
-               "pcsx_rearmed/bios/\n\n"
-#endif
+               MENU_BIOS_PATH "\n\n"
+
                "While many games work fine with fake\n"
                "(HLE) BIOS, others (like MGS and FF8)\n"
                "require BIOS to work.\n"
                "While many games work fine with fake\n"
                "(HLE) BIOS, others (like MGS and FF8)\n"
                "require BIOS to work.\n"
@@ -1672,7 +2019,6 @@ static void menu_bios_warn(void)
 // ------------ main menu ------------
 
 static menu_entry e_menu_main[];
 // ------------ main menu ------------
 
 static menu_entry e_menu_main[];
-void OnFile_Exit();
 
 static void draw_frame_main(void)
 {
 
 static void draw_frame_main(void)
 {
@@ -1691,7 +2037,7 @@ static void draw_frame_main(void)
        }
 
        if (ready_to_go) {
        }
 
        if (ready_to_go) {
-               capacity = plat_get_bat_capacity();
+               capacity = plat_target_bat_capacity_get();
                ltime = time(NULL);
                tmp = localtime(&ltime);
                strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
                ltime = time(NULL);
                tmp = localtime(&ltime);
                strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
@@ -1716,7 +2062,7 @@ static const char credits_text[] =
        "(C) 2005-2009 PCSX-df Team\n"
        "(C) 2009-2011 PCSX-Reloaded Team\n\n"
        "ARM recompiler (C) 2009-2011 Ari64\n"
        "(C) 2005-2009 PCSX-df Team\n"
        "(C) 2009-2011 PCSX-Reloaded Team\n\n"
        "ARM recompiler (C) 2009-2011 Ari64\n"
-#ifdef __ARM_NEON__
+#ifdef BUILTIN_GPU_NEON
        "ARM NEON GPU (c) 2011-2012 Exophase\n"
 #endif
        "PEOpS GPU and SPU by Pete Bernert\n"
        "ARM NEON GPU (c) 2011-2012 Exophase\n"
 #endif
        "PEOpS GPU and SPU by Pete Bernert\n"
@@ -1724,19 +2070,16 @@ static const char credits_text[] =
        "PCSX4ALL plugin by PCSX4ALL team\n"
        "  Chui, Franxis, Unai\n\n"
        "integration, optimization and\n"
        "PCSX4ALL plugin by PCSX4ALL team\n"
        "  Chui, Franxis, Unai\n\n"
        "integration, optimization and\n"
-       "  frontend (C) 2010-2012 notaz\n";
+       "  frontend (C) 2010-2015 notaz\n";
 
 static int reset_game(void)
 {
 
 static int reset_game(void)
 {
-       // sanity check
-       if (bios_sel == 0 && !Config.HLE)
-               return -1;
-
        ClosePlugins();
        OpenPlugins();
        SysReset();
        ClosePlugins();
        OpenPlugins();
        SysReset();
-       if (CheckCdrom() != -1) {
-               LoadCdrom();
+       if (Config.HLE) {
+               if (LoadCdrom() == -1)
+                       return -1;
        }
        return 0;
 }
        }
        return 0;
 }
@@ -1752,7 +2095,7 @@ static int reload_plugins(const char *cdimg)
        pcnt_hook_plugins();
        NetOpened = 0;
        if (OpenPlugins() == -1) {
        pcnt_hook_plugins();
        NetOpened = 0;
        if (OpenPlugins() == -1) {
-               me_update_msg("failed to open plugins");
+               menu_update_msg("failed to open plugins");
                return -1;
        }
        plugin_call_rearmed_cbs();
                return -1;
        }
        plugin_call_rearmed_cbs();
@@ -1766,13 +2109,17 @@ static int reload_plugins(const char *cdimg)
 
 static int run_bios(void)
 {
 
 static int run_bios(void)
 {
+       boolean origSlowBoot = Config.SlowBoot;
+
        if (bios_sel == 0)
                return -1;
 
        ready_to_go = 0;
        if (reload_plugins(NULL) != 0)
                return -1;
        if (bios_sel == 0)
                return -1;
 
        ready_to_go = 0;
        if (reload_plugins(NULL) != 0)
                return -1;
+       Config.SlowBoot = 1;
        SysReset();
        SysReset();
+       Config.SlowBoot = origSlowBoot;
 
        ready_to_go = 1;
        return 0;
 
        ready_to_go = 1;
        return 0;
@@ -1780,9 +2127,11 @@ static int run_bios(void)
 
 static int run_exe(void)
 {
 
 static int run_exe(void)
 {
+       const char *exts[] = { "exe", NULL };
        const char *fname;
 
        const char *fname;
 
-       fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
+       fname = menu_loop_romsel(last_selected_fname,
+               sizeof(last_selected_fname), exts, NULL);
        if (fname == NULL)
                return -1;
 
        if (fname == NULL)
                return -1;
 
@@ -1792,7 +2141,7 @@ static int run_exe(void)
 
        SysReset();
        if (Load(fname) != 0) {
 
        SysReset();
        if (Load(fname) != 0) {
-               me_update_msg("exe load failed, bad file?");
+               menu_update_msg("exe load failed, bad file?");
                printf("meh\n");
                return -1;
        }
                printf("meh\n");
                return -1;
        }
@@ -1803,6 +2152,8 @@ static int run_exe(void)
 
 static int run_cd_image(const char *fname)
 {
 
 static int run_cd_image(const char *fname)
 {
+       int autoload_state = g_autostateld_opt;
+
        ready_to_go = 0;
        reload_plugins(fname);
 
        ready_to_go = 0;
        reload_plugins(fname);
 
@@ -1812,7 +2163,7 @@ static int run_cd_image(const char *fname)
        if (CheckCdrom() == -1) {
                // Only check the CD if we are starting the console with a CD
                ClosePlugins();
        if (CheckCdrom() == -1) {
                // Only check the CD if we are starting the console with a CD
                ClosePlugins();
-               me_update_msg("unsupported/invalid CD image");
+               menu_update_msg("unsupported/invalid CD image");
                return -1;
        }
 
                return -1;
        }
 
@@ -1821,13 +2172,35 @@ static int run_cd_image(const char *fname)
        // Read main executable directly from CDRom and start it
        if (LoadCdrom() == -1) {
                ClosePlugins();
        // Read main executable directly from CDRom and start it
        if (LoadCdrom() == -1) {
                ClosePlugins();
-               me_update_msg("failed to load CD image");
+               menu_update_msg("failed to load CD image");
                return -1;
        }
 
                return -1;
        }
 
-       emu_on_new_cd();
+       emu_on_new_cd(1);
        ready_to_go = 1;
 
        ready_to_go = 1;
 
+       if (autoload_state) {
+               unsigned int newest = 0;
+               int time, slot, newest_slot = -1;
+
+               for (slot = 0; slot < 10; slot++) {
+                       if (emu_check_save_file(slot, &time)) {
+                               if ((unsigned int)time > newest) {
+                                       newest = time;
+                                       newest_slot = slot;
+                               }
+                       }
+               }
+
+               if (newest_slot >= 0) {
+                       lprintf("autoload slot %d\n", newest_slot);
+                       emu_load_state(newest_slot);
+               }
+               else {
+                       lprintf("no save to autoload.\n");
+               }
+       }
+
        return 0;
 }
 
        return 0;
 }
 
@@ -1836,7 +2209,9 @@ static int romsel_run(void)
        int prev_gpu, prev_spu;
        const char *fname;
 
        int prev_gpu, prev_spu;
        const char *fname;
 
-       fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
+       fname = menu_loop_romsel(last_selected_fname,
+                       sizeof(last_selected_fname), filter_exts,
+                       optional_cdimg_filter);
        if (fname == NULL)
                return -1;
 
        if (fname == NULL)
                return -1;
 
@@ -1860,15 +2235,18 @@ static int romsel_run(void)
                        return -1;
        }
 
                        return -1;
        }
 
-       strcpy(last_selected_fname, rom_fname_reload);
+       strcpy(last_selected_fname, fname);
+       menu_do_last_cd_img(0);
        return 0;
 }
 
 static int swap_cd_image(void)
 {
        return 0;
 }
 
 static int swap_cd_image(void)
 {
-       char *fname;
+       const char *fname;
 
 
-       fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
+       fname = menu_loop_romsel(last_selected_fname,
+                       sizeof(last_selected_fname), filter_exts,
+                       optional_cdimg_filter);
        if (fname == NULL)
                return -1;
 
        if (fname == NULL)
                return -1;
 
@@ -1879,18 +2257,18 @@ static int swap_cd_image(void)
 
        set_cd_image(fname);
        if (ReloadCdromPlugin() < 0) {
 
        set_cd_image(fname);
        if (ReloadCdromPlugin() < 0) {
-               me_update_msg("failed to load cdr plugin");
+               menu_update_msg("failed to load cdr plugin");
                return -1;
        }
        if (CDR_open() < 0) {
                return -1;
        }
        if (CDR_open() < 0) {
-               me_update_msg("failed to open cdr plugin");
+               menu_update_msg("failed to open cdr plugin");
                return -1;
        }
 
        SetCdOpenCaseTime(time(NULL) + 2);
        LidInterrupt();
 
                return -1;
        }
 
        SetCdOpenCaseTime(time(NULL) + 2);
        LidInterrupt();
 
-       strcpy(last_selected_fname, rom_fname_reload);
+       strcpy(last_selected_fname, fname);
        return 0;
 }
 
        return 0;
 }
 
@@ -1902,7 +2280,7 @@ static int swap_cd_multidisk(void)
 
        CDR_close();
        if (CDR_open() < 0) {
 
        CDR_close();
        if (CDR_open() < 0) {
-               me_update_msg("failed to open cdr plugin");
+               menu_update_msg("failed to open cdr plugin");
                return -1;
        }
 
                return -1;
        }
 
@@ -1914,11 +2292,12 @@ static int swap_cd_multidisk(void)
 
 static void load_pcsx_cht(void)
 {
 
 static void load_pcsx_cht(void)
 {
-       char path[256];
-       char *fname;
+       static const char *exts[] = { "cht", NULL };
+       const char *fname;
+       char msg[64];
 
 
-       path[0] = 0;
-       fname = menu_loop_romsel(path, sizeof(path));
+       fname = menu_loop_romsel(last_selected_fname,
+                       sizeof(last_selected_fname), exts, NULL);
        if (fname == NULL)
                return;
 
        if (fname == NULL)
                return;
 
@@ -1926,10 +2305,10 @@ static void load_pcsx_cht(void)
        LoadCheats(fname);
 
        if (NumCheats == 0 && NumCodes == 0)
        LoadCheats(fname);
 
        if (NumCheats == 0 && NumCodes == 0)
-               me_update_msg("failed to load cheats");
+               menu_update_msg("failed to load cheats");
        else {
        else {
-               snprintf(path, sizeof(path), "%d cheat(s) loaded", NumCheats + NumCodes);
-               me_update_msg(path);
+               snprintf(msg, sizeof(msg), "%d cheat(s) loaded", NumCheats + NumCodes);
+               menu_update_msg(msg);
        }
        me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
 }
        }
        me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
 }
@@ -1985,8 +2364,8 @@ static int main_menu_handler(int id, int keys)
                in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
                break;
        case MA_MAIN_EXIT:
                in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
                break;
        case MA_MAIN_EXIT:
-               OnFile_Exit();
-               break;
+               emu_core_ask_exit();
+               return 1;
        default:
                lprintf("%s: something unknown selected\n", __FUNCTION__);
                break;
        default:
                lprintf("%s: something unknown selected\n", __FUNCTION__);
                break;
@@ -2044,13 +2423,22 @@ static void menu_leave_emu(void);
 
 void menu_loop(void)
 {
 
 void menu_loop(void)
 {
+       static int warned_about_bios = 0;
        static int sel = 0;
 
        menu_leave_emu();
 
        static int sel = 0;
 
        menu_leave_emu();
 
-       if (bioses[1] == NULL && !warned_about_bios) {
-               menu_bios_warn();
-               warned_about_bios = 1;
+       if (config_save_counter == 0) {
+               // assume first run
+               if (bioses[1] != NULL) {
+                       // autoselect BIOS to make user's life easier
+                       snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[1]);
+                       bios_sel = 1;
+               }
+               else if (!warned_about_bios) {
+                       menu_bios_warn();
+                       warned_about_bios = 1;
+               }
        }
 
        me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
        }
 
        me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
@@ -2063,7 +2451,7 @@ void menu_loop(void)
 
        do {
                me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
 
        do {
                me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
-       } while (!ready_to_go);
+       } while (!ready_to_go && !g_emu_want_quit);
 
        /* wait until menu, ok, back is released */
        while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
 
        /* wait until menu, ok, back is released */
        while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
@@ -2117,7 +2505,8 @@ static void scan_bios_plugins(void)
                        continue;
 
                snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
                        continue;
 
                snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
-               if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
+               if (stat(fname, &st) != 0
+                   || (st.st_size != 512*1024 && st.st_size != 4*1024*1024)) {
                        printf("bad BIOS file: %s\n", ent->d_name);
                        continue;
                }
                        printf("bad BIOS file: %s\n", ent->d_name);
                        continue;
                }
@@ -2228,20 +2617,19 @@ do_memcards:
 void menu_init(void)
 {
        char buff[MAXPATHLEN];
 void menu_init(void)
 {
        char buff[MAXPATHLEN];
+       int i;
 
 
-       strcpy(last_selected_fname, "/media");
-
-       cpu_clock_st = cpu_clock = plat_cpu_clock_get();
+       cpu_clock_st = cpu_clock = plat_target_cpu_clock_get();
 
        scan_bios_plugins();
 
        scan_bios_plugins();
-       menu_init_common();
+       menu_init_base();
 
        menu_set_defconfig();
        menu_load_config(0);
        menu_do_last_cd_img(1);
 
        menu_set_defconfig();
        menu_load_config(0);
        menu_do_last_cd_img(1);
-       last_psx_w = 320;
-       last_psx_h = 240;
-       last_psx_bpp = 16;
+       last_vout_w = 320;
+       last_vout_h = 240;
+       last_vout_bpp = 16;
 
        g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
        g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
 
        g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
        g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
@@ -2253,72 +2641,40 @@ void menu_init(void)
        emu_make_path(buff, "skin/background.png", sizeof(buff));
        readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
 
        emu_make_path(buff, "skin/background.png", sizeof(buff));
        readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
 
-#ifndef __ARM_ARCH_7A__ /* XXX */
-       me_enable(e_menu_gfx_options, MA_OPT_SCALER, 0);
-       me_enable(e_menu_gfx_options, MA_OPT_FILTERING, 0);
-       me_enable(e_menu_gfx_options, MA_OPT_SCALER_C, 0);
-       me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
-#else
-       me_enable(e_menu_gfx_options, MA_OPT_SCALER2, 0);
-       me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, 0);
-       me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
-#endif
-}
-
-void menu_notify_mode_change(int w, int h, int bpp)
-{
-       float mult;
-       int imult;
-
-       last_psx_w = w;
-       last_psx_h = h;
-       last_psx_bpp = bpp;
-
-       // XXX: should really menu code cotrol the layer size?
-       switch (scaling) {
-       case SCALE_1_1:
-               g_layer_w = w; g_layer_h = h;
-               break;
+       i = plat_target.cpu_clock_set != NULL
+               && plat_target.cpu_clock_get != NULL && cpu_clock_st > 0;
+       me_enable(e_menu_options, MA_OPT_CPU_CLOCKS, i);
 
 
-       case SCALE_4_3v2:
-               if (h > g_menuscreen_h || (240 < h && h <= 360))
-                       goto fractional_4_3;
-
-               // 4:3 that prefers integer scaling
-               imult = g_menuscreen_h / h;
-               g_layer_w = w * imult;
-               g_layer_h = h * imult;
-               mult = (float)g_layer_w / (float)g_layer_h;
-               if (mult < 1.25f || mult > 1.666f)
-                       g_layer_w = 4.0f/3.0f * (float)g_layer_h;
-               printf("  -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
-               break;
+       i = me_id2offset(e_menu_gfx_options, MA_OPT_VOUT_MODE);
+       e_menu_gfx_options[i].data = plat_target.vout_methods;
+       me_enable(e_menu_gfx_options, MA_OPT_VOUT_MODE,
+               plat_target.vout_methods != NULL);
 
 
-       fractional_4_3:
-       case SCALE_4_3:
-               mult = 240.0f / (float)h * 4.0f / 3.0f;
-               if (h > 256)
-                       mult *= 2.0f;
-               g_layer_w = mult * (float)g_menuscreen_h;
-               g_layer_h = g_menuscreen_h;
-               printf("  -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
-               break;
+       i = me_id2offset(e_menu_gfx_options, MA_OPT_HWFILTER);
+       e_menu_gfx_options[i].data = plat_target.hwfilters;
+       me_enable(e_menu_gfx_options, MA_OPT_HWFILTER,
+               plat_target.hwfilters != NULL);
 
 
-       case SCALE_FULLSCREEN:
-               g_layer_w = g_menuscreen_w;
-               g_layer_h = g_menuscreen_h;
-               break;
+       me_enable(e_menu_gfx_options, MA_OPT_GAMMA,
+               plat_target.gamma_set != NULL);
 
 
-       default:
-               break;
-       }
+#ifdef HAVE_PRE_ARMV7
+       me_enable(e_menu_gfx_options, MA_OPT_SWFILTER, 0);
+#endif
+       me_enable(e_menu_gfx_options, MA_OPT_VARSCALER, MENU_SHOW_VARSCALER);
+       me_enable(e_menu_gfx_options, MA_OPT_VOUT_MODE, MENU_SHOW_VOUTMODE);
+       me_enable(e_menu_gfx_options, MA_OPT_VARSCALER_C, MENU_SHOW_VARSCALER);
+       me_enable(e_menu_gfx_options, MA_OPT_SCALER2, MENU_SHOW_SCALER2);
+       me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, MENU_SHOW_NUBS_BTNS);
+       me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, MENU_SHOW_VIBRATION);
+       me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, MENU_SHOW_DEADZONE);
+}
 
 
-       g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
-       g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
-       if (g_layer_x < 0) g_layer_x = 0;
-       if (g_layer_y < 0) g_layer_y = 0;
-       if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
-       if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
+void menu_notify_mode_change(int w, int h, int bpp)
+{
+       last_vout_w = w;
+       last_vout_h = h;
+       last_vout_bpp = bpp;
 }
 
 static void menu_leave_emu(void)
 }
 
 static void menu_leave_emu(void)
@@ -2333,19 +2689,19 @@ static void menu_leave_emu(void)
 
        memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
        if (pl_vout_buf != NULL && ready_to_go) {
 
        memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
        if (pl_vout_buf != NULL && ready_to_go) {
-               int x = max(0, g_menuscreen_w - last_psx_w);
-               int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
-               int w = min(g_menuscreen_w, last_psx_w);
-               int h = min(g_menuscreen_h, last_psx_h);
+               int x = max(0, g_menuscreen_w - last_vout_w);
+               int y = max(0, g_menuscreen_h / 2 - last_vout_h / 2);
+               int w = min(g_menuscreen_w, last_vout_w);
+               int h = min(g_menuscreen_h, last_vout_h);
                u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
                char *s = pl_vout_buf;
 
                u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
                char *s = pl_vout_buf;
 
-               if (last_psx_bpp == 16) {
-                       for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w * 2)
+               if (last_vout_bpp == 16) {
+                       for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 2)
                                menu_darken_bg(d, s, w, 0);
                }
                else {
                                menu_darken_bg(d, s, w, 0);
                }
                else {
-                       for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w * 3) {
+                       for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 3) {
                                rgb888_to_rgb565(d, s, w * 3);
                                menu_darken_bg(d, d, w, 0);
                        }
                                rgb888_to_rgb565(d, s, w * 3);
                                menu_darken_bg(d, d, w, 0);
                        }
@@ -2353,7 +2709,7 @@ static void menu_leave_emu(void)
        }
 
        if (ready_to_go)
        }
 
        if (ready_to_go)
-               cpu_clock = plat_cpu_clock_get();
+               cpu_clock = plat_target_cpu_clock_get();
 }
 
 void menu_prepare_emu(void)
 }
 
 void menu_prepare_emu(void)
@@ -2362,21 +2718,29 @@ void menu_prepare_emu(void)
 
        plat_video_menu_leave();
 
 
        plat_video_menu_leave();
 
-       menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
-
+       #if !defined(DRC_DISABLE) || defined(LIGHTREC)
        psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
        psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
-       if (psxCpu != prev_cpu)
-               // note that this does not really reset, just clears drc caches
+       #else
+       psxCpu = &psxInt;
+       #endif
+       if (psxCpu != prev_cpu) {
+               prev_cpu->Notify(R3000ACPU_NOTIFY_BEFORE_SAVE, NULL);
+               prev_cpu->Shutdown();
+               psxCpu->Init();
                psxCpu->Reset();
                psxCpu->Reset();
+               psxCpu->Notify(R3000ACPU_NOTIFY_AFTER_LOAD, NULL);
+       }
+
+       menu_sync_config();
+       psxCpu->ApplyConfig();
 
        // core doesn't care about Config.Cdda changes,
        // so handle them manually here
        if (Config.Cdda)
                CDR_stop();
 
 
        // core doesn't care about Config.Cdda changes,
        // so handle them manually here
        if (Config.Cdda)
                CDR_stop();
 
-       menu_sync_config();
        if (cpu_clock > 0)
        if (cpu_clock > 0)
-               plat_cpu_clock_apply(cpu_clock);
+               plat_target_cpu_clock_set(cpu_clock);
 
        // push config to GPU plugin
        plugin_call_rearmed_cbs();
 
        // push config to GPU plugin
        plugin_call_rearmed_cbs();
@@ -2386,11 +2750,9 @@ void menu_prepare_emu(void)
                if (ret)
                        fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
        }
                if (ret)
                        fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
        }
-
-       dfinput_activate();
 }
 
 }
 
-void me_update_msg(const char *msg)
+void menu_update_msg(const char *msg)
 {
        strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
        menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
 {
        strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
        menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
@@ -2401,6 +2763,6 @@ void me_update_msg(const char *msg)
 
 void menu_finish(void)
 {
 
 void menu_finish(void)
 {
-       menu_do_last_cd_img(0);
-       plat_cpu_clock_apply(cpu_clock_st);
+       if (cpu_clock_st > 0)
+               plat_target_cpu_clock_set(cpu_clock_st);
 }
 }