cdrom: change pause timing again
[pcsx_rearmed.git] / frontend / menu.c
index e1402de..58efd21 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * (C) Gražvydas "notaz" Ignotas, 2010-2013
+ * (C) Gražvydas "notaz" Ignotas, 2010-2015
  *
  * This work is licensed under the terms of any of these licenses
  * (at your option):
@@ -8,7 +8,12 @@
  * See the COPYING file in the top-level directory.
  */
 
-#define _GNU_SOURCE
+#define _GNU_SOURCE 1
+#ifdef __FreeBSD__
+#define STAT stat
+#else
+#define STAT stat64
+#endif
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
@@ -26,6 +31,7 @@
 #include "plugin_lib.h"
 #include "plat.h"
 #include "pcnt.h"
+#include "cspace.h"
 #include "libpicofe/plat.h"
 #include "libpicofe/input.h"
 #include "libpicofe/linux/in_evdev.h"
@@ -35,9 +41,9 @@
 #include "../libpcsxcore/cdriso.h"
 #include "../libpcsxcore/cheat.h"
 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
-#include "../plugins/dfinput/externals.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 */
@@ -74,6 +80,7 @@ typedef enum
        MA_OPT_SAVECFG,
        MA_OPT_SAVECFG_GAME,
        MA_OPT_CPU_CLOCKS,
+       MA_OPT_SPU_THREAD,
        MA_OPT_DISP_OPTS,
        MA_OPT_VARSCALER,
        MA_OPT_VARSCALER_C,
@@ -82,33 +89,34 @@ typedef enum
        MA_OPT_SWFILTER,
        MA_OPT_GAMMA,
        MA_OPT_VOUT_MODE,
+       MA_OPT_SCANLINES,
+       MA_OPT_SCANLINE_LEVEL,
+       MA_OPT_CENTERING,
 } menu_id;
 
 static int last_vout_w, last_vout_h, last_vout_bpp;
-static int cpu_clock, cpu_clock_st, volume_boost, frameskip;
+static int cpu_clock, cpu_clock_st, volume_boost;
+static int frameskip = 1; // 0 - auto, 1 - off
 static char last_selected_fname[MAXPATHLEN];
 static int config_save_counter, region, in_type_sel1, in_type_sel2;
 static int psx_clock;
-static int memcard1_sel, memcard2_sel;
+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_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
 
-// 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];
@@ -209,11 +217,14 @@ static int optional_cdimg_filter(struct dirent **namelist, int count,
        const char *basedir)
 {
        const char *ext, *p;
-       char buf[256], buf2[256];
+       char buf[256], buf2[257];
        int i, d, ret, good_cue;
-       struct stat64 statf;
+       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;
@@ -251,11 +262,13 @@ static int optional_cdimg_filter(struct dirent **namelist, int count,
                                p = strrchr(buf2, '/');
                                if (p == NULL)
                                        p = strrchr(buf2, '\\');
-                               if (p == NULL)
+                               if (p != NULL)
+                                       p++;
+                               else
                                        p = buf2;
 
                                snprintf(buf, sizeof(buf), "%s/%s", basedir, p);
-                               ret = stat64(buf, &statf);
+                               ret = STAT(buf, &statf);
                                if (ret == 0) {
                                        rm_namelist_entry(namelist, count, p);
                                        good_cue = 1;
@@ -299,24 +312,28 @@ static void menu_sync_config(void)
                Config.PsxAuto = 0;
                Config.PsxType = region - 1;
        }
-       cycle_multiplier = 10000 / psx_clock;
+       Config.cycle_multiplier = 10000 / psx_clock;
 
        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) {
-       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;
        }
 
-       iVolume = 768 + 128 * volume_boost;
+       spu_config.iVolume = 768 + 128 * volume_boost;
        pl_rearmed_cbs.frameskip = frameskip - 1;
        pl_timing_prepare(Config.PsxType);
 }
@@ -327,11 +344,14 @@ static void menu_set_defconfig(void)
 
        g_opts = 0;
        g_scaler = SCALE_4_3;
+       g_gamma = 100;
        volume_boost = 0;
-       frameskip = 0;
+       frameskip = 1; // 1 - off
        analog_deadzone = 50;
        soft_scaling = 1;
        soft_filter = 0;
+       scanlines = 0;
+       scanline_level = 20;
        plat_target.vout_fullscreen = 0;
        psx_clock = DEFAULT_PSX_CLOCK;
 
@@ -380,22 +400,26 @@ static const struct {
        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(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(GpuListWalking),
+       CE_CONFIG_VAL(FractionalFramerate),
+       CE_CONFIG_VAL(PreciseExceptions),
        CE_INTVAL(region),
-       CE_INTVAL_V(g_scaler, 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(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),
@@ -405,18 +429,29 @@ static const struct {
        CE_INTVAL(in_type_sel1),
        CE_INTVAL(in_type_sel2),
        CE_INTVAL(analog_deadzone),
+       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, 3),
+       CE_INTVAL_V(frameskip, 4),
        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.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),
@@ -427,9 +462,14 @@ static const struct {
        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_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),
@@ -463,6 +503,13 @@ static void make_cfg_fname(char *buf, size_t size, int is_game)
 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)
 {
        char cfgfile[MAXPATHLEN];
@@ -485,13 +532,13 @@ static int menu_write_config(int is_game)
                        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:
-                       fprintf(f, "%x\n", *(u16 *)config_data[i].val);
+                       write_u32_value(f, *(u16 *)config_data[i].val);
                        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",
@@ -510,7 +557,7 @@ static int menu_do_last_cd_img(int is_get)
 {
        static const char *defaults[] = { "/media", "/mnt/sd", "/mnt" };
        char path[256];
-       struct stat64 st;
+       struct STAT st;
        FILE *f;
        int i, ret = -1;
 
@@ -533,7 +580,7 @@ static int menu_do_last_cd_img(int is_get)
 out:
        if (is_get) {
                for (i = 0; last_selected_fname[0] == 0
-                      || stat64(last_selected_fname, &st) != 0; i++)
+                      || STAT(last_selected_fname, &st) != 0; i++)
                {
                        if (i >= ARRAY_SIZE(defaults))
                                break;
@@ -558,7 +605,7 @@ static void parse_str_val(char *cval, const char *src)
 
 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;
@@ -661,12 +708,38 @@ fail:
                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;
 }
 
 static const char *filter_exts[] = {
        "bin", "img", "mdf", "iso", "cue", "z",
-       "bz",  "znx", "pbp", "cbn"
+       #ifdef HAVE_CHD
+       "chd",
+       #endif
+       "bz",  "znx", "pbp", "cbn", NULL
 };
 
 // rrrr rggg gggb bbbb
@@ -681,7 +754,7 @@ static unsigned short fname2color(const char *fname)
        if (ext == NULL)
                return 0xffff;
        ext++;
-       for (i = 0; i < array_size(filter_exts); i++)
+       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++)
@@ -693,7 +766,7 @@ static unsigned short fname2color(const char *fname)
 static void draw_savestate_bg(int slot);
 
 #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
@@ -774,7 +847,7 @@ static void draw_savestate_bg(int slot)
 
                // 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:
@@ -813,7 +886,7 @@ me_bind_action emuctrl_actions[] =
        { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
        { "Take Screenshot  ", 1 << SACTION_SCREENSHOT },
        { "Show/Hide FPS    ", 1 << SACTION_TOGGLE_FPS },
-#ifdef __ARM_ARCH_7A__
+#ifndef HAVE_PRE_ARMV7
        { "Switch Renderer  ", 1 << SACTION_SWITCH_DISPMODE },
 #endif
        { "Fast Forward     ", 1 << SACTION_FAST_FORWARD },
@@ -832,6 +905,7 @@ me_bind_action emuctrl_actions[] =
        { "Volume Up        ", 1 << SACTION_VOLUME_UP },
        { "Volume Down      ", 1 << SACTION_VOLUME_DOWN },
 #endif
+       { "Analog toggle    ", 1 << SACTION_ANALOG_TOGGLE },
        { NULL,                0 }
 };
 
@@ -864,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;
-
-       mystrip(d);
 }
 
 static void keys_write_all(FILE *f)
@@ -972,7 +1044,10 @@ static void keys_load_all(const char *cfg)
        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);
+
                dev_id = in_config_parse_dev(dev);
                if (dev_id < 0) {
                        printf("input: can't handle dev: %s\n", dev);
@@ -1147,6 +1222,8 @@ static const char *men_in_type_sel[] = {
        "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.";
@@ -1191,34 +1268,64 @@ static int menu_loop_keyconfig(int id, int keys)
 
 // ------------ 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_overlay[]   = "Overlay provides hardware accelerated scaling";
 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)
 {
+       void *saved_layer = NULL;
+       size_t saved_layer_size = 0;
+       int was_layer_clipped = 0;
        unsigned int inp;
 
+       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);
 
+       menu_draw_begin(0, 1);
+       memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
+       menu_draw_end();
+
        for (;;)
        {
-               menu_draw_begin(0, 1);
-               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);
@@ -1236,33 +1343,46 @@ static int menu_loop_cscaler(int id, int keys)
                        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);
+                       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();
+       free(saved_layer);
 
        return 0;
 }
 
 static menu_entry e_menu_gfx_options[] =
 {
-       mee_enum      ("Scaler",                   MA_OPT_VARSCALER, g_scaler, 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_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_cust_h    ("Setup custom scaler",      MA_OPT_VARSCALER_C, menu_loop_cscaler, NULL, h_cscaler),
@@ -1280,7 +1400,7 @@ static int menu_loop_gfx_options(int id, int keys)
 
 // ------------ bios/plugins ------------
 
-#ifdef __ARM_NEON__
+#ifdef BUILTIN_GPU_NEON
 
 static const char h_gpu_neon[] =
        "Configure built-in NEON GPU plugin";
@@ -1294,8 +1414,9 @@ 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 (slow)", 0, pl_rearmed_cbs.gpu_neon.enhancement_enable, 1, h_gpu_neon_enhanced),
+       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,
 };
 
@@ -1308,12 +1429,30 @@ static int menu_loop_plugin_gpu_neon(int id, int keys)
 
 #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[] =
 {
-       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,
 };
 
@@ -1324,6 +1463,7 @@ static int menu_loop_plugin_gpu_unai(int id, int keys)
        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";
@@ -1396,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 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),
-       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,
 };
 
@@ -1417,18 +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[] = 
-#ifdef __ARM_NEON__
+#ifdef BUILTIN_GPU_NEON
                                   "builtin_gpu is the NEON GPU, very fast and accurate\n"
 #endif
                                   "gpu_peops is Pete's soft GPU, slow but accurate\n"
-                                  "gpu_unai is GPU from PCSX4ALL, fast but glitchy\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";
-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[] =
@@ -1436,10 +1581,11 @@ 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),
-#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 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),
@@ -1464,28 +1610,37 @@ static int menu_loop_plugin_options(int id, int keys)
 
 // ------------ 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";
+#endif
+static const char h_cfg_stalls[]  = "Will cause some games to run too fast";
 
 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),
+#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;
+       menu_iopts[0] = Config.DisableStalls;
        me_loop(e_menu_speed_hacks, &sel);
+       Config.DisableStalls = menu_iopts[0];
        return 0;
 }
 
+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)";
@@ -1493,29 +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_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)";
+#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_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),
-       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_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,
 };
@@ -1523,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 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);
+
+       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;
 }
 
@@ -1546,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_sputhr[]          = "Warning: has some known bugs\n";
 
 static menu_entry e_menu_options[] =
 {
@@ -1555,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),
+#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),
@@ -1567,10 +1759,9 @@ static menu_entry e_menu_options[] =
 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);
@@ -1696,10 +1887,10 @@ out:
 
 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]);
-       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);
@@ -1828,7 +2019,6 @@ static void menu_bios_warn(void)
 // ------------ main menu ------------
 
 static menu_entry e_menu_main[];
-void OnFile_Exit();
 
 static void draw_frame_main(void)
 {
@@ -1872,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"
-#ifdef __ARM_NEON__
+#ifdef BUILTIN_GPU_NEON
        "ARM NEON GPU (c) 2011-2012 Exophase\n"
 #endif
        "PEOpS GPU and SPU by Pete Bernert\n"
@@ -1880,19 +2070,16 @@ static const char credits_text[] =
        "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)
 {
-       // sanity check
-       if (bios_sel == 0 && !Config.HLE)
-               return -1;
-
        ClosePlugins();
        OpenPlugins();
        SysReset();
-       if (CheckCdrom() != -1) {
-               LoadCdrom();
+       if (Config.HLE) {
+               if (LoadCdrom() == -1)
+                       return -1;
        }
        return 0;
 }
@@ -1922,13 +2109,17 @@ static int reload_plugins(const char *cdimg)
 
 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;
+       Config.SlowBoot = 1;
        SysReset();
+       Config.SlowBoot = origSlowBoot;
 
        ready_to_go = 1;
        return 0;
@@ -1936,10 +2127,11 @@ static int run_bios(void)
 
 static int run_exe(void)
 {
+       const char *exts[] = { "exe", NULL };
        const char *fname;
 
        fname = menu_loop_romsel(last_selected_fname,
-               sizeof(last_selected_fname), NULL);
+               sizeof(last_selected_fname), exts, NULL);
        if (fname == NULL)
                return -1;
 
@@ -1960,6 +2152,8 @@ static int run_exe(void)
 
 static int run_cd_image(const char *fname)
 {
+       int autoload_state = g_autostateld_opt;
+
        ready_to_go = 0;
        reload_plugins(fname);
 
@@ -1985,6 +2179,28 @@ static int run_cd_image(const char *fname)
        emu_on_new_cd(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;
 }
 
@@ -1994,7 +2210,8 @@ static int romsel_run(void)
        const char *fname;
 
        fname = menu_loop_romsel(last_selected_fname,
-               sizeof(last_selected_fname), optional_cdimg_filter);
+                       sizeof(last_selected_fname), filter_exts,
+                       optional_cdimg_filter);
        if (fname == NULL)
                return -1;
 
@@ -2025,10 +2242,11 @@ static int romsel_run(void)
 
 static int swap_cd_image(void)
 {
-       char *fname;
+       const char *fname;
 
        fname = menu_loop_romsel(last_selected_fname,
-               sizeof(last_selected_fname), optional_cdimg_filter);
+                       sizeof(last_selected_fname), filter_exts,
+                       optional_cdimg_filter);
        if (fname == NULL)
                return -1;
 
@@ -2074,11 +2292,12 @@ static int swap_cd_multidisk(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), NULL);
+       fname = menu_loop_romsel(last_selected_fname,
+                       sizeof(last_selected_fname), exts, NULL);
        if (fname == NULL)
                return;
 
@@ -2088,8 +2307,8 @@ static void load_pcsx_cht(void)
        if (NumCheats == 0 && NumCodes == 0)
                menu_update_msg("failed to load cheats");
        else {
-               snprintf(path, sizeof(path), "%d cheat(s) loaded", NumCheats + NumCodes);
-               menu_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);
 }
@@ -2145,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:
-               OnFile_Exit();
-               break;
+               emu_core_ask_exit();
+               return 1;
        default:
                lprintf("%s: something unknown selected\n", __FUNCTION__);
                break;
@@ -2232,7 +2451,7 @@ void menu_loop(void)
 
        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))
@@ -2286,7 +2505,8 @@ static void scan_bios_plugins(void)
                        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;
                }
@@ -2423,7 +2643,7 @@ void menu_init(void)
 
        i = plat_target.cpu_clock_set != NULL
                && plat_target.cpu_clock_get != NULL && cpu_clock_st > 0;
-       me_enable(e_menu_gfx_options, MA_OPT_CPU_CLOCKS, i);
+       me_enable(e_menu_options, MA_OPT_CPU_CLOCKS, i);
 
        i = me_id2offset(e_menu_gfx_options, MA_OPT_VOUT_MODE);
        e_menu_gfx_options[i].data = plat_target.vout_methods;
@@ -2438,7 +2658,7 @@ void menu_init(void)
        me_enable(e_menu_gfx_options, MA_OPT_GAMMA,
                plat_target.gamma_set != NULL);
 
-#ifndef __ARM_ARCH_7A__
+#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);
@@ -2498,20 +2718,27 @@ void menu_prepare_emu(void)
 
        plat_video_menu_leave();
 
+       #if !defined(DRC_DISABLE) || defined(LIGHTREC)
        psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
+       #else
+       psxCpu = &psxInt;
+       #endif
        if (psxCpu != prev_cpu) {
+               prev_cpu->Notify(R3000ACPU_NOTIFY_BEFORE_SAVE, NULL);
                prev_cpu->Shutdown();
                psxCpu->Init();
-               // note that this does not really reset, just clears drc caches
                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();
 
-       menu_sync_config();
        if (cpu_clock > 0)
                plat_target_cpu_clock_set(cpu_clock);
 
@@ -2523,8 +2750,6 @@ void menu_prepare_emu(void)
                if (ret)
                        fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
        }
-
-       dfinput_activate();
 }
 
 void menu_update_msg(const char *msg)