partially revived platform support for PSP (unfinished)
authorkub <derkub@gmail.com>
Sun, 10 Jan 2021 11:09:18 +0000 (12:09 +0100)
committerkub <derkub@gmail.com>
Sun, 10 Jan 2021 11:13:56 +0000 (12:13 +0100)
just to have a platform with an unusal screen resolution
- suspend/resume handling probably non-working
- no scaling settings
- no image generation
currently no intentions to finish this.

17 files changed:
Makefile
pico/32x/draw.c
pico/debug.c
pico/draw.c
pico/draw_arm.S
pico/mode4.c
platform/common/menu_pico.c
platform/psp/emu.c
platform/psp/emu.h
platform/psp/in_psp.c [new file with mode: 0644]
platform/psp/in_psp.h [new file with mode: 0644]
platform/psp/main.c
platform/psp/menu.c
platform/psp/mp3.c
platform/psp/plat.c [new file with mode: 0644]
platform/psp/psp.c
platform/psp/psp.h

index 673292b..1cfd5ff 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -34,10 +34,12 @@ gperf ?= 0
 
 ifneq ("$(PLATFORM)", "libretro")
        CFLAGS += -Wall -g
+ifneq ("$(PLATFORM)", "psp")
 ifneq ($(findstring gcc,$(shell $(CC) -v 2>&1)),)
        CFLAGS += -ffunction-sections -fdata-sections
        LDFLAGS += -Wl,--gc-sections
 endif
+endif
 
 ifeq "$(DEBUG)" "0"
        CFLAGS += -O3 -DNDEBUG
@@ -162,6 +164,20 @@ USE_FRONTEND = 1
 PLATFORM_MP3 = 1
 PLATFORM_ZLIB = 1
 endif
+ifeq "$(PLATFORM)" "psp"
+CFLAGS += -DUSE_BGR565 -DDRAW2_OVERRIDE_LINE_WIDTH=512 -G8 # -DLPRINTF_STDIO -DFW15
+platform/common/main.o: CFLAGS += -Dmain=pico_main
+OBJS += platform/psp/plat.o
+OBJS += platform/psp/emu.o
+OBJS += platform/psp/in_psp.o
+OBJS += platform/psp/psp.o
+#OBJS += platform/psp/menu.o
+OBJS += platform/psp/asm_utils.o
+OBJS += platform/psp/mp3.o
+#OBJS += platform/psp/data/bg32.o
+#OBJS += platform/psp/data/bg40.o
+USE_FRONTEND = 1
+endif
 ifeq "$(PLATFORM)" "libretro"
 OBJS += platform/libretro/libretro.o
 ifeq "$(USE_LIBRETRO_VFS)" "1"
@@ -207,6 +223,7 @@ endif
 
 endif # USE_FRONTEND
 
+ifneq "$(PLATFORM)" "psp"
 OBJS += platform/common/mp3.o platform/common/mp3_sync.o
 ifeq "$(PLATFORM_MP3)" "1"
 OBJS += platform/common/mp3_helix.o
@@ -215,6 +232,7 @@ OBJS += platform/common/mp3_libavcodec.o
 else
 OBJS += platform/common/mp3_minimp3.o
 endif
+endif
 
 ifeq "$(PLATFORM_ZLIB)" "1"
 # zlib
@@ -259,6 +277,15 @@ else
        $(LD) $(LINKOUT)$@ $^ $(LDFLAGS) $(LDLIBS)
 endif
 
+ifeq "$(PLATFORM)" "psp"
+PSPSDK = /home/.build/opt/pspdev/psp/sdk
+PSP_EBOOT_TITLE = PicoDrive
+LIBS += -lpng -lm -lz -lpspgu -lpsppower -lpspaudio -lpsprtc -lpspaudiocodec
+EXTRA_TARGETS = EBOOT.PBP
+include /home/.build/opt/pspdev/psp/sdk/lib/build.mak
+# TODO image generation
+endif
+
 pprof: platform/linux/pprof.c
        $(CC) $(CFLAGS) -O2 -ggdb -DPPROF -DPPROF_TOOL -I../../ -I. $^ -o $@ $(LDFLAGS) $(LDLIBS)
 
index 6954eca..3ca858d 100644 (file)
@@ -12,6 +12,9 @@
 #if defined(USE_BGR555)
 #define PXCONV(t)   (t)
 #define PXPRIO      0x8000  // prio in MSB
+#elif defined(USE_BGR565)
+#define PXCONV(t)   (((t)&m1)  | (((t)&(m2|m3)) << 1))
+#define PXPRIO      0x0020  // prio in LS green bit
 #else // RGB565 
 #define PXCONV(t)   ((((t)&m1) << 11) | (((t)&m2) << 1) | (((t)&m3) >> 10))
 #define PXPRIO      0x0020  // prio in LS green bit
index e4b5232..51cc903 100644 (file)
@@ -148,7 +148,11 @@ char *PDebugSpriteList(void)
 }
 
 #define GREEN1  0x0700
-#ifdef USE_BGR555
+#if defined(USE_BGR555)
+ #define YELLOW1 0x039c
+ #define BLUE1   0x7800
+ #define RED1    0x001e
+#elif defined(USE_BGR565)
  #define YELLOW1 0x071c
  #define BLUE1   0xf000
  #define RED1    0x001e
index 8aa39de..3f39796 100644 (file)
@@ -69,6 +69,10 @@ u32 VdpSATCache[128];  // VDP sprite cache (1st 32 sprite attr bits)
 #define PXCONV(t)   ((t & 0x000e000e)<< 1) | ((t & 0x00e000e0)<<2) | ((t & 0x0e000e00)<<3)\r
 #define PXMASKL     0x04210421  // 0x0c630c63, LSB for all colours\r
 #define PXMASKH     0x39ce39ce  // 0x3def3def, all but MSB for all colours\r
+#elif defined(USE_BGR565)\r
+#define PXCONV(t)   ((t & 0x000e000e)<< 1) | ((t & 0x00e000e0)<<3) | ((t & 0x0e000e00)<<4)\r
+#define PXMASKL     0x08610861  // 0x18e318e3\r
+#define PXMASKH     0x738e738e  // 0x7bef7bef\r
 #else // RGB565\r
 #define PXCONV(t)   ((t & 0x000e000e)<<12) | ((t & 0x00e000e0)<<3) | ((t & 0x0e000e00)>>7)\r
 #define PXMASKL     0x08610861  // 0x18e318e3\r
@@ -2004,7 +2008,7 @@ void PicoDrawSetOutFormat(pdso_t which, int use_32x_line_mode)
 \r
 void PicoDrawSetOutBufMD(void *dest, int increment)\r
 {\r
-  if (FinalizeLine == FinalizeLine8bit && increment == 328) {\r
+  if (FinalizeLine == FinalizeLine8bit && increment >= 328) {\r
     // kludge for no-copy mode\r
     PicoDrawSetInternalBuf(dest, increment);\r
   }\r
index 8b717a5..e05c2fd 100644 (file)
@@ -8,7 +8,7 @@
  *\r
  * this is highly specialized, be careful if changing related C code!\r
  *\r
- * NB only does RGB565 output, BGR555 isn't supported\r
+ * NB only does RGB565 output, BGR isn't supported\r
  */\r
 \r
 #include "pico_int_offs.h"\r
index f8ce646..9e853d4 100644 (file)
@@ -337,9 +337,12 @@ void PicoDoHighPal555M4(void)
   /* cram is always stored as shorts, even though real hardware probably uses bytes */
   for (i = 0x20/2; i > 0; i--, spal++, dpal++) {
     t = *spal;
-#ifdef USE_BGR555
+#if defined(USE_BGR555)
     t = ((t & 0x00030003)<< 3) | ((t & 0x000c000c)<<6) | ((t & 0x00300030)<<9);
     t |= (t >> 2) | ((t >> 4) & 0x04210421);
+#elif defined(USE_BGR565)
+    t = ((t & 0x00030003)<< 3) | ((t & 0x000c000c)<<7) | ((t & 0x00300030)<<10);
+    t |= (t >> 2) | ((t >> 4) & 0x08610861);
 #else
     t = ((t & 0x00030003)<<14) | ((t & 0x000c000c)<<7) | ((t & 0x00300030)>>1);
     t |= (t >> 2) | ((t >> 4) & 0x08610861);
index 4651954..fe9f032 100644 (file)
 #define MENU_X2 0
 #endif
 
+#if defined USE_BGR555
+#define COL_ROM        0x5eff
+#define COL_OTH        0x5ff5
+#elif defined USE_BGR565
+#define COL_ROM        0xfdf7
+#define COL_OTH        0xaff5
+#else
+#define COL_ROM        0xbdff
+#define        COL_OTH 0xaff5
+#endif
+
 // FIXME
 #define REVISION "0"
 
@@ -49,9 +60,9 @@ static unsigned short fname2color(const char *fname)
        }
 
        for (i = 0; rom_exts[i] != NULL; i++)
-               if (strcasecmp(ext, rom_exts[i]) == 0) return 0xbdff; // FIXME: mk defines
+               if (strcasecmp(ext, rom_exts[i]) == 0) return COL_ROM;
        for (i = 0; i < array_size(other_exts); i++)
-               if (strcasecmp(ext, other_exts[i]) == 0) return 0xaff5;
+               if (strcasecmp(ext, other_exts[i]) == 0) return COL_OTH;
        return 0xffff;
 }
 
@@ -62,6 +73,8 @@ static const char *men_dummy[] = { NULL };
 /* platform specific options and handlers */
 #if   defined(__GP2X__)
 #include <platform/gp2x/menu.c>
+#elif defined(__PSP__)
+#include <platform/psp/menu.c>
 #elif defined(PANDORA)
 #include <platform/pandora/menu.c>
 #else
@@ -72,8 +85,9 @@ static const char *men_dummy[] = { NULL };
 static void make_bg(int no_scale)
 {
        unsigned short *src = (void *)g_menubg_src_ptr;
-       int w = g_screen_width, h = g_screen_height;
-       int pp = g_screen_ppitch;
+       int w = g_menubg_src_w ? g_menubg_src_w : g_screen_width;
+       int h = g_menubg_src_h ? g_menubg_src_h : g_screen_height;
+       int pp = g_menubg_src_pp ? g_menubg_src_pp : g_screen_ppitch;
        short *dst;
        int x, y;
 
index 93e55c9..1b4a90e 100644 (file)
 #include <pspaudio.h>
 
 #include "psp.h"
-#include "menu.h"
 #include "emu.h"
 #include "mp3.h"
+#include "in_psp.h"
 #include "asm_utils.h"
 #include "../common/emu.h"
-#include "../common/config.h"
+#include "../common/input_pico.h"
+#include "platform/libpicofe/input.h"
+#include "platform/libpicofe/menu.h"
+
 #include <pico/pico_int.h>
+#include <pico/cd/genplus_macros.h>
+#include <pico/cd/cdd.h>
 #include <pico/cd/cue.h>
 
 #define OSD_FPS_X 432
 
-// additional pspaudio imports, credits to crazyc
-int sceAudio_38553111(unsigned short samples, unsigned short freq, char unknown);  // play with conversion?
-int sceAudio_5C37C0AE(void);                           // end play?
-int sceAudio_E0727056(int volume, void *buffer);       // blocking output
-int sceAudioOutput2GetRestSample();
-
-
-//unsigned char *Draw2FB = (unsigned char *)VRAM_CACHED_STUFF + 8; // +8 to be able to skip border with 1 quadword..
 int engineStateSuspend;
 
 #define PICO_PEN_ADJUST_X 4
 #define PICO_PEN_ADJUST_Y 2
-static int pico_pen_x = 320/2, pico_pen_y = 240/2;
 
-static void sound_init(void);
-static void sound_deinit(void);
-static void blit2(const char *fps, const char *notice, int lagging_behind);
-static void clearArea(int full);
+struct Vertex
+{
+       short u,v;
+       short x,y,z;
+};
+
+static struct Vertex __attribute__((aligned(4))) g_vertices[2];
+static unsigned short __attribute__((aligned(16))) localPal[0x100];
+static int need_pal_upload = 0;
+static int fbimg_offs = 0;
+static int h32_mode = 0;
+
+static const struct in_default_bind in_psp_defbinds[] =
+{
+       { PSP_CTRL_UP,          IN_BINDTYPE_PLAYER12, GBTN_UP },
+       { PSP_CTRL_DOWN,        IN_BINDTYPE_PLAYER12, GBTN_DOWN },
+       { PSP_CTRL_LEFT,        IN_BINDTYPE_PLAYER12, GBTN_LEFT },
+       { PSP_CTRL_RIGHT,       IN_BINDTYPE_PLAYER12, GBTN_RIGHT },
+       { PSP_CTRL_SQUARE,      IN_BINDTYPE_PLAYER12, GBTN_A },
+       { PSP_CTRL_CROSS,       IN_BINDTYPE_PLAYER12, GBTN_B },
+       { PSP_CTRL_CIRCLE,      IN_BINDTYPE_PLAYER12, GBTN_C },
+       { PSP_CTRL_START,       IN_BINDTYPE_PLAYER12, GBTN_START },
+       { PSP_CTRL_TRIANGLE,    IN_BINDTYPE_EMU, PEVB_SWITCH_RND },
+       { PSP_CTRL_LTRIGGER,    IN_BINDTYPE_EMU, PEVB_STATE_SAVE },
+       { PSP_CTRL_RTRIGGER,    IN_BINDTYPE_EMU, PEVB_STATE_LOAD },
+       { PSP_CTRL_SELECT,      IN_BINDTYPE_EMU, PEVB_MENU },
+       { 0, 0, 0 }
+};
+
 
-int plat_get_root_dir(char *dst, int len)
+const char *renderer_names[] = { "16bit accurate", " 8bit accurate", " 8bit fast", NULL };
+const char *renderer_names32x[] = { "accurate", "faster", "fastest", NULL };
+enum renderer_types { RT_16BIT, RT_8BIT_ACC, RT_8BIT_FAST, RT_COUNT };
+
+#define is_16bit_mode() \
+       (get_renderer() == RT_16BIT || (PicoIn.AHW & PAHW_32X))
+
+static int get_renderer(void)
 {
-       if (len > 0) *dst = 0;
-       return 0;
+       if (PicoIn.AHW & PAHW_32X)
+               return currentConfig.renderer32x;
+       else
+               return currentConfig.renderer;
+}
+
+static void change_renderer(int diff)
+{
+       int *r;
+       if (PicoIn.AHW & PAHW_32X)
+               r = &currentConfig.renderer32x;
+       else
+               r = &currentConfig.renderer;
+       *r += diff;
+
+       if      (*r >= RT_COUNT)
+               *r = 0;
+       else if (*r < 0)
+               *r = RT_COUNT - 1;
+}
+
+static void apply_renderer(void)
+{
+       PicoIn.opt &= ~POPT_ALT_RENDERER;
+       PicoIn.opt |=  POPT_DIS_32C_BORDER;
+
+       switch (currentConfig.renderer) {
+       case RT_16BIT:
+               PicoDrawSetOutFormat(PDF_RGB555, 0);
+               break;
+       case RT_8BIT_ACC:
+               PicoDrawSetOutFormat(PDF_8BIT, 0);
+               break;
+       case RT_8BIT_FAST:
+               PicoIn.opt |=  POPT_ALT_RENDERER;
+               PicoDrawSetOutFormat(PDF_NONE, 0);
+               break;
+       }
 }
 
 static void osd_text(int x, const char *text, int is_active, int clear_all)
@@ -58,80 +122,18 @@ static void osd_text(int x, const char *text, int is_active, int clear_all)
        unsigned short *screen = is_active ? psp_video_get_active_fb() : psp_screen;
        int len = clear_all ? (480 / 2) : (strlen(text) * 8 / 2);
        int *p, h;
-       void *tmp;
+       void *tmp = g_screen_ptr;
        for (h = 0; h < 8; h++) {
                p = (int *) (screen+x+512*(264+h));
                p = (int *) ((int)p & ~3); // align
                memset32_uncached(p, 0, len);
        }
-       if (is_active) { tmp = psp_screen; psp_screen = screen; } // nasty pointer tricks
+       g_screen_ptr = screen; // nasty pointer tricks
        emu_text_out16(x, 264, text);
-       if (is_active) psp_screen = tmp;
-}
-
-void emu_msg_cb(const char *msg)
-{
-       osd_text(4, msg, 1, 1);
-       noticeMsgTime = sceKernelGetSystemTimeLow() - 2000000;
-
-       /* assumption: emu_msg_cb gets called only when something slow is about to happen */
-       reset_timing = 1;
-}
-
-/* FIXME: move to plat */
-void emu_Init(void)
-{
-       sound_init();
-}
-
-void emu_Deinit(void)
-{
-       sound_deinit();
-}
-
-void pemu_prep_defconfig(void)
-{
-       defaultConfig.s_PsndRate = 22050;
-       defaultConfig.s_PicoCDBuffers = 64;
-       defaultConfig.CPUclock = 333;
-       defaultConfig.KeyBinds[ 4] = 1<<0; // SACB RLDU
-       defaultConfig.KeyBinds[ 6] = 1<<1;
-       defaultConfig.KeyBinds[ 7] = 1<<2;
-       defaultConfig.KeyBinds[ 5] = 1<<3;
-       defaultConfig.KeyBinds[14] = 1<<4;
-       defaultConfig.KeyBinds[13] = 1<<5;
-       defaultConfig.KeyBinds[15] = 1<<6;
-       defaultConfig.KeyBinds[ 3] = 1<<7;
-       defaultConfig.KeyBinds[12] = 1<<26; // switch rnd
-       defaultConfig.KeyBinds[ 8] = 1<<27; // save state
-       defaultConfig.KeyBinds[ 9] = 1<<28; // load state
-       defaultConfig.KeyBinds[28] = 1<<0; // num "buttons"
-       defaultConfig.KeyBinds[30] = 1<<1;
-       defaultConfig.KeyBinds[31] = 1<<2;
-       defaultConfig.KeyBinds[29] = 1<<3;
-       defaultConfig.scaling = 1;     // bilinear filtering for psp
-       defaultConfig.scale = 1.20;    // fullscreen
-       defaultConfig.hscale40 = 1.25;
-       defaultConfig.hscale32 = 1.56;
+       g_screen_ptr = tmp;
 }
 
 
-extern void amips_clut(unsigned short *dst, unsigned char *src, unsigned short *pal, int count);
-extern void amips_clut_6bit(unsigned short *dst, unsigned char *src, unsigned short *pal, int count);
-
-static void (*amips_clut_f)(unsigned short *dst, unsigned char *src, unsigned short *pal, int count) = NULL;
-
-struct Vertex
-{
-       short u,v;
-       short x,y,z;
-};
-
-static struct Vertex __attribute__((aligned(4))) g_vertices[2];
-static unsigned short __attribute__((aligned(16))) localPal[0x100];
-static int dynamic_palette = 0, need_pal_upload = 0, blit_16bit_mode = 0;
-static int fbimg_offs = 0;
-
 static void set_scaling_params(void)
 {
        int src_width, fbimg_width, fbimg_height, fbimg_xoffs, fbimg_yoffs, border_hack = 0;
@@ -139,7 +141,7 @@ static void set_scaling_params(void)
        g_vertices[0].z = g_vertices[1].z = 0;
 
        fbimg_height = (int)(240.0 * currentConfig.scale + 0.5);
-       if (Pico.video.reg[12] & 1) {
+       if (!h32_mode) {
                fbimg_width = (int)(320.0 * currentConfig.scale * currentConfig.hscale40 + 0.5);
                src_width = 320;
        } else {
@@ -183,6 +185,11 @@ static void set_scaling_params(void)
                g_vertices[1].u--;
                g_vertices[1].x--;
        }
+       if (!is_16bit_mode()) {
+               // 8-bit modes have an 8 px overlap area on the left
+               g_vertices[0].u += 8;
+               g_vertices[1].u += 8;
+       }
        fbimg_offs = (fbimg_yoffs*512 + fbimg_xoffs) * 2; // dst is always 16bit
 
        /*
@@ -193,109 +200,55 @@ static void set_scaling_params(void)
        */
 }
 
-static void do_pal_update(int allow_sh, int allow_as)
+static void do_pal_update(void)
 {
        unsigned int *dpal=(void *)localPal;
        int i;
 
        //for (i = 0x3f/2; i >= 0; i--)
        //      dpal[i] = ((spal[i]&0x000f000f)<< 1)|((spal[i]&0x00f000f0)<<3)|((spal[i]&0x0f000f00)<<4);
-       if ((currentConfig.EmuOpt&0x80) || (PicoOpt&0x10)) {
-               do_pal_convert(localPal, Pico.cram, currentConfig.gamma, currentConfig.gamma2);
+       if (PicoIn.opt & POPT_ALT_RENDERER) {
+               do_pal_convert(localPal, PicoMem.cram, currentConfig.gamma, currentConfig.gamma2);
                Pico.m.dirtyPal = 0;
        }
-       else if (Pico.est.rendstatus&0x20)
+       else if (Pico.est.rendstatus & PDRAW_SONIC_MODE)
        {
                switch (Pico.est.SonicPalCount) {
-               case 3: do_pal_convert(localPal+0xc0, Pico.est.SonicPal+0xc0, currentConfig.gamma, currentConfig.gamma2);
-               case 2: do_pal_convert(localPal+0x80, Pico.est.SonicPal+0x80, currentConfig.gamma, currentConfig.gamma2);
-               case 1: do_pal_convert(localPal+0x40, Pico.est.SonicPal+0x40, currentConfig.gamma, currentConfig.gamma2);
+               case 3: do_pal_convert(localPal+0xc0/2, Pico.est.SonicPal+0xc0, currentConfig.gamma, currentConfig.gamma2);
+               case 2: do_pal_convert(localPal+0x80/2, Pico.est.SonicPal+0x80, currentConfig.gamma, currentConfig.gamma2);
+               case 1: do_pal_convert(localPal+0x40/2, Pico.est.SonicPal+0x40, currentConfig.gamma, currentConfig.gamma2);
                default:do_pal_convert(localPal, Pico.est.SonicPal, currentConfig.gamma, currentConfig.gamma2);
                }
        }
-       else if (allow_sh && (Pico.video.reg[0xC]&8)) // shadow/hilight?
+       else if (Pico.video.reg[0xC]&8) // shadow/hilight?
        {
                do_pal_convert(localPal, Pico.est.SonicPal, currentConfig.gamma, currentConfig.gamma2);
                // shadowed pixels
-               for (i = 0x3f/2; i >= 0; i--)
-                       dpal[0x20|i] = dpal[0x60|i] = (dpal[i]>>1)&0x7bcf7bcf;
+               for (i = 0; i < 0x40 / 2; i++) {
+                       dpal[0xc0/2 + i] = dpal[i];
+                       dpal[0x80/2 + i] = (dpal[i] >> 1) & 0x738e738e;
+               }
                // hilighted pixels
-               for (i = 0x3f; i >= 0; i--) {
-                       int t=localPal[i]&0xf79e;t+=0x4208;
-                       if (t&0x20) t|=0x1e;
-                       if (t&0x800) t|=0x780;
-                       if (t&0x10000) t|=0xf000;
-                       t&=0xf79e;
-                       localPal[0x80|i]=(unsigned short)t;
+               for (i = 0; i < 0x40 / 2; i++) {
+                       u32 t = ((dpal[i] >> 1) & 0x738e738e) + 0x738e738e;
+                       t |= (t >> 4) & 0x08610861;
+                       dpal[0x40/2 + i] = t;
                }
-               localPal[0xe0] = 0;
-               localPal[0xf0] = 0x001f;
        }
-       else if (allow_as && (Pico.est.rendstatus & PDRAW_SPR_LO_ON_HI))
+       else
        {
                do_pal_convert(localPal, Pico.est.SonicPal, currentConfig.gamma, currentConfig.gamma2);
                memcpy((int *)dpal+0x40/2, (void *)localPal, 0x40*2);
                memcpy((int *)dpal+0x80/2, (void *)localPal, 0x80*2);
        }
+       localPal[0xe0] = 0;
+       localPal[0xf0] = 0x001f;
 
        if (Pico.m.dirtyPal == 2)
                Pico.m.dirtyPal = 0;
        need_pal_upload = 1;
 }
 
-static void do_slowmode_lines(int line_to)
-{
-       int line = 0, line_len = (Pico.video.reg[12]&1) ? 320 : 256;
-       unsigned short *dst = (unsigned short *)VRAM_STUFF + 512*240/2;
-       unsigned char  *src = (unsigned char  *)VRAM_CACHED_STUFF + 16;
-       if (!(Pico.video.reg[1]&8)) { line = 8; dst += 512*8; src += 512*8; }
-
-       for (; line < line_to; line++, dst+=512, src+=512)
-               amips_clut_f(dst, src, localPal, line_len);
-}
-
-static void EmuScanPrepare(void)
-{
-       Pico.est.HighCol = (unsigned char *)VRAM_CACHED_STUFF + 8;
-       if (!(Pico.video.reg[1]&8)) Pico.est.HighCol += 8*512;
-
-       if (dynamic_palette > 0)
-               dynamic_palette--;
-
-       if (Pico.m.dirtyPal)
-               do_pal_update(1, 1);
-       if (!(Pico.video.reg[0xC] & 8))
-            amips_clut_f = amips_clut_6bit;
-       else amips_clut_f = amips_clut;
-}
-
-static int EmuScanSlowBegin(unsigned int num)
-{
-       if (!dynamic_palette)
-               Pico.est.HighCol = (unsigned char *)VRAM_CACHED_STUFF + num * 512 + 8;
-
-       return 0;
-}
-
-static int EmuScanSlowEnd(unsigned int num)
-{
-       if (Pico.m.dirtyPal) {
-               if (!dynamic_palette) {
-                       do_slowmode_lines(num);
-                       dynamic_palette = 3; // last for 2 more frames
-               }
-               do_pal_update(1, 1);
-       }
-
-       if (dynamic_palette) {
-               int line_len = (Pico.video.reg[12]&1) ? 320 : 256;
-               void *dst = (char *)VRAM_STUFF + 512*240 + 512*2*num;
-               amips_clut_f(dst, Pico.est.HighCol + 8, localPal, line_len);
-       }
-
-       return 0;
-}
-
 static void blitscreen_clut(void)
 {
        int offs = fbimg_offs;
@@ -304,34 +257,17 @@ static void blitscreen_clut(void)
        sceGuSync(0,0); // sync with prev
        sceGuStart(GU_DIRECT, guCmdList);
        sceGuDrawBuffer(GU_PSM_5650, (void *)offs, 512); // point to back buffer
+       sceGuTexMode(is_16bit_mode() ? GU_PSM_5650:GU_PSM_T8,0,0,0);
+       sceGuTexImage(0,512,512,512,g_screen_ptr);
 
-       if (dynamic_palette)
-       {
-               if (!blit_16bit_mode) { // the current mode is not 16bit
-                       sceGuTexMode(GU_PSM_5650, 0, 0, 0);
-                       sceGuTexImage(0,512,512,512,(char *)VRAM_STUFF + 512*240);
-
-                       blit_16bit_mode = 1;
-               }
-       }
-       else
-       {
-               if (blit_16bit_mode) {
-                       sceGuClutMode(GU_PSM_5650,0,0xff,0);
-                       sceGuTexMode(GU_PSM_T8,0,0,0); // 8-bit image
-                       sceGuTexImage(0,512,512,512,(char *)VRAM_STUFF + 16);
-                       blit_16bit_mode = 0;
-               }
-
-               if ((PicoIn.opt&0x10) && Pico.m.dirtyPal)
-                       do_pal_update(0, 0);
+       if (Pico.m.dirtyPal)
+               do_pal_update();
 
-               sceKernelDcacheWritebackAll();
+       sceKernelDcacheWritebackAll();
 
-               if (need_pal_upload) {
-                       need_pal_upload = 0;
-                       sceGuClutLoad((256/8), localPal); // upload 32*8 entries (256)
-               }
+       if (need_pal_upload) {
+               need_pal_upload = 0;
+               sceGuClutLoad((256/8), localPal); // upload 32*8 entries (256)
        }
 
 #if 1
@@ -376,10 +312,10 @@ static void cd_leds(void)
 
 static void draw_pico_ptr(void)
 {
-       unsigned char *p = (unsigned char *)VRAM_STUFF + 16;
+       unsigned char *p = (unsigned char *)VRAM_CACHED_STUFF + 8;
 
        // only if pen enabled and for 8bit mode
-       if (pico_inp_mode == 0 || blit_16bit_mode) return;
+       if (pico_inp_mode == 0 || is_16bit_mode()) return;
 
        p += 512 * (pico_pen_y + PICO_PEN_ADJUST_Y);
        p += pico_pen_x + PICO_PEN_ADJUST_X;
@@ -389,76 +325,17 @@ static void draw_pico_ptr(void)
 }
 
 
-#if 0
-static void dbg_text(void)
-{
-       int *p, h, len;
-       char text[128];
-
-       sprintf(text, "sl: %i, 16b: %i", g_vertices[0].u == 0 && g_vertices[1].u == g_vertices[1].x, blit_16bit_mode);
-       len = strlen(text) * 8 / 2;
-       for (h = 0; h < 8; h++) {
-               p = (int *) ((unsigned short *) psp_screen+2+512*(256+h));
-               p = (int *) ((int)p & ~3); // align
-               memset32_uncached(p, 0, len);
-       }
-       emu_text_out16(2, 256, text);
-}
-#endif
-
-/* called after rendering is done, but frame emulation is not finished */
-void blit1(void)
-{
-       if (PicoIn.opt&0x10)
-       {
-               int i;
-               unsigned char *pd;
-               // clear top and bottom trash
-               for (pd = Pico.est.Draw2FB+8, i = 8; i > 0; i--, pd += 512)
-                       memset32((int *)pd, 0xe0e0e0e0, 320/4);
-               for (pd = Pico.est.Draw2FB+512*232+8, i = 8; i > 0; i--, pd += 512)
-                       memset32((int *)pd, 0xe0e0e0e0, 320/4);
-       }
-
-       if (PicoIn.AHW & PAHW_PICO)
-               draw_pico_ptr();
-
-       blitscreen_clut();
-}
-
-
-static void blit2(const char *fps, const char *notice, int lagging_behind)
-{
-       int vsync = 0, emu_opt = currentConfig.EmuOpt;
-
-       if (notice || (emu_opt & 2)) {
-               if (notice)      osd_text(4, notice, 0, 0);
-               if (emu_opt & 2) osd_text(OSD_FPS_X, fps, 0, 0);
-       }
-
-       //dbg_text();
-
-       if ((emu_opt & 0x400) && (PicoIn.AHW & PAHW_MCD))
-               cd_leds();
-
-       if (currentConfig.EmuOpt & 0x2000) { // want vsync
-               if (!(currentConfig.EmuOpt & 0x10000) || !lagging_behind) vsync = 1;
-       }
-
-       psp_video_flip(vsync);
-}
-
 // clears whole screen or just the notice area (in all buffers)
 static void clearArea(int full)
 {
+       void *fb = psp_video_get_active_fb();
+
        if (full) {
                memset32_uncached(psp_screen, 0, 512*272*2/4);
-               psp_video_flip(0);
-               memset32_uncached(psp_screen, 0, 512*272*2/4);
+               memset32_uncached(fb, 0, 512*272*2/4);
                memset32(VRAM_CACHED_STUFF, 0xe0e0e0e0, 512*240/4);
                memset32((int *)VRAM_CACHED_STUFF+512*240/4, 0, 512*240*2/4);
        } else {
-               void *fb = psp_video_get_active_fb();
                memset32_uncached((int *)((char *)psp_screen + 512*264*2), 0, 512*8*2/4);
                memset32_uncached((int *)((char *)fb         + 512*264*2), 0, 512*8*2/4);
        }
@@ -471,7 +348,6 @@ static void vidResetMode(void)
        sceGuStart(GU_DIRECT, guCmdList);
 
        sceGuClutMode(GU_PSM_5650,0,0xff,0);
-       sceGuTexMode(GU_PSM_T8,0,0,0); // 8-bit image
        sceGuTexFunc(GU_TFX_REPLACE,GU_TCC_RGB);
        if (currentConfig.scaling)
             sceGuTexFilter(GU_LINEAR, GU_LINEAR);
@@ -479,28 +355,13 @@ static void vidResetMode(void)
        sceGuTexScale(1.0f,1.0f);
        sceGuTexOffset(0.0f,0.0f);
 
-       sceGuTexImage(0,512,512,512,(char *)VRAM_STUFF + 16);
-
-       // slow rend.
-       PicoDrawSetOutFormat(PDF_NONE, 0);
-       PicoDrawSetCallbacks(EmuScanSlowBegin, EmuScanSlowEnd);
-
-       localPal[0xe0] = 0;
-       localPal[0xf0] = 0x001f;
        Pico.m.dirtyPal = 1;
-       blit_16bit_mode = dynamic_palette = 0;
 
        sceGuFinish();
        set_scaling_params();
        sceGuSync(0,0);
 }
 
-void plat_debug_cat(char *str)
-{
-       strcat(str, blit_16bit_mode ? "soft clut\n" : "hard clut\n");
-}
-
-
 /* sound stuff */
 #define SOUND_BLOCK_SIZE_NTSC (1470*2) // 1024 // 1152
 #define SOUND_BLOCK_SIZE_PAL  (1764*2)
@@ -533,7 +394,7 @@ static int sound_thread(SceSize args, void *argp)
 
                // lprintf("sthr: got data: %i\n", samples_made - samples_done);
 
-               ret = sceAudio_E0727056(PSP_AUDIO_VOLUME_MAX, snd_playptr);
+               ret = sceAudioSRCOutputBlocking(PSP_AUDIO_VOLUME_MAX, snd_playptr);
 
                samples_done += samples_block;
                snd_playptr  += samples_block;
@@ -541,7 +402,7 @@ static int sound_thread(SceSize args, void *argp)
                        snd_playptr = sndBuffer;
                // 1.5 kernel returns 0, newer ones return # of samples queued
                if (ret < 0)
-                       lprintf("sthr: sceAudio_E0727056: %08x; pos %i/%i\n", ret, samples_done, samples_made);
+                       lprintf("sthr: sceAudioSRCOutputBlocking: %08x; pos %i/%i\n", ret, samples_done, samples_made);
 
                // shouln't happen, but just in case
                if (samples_made - samples_done >= samples_block*3) {
@@ -581,10 +442,20 @@ static void sound_init(void)
 void pemu_sound_start(void)
 {
        static int PsndRate_old = 0, PicoOpt_old = 0, pal_old = 0;
+       static int mp3_init_done;
        int ret, stereo;
 
        samples_made = samples_done = 0;
 
+       if (PicoIn.AHW & PAHW_MCD) {
+               // mp3...
+               if (!mp3_init_done) {
+                       ret = mp3_init();
+                       mp3_init_done = 1;
+                       if (ret) emu_status_msg("mp3 init failed (%i)", ret);
+               }
+       }
+
        if (PicoIn.sndRate != PsndRate_old || (PicoIn.opt&0x0b) != (PicoOpt_old&0x0b) || Pico.m.pal != pal_old) {
                PsndRerate(Pico.m.frame_count ? 1 : 0);
        }
@@ -598,10 +469,10 @@ void pemu_sound_start(void)
                        PicoIn.sndRate, Pico.snd.len, stereo, Pico.m.pal, samples_block);
 
        // while (sceAudioOutput2GetRestSample() > 0) psp_msleep(100);
-       // sceAudio_5C37C0AE();
-       ret = sceAudio_38553111(samples_block/2, PicoIn.sndRate, 2); // seems to not need that stupid 64byte alignment
+       // sceAudioSRCChRelease();
+       ret = sceAudioSRCChReserve(samples_block/2, PicoIn.sndRate, 2); // seems to not need that stupid 64byte alignment
        if (ret < 0) {
-               lprintf("sceAudio_38553111() failed: %i\n", ret);
+               lprintf("sceAudioSRCChReserve() failed: %i\n", ret);
                emu_status_msg("sound init failed (%i), snd disabled", ret);
                currentConfig.EmuOpt &= ~EOPT_EN_SOUND;
        } else {
@@ -621,8 +492,8 @@ void pemu_sound_stop(void)
        int i;
        if (samples_done == 0)
        {
-               // if no data is written between sceAudio_38553111 and sceAudio_5C37C0AE calls,
-               // we get a deadlock on next sceAudio_38553111 call
+               // if no data is written between sceAudioSRCChReserve and sceAudioSRCChRelease calls,
+               // we get a deadlock on next sceAudioSRCChReserve call
                // so this is yet another workaround:
                memset32((int *)(void *)sndBuffer, 0, samples_block*4/4);
                samples_made = samples_block * 3;
@@ -632,7 +503,7 @@ void pemu_sound_stop(void)
        samples_made = samples_done = 0;
        for (i = 0; sceAudioOutput2GetRestSample() > 0 && i < 16; i++)
                psp_msleep(100);
-       sceAudio_5C37C0AE();
+       sceAudioSRCChRelease();
 }
 
 /* wait until we can write more sound */
@@ -676,387 +547,164 @@ static void writeSound(int len)
 }
 
 
-static void SkipFrame(void)
+/* set default configuration values */
+void pemu_prep_defconfig(void)
 {
-       PicoIn.skipFrame=1;
-       PicoFrame();
-       PicoIn.skipFrame=0;
+       defaultConfig.s_PsndRate = 22050;
+       defaultConfig.s_PicoCDBuffers = 64;
+       defaultConfig.CPUclock = 333;
+       defaultConfig.scaling = 1;     // bilinear filtering for psp
+       defaultConfig.scale = 1.20;    // fullscreen
+       defaultConfig.hscale40 = 1.25;
+       defaultConfig.hscale32 = 1.56;
 }
 
-void pemu_forced_frame(int no_scale, int do_emu)
+/* check configuration for inconsistencies */
+void pemu_validate_config(void)
 {
-       int po_old = PicoIn.opt;
-       int eo_old = currentConfig.EmuOpt;
+       if (currentConfig.CPUclock < 33 || currentConfig.CPUclock > 333)
+               currentConfig.CPUclock = 333;
+}
 
-       PicoIn.opt &= ~POPT_ALT_RENDERER;
-       PicoIn.opt |= POPT_ACC_SPRITES;
-       if (!no_scale && defaultConfig.scaling)
-               PicoIn.opt |= POPT_EN_SOFTSCALE;
-       currentConfig.EmuOpt |= 0x80;
+/* finalize rendering a frame */
+void pemu_finalize_frame(const char *fps, const char *notice)
+{
+       int emu_opt = currentConfig.EmuOpt;
 
-       vidResetMode();
-       memset32(VRAM_CACHED_STUFF, 0xe0e0e0e0, 512*8/4); // borders
-       memset32((int *)VRAM_CACHED_STUFF + 512*232/4, 0xe0e0e0e0, 512*8/4);
-       memset32_uncached((int *)psp_screen + 512*264*2/4, 0, 512*8*2/4);
-
-       PicoDrawSetOutFormat(PDF_NONE, 0);
-       PicoDrawSetCallbacks(EmuScanSlowBegin, EmuScanSlowEnd);
-       EmuScanPrepare();
-       PicoFrameDrawOnly();
-       blit1();
-       sceGuSync(0,0);
+       if (PicoIn.AHW & PAHW_PICO)
+               draw_pico_ptr();
+
+       blitscreen_clut();
 
-       PicoIn.opt = po_old;
-       currentConfig.EmuOpt = eo_old;
+       // XXX move this to flip to give texture renderer more time?
+       if (notice)      osd_text(4, notice, 0, 0);
+       if (emu_opt & 2) osd_text(OSD_FPS_X, fps, 0, 0);
+
+       if ((emu_opt & 0x400) && (PicoIn.AHW & PAHW_MCD))
+               cd_leds();
 }
 
+/* FIXME: move plat_* to plat? */
 
-static void RunEventsPico(unsigned int events, unsigned int keys)
+void plat_debug_cat(char *str)
 {
-       emu_RunEventsPico(events);
-
-       if (pico_inp_mode != 0)
-       {
-               PicoIn.pad[0] &= ~0x0f; // release UDLR
-               if (keys & PBTN_UP)   { pico_pen_y--; if (pico_pen_y < 8) pico_pen_y = 8; }
-               if (keys & PBTN_DOWN) { pico_pen_y++; if (pico_pen_y > 224-PICO_PEN_ADJUST_Y) pico_pen_y = 224-PICO_PEN_ADJUST_Y; }
-               if (keys & PBTN_LEFT) { pico_pen_x--; if (pico_pen_x < 0) pico_pen_x = 0; }
-               if (keys & PBTN_RIGHT) {
-                       int lim = (Pico.video.reg[12]&1) ? 319 : 255;
-                       pico_pen_x++;
-                       if (pico_pen_x > lim-PICO_PEN_ADJUST_X)
-                               pico_pen_x = lim-PICO_PEN_ADJUST_X;
-               }
-               PicoPicohw.pen_pos[0] = pico_pen_x;
-               if (!(Pico.video.reg[12]&1)) PicoPicohw.pen_pos[0] += pico_pen_x/4;
-               PicoPicohw.pen_pos[0] += 0x3c;
-               PicoPicohw.pen_pos[1] = pico_inp_mode == 1 ? (0x2f8 + pico_pen_y) : (0x1fc + pico_pen_y);
-       }
 }
 
-static void RunEvents(unsigned int which)
+/* platform dependend emulator initialization */
+void plat_init(void)
 {
-       if (which & 0x1800) // save or load (but not both)
-       {
-               int do_it = 1;
-
-               if ( emu_check_save_file(state_slot) &&
-                               (( (which & 0x1000) && (currentConfig.EmuOpt & 0x800)) || // load
-                                (!(which & 0x1000) && (currentConfig.EmuOpt & 0x200))) ) // save
-               {
-                       int keys;
-                       sceGuSync(0,0);
-                       blit2("", (which & 0x1000) ? "LOAD STATE? (X=yes, O=no)" : "OVERWRITE SAVE? (X=yes, O=no)", 0);
-                       while( !((keys = psp_pad_read(1)) & (PBTN_X|PBTN_CIRCLE)) )
-                               psp_msleep(50);
-                       if (keys & PBTN_CIRCLE) do_it = 0;
-                       while(  ((keys = psp_pad_read(1)) & (PBTN_X|PBTN_CIRCLE)) ) // wait for release
-                               psp_msleep(50);
-                       clearArea(0);
-               }
-
-               if (do_it)
-               {
-                       osd_text(4, (which & 0x1000) ? "LOADING GAME" : "SAVING GAME", 1, 0);
-                       PicoStateProgressCB = emu_msg_cb;
-                       emu_save_load_game((which & 0x1000) >> 12, 0);
-                       PicoStateProgressCB = NULL;
-                       psp_msleep(0);
-               }
-
-               reset_timing = 1;
-       }
-       if (which & 0x0400) // switch renderer
-       {
-               if (PicoIn.opt&0x10) { PicoIn.opt&=~0x10; currentConfig.EmuOpt |=  0x80; }
-               else              { PicoIn.opt|= 0x10; currentConfig.EmuOpt &= ~0x80; }
-
-               vidResetMode();
+       flip_after_sync = 1;
+       in_psp_init(in_psp_defbinds);
+       in_probe();
+       sound_init();
+}
 
-               if (PicoIn.opt & POPT_ALT_RENDERER)
-                       emu_status_msg("fast renderer");
-               else if (currentConfig.EmuOpt&0x80)
-                       emu_status_msg("accurate renderer");
-       }
-       if (which & 0x0300)
-       {
-               if(which&0x0200) {
-                       state_slot -= 1;
-                       if(state_slot < 0) state_slot = 9;
-               } else {
-                       state_slot += 1;
-                       if(state_slot > 9) state_slot = 0;
-               }
-               emu_status_msg("SAVE SLOT %i [%s]", state_slot,
-                       emu_check_save_file(state_slot) ? "USED" : "FREE");
-       }
+/* platform dependend emulator deinitialization */
+void plat_finish(void)
+{
+       sound_deinit();
 }
 
-static void updateKeys(void)
+/* display emulator status messages before holding emulation */
+void plat_status_msg_busy_first(const char *msg)
 {
-       unsigned int keys, allActions[2] = { 0, 0 }, events;
-       static unsigned int prevEvents = 0;
-       int i;
+       plat_status_msg_busy_next(msg);
+}
 
-       /* FIXME: port to input fw, merge with emu.c:emu_update_input() */
-       keys = psp_pad_read(0);
-       if (keys & PSP_CTRL_HOME)
-               sceDisplayWaitVblankStart();
+void plat_status_msg_busy_next(const char *msg)
+{
+       plat_status_msg_clear();
+       pemu_finalize_frame("", msg);
+       plat_video_flip();
+       emu_status_msg("");
+       reset_timing = 1;
+}
 
-       if (keys & PBTN_SELECT)
-               engineState = PGS_Menu;
+/* clear status message area */
+void plat_status_msg_clear(void)
+{
+       clearArea(0);
+}
 
-       keys &= CONFIGURABLE_KEYS;
+/* change the audio volume setting */
+void plat_update_volume(int has_changed, int is_up)
+{
+}
 
-       PicoIn.pad[0] = allActions[0] & 0xfff;
-       PicoIn.pad[1] = allActions[1] & 0xfff;
+/* prepare for MD screen mode change */
+void emu_video_mode_change(int start_line, int line_count, int is_32cols)
+{
+       h32_mode = is_32cols;
+       vidResetMode();
+       if (h32_mode)   // clear borders from h40 remnants
+               clearArea(1);
+}
 
-       if (allActions[0] & 0x7000) emu_DoTurbo(&PicoIn.pad[0], allActions[0]);
-       if (allActions[1] & 0x7000) emu_DoTurbo(&PicoIn.pad[1], allActions[1]);
+/* render one frame in RGB */
+void pemu_forced_frame(int no_scale, int do_emu)
+{
+       PicoIn.opt &= ~POPT_DIS_32C_BORDER;
+       PicoDrawSetOutBuf(g_screen_ptr, g_screen_ppitch * 2);
+       Pico.m.dirtyPal = 1;
 
-       events = (allActions[0] | allActions[1]) >> 16;
+       if (!no_scale)
+               no_scale = currentConfig.scaling == EOPT_SCALE_NONE;
+       emu_cmn_forced_frame(no_scale, do_emu);
+}
 
-       if ((events ^ prevEvents) & 0x40) {
-               emu_set_fastforward(events & 0x40);
-               reset_timing = 1;
-       }
+/* change the platform output rendering */
+void plat_video_toggle_renderer(int change, int is_menu_call)
+{
+       change_renderer(change);
 
-       events &= ~prevEvents;
+       if (is_menu_call)
+               return;
 
-       if (PicoIn.AHW == PAHW_PICO)
-               RunEventsPico(events, keys);
-       if (events) RunEvents(events);
-       if (movie_data) emu_updateMovie();
+       apply_renderer();
+       vidResetMode();
+       rendstatus_old = -1;
 
-       prevEvents = (allActions[0] | allActions[1]) >> 16;
+       if (PicoIn.AHW & PAHW_32X)
+               emu_status_msg(renderer_names32x[get_renderer()]);
+       else
+               emu_status_msg(renderer_names[get_renderer()]);
 }
 
-
-static void simpleWait(unsigned int until)
+/* set the buffer for emulator output rendering */
+void plat_video_set_buffer(void *buf)
 {
-       unsigned int tval;
-       int diff;
-
-       tval = sceKernelGetSystemTimeLow();
-       diff = (int)until - (int)tval;
-       if (diff >= 512 && diff < 100*1024)
-               sceKernelDelayThread(diff);
+       if (currentConfig.renderer == RT_16BIT || (PicoIn.AHW & PAHW_32X))
+               PicoDrawSetOutBuf(g_screen_ptr, g_screen_ppitch * 2);
+       else
+               PicoDrawSetOutBuf(g_screen_ptr, g_screen_ppitch);
 }
 
-void pemu_loop(void)
+/* prepare for emulator output rendering */
+void plat_video_loop_prepare(void) 
 {
-       static int mp3_init_done = 0;
-       char fpsbuff[24]; // fps count c string
-       unsigned int tval, tval_thissec = 0; // timing
-       int target_fps, target_frametime, lim_time, tval_diff, i, oldmodes = 0;
-       int pframes_done, pframes_shown; // "period" frames, used for sync
-       int  frames_done,  frames_shown, tval_fpsc = 0; // actual frames
-       char *notice = NULL;
-
-       lprintf("entered emu_Loop()\n");
-
-       fpsbuff[0] = 0;
-
-       if (currentConfig.CPUclock != psp_get_cpu_clock()) {
-               lprintf("setting cpu clock to %iMHz... ", currentConfig.CPUclock);
-               i = psp_set_cpu_clock(currentConfig.CPUclock);
-               lprintf(i ? "failed\n" : "done\n");
-               currentConfig.CPUclock = psp_get_cpu_clock();
-       }
-
-       // make sure we are in correct mode
+       apply_renderer();
        vidResetMode();
        clearArea(1);
-       Pico.m.dirtyPal = 1;
-       oldmodes = ((Pico.video.reg[12]&1)<<2) ^ 0xc;
-
-       // pal/ntsc might have changed, reset related stuff
-       target_fps = Pico.m.pal ? 50 : 60;
-       target_frametime = Pico.m.pal ? (1000000<<8)/50 : (1000000<<8)/60+1;
-       reset_timing = 1;
-
-       if (PicoIn.AHW & PAHW_MCD) {
-               // prepare CD buffer
-               PicoCDBufferInit();
-               // mp3...
-               if (!mp3_init_done) {
-                       i = mp3_init();
-                       mp3_init_done = 1;
-                       if (i) { engineState = PGS_Menu; return; }
-               }
-       }
-
-       // prepare sound stuff
-       PicoIn.sndOut = NULL;
-       if (currentConfig.EmuOpt & EOPT_EN_SOUND)
-       {
-               pemu_sound_start();
-       }
-
-       sceDisplayWaitVblankStart();
-       pframes_shown = pframes_done =
-        frames_shown =  frames_done = 0;
-
-       tval_fpsc = sceKernelGetSystemTimeLow();
-
-       // loop?
-       while (engineState == PGS_Running)
-       {
-               int modes;
-
-               tval = sceKernelGetSystemTimeLow();
-               if (reset_timing || tval < tval_fpsc) {
-                       //stdbg("timing reset");
-                       reset_timing = 0;
-                       tval_thissec = tval;
-                       pframes_shown = pframes_done = 0;
-               }
-
-               // show notice message?
-               if (noticeMsgTime) {
-                       static int noticeMsgSum;
-                       if (tval - noticeMsgTime > 2000000) { // > 2.0 sec
-                               noticeMsgTime = 0;
-                               clearArea(0);
-                               notice = 0;
-                       } else {
-                               int sum = noticeMsg[0]+noticeMsg[1]+noticeMsg[2];
-                               if (sum != noticeMsgSum) { clearArea(0); noticeMsgSum = sum; }
-                               notice = noticeMsg;
-                       }
-               }
-
-               // check for mode changes
-               modes = ((Pico.video.reg[12]&1)<<2)|(Pico.video.reg[1]&8);
-               if (modes != oldmodes) {
-                       oldmodes = modes;
-                       clearArea(1);
-                       set_scaling_params();
-               }
-
-               // second passed?
-               if (tval - tval_fpsc >= 1000000)
-               {
-                       if (currentConfig.EmuOpt & 2)
-                               sprintf(fpsbuff, "%02i/%02i  ", frames_shown, frames_done);
-                       frames_done = frames_shown = 0;
-                       tval_fpsc += 1000000;
-               }
-
-               if (tval - tval_thissec >= 1000000)
-               {
-                       // missing 1 frame?
-                       if (currentConfig.Frameskip < 0 && pframes_done < target_fps) {
-                               SkipFrame(); pframes_done++; frames_done++;
-                       }
-
-                       tval_thissec += 1000000;
-
-                       if (currentConfig.Frameskip < 0) {
-                               pframes_done  -= target_fps; if (pframes_done  < 0) pframes_done  = 0;
-                               pframes_shown -= target_fps; if (pframes_shown < 0) pframes_shown = 0;
-                               if (pframes_shown > pframes_done) pframes_shown = pframes_done;
-                       } else {
-                               pframes_done = pframes_shown = 0;
-                       }
-               }
-#ifdef PFRAMES
-               sprintf(fpsbuff, "%i", Pico.m.frame_count);
-#endif
-
-               lim_time = (pframes_done+1) * target_frametime;
-               if (currentConfig.Frameskip >= 0) // frameskip enabled
-               {
-                       for (i = 0; i < currentConfig.Frameskip; i++) {
-                               updateKeys();
-                               SkipFrame(); pframes_done++; frames_done++;
-                               if (!(currentConfig.EmuOpt&0x40000)) { // do framelimitting if needed
-                                       int tval_diff;
-                                       tval = sceKernelGetSystemTimeLow();
-                                       tval_diff = (int)(tval - tval_thissec) << 8;
-                                       if (tval_diff < lim_time) // we are too fast
-                                               simpleWait(tval + ((lim_time - tval_diff)>>8));
-                               }
-                               lim_time += target_frametime;
-                       }
-               }
-               else // auto frameskip
-               {
-                       int tval_diff;
-                       tval = sceKernelGetSystemTimeLow();
-                       tval_diff = (int)(tval - tval_thissec) << 8;
-                       if (tval_diff > lim_time && (pframes_done/16 < pframes_shown))
-                       {
-                               // no time left for this frame - skip
-                               if (tval_diff - lim_time >= (300000<<8)) {
-                                       reset_timing = 1;
-                                       continue;
-                               }
-                               updateKeys();
-                               SkipFrame(); pframes_done++; frames_done++;
-                               continue;
-                       }
-               }
-
-               updateKeys();
-
-               if (!(PicoIn.opt&0x10))
-                       EmuScanPrepare();
-
-               PicoFrame();
-
-               sceGuSync(0,0);
-
-               // check time
-               tval = sceKernelGetSystemTimeLow();
-               tval_diff = (int)(tval - tval_thissec) << 8;
-
-               blit2(fpsbuff, notice, tval_diff > lim_time);
-
-               if (currentConfig.Frameskip < 0 && tval_diff - lim_time >= (300000<<8)) { // slowdown detection
-                       reset_timing = 1;
-               }
-               else if (!(currentConfig.EmuOpt&0x40000) || currentConfig.Frameskip < 0)
-               {
-                       // sleep if we are still too fast
-                       if (tval_diff < lim_time)
-                       {
-                               // we are too fast
-                               simpleWait(tval + ((lim_time - tval_diff) >> 8));
-                       }
-               }
-
-               pframes_done++; pframes_shown++;
-                frames_done++;  frames_shown++;
-       }
-
-
-       emu_set_fastforward(0);
-
-       if (PicoIn.AHW & PAHW_MCD) PicoCDBufferFree();
-
-       if (PicoIn.sndOut != NULL) {
-               pemu_sound_stop();
-               PicoIn.sndOut = NULL;
-       }
+}
 
-       // save SRAM
-       if ((currentConfig.EmuOpt & 1) && SRam.changed) {
-               emu_msg_cb("Writing SRAM/BRAM..");
-               emu_save_load_game(0, 1);
-               SRam.changed = 0;
-       }
+/* prepare for entering the emulator loop */
+void pemu_loop_prep(void)
+{
+}
 
-       // clear fps counters and stuff
-       memset32_uncached((int *)psp_video_get_active_fb() + 512*264*2/4, 0, 512*8*2/4);
+/* terminate the emulator loop */
+void pemu_loop_end(void)
+{
+       pemu_sound_stop();
 }
 
-void emu_HandleResume(void)
+// TODO 
+void emu_handle_resume(void)
 {
        if (!(PicoIn.AHW & PAHW_MCD)) return;
 
        // reopen first CD track
-       if (Pico_mcd->TOC.Tracks[0].F != NULL)
+       if (cdd.toc.tracks[0].fd != NULL)
        {
                char *fname = rom_fname_reload;
                int len = strlen(rom_fname_reload);
@@ -1070,16 +718,18 @@ void emu_HandleResume(void)
                }
 
                lprintf("emu_HandleResume: reopen %s\n", fname);
-               pm_close(Pico_mcd->TOC.Tracks[0].F);
-               Pico_mcd->TOC.Tracks[0].F = pm_open(fname);
-               lprintf("reopen %s\n", Pico_mcd->TOC.Tracks[0].F != NULL ? "ok" : "failed");
+               pm_close(cdd.toc.tracks[0].fd);
+               cdd.toc.tracks[0].fd = pm_open(fname);
+               lprintf("reopen %s\n", cdd.toc.tracks[0].fd != NULL ? "ok" : "failed");
 
                if (cue_data != NULL) cue_destroy(cue_data);
        }
 
        mp3_reopen_file();
 
-       if (!(Pico_mcd->s68k_regs[0x36] & 1) && (Pico_mcd->scd.Status_CDC & 1))
-               cdda_start_play();
+#if 0  // TODO
+       if (!(Pico_mcd->s68k_regs[0x36] & 1)/* && (Pico_mcd->scd.Status_CDC & 1)*/)
+               cdd_change_track(cdd.index, cdd.lba);
+#endif
 }
 
index 4ef5383..e920274 100644 (file)
@@ -1,9 +1,7 @@
 
 extern int engineStateSuspend;
 
-void emu_HandleResume(void);
-
-void emu_msg_cb(const char *msg);
+void emu_handle_resume(void);
 
 // actually comes from Pico/Misc_amips.s
 void memset32_uncached(int *dest, int c, int count);
diff --git a/platform/psp/in_psp.c b/platform/psp/in_psp.c
new file mode 100644 (file)
index 0000000..4f9e2f4
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * (C) Gražvydas "notaz" Ignotas, 2006-2012
+ * (C) kub 2020
+ *
+ * This work is licensed under the terms of any of these licenses
+ * (at your option):
+ *  - GNU GPL, version 2 or later.
+ *  - GNU LGPL, version 2.1 or later.
+ *  - MAME license.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "../libpicofe/input.h"
+#include "psp.h"
+#include "in_psp.h"
+
+#define IN_PSP_PREFIX "psp:"
+#define IN_PSP_NBUTTONS 32
+
+/* note: in_psp handles combos (if 2 btns have the same bind,
+ * both must be pressed for action to happen) */
+static int in_psp_combo_keys = 0;
+static int in_psp_combo_acts = 0;
+
+
+static const char *in_psp_keys[IN_PSP_NBUTTONS] = {
+       [0 ... IN_PSP_NBUTTONS-1] = NULL,
+};
+
+
+/* credits to https://graphics.stanford.edu/~seander/bithacks.html */
+static int lg2(unsigned v)
+{
+       int r, s;
+
+       r = (v > 0xFFFF) << 4; v >>= r;
+       s = (v > 0xFF  ) << 3; v >>= s; r |= s;
+       s = (v > 0xF   ) << 2; v >>= s; r |= s;
+       s = (v > 0x3   ) << 1; v >>= s; r |= s;
+                                       r |= (v >> 1);
+       return r;
+}
+
+static int in_psp_get_bits(void)
+{
+       return psp_pad_read(0);
+}
+
+static void in_psp_probe(const in_drv_t *drv)
+{
+       in_register(IN_PSP_PREFIX "PSP pad", -1, NULL,
+               IN_PSP_NBUTTONS, in_psp_keys, 1);
+}
+
+static void in_psp_free(void *drv_data)
+{
+}
+
+static const char * const *
+in_psp_get_key_names(const in_drv_t *drv, int *count)
+{
+       *count = IN_PSP_NBUTTONS;
+       return in_psp_keys;
+}
+
+/* ORs result with pressed buttons */
+static int in_psp_update(void *drv_data, const int *binds, int *result)
+{
+       int type_start = 0;
+       int i, t, keys;
+
+       keys = in_psp_get_bits();
+
+       if (keys & in_psp_combo_keys) {
+               result[IN_BINDTYPE_EMU] = in_combos_do(keys, binds, IN_PSP_NBUTTONS,
+                                               in_psp_combo_keys, in_psp_combo_acts);
+               type_start = IN_BINDTYPE_PLAYER12;
+       }
+
+       for (i = 0; keys; i++, keys >>= 1) {
+               if (!(keys & 1))
+                       continue;
+
+               for (t = type_start; t < IN_BINDTYPE_COUNT; t++)
+                       result[t] |= binds[IN_BIND_OFFS(i, t)];
+       }
+
+       return 0;
+}
+
+int in_psp_update_keycode(void *data, int *is_down)
+{
+       static int old_val = 0;
+       int val, diff, i;
+
+       val = in_psp_get_bits();
+       diff = val ^ old_val;
+       if (diff == 0)
+               return -1;
+
+       /* take one bit only */
+       for (i = 0; i < sizeof(diff)*8; i++)
+               if (diff & (1<<i))
+                       break;
+
+       old_val ^= 1 << i;
+
+       if (is_down)
+               *is_down = !!(val & (1<<i));
+       return i;
+}
+
+static const struct {
+       short key;
+       short pbtn;
+} key_pbtn_map[] =
+{
+       { PSP_CTRL_UP,          PBTN_UP },
+       { PSP_CTRL_DOWN,        PBTN_DOWN },
+       { PSP_CTRL_LEFT,        PBTN_LEFT },
+       { PSP_CTRL_RIGHT,       PBTN_RIGHT },
+       { PSP_CTRL_CIRCLE,      PBTN_MOK },
+       { PSP_CTRL_CROSS,       PBTN_MBACK },
+       { PSP_CTRL_TRIANGLE,    PBTN_MA2 },
+       { PSP_CTRL_SQUARE,      PBTN_MA3 },
+       { PSP_CTRL_LTRIGGER,    PBTN_L },
+       { PSP_CTRL_RTRIGGER,    PBTN_R },
+       { PSP_CTRL_SELECT,      PBTN_MENU },
+};
+
+#define KEY_PBTN_MAP_SIZE (sizeof(key_pbtn_map) / sizeof(key_pbtn_map[0]))
+
+static int in_psp_menu_translate(void *drv_data, int keycode, char *charcode)
+{
+       int i;
+       if (keycode < 0)
+       {
+               /* menu -> kc */
+               keycode = -keycode;
+               for (i = 0; i < KEY_PBTN_MAP_SIZE; i++)
+                       if (key_pbtn_map[i].pbtn == keycode)
+                               return lg2(key_pbtn_map[i].key);
+       }
+       else
+       {
+               for (i = 0; i < KEY_PBTN_MAP_SIZE; i++)
+                       if (key_pbtn_map[i].key == 1<<keycode)
+                               return key_pbtn_map[i].pbtn;
+       }
+
+       return 0;
+}
+
+/* remove binds of missing keys, count remaining ones */
+static int in_psp_clean_binds(void *drv_data, int *binds, int *def_binds)
+{
+       int i, count = 0;
+
+       for (i = 0; i < IN_PSP_NBUTTONS; i++) {
+               int t, offs;
+               for (t = 0; t < IN_BINDTYPE_COUNT; t++) {
+                       offs = IN_BIND_OFFS(i, t);
+                       if (in_psp_keys[i] == NULL)
+                               binds[offs] = def_binds[offs] = 0;
+                       if (binds[offs])
+                               count++;
+               }
+       }
+
+       in_combos_find(binds, IN_PSP_NBUTTONS, &in_psp_combo_keys, &in_psp_combo_acts);
+
+       return count;
+}
+
+static const in_drv_t in_psp_drv = {
+       .prefix         = IN_PSP_PREFIX,
+       .probe          = in_psp_probe,
+       .free           = in_psp_free,
+       .get_key_names  = in_psp_get_key_names,
+       .clean_binds    = in_psp_clean_binds,
+       .update         = in_psp_update,
+       .update_keycode = in_psp_update_keycode,
+       .menu_translate = in_psp_menu_translate,
+};
+
+void in_psp_init(const struct in_default_bind *defbinds)
+{
+       in_psp_combo_keys = in_psp_combo_acts = 0;
+
+       /* fill keys array, converting key bitmasks to indexes */
+       in_psp_keys[lg2(PSP_CTRL_UP)] = "Up";
+       in_psp_keys[lg2(PSP_CTRL_LEFT)] = "Left";
+       in_psp_keys[lg2(PSP_CTRL_DOWN)] = "Down";
+       in_psp_keys[lg2(PSP_CTRL_RIGHT)] = "Right";
+       in_psp_keys[lg2(PSP_CTRL_START)] = "Start";
+       in_psp_keys[lg2(PSP_CTRL_SELECT)] = "Select";
+       in_psp_keys[lg2(PSP_CTRL_LTRIGGER)] = "L";
+       in_psp_keys[lg2(PSP_CTRL_RTRIGGER)] = "R";
+       in_psp_keys[lg2(PSP_CTRL_TRIANGLE)] = "Triangle";
+       in_psp_keys[lg2(PSP_CTRL_CIRCLE)] = "Circle";
+       in_psp_keys[lg2(PSP_CTRL_CROSS)] = "Cross";
+       in_psp_keys[lg2(PSP_CTRL_SQUARE)] = "Square";
+
+       in_register_driver(&in_psp_drv, defbinds, NULL);
+}
+
diff --git a/platform/psp/in_psp.h b/platform/psp/in_psp.h
new file mode 100644 (file)
index 0000000..c3dd9b3
--- /dev/null
@@ -0,0 +1,4 @@
+
+struct in_default_bind;
+
+void in_psp_init(const struct in_default_bind *defbinds);
index 94e38a4..e4a5c20 100644 (file)
@@ -11,9 +11,8 @@
 #include "emu.h"
 #include "menu.h"
 #include "mp3.h"
-#include "../common/menu.h"
 #include "../common/emu.h"
-#include "../common/config.h"
+#include "../libpicofe/menu.h"
 #include "../libpicofe/lprintf.h"
 
 #ifdef GPROF
index 12fd728..c7c97cf 100644 (file)
-/*
- * PicoDrive
- * (C) notaz, 2006-2008
- *
- * This work is licensed under the terms of MAME license.
- * See COPYING file in the top-level directory.
- */
 
-// don't like to use loads of #ifdefs, so duplicating GP2X code
-// horribly instead
+// TODO scaling configuration non-functional ATM
 
-#include <string.h>
-#include <stdlib.h>
-#include <wchar.h>
-#include <unistd.h>
-#include <sys/syslimits.h> // PATH_MAX
+static const char *men_scaler[] = { "unscaled", "4:3", "fullscreen", NULL };
+#if 0
+static const char h_cscaler40[]   = "Configures the custom scaler for wide resolution";
+static const char h_cscaler32[]   = "Configures the custom scaler for narrow resolution";
 
-#include <pspdisplay.h>
-#include <pspgu.h>
-#include <pspiofilemgr.h>
-#include <psputils.h>
-
-#include "psp.h"
-#include "emu.h"
-#include "menu.h"
-#include "mp3.h"
-#include "../common/menu.h"
-#include "../common/emu.h"
-#include "../common/readpng.h"
-#include "../common/input.h"
-#include "../common/version.h"
-
-#include <pico/pico_int.h>
-#include <pico/patch.h>
-#include <zlib.h>
-
-
-#define pspKeyUnkn "???"
-const char * const keyNames[] = {
-       "SELECT",   pspKeyUnkn, pspKeyUnkn, "START",    "UP",       "RIGHT",     "DOWN",     "LEFT",
-       "L",        "R",        pspKeyUnkn, pspKeyUnkn, "TRIANGLE", "CIRCLE",    "X",        "SQUARE",
-       "HOME",     "HOLD",     "WLAN_UP",  "REMOTE",   "VOLUP",    "VOLDOWN",   "SCREEN",   "NOTE",
-       pspKeyUnkn, pspKeyUnkn, pspKeyUnkn, pspKeyUnkn, "NUB UP",   "NUB RIGHT", "NUB DOWN", "NUB LEFT" // fake
-};
-
-static unsigned short bg_buffer[480*272] __attribute__((aligned(16)));
-#define menu_screen psp_screen
-
-void menu_darken_bg(void *dst, const void *src, int pixels, int darker);
-static void menu_prepare_bg(int use_game_bg, int use_fg);
-
-
-void menu_draw_begin(void)
-{
-       // short *src = (short *)bg_buffer, *dst = (short *)menu_screen;
-       // int i;
-
-       // for (i = 272; i >= 0; i--, dst += 512, src += 480)
-       //      memcpy((int *)dst, (int *)src, 480*2);
-
-       sceGuSync(0,0); // sync with prev
-       sceGuStart(GU_DIRECT, guCmdList);
-       sceGuCopyImage(GU_PSM_5650, 0, 0, 480, 272, 480, bg_buffer, 0, 0, 512, menu_screen);
-       sceGuFinish();
-       sceGuSync(0,0);
-}
-
-
-void menu_draw_end(void)
-{
-       psp_video_flip(1);
-}
-
-
-// --------- loading ROM screen ----------
-
-static int lcdr_line = 0;
-
-static void load_progress_cb(int percent)
-{
-       int ln, len = percent * 480 / 100;
-       unsigned short *dst;
-
-       //sceDisplayWaitVblankStart();
-
-       dst = (unsigned short *)menu_screen + 512*10*lcdr_line;
-
-       if (len > 480) len = 480;
-       for (ln = 8; ln > 0; ln--, dst += 512)
-               memset(dst, 0xff, len*2);
-}
-
-static void cdload_progress_cb(int percent)
-{
-       int ln, len = percent * 480 / 100;
-       unsigned short *dst;
-
-       if (lcdr_line <= 2) {
-               lcdr_line++;
-               smalltext_out16(1, lcdr_line++ * 10, "Processing CD image / MP3s", 0xffff);
-               smalltext_out16_lim(1, lcdr_line++ * 10, romFileName, 0xffff, 80);
-       }
-
-       dst = (unsigned short *)menu_screen + 512*10*lcdr_line;
-
-       if (len > 480) len = 480;
-       for (ln = 8; ln > 0; ln--, dst += 512)
-               memset(dst, 0xff, len*2);
-}
-
-void menu_romload_prepare(const char *rom_name)
-{
-       const char *p = rom_name + strlen(rom_name);
-       while (p > rom_name && *p != '/') p--;
-
-       psp_video_switch_to_single();
-       if (rom_loaded) menu_draw_begin();
-       else memset32_uncached(psp_screen, 0, 512*272*2/4);
-
-       smalltext_out16(1, 1, "Loading", 0xffff);
-       smalltext_out16_lim(1, 10, p, 0xffff, 80);
-       PicoCartLoadProgressCB = load_progress_cb;
-       PicoCDLoadProgressCB = cdload_progress_cb;
-       lcdr_line = 2;
-}
-
-void menu_romload_end(void)
-{
-       PicoCartLoadProgressCB = PicoCDLoadProgressCB = NULL;
-       smalltext_out16(1, ++lcdr_line*10, "Starting emulation...", 0xffff);
-}
-
-// -------------- ROM selector --------------
-
-struct my_dirent
-{
-       unsigned int d_type;
-       char d_name[255];
-};
-
-// bbbb bggg gggr rrrr
-static unsigned short file2color(const char *fname)
-{
-       const char *ext = fname + strlen(fname) - 3;
-       static const char *rom_exts[]   = { "zip", "bin", "smd", "gen", "iso", "cso", "cue" };
-       static const char *other_exts[] = { "gmv", "pat" };
-       int i;
-
-       if (ext < fname) ext = fname;
-       for (i = 0; i < sizeof(rom_exts)/sizeof(rom_exts[0]); i++)
-               if (strcasecmp(ext, rom_exts[i]) == 0) return 0xfdf7;
-       for (i = 0; i < sizeof(other_exts)/sizeof(other_exts[0]); i++)
-               if (strcasecmp(ext, other_exts[i]) == 0) return 0xaff5;
-       return 0xffff;
-}
-
-static void draw_dirlist(char *curdir, struct my_dirent **namelist, int n, int sel)
-{
-       int start, i, pos;
-
-       start = 13 - sel;
-       n--; // exclude current dir (".")
-
-       menu_draw_begin();
-
-       if (!rom_loaded) {
-//             menu_darken_bg(menu_screen, menu_screen, 321*240, 0);
-       }
-
-       menu_darken_bg((char *)menu_screen + 512*129*2, (char *)menu_screen + 512*129*2, 512*10, 0);
-
-       if (start - 2 >= 0)
-               smalltext_out16_lim(14, (start - 2)*10, curdir, 0xffff, 53-2);
-       for (i = 0; i < n; i++) {
-               pos = start + i;
-               if (pos < 0)  continue;
-               if (pos > 26) break;
-               if (namelist[i+1]->d_type & FIO_S_IFDIR) {
-                       smalltext_out16_lim(14,   pos*10, "/", 0xd7ff, 1);
-                       smalltext_out16_lim(14+6, pos*10, namelist[i+1]->d_name, 0xd7ff, 80-3);
-               } else {
-                       unsigned short color = file2color(namelist[i+1]->d_name);
-                       smalltext_out16_lim(14,   pos*10, namelist[i+1]->d_name, color, 80-2);
-               }
-       }
-       text_out16(5, 130, ">");
-       menu_draw_end();
-}
-
-static int scandir_cmp(const void *p1, const void *p2)
+static int menu_loop_cscaler(int id, int keys)
 {
-       struct my_dirent **d1 = (struct my_dirent **)p1, **d2 = (struct my_dirent **)p2;
-       if ((*d1)->d_type & (*d2)->d_type & FIO_S_IFDIR)
-               return strcasecmp((*d1)->d_name, (*d2)->d_name);
-       if ((*d1)->d_type & FIO_S_IFDIR) return -1; // put before
-       if ((*d2)->d_type & FIO_S_IFDIR) return  1;
-       return strcasecmp((*d1)->d_name, (*d2)->d_name);
-}
-
-static char *filter_exts[] = {
-       ".mp3", ".srm", ".brm", "s.gz", ".mds", "bcfg", ".txt", ".htm", "html",
-       ".jpg", ".pbp"
-};
-
-static int scandir_filter(const struct my_dirent *ent)
-{
-       const char *p;
-       int i;
-
-       if (ent == NULL || ent->d_name == NULL) return 0;
-       if (strlen(ent->d_name) < 5) return 1;
-
-       p = ent->d_name + strlen(ent->d_name) - 4;
-
-       for (i = 0; i < sizeof(filter_exts)/sizeof(filter_exts[0]); i++)
-       {
-               if (strcasecmp(p, filter_exts[i]) == 0) return 0;
-       }
-
-       return 1;
-}
-
-static int my_scandir(const char *dir, struct my_dirent ***namelist_out,
-               int(*filter)(const struct my_dirent *),
-               int(*compar)(const void *, const void *))
-{
-       int ret = -1, dir_uid = -1, name_alloc = 4, name_count = 0;
-       struct my_dirent **namelist = NULL, *ent;
-       SceIoDirent sce_ent;
-
-       namelist = malloc(sizeof(*namelist) * name_alloc);
-       if (namelist == NULL) { lprintf("%s:%i: OOM\n", __FILE__, __LINE__); goto fail; }
-
-       // try to read first..
-       dir_uid = sceIoDopen(dir);
-       if (dir_uid >= 0)
-       {
-               /* it is very important to clear SceIoDirent to be passed to sceIoDread(), */
-               /* or else it may crash, probably misinterpreting something in it. */
-               memset(&sce_ent, 0, sizeof(sce_ent));
-               ret = sceIoDread(dir_uid, &sce_ent);
-               if (ret < 0)
-               {
-                       lprintf("sceIoDread(\"%s\") failed with %i\n", dir, ret);
-                       goto fail;
-               }
-       }
-       else
-               lprintf("sceIoDopen(\"%s\") failed with %i\n", dir, dir_uid);
-
-       while (ret > 0)
-       {
-               ent = malloc(sizeof(*ent));
-               if (ent == NULL) { lprintf("%s:%i: OOM\n", __FILE__, __LINE__); goto fail; }
-               ent->d_type = sce_ent.d_stat.st_mode;
-               strncpy(ent->d_name, sce_ent.d_name, sizeof(ent->d_name));
-               ent->d_name[sizeof(ent->d_name)-1] = 0;
-               if (filter == NULL || filter(ent))
-                    namelist[name_count++] = ent;
-               else free(ent);
-
-               if (name_count >= name_alloc)
-               {
-                       void *tmp;
-                       name_alloc *= 2;
-                       tmp = realloc(namelist, sizeof(*namelist) * name_alloc);
-                       if (tmp == NULL) { lprintf("%s:%i: OOM\n", __FILE__, __LINE__); goto fail; }
-                       namelist = tmp;
-               }
-
-               memset(&sce_ent, 0, sizeof(sce_ent));
-               ret = sceIoDread(dir_uid, &sce_ent);
-       }
-
-       // sort
-       if (compar != NULL && name_count > 3) qsort(&namelist[2], name_count - 2, sizeof(namelist[0]), compar);
-
-       // all done.
-       ret = name_count;
-       *namelist_out = namelist;
-       goto end;
-
-fail:
-       if (namelist != NULL)
-       {
-               while (name_count--)
-                       free(namelist[name_count]);
-               free(namelist);
-       }
-end:
-       if (dir_uid >= 0) sceIoDclose(dir_uid);
-       return ret;
-}
+       unsigned int inp;
 
+       currentConfig.scaling = SCALE_CUSTOM;
 
-static SceIoStat cpstat;
-
-static char *romsel_loop(char *curr_path)
-{
-       struct my_dirent **namelist;
-       int n, iret, sel = 0;
-       unsigned long inp = 0;
-       char *ret = NULL, *fname = NULL;
-
-       // is this a dir or a full path?
-       memset(&cpstat, 0, sizeof(cpstat));
-       iret = sceIoGetstat(curr_path, &cpstat);
-       if (iret >= 0 && (cpstat.st_mode & FIO_S_IFDIR)); // dir
-       else if (iret >= 0 && (cpstat.st_mode & FIO_S_IFREG)) { // file
-               char *p;
-               for (p = curr_path + strlen(curr_path) - 1; p > curr_path && *p != '/'; p--);
-               if (p > curr_path) {
-                       *p = 0;
-                       fname = p+1;
-               }
-               else strcpy(curr_path, "ms0:/");
-       }
-       else strcpy(curr_path, "ms0:/"); // something else
-
-       n = my_scandir(curr_path, &namelist, scandir_filter, scandir_cmp);
-       if (n < 0) {
-               // try root..
-               n = my_scandir("ms0:/", &namelist, scandir_filter, scandir_cmp);
-               if (n < 0) {
-                       // oops, we failed
-                       lprintf("scandir failed, dir: "); lprintf(curr_path); lprintf("\n");
-                       return NULL;
-               }
-       }
-
-       // try to find sel
-       if (fname != NULL) {
-               int i;
-               for (i = 1; i < n; i++) {
-                       if (strcmp(namelist[i]->d_name, fname) == 0) {
-                               sel = i - 1;
-                               break;
-                       }
-               }
-       }
+       pnd_setup_layer(1, g_layer_cx, g_layer_cy, g_layer_cw, g_layer_ch);
+       pnd_restore_layer_data();
 
        for (;;)
        {
-               draw_dirlist(curr_path, namelist, n, sel);
-               inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_L|PBTN_R|PBTN_X|PBTN_CIRCLE, 0);
-               if(inp & PBTN_UP  )  { sel--;   if (sel < 0)   sel = n-2; }
-               if(inp & PBTN_DOWN)  { sel++;   if (sel > n-2) sel = 0; }
-               if(inp & PBTN_LEFT)  { sel-=10; if (sel < 0)   sel = 0; }
-               if(inp & PBTN_L)     { sel-=24; if (sel < 0)   sel = 0; }
-               if(inp & PBTN_RIGHT) { sel+=10; if (sel > n-2) sel = n-2; }
-               if(inp & PBTN_R)     { sel+=24; if (sel > n-2) sel = n-2; }
-               if(inp & PBTN_CIRCLE) // enter dir/select
-               {
-                       if (namelist[sel+1]->d_type & FIO_S_IFDIR)
-                       {
-                               int newlen = strlen(curr_path) + strlen(namelist[sel+1]->d_name) + 2;
-                               char *p, *newdir = malloc(newlen);
-                               if (strcmp(namelist[sel+1]->d_name, "..") == 0) {
-                                       char *start = curr_path;
-                                       p = start + strlen(start) - 1;
-                                       while (*p == '/' && p > start) p--;
-                                       while (*p != '/' && *p != ':' && p > start) p--;
-                                       if (p <= start || *p == ':') strcpy(newdir, "ms0:/");
-                                       else { strncpy(newdir, start, p-start); newdir[p-start] = 0; }
-                               } else {
-                                       strcpy(newdir, curr_path);
-                                       p = newdir + strlen(newdir) - 1;
-                                       while (*p == '/' && p >= newdir) *p-- = 0;
-                                       strcat(newdir, "/");
-                                       strcat(newdir, namelist[sel+1]->d_name);
-                               }
-                               ret = romsel_loop(newdir);
-                               free(newdir);
-                               break;
-                       }
-                       else if (namelist[sel+1]->d_type & FIO_S_IFREG)
-                       {
-                               strcpy(romFileName, curr_path);
-                               strcat(romFileName, "/");
-                               strcat(romFileName, namelist[sel+1]->d_name);
-                               ret = romFileName;
-                               break;
-                       }
-               }
-               if(inp & PBTN_X) break; // cancel
-       }
-
-       if (n > 0) {
-               while(n--) free(namelist[n]);
-               free(namelist);
-       }
-
-       return ret;
-}
-
-// ------------ patch/gg menu ------------
-
-static void draw_patchlist(int sel)
-{
-       int start, i, pos, active;
-
-       start = 13 - sel;
-
-       menu_draw_begin();
-
-       for (i = 0; i < PicoPatchCount; i++) {
-               pos = start + i;
-               if (pos < 0)  continue;
-               if (pos > 26) break;
-               active = PicoPatches[i].active;
-               smalltext_out16_lim(14,     pos*10, active ? "ON " : "OFF", active ? 0xfff6 : 0xffff, 3);
-               smalltext_out16_lim(14+6*4, pos*10, PicoPatches[i].name, active ? 0xfff6 : 0xffff, 53-6);
-       }
-       pos = start + i;
-       if (pos < 27) smalltext_out16_lim(14, pos*10, "done", 0xffff, 4);
-
-       text_out16(5, 130, ">");
-       menu_draw_end();
-}
-
-
-static void patches_menu_loop(void)
-{
-       int menu_sel = 0;
-       unsigned long inp = 0;
+               menu_draw_begin(0, 1);
+               menuscreen_memset_lines(g_menuscreen_ptr, 0, g_menuscreen_h);
+               text_out16(2, 480 - 18, "%dx%d | d-pad to resize, R+d-pad to move", g_layer_cw, g_layer_ch);
+               menu_draw_end();
 
-       for(;;)
-       {
-               draw_patchlist(menu_sel);
-               inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_L|PBTN_R|PBTN_X|PBTN_CIRCLE, 0);
-               if(inp & PBTN_UP  ) { menu_sel--; if (menu_sel < 0) menu_sel = PicoPatchCount; }
-               if(inp & PBTN_DOWN) { menu_sel++; if (menu_sel > PicoPatchCount) menu_sel = 0; }
-               if(inp &(PBTN_LEFT|PBTN_L))  { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; }
-               if(inp &(PBTN_RIGHT|PBTN_R)) { menu_sel+=10; if (menu_sel > PicoPatchCount) menu_sel = PicoPatchCount; }
-               if(inp & PBTN_CIRCLE) { // action
-                       if (menu_sel < PicoPatchCount)
-                               PicoPatches[menu_sel].active = !PicoPatches[menu_sel].active;
-                       else    return;
-               }
-               if(inp & PBTN_X) return;
-       }
-
-}
-
-// ------------ savestate loader ------------
-
-static int state_slot_flags = 0;
-
-static void state_check_slots(void)
-{
-       int slot;
-
-       state_slot_flags = 0;
-
-       for (slot = 0; slot < 10; slot++)
-       {
-               if (emu_checkSaveFile(slot))
-               {
-                       state_slot_flags |= 1 << slot;
-               }
-       }
-}
-
-static void *get_oldstate_for_preview(void)
-{
-       unsigned char *ptr = malloc(sizeof(Pico.vram) + sizeof(Pico.cram) + sizeof(Pico.vsram) + sizeof(Pico.video));
-       if (ptr == NULL) return NULL;
-
-       memcpy(ptr, Pico.vram, sizeof(Pico.vram));
-       memcpy(ptr + sizeof(Pico.vram), Pico.cram, sizeof(Pico.cram));
-       memcpy(ptr + sizeof(Pico.vram) + sizeof(Pico.cram), Pico.vsram, sizeof(Pico.vsram));
-       memcpy(ptr + sizeof(Pico.vram) + sizeof(Pico.cram) + sizeof(Pico.vsram), &Pico.video, sizeof(Pico.video));
-       return ptr;
-}
-
-static void restore_oldstate(void *ptrx)
-{
-       unsigned char *ptr = ptrx;
-       memcpy(Pico.vram,  ptr,  sizeof(Pico.vram));
-       memcpy(Pico.cram,  ptr + sizeof(Pico.vram), sizeof(Pico.cram));
-       memcpy(Pico.vsram, ptr + sizeof(Pico.vram) + sizeof(Pico.cram), sizeof(Pico.vsram));
-       memcpy(&Pico.video,ptr + sizeof(Pico.vram) + sizeof(Pico.cram) + sizeof(Pico.vsram), sizeof(Pico.video));
-       free(ptrx);
-}
-
-static void draw_savestate_bg(int slot)
-{
-       void *file, *oldstate;
-       char *fname;
-
-       fname = emu_GetSaveFName(1, 0, slot);
-       if (!fname) return;
-
-       oldstate = get_oldstate_for_preview();
-       if (oldstate == NULL) return;
-
-       if (strcmp(fname + strlen(fname) - 3, ".gz") == 0) {
-               file = gzopen(fname, "rb");
-               emu_setSaveStateCbs(1);
-       } else {
-               file = fopen(fname, "rb");
-               emu_setSaveStateCbs(0);
-       }
-
-       if (file) {
-               if (PicoIn.AHW & PAHW_MCD) {
-                       PicoCdLoadStateGfx(file);
-               } else {
-                       areaSeek(file, 0x10020, SEEK_SET);  // skip header and RAM in state file
-                       areaRead(Pico.vram, 1, sizeof(Pico.vram), file);
-                       areaSeek(file, 0x2000, SEEK_CUR);
-                       areaRead(Pico.cram, 1, sizeof(Pico.cram), file);
-                       areaRead(Pico.vsram, 1, sizeof(Pico.vsram), file);
-                       areaSeek(file, 0x221a0, SEEK_SET);
-                       areaRead(&Pico.video, 1, sizeof(Pico.video), file);
-               }
-               areaClose(file);
-       }
-
-       emu_forcedFrame(0);
-       menu_prepare_bg(1, 0);
-
-       restore_oldstate(oldstate);
-}
-
-static void draw_savestate_menu(int menu_sel, int is_loading)
-{
-       int tl_x = 80+25, tl_y = 16+60, y, i;
-
-       if (state_slot_flags & (1 << menu_sel))
-               draw_savestate_bg(menu_sel);
-       menu_draw_begin();
-
-       text_out16(tl_x, 16+30, is_loading ? "Load state" : "Save state");
-
-       menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 108);
-
-       /* draw all 10 slots */
-       y = tl_y;
-       for (i = 0; i < 10; i++, y+=10)
-       {
-               text_out16(tl_x, y, "SLOT %i (%s)", i, (state_slot_flags & (1 << i)) ? "USED" : "free");
-       }
-       text_out16(tl_x, y, "back");
-
-       menu_draw_end();
-}
-
-static int savestate_menu_loop(int is_loading)
-{
-       static int menu_sel = 10;
-       int menu_sel_max = 10;
-       unsigned long inp = 0;
-
-       state_check_slots();
-
-       for(;;)
-       {
-               draw_savestate_menu(menu_sel, is_loading);
-               inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_X|PBTN_CIRCLE, 0);
-               if(inp & PBTN_UP  ) {
-                       do {
-                               menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max;
-                       } while (!(state_slot_flags & (1 << menu_sel)) && menu_sel != menu_sel_max && is_loading);
-               }
-               if(inp & PBTN_DOWN) {
-                       do {
-                               menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0;
-                       } while (!(state_slot_flags & (1 << menu_sel)) && menu_sel != menu_sel_max && is_loading);
-               }
-               if(inp & PBTN_CIRCLE) { // save/load
-                       if (menu_sel < 10) {
-                               state_slot = menu_sel;
-                               PicoStateProgressCB = emu_msg_cb; /* also suitable for menu */
-                               if (emu_SaveLoadGame(is_loading, 0)) {
-                                       strcpy(menuErrorMsg, is_loading ? "Load failed" : "Save failed");
-                                       return 1;
-                               }
-                               return 0;
-                       } else  return 1;
-               }
-               if(inp & PBTN_X) return 1;
-       }
-}
-
-// -------------- key config --------------
-
-static char *action_binds(int player_idx, int action_mask)
-{
-       static char strkeys[32*5];
-       int i;
-
-       strkeys[0] = 0;
-       for (i = 0; i < 32; i++) // i is key index
-       {
-               if (currentConfig.KeyBinds[i] & action_mask)
-               {
-                       if (player_idx >= 0 && ((currentConfig.KeyBinds[i] >> 16) & 3) != player_idx) continue;
-                       if (strkeys[0]) {
-                               strcat(strkeys, i >= 28 ? ", " : " + "); // nub "buttons" don't create combos
-                               strcat(strkeys, keyNames[i]);
-                               break;
-                       }
-                       else strcpy(strkeys, keyNames[i]);
+               inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT
+                                  |PBTN_R|PBTN_MOK|PBTN_MBACK, NULL, 40);
+               if (inp & PBTN_UP)    g_layer_cy--;
+               if (inp & PBTN_DOWN)  g_layer_cy++;
+               if (inp & PBTN_LEFT)  g_layer_cx--;
+               if (inp & PBTN_RIGHT) g_layer_cx++;
+               if (!(inp & PBTN_R)) {
+                       if (inp & PBTN_UP)    g_layer_ch += 2;
+                       if (inp & PBTN_DOWN)  g_layer_ch -= 2;
+                       if (inp & PBTN_LEFT)  g_layer_cw += 2;
+                       if (inp & PBTN_RIGHT) g_layer_cw -= 2;
                }
-       }
-
-       return strkeys;
-}
-
-static void unbind_action(int action)
-{
-       int i;
-
-       for (i = 0; i < 32; i++)
-               currentConfig.KeyBinds[i] &= ~action;
-}
-
-static int count_bound_keys(int action, int pl_idx)
-{
-       int i, keys = 0;
-
-       for (i = 0; i < 32; i++)
-       {
-               if (pl_idx >= 0 && (currentConfig.KeyBinds[i]&0x30000) != (pl_idx<<16)) continue;
-               if (currentConfig.KeyBinds[i] & action) keys++;
-       }
-
-       return keys;
-}
-
-static void draw_key_config(const me_bind_action *opts, int opt_cnt, int player_idx, int sel)
-{
-       int x, y, tl_y = 16+20, i;
-
-       menu_draw_begin();
-       if (player_idx >= 0) {
-               text_out16(80+80, 16, "Player %i controls", player_idx + 1);
-               x = 80+80;
-       } else {
-               text_out16(80+80, 16, "Emulator controls");
-               x = 80+40;
-       }
-
-       menu_draw_selection(x - 16, tl_y + sel*10, (player_idx >= 0) ? 66 : 130);
-
-       y = tl_y;
-       for (i = 0; i < opt_cnt; i++, y+=10)
-               text_out16(x, y, "%s : %s", opts[i].name, action_binds(player_idx, opts[i].mask));
-
-       text_out16(x, y, "Done");
-
-       if (sel < opt_cnt) {
-               text_out16(80+30, 220, "Press a button to bind/unbind");
-               text_out16(80+30, 230, "Use SELECT to clear");
-               text_out16(80+30, 240, "To bind UP/DOWN, hold SELECT");
-               text_out16(80+30, 250, "Select \"Done\" to exit");
-       } else {
-               text_out16(80+30, 230, "Use Options -> Save cfg");
-               text_out16(80+30, 240, "to save controls");
-               text_out16(80+30, 250, "Press X or O to exit");
-       }
-       menu_draw_end();
-}
-
-static void key_config_loop(const me_bind_action *opts, int opt_cnt, int player_idx)
-{
-       int sel = 0, menu_sel_max = opt_cnt, prev_select = 0, i;
-       unsigned long inp = 0;
-
-       for (;;)
-       {
-               draw_key_config(opts, opt_cnt, player_idx, sel);
-               inp = in_menu_wait(CONFIGURABLE_KEYS|PBTN_SELECT, 1);
-               if (!(inp & PBTN_SELECT)) {
-                       prev_select = 0;
-                       if(inp & PBTN_UP  ) { sel--; if (sel < 0) sel = menu_sel_max; continue; }
-                       if(inp & PBTN_DOWN) { sel++; if (sel > menu_sel_max) sel = 0; continue; }
-               }
-               if (sel >= opt_cnt) {
-                       if (inp & (PBTN_X|PBTN_CIRCLE)) break;
-                       else continue;
-               }
-               // if we are here, we want to bind/unbind something
-               if ((inp & PBTN_SELECT) && !prev_select)
-                       unbind_action(opts[sel].mask);
-               prev_select = inp & PBTN_SELECT;
-               inp &= CONFIGURABLE_KEYS;
-               inp &= ~PBTN_SELECT;
-               for (i = 0; i < 32; i++)
-                       if (inp & (1 << i)) {
-                               if (count_bound_keys(opts[sel].mask, player_idx) >= 2)
-                                    currentConfig.KeyBinds[i] &= ~opts[sel].mask; // allow to unbind only
-                               else currentConfig.KeyBinds[i] ^=  opts[sel].mask;
-                               if (player_idx >= 0 && (currentConfig.KeyBinds[i] & opts[sel].mask)) {
-                                       currentConfig.KeyBinds[i] &= ~(3 << 16);
-                                       currentConfig.KeyBinds[i] |= player_idx << 16;
-                               }
-                       }
-       }
-}
-
-menu_entry ctrlopt_entries[] =
-{
-       { "Player 1",                  MB_NONE,  MA_CTRL_PLAYER1,       NULL, 0, 0, 0, 1, 0 },
-       { "Player 2",                  MB_NONE,  MA_CTRL_PLAYER2,       NULL, 0, 0, 0, 1, 0 },
-       { "Emulator controls",         MB_NONE,  MA_CTRL_EMU,           NULL, 0, 0, 0, 1, 0 },
-       { "6 button pad",              MB_ONOFF, MA_OPT_6BUTTON_PAD,   &PicoIn.opt, 0x020, 0, 0, 1, 1 },
-       { "Turbo rate",                MB_RANGE, MA_CTRL_TURBO_RATE,   &currentConfig.turbo_rate, 0, 1, 30, 1, 1 },
-       { "Done",                      MB_NONE,  MA_CTRL_DONE,          NULL, 0, 0, 0, 1, 0 },
-};
-
-#define CTRLOPT_ENTRY_COUNT (sizeof(ctrlopt_entries) / sizeof(ctrlopt_entries[0]))
-const int ctrlopt_entry_count = CTRLOPT_ENTRY_COUNT;
-
-static void draw_kc_sel(int menu_sel)
-{
-       int tl_x = 80+25+40, tl_y = 16+60, y;
-
-       y = tl_y;
-       menu_draw_begin();
-       menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 138);
-
-       me_draw(ctrlopt_entries, ctrlopt_entry_count, tl_x, tl_y, NULL, NULL);
-
-       menu_draw_end();
-}
-
-
-// player2_flag, ?, ?, ?, ?, ?, ?, menu
-// "NEXT SAVE SLOT", "PREV SAVE SLOT", "SWITCH RENDERER", "SAVE STATE",
-// "LOAD STATE", "VOLUME UP", "VOLUME DOWN", "DONE"
-me_bind_action emuctrl_actions[] =
-{
-       { "Load State       ", 1<<28 },
-       { "Save State       ", 1<<27 },
-       { "Prev Save Slot   ", 1<<25 },
-       { "Next Save Slot   ", 1<<24 },
-       { "Switch Renderer  ", 1<<26 },
-       { "Fast forward     ", 1<<22 },
-       { "Pico Next page   ", 1<<21 },
-       { "Pico Prev page   ", 1<<20 },
-       { "Pico Switch input", 1<<19 },
-       { NULL,                0     }
-};
-
-static void kc_sel_loop(void)
-{
-       int menu_sel = 5, menu_sel_max = 5;
-       unsigned long inp = 0;
-       menu_id selected_id;
-
-       while (1)
-       {
-               draw_kc_sel(menu_sel);
-               inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_X|PBTN_CIRCLE, 0);
-               selected_id = me_index2id(ctrlopt_entries, CTRLOPT_ENTRY_COUNT, menu_sel);
-               if (inp & (PBTN_LEFT|PBTN_RIGHT)) // multi choise
-                       me_process(ctrlopt_entries, CTRLOPT_ENTRY_COUNT, selected_id, (inp&PBTN_RIGHT) ? 1 : 0);
-               if (inp & PBTN_UP  ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }
-               if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }
-               if (inp & PBTN_CIRCLE) {
-                       int is_6button = PicoIn.opt & POPT_6BTN_PAD;
-                       switch (selected_id) {
-                               case MA_CTRL_PLAYER1: key_config_loop(me_ctrl_actions, is_6button ? 15 : 11, 0); return;
-                               case MA_CTRL_PLAYER2: key_config_loop(me_ctrl_actions, is_6button ? 15 : 11, 1); return;
-                               case MA_CTRL_EMU:     key_config_loop(emuctrl_actions,
-                                                       sizeof(emuctrl_actions)/sizeof(emuctrl_actions[0]) - 1, -1); return;
-                               case MA_CTRL_DONE:    if (!rom_loaded) emu_WriteConfig(0); return;
-                               default: return;
-                       }
-               }
-               if (inp & PBTN_X) return;
-       }
-}
-
-
-// --------- sega/mega cd options ----------
-
-menu_entry cdopt_entries[] =
-{
-       { NULL,                        MB_NONE,  MA_CDOPT_TESTBIOS_USA, NULL, 0, 0, 0, 1, 0 },
-       { NULL,                        MB_NONE,  MA_CDOPT_TESTBIOS_EUR, NULL, 0, 0, 0, 1, 0 },
-       { NULL,                        MB_NONE,  MA_CDOPT_TESTBIOS_JAP, NULL, 0, 0, 0, 1, 0 },
-       { "CD LEDs",                   MB_ONOFF, MA_CDOPT_LEDS,         &currentConfig.EmuOpt,  0x0400, 0, 0, 1, 1 },
-       { "CDDA audio",                MB_ONOFF, MA_CDOPT_CDDA,         &PicoIn.opt, 0x0800, 0, 0, 1, 1 },
-       { "PCM audio",                 MB_ONOFF, MA_CDOPT_PCM,          &PicoIn.opt, 0x0400, 0, 0, 1, 1 },
-       { NULL,                        MB_NONE,  MA_CDOPT_READAHEAD,    NULL, 0, 0, 0, 1, 1 },
-       { "SaveRAM cart",              MB_ONOFF, MA_CDOPT_SAVERAM,      &PicoIn.opt, 0x8000, 0, 0, 1, 1 },
-       { "Scale/Rot. fx (slow)",      MB_ONOFF, MA_CDOPT_SCALEROT_CHIP,&PicoIn.opt, 0x1000, 0, 0, 1, 1 },
-       { "Better sync (slow)",        MB_ONOFF, MA_CDOPT_BETTER_SYNC,  &PicoIn.opt, 0x2000, 0, 0, 1, 1 },
-       { "done",                      MB_NONE,  MA_CDOPT_DONE,         NULL, 0, 0, 0, 1, 0 },
-};
-
-#define CDOPT_ENTRY_COUNT (sizeof(cdopt_entries) / sizeof(cdopt_entries[0]))
-const int cdopt_entry_count = CDOPT_ENTRY_COUNT;
-
-
-struct bios_names_t
-{
-       char us[32], eu[32], jp[32];
-};
-
-static void menu_cdopt_cust_draw(const menu_entry *entry, int x, int y, void *param)
-{
-       struct bios_names_t *bios_names = param;
-       char ra_buff[16];
-
-       switch (entry->id)
-       {
-               case MA_CDOPT_TESTBIOS_USA: text_out16(x, y, "USA BIOS:     %s", bios_names->us); break;
-               case MA_CDOPT_TESTBIOS_EUR: text_out16(x, y, "EUR BIOS:     %s", bios_names->eu); break;
-               case MA_CDOPT_TESTBIOS_JAP: text_out16(x, y, "JAP BIOS:     %s", bios_names->jp); break;
-               case MA_CDOPT_READAHEAD:
-                       if (PicoCDBuffers > 1) sprintf(ra_buff, "%5iK", PicoCDBuffers * 2);
-                       else strcpy(ra_buff, "     OFF");
-                       text_out16(x, y, "ReadAhead buffer      %s", ra_buff);
+               if (inp & (PBTN_MOK|PBTN_MBACK))
                        break;
-               default:break;
-       }
-}
-
-static void draw_cd_menu_options(int menu_sel, struct bios_names_t *bios_names)
-{
-       int tl_x = 80+25, tl_y = 16+60;
-       menu_id selected_id;
-       char ra_buff[16];
-
-       if (PicoCDBuffers > 1) sprintf(ra_buff, "%5iK", PicoCDBuffers * 2);
-       else strcpy(ra_buff, "     OFF");
-
-       menu_draw_begin();
-
-       menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 246);
-
-       me_draw(cdopt_entries, CDOPT_ENTRY_COUNT, tl_x, tl_y, menu_cdopt_cust_draw, bios_names);
-
-       selected_id = me_index2id(cdopt_entries, CDOPT_ENTRY_COUNT, menu_sel);
-       if ((selected_id == MA_CDOPT_TESTBIOS_USA && strcmp(bios_names->us, "NOT FOUND")) ||
-               (selected_id == MA_CDOPT_TESTBIOS_EUR && strcmp(bios_names->eu, "NOT FOUND")) ||
-               (selected_id == MA_CDOPT_TESTBIOS_JAP && strcmp(bios_names->jp, "NOT FOUND")))
-                       text_out16(tl_x, 250, "Press start to test selected BIOS");
-
-       menu_draw_end();
-}
-
-static void cd_menu_loop_options(void)
-{
-       static int menu_sel = 0;
-       int menu_sel_max = 10;
-       unsigned long inp = 0;
-       struct bios_names_t bios_names;
-       menu_id selected_id;
-       char *bios, *p;
-
-       if (emu_findBios(4, &bios)) { // US
-               for (p = bios+strlen(bios)-1; p > bios && *p != '/'; p--);
-               if (*p == '/') p++;
-               strncpy(bios_names.us, p, sizeof(bios_names.us)); bios_names.us[sizeof(bios_names.us)-1] = 0;
-       } else  strcpy(bios_names.us, "NOT FOUND");
-
-       if (emu_findBios(8, &bios)) { // EU
-               for (p = bios+strlen(bios)-1; p > bios && *p != '/'; p--);
-               if (*p == '/') p++;
-               strncpy(bios_names.eu, p, sizeof(bios_names.eu)); bios_names.eu[sizeof(bios_names.eu)-1] = 0;
-       } else  strcpy(bios_names.eu, "NOT FOUND");
-
-       if (emu_findBios(1, &bios)) { // JP
-               for (p = bios+strlen(bios)-1; p > bios && *p != '/'; p--);
-               if (*p == '/') p++;
-               strncpy(bios_names.jp, p, sizeof(bios_names.jp)); bios_names.jp[sizeof(bios_names.jp)-1] = 0;
-       } else  strcpy(bios_names.jp, "NOT FOUND");
-
-       menuErrorMsg[0] = 0;
-
-       for (;;)
-       {
-               draw_cd_menu_options(menu_sel, &bios_names);
-               inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_X|PBTN_CIRCLE|PBTN_START, 0);
-               if (inp & PBTN_UP  ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }
-               if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }
-               selected_id = me_index2id(cdopt_entries, CDOPT_ENTRY_COUNT, menu_sel);
-               if (inp & (PBTN_LEFT|PBTN_RIGHT)) { // multi choise
-                       if (!me_process(cdopt_entries, CDOPT_ENTRY_COUNT, selected_id, (inp&PBTN_RIGHT) ? 1 : 0) &&
-                           selected_id == MA_CDOPT_READAHEAD) {
-                               if (inp & PBTN_LEFT) {
-                                       PicoCDBuffers >>= 1;
-                                       if (PicoCDBuffers < 2) PicoCDBuffers = 0;
-                               } else {
-                                       if (PicoCDBuffers < 2) PicoCDBuffers = 2;
-                                       else PicoCDBuffers <<= 1;
-                                       if (PicoCDBuffers > 8*1024) PicoCDBuffers = 8*1024; // 16M
-                               }
-                       }
-               }
-               if (inp & PBTN_CIRCLE) // toggleable options
-                       if (!me_process(cdopt_entries, CDOPT_ENTRY_COUNT, selected_id, 1) &&
-                           selected_id == MA_CDOPT_DONE) {
-                               return;
-                       }
-               if (inp & PBTN_START) {
-                       switch (selected_id) { // BIOS testers
-                               case MA_CDOPT_TESTBIOS_USA:
-                                       if (emu_findBios(4, &bios)) { // test US
-                                               strcpy(romFileName, bios);
-                                               engineState = PGS_ReloadRom;
-                                               return;
-                                       }
-                                       break;
-                               case MA_CDOPT_TESTBIOS_EUR:
-                                       if (emu_findBios(8, &bios)) { // test EU
-                                               strcpy(romFileName, bios);
-                                               engineState = PGS_ReloadRom;
-                                               return;
-                                       }
-                                       break;
-                               case MA_CDOPT_TESTBIOS_JAP:
-                                       if (emu_findBios(1, &bios)) { // test JP
-                                               strcpy(romFileName, bios);
-                                               engineState = PGS_ReloadRom;
-                                               return;
-                                       }
-                                       break;
-                               default:
-                                       break;
-                       }
-               }
-               if (inp & PBTN_X) return;
-       }
-}
-
-// --------- display options ----------
-
-menu_entry opt3_entries[] =
-{
-       { NULL,                        MB_NONE,  MA_OPT3_SCALE,         NULL, 0, 0, 0, 1, 1 },
-       { NULL,                        MB_NONE,  MA_OPT3_HSCALE32,      NULL, 0, 0, 0, 1, 1 },
-       { NULL,                        MB_NONE,  MA_OPT3_HSCALE40,      NULL, 0, 0, 0, 1, 1 },
-       { NULL,                        MB_ONOFF, MA_OPT3_FILTERING,     &currentConfig.scaling, 1,  0,  0, 1, 1 },
-       { NULL,                        MB_RANGE, MA_OPT3_GAMMAA,        &currentConfig.gamma,   0, -4, 16, 1, 1 },
-       { NULL,                        MB_RANGE, MA_OPT3_BLACKLVL,      &currentConfig.gamma2,  0,  0,  2, 1, 1 },
-       { NULL,                        MB_NONE,  MA_OPT3_VSYNC,         NULL, 0, 0, 0, 1, 1 },
-       { "Set to unscaled centered",  MB_NONE,  MA_OPT3_PRES_NOSCALE,  NULL, 0, 0, 0, 1, 0 },
-       { "Set to 4:3 scaled",         MB_NONE,  MA_OPT3_PRES_SCALE43,  NULL, 0, 0, 0, 1, 0 },
-       { "Set to fullscreen",         MB_NONE,  MA_OPT3_PRES_FULLSCR,  NULL, 0, 0, 0, 1, 0 },
-       { "done",                      MB_NONE,  MA_OPT3_DONE,          NULL, 0, 0, 0, 1, 0 },
-};
-
-#define OPT3_ENTRY_COUNT (sizeof(opt3_entries) / sizeof(opt3_entries[0]))
-const int opt3_entry_count = OPT3_ENTRY_COUNT;
-
-
-static void menu_opt3_cust_draw(const menu_entry *entry, int x, int y, void *param)
-{
-       switch (entry->id)
-       {
-               case MA_OPT3_SCALE:
-                       text_out16(x, y, "Scale factor:                      %.2f", currentConfig.scale);
-                       break;
-               case MA_OPT3_HSCALE32:
-                       text_out16(x, y, "Hor. scale (for low res. games):   %.2f", currentConfig.hscale32);
-                       break;
-               case MA_OPT3_HSCALE40:
-                       text_out16(x, y, "Hor. scale (for hi res. games):    %.2f", currentConfig.hscale40);
-                       break;
-               case MA_OPT3_FILTERING:
-                       text_out16(x, y, "Bilinear filtering                 %s", currentConfig.scaling?"ON":"OFF");
-                       break;
-               case MA_OPT3_GAMMAA:
-                       text_out16(x, y, "Gamma adjustment                  %2i", currentConfig.gamma);
-                       break;
-               case MA_OPT3_BLACKLVL:
-                       text_out16(x, y, "Black level                       %2i", currentConfig.gamma2);
-                       break;
-               case MA_OPT3_VSYNC: {
-                       char *val = "    never";
-                       if (currentConfig.EmuOpt & 0x2000)
-                               val = (currentConfig.EmuOpt & 0x10000) ? "sometimes" : "   always";
-                       text_out16(x, y, "Wait for vsync (slow)         %s", val);
-                       break;
-               }
-               default: break;
-       }
-}
-
-static void menu_opt3_preview(int is_32col)
-{
-       void *oldstate = NULL;
-
-       if (!rom_loaded || ((Pico.video.reg[12]&1)^1) != is_32col)
-       {
-               extern char bgdatac32_start[], bgdatac40_start[];
-               extern int bgdatac32_size, bgdatac40_size;
-               void *bgdata = is_32col ? bgdatac32_start : bgdatac40_start;
-               unsigned long insize = is_32col ? bgdatac32_size : bgdatac40_size, outsize = 65856;
-               int ret;
-               ret = uncompress((Bytef *)bg_buffer, &outsize, bgdata, insize);
-               if (ret == 0)
-               {
-                       if (rom_loaded) oldstate = get_oldstate_for_preview();
-                       memcpy(Pico.vram,  bg_buffer, sizeof(Pico.vram));
-                       memcpy(Pico.cram,  (char *)bg_buffer + 0x10000, 0x40*2);
-                       memcpy(Pico.vsram, (char *)bg_buffer + 0x10080, 0x40*2);
-                       memcpy(&Pico.video,(char *)bg_buffer + 0x10100, 0x40);
-               }
-               else
-                       lprintf("uncompress returned %i\n", ret);
-       }
-
-       memset32_uncached(psp_screen, 0, 512*272*2/4);
-       emu_forcedFrame(0);
-       menu_prepare_bg(1, 0);
-
-       if (oldstate) restore_oldstate(oldstate);
-}
-
-static void draw_dispmenu_options(int menu_sel)
-{
-       int tl_x = 80, tl_y = 16+50;
-
-       menu_draw_begin();
-
-       menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 316);
-
-       me_draw(opt3_entries, OPT3_ENTRY_COUNT, tl_x, tl_y, menu_opt3_cust_draw, NULL);
-
-       menu_draw_end();
-}
-
-static void dispmenu_loop_options(void)
-{
-       static int menu_sel = 0;
-       int menu_sel_max, is_32col = (Pico.video.reg[12]&1)^1;
-       unsigned long inp = 0;
-       menu_id selected_id;
-
-       menu_sel_max = me_count_enabled(opt3_entries, OPT3_ENTRY_COUNT) - 1;
-
-       for (;;)
-       {
-               draw_dispmenu_options(menu_sel);
-               inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_X|PBTN_CIRCLE, 0);
-               if (inp & PBTN_UP  ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }
-               if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }
-               selected_id = me_index2id(opt3_entries, OPT3_ENTRY_COUNT, menu_sel);
-               if (selected_id == MA_OPT3_HSCALE40 &&  is_32col) { is_32col = 0; menu_opt3_preview(is_32col); }
-               if (selected_id == MA_OPT3_HSCALE32 && !is_32col) { is_32col = 1; menu_opt3_preview(is_32col); }
-
-               if (inp & (PBTN_LEFT|PBTN_RIGHT)) // multi choise
-               {
-                       float *setting = NULL;
-                       int tmp;
-                       me_process(opt3_entries, OPT3_ENTRY_COUNT, selected_id, (inp&PBTN_RIGHT) ? 1 : 0);
-                       switch (selected_id) {
-                               case MA_OPT3_SCALE:     setting = &currentConfig.scale; break;
-                               case MA_OPT3_HSCALE40:  setting = &currentConfig.hscale40; is_32col = 0; break;
-                               case MA_OPT3_HSCALE32:  setting = &currentConfig.hscale32; is_32col = 1; break;
-                               case MA_OPT3_FILTERING:
-                               case MA_OPT3_GAMMAA:
-                               case MA_OPT3_BLACKLVL:  menu_opt3_preview(is_32col); break;
-                               case MA_OPT3_VSYNC:
-                                       tmp = ((currentConfig.EmuOpt>>13)&1) | ((currentConfig.EmuOpt>>15)&2);
-                                       tmp = (inp & PBTN_LEFT) ? (tmp>>1) : ((tmp<<1)|1);
-                                       if (tmp > 3) tmp = 3;
-                                       currentConfig.EmuOpt &= ~0x12000;
-                                       currentConfig.EmuOpt |= ((tmp&2)<<15) | ((tmp&1)<<13);
-                                       break;
-                               default: break;
-                       }
-                       if (setting != NULL) {
-                               while ((inp = psp_pad_read(0)) & (PBTN_LEFT|PBTN_RIGHT)) {
-                                       *setting += (inp & PBTN_LEFT) ? -0.01 : 0.01;
-                                       if (*setting <= 0) *setting = 0.01;
-                                       menu_opt3_preview(is_32col);
-                                       draw_dispmenu_options(menu_sel); // will wait vsync
-                               }
-                       }
-               }
-               if (inp & PBTN_CIRCLE) { // toggleable options
-                       me_process(opt3_entries, OPT3_ENTRY_COUNT, selected_id, 1);
-                       switch (selected_id) {
-                               case MA_OPT3_DONE:
-                                       return;
-                               case MA_OPT3_PRES_NOSCALE:
-                                       currentConfig.scale = currentConfig.hscale40 = currentConfig.hscale32 = 1.0;
-                                       menu_opt3_preview(is_32col);
-                                       break;
-                               case MA_OPT3_PRES_SCALE43:
-                                       currentConfig.scale = 1.20;
-                                       currentConfig.hscale40 = 1.00;
-                                       currentConfig.hscale32 = 1.25;
-                                       menu_opt3_preview(is_32col);
-                                       break;
-                               case MA_OPT3_PRES_FULLSCR:
-                                       currentConfig.scale = 1.20;
-                                       currentConfig.hscale40 = 1.25;
-                                       currentConfig.hscale32 = 1.56;
-                                       menu_opt3_preview(is_32col);
-                                       break;
-                               case MA_OPT3_FILTERING:
-                                       menu_opt3_preview(is_32col);
-                                       break;
-                               default: break;
-                       }
-               }
-               if (inp & PBTN_X) return;
-       }
-}
-
-
-// --------- advanced options ----------
-
-menu_entry opt2_entries[] =
-{
-       { "Disable sprite limit",      MB_ONOFF, MA_OPT2_NO_SPRITE_LIM,  &PicoIn.opt, 0x40000, 0, 0, 1, 1 },
-       { "Emulate Z80",               MB_ONOFF, MA_OPT2_ENABLE_Z80,     &PicoIn.opt, 0x00004, 0, 0, 1, 1 },
-       { "Emulate YM2612 (FM)",       MB_ONOFF, MA_OPT2_ENABLE_YM2612,  &PicoIn.opt, 0x00001, 0, 0, 1, 1 },
-       { "Emulate SN76496 (PSG)",     MB_ONOFF, MA_OPT2_ENABLE_SN76496, &PicoIn.opt, 0x00002, 0, 0, 1, 1 },
-       { "Emulate YM2413 (FM)",       MB_ONOFF, MA_OPT2_ENABLE_YM2413,  &PicoIn.opt, 0x00020, 0, 0, 1, 1 },
-       { "gzip savestates",           MB_ONOFF, MA_OPT2_GZIP_STATES,    &currentConfig.EmuOpt, 0x00008, 0, 0, 1, 1 },
-       { "Don't save last used ROM",  MB_ONOFF, MA_OPT2_NO_LAST_ROM,    &currentConfig.EmuOpt, 0x00020, 0, 0, 1, 1 },
-       { "Status line in main menu",  MB_ONOFF, MA_OPT2_STATUS_LINE,    &currentConfig.EmuOpt, 0x20000, 0, 0, 1, 1 },
-       { "Disable idle loop patching",MB_ONOFF, MA_OPT2_NO_IDLE_LOOPS,  &PicoIn.opt, 0x80000, 0, 0, 1, 1 },
-       { "Disable frame limiter",     MB_ONOFF, MA_OPT2_NO_FRAME_LIMIT, &currentConfig.EmuOpt, 0x40000, 0, 0, 1, 1 },
-       { "done",                      MB_NONE,  MA_OPT2_DONE,           NULL, 0, 0, 0, 1, 0 },
-};
-
-#define OPT2_ENTRY_COUNT (sizeof(opt2_entries) / sizeof(opt2_entries[0]))
-const int opt2_entry_count = OPT2_ENTRY_COUNT;
-
-
-static void draw_amenu_options(int menu_sel)
-{
-       int tl_x = 80+25, tl_y = 16+50;
-
-       menu_draw_begin();
-
-       menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 252);
-
-       me_draw(opt2_entries, OPT2_ENTRY_COUNT, tl_x, tl_y, NULL, NULL);
-
-       menu_draw_end();
-}
-
-static void amenu_loop_options(void)
-{
-       static int menu_sel = 0;
-       int menu_sel_max;
-       unsigned long inp = 0;
-       menu_id selected_id;
-
-       menu_sel_max = me_count_enabled(opt2_entries, OPT2_ENTRY_COUNT) - 1;
-
-       for(;;)
-       {
-               draw_amenu_options(menu_sel);
-               inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_X|PBTN_CIRCLE, 0);
-               if (inp & PBTN_UP  ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }
-               if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }
-               selected_id = me_index2id(opt2_entries, OPT2_ENTRY_COUNT, menu_sel);
-               if (inp & (PBTN_LEFT|PBTN_RIGHT)) { // multi choise
-                       if (!me_process(opt2_entries, OPT2_ENTRY_COUNT, selected_id, (inp&PBTN_RIGHT) ? 1 : 0) &&
-                           selected_id == MA_OPT2_GAMMA) {
-                               // TODO?
-                       }
-               }
-               if (inp & PBTN_CIRCLE) { // toggleable options
-                       if (!me_process(opt2_entries, OPT2_ENTRY_COUNT, selected_id, 1) &&
-                           selected_id == MA_OPT2_DONE) {
-                               return;
-                       }
-               }
-               if (inp & PBTN_X) return;
-       }
-}
-
-// -------------- options --------------
-
-
-menu_entry opt_entries[] =
-{
-       { NULL,                        MB_NONE,  MA_OPT_RENDERER,      NULL, 0, 0, 0, 1, 1 },
-       { "Accurate sprites",          MB_ONOFF, MA_OPT_ACC_SPRITES,   &PicoIn.opt, 0x080, 0, 0, 0, 1 },
-       { "Show FPS",                  MB_ONOFF, MA_OPT_SHOW_FPS,      &currentConfig.EmuOpt,  0x0002,  0,  0, 1, 1 },
-       { NULL,                        MB_RANGE, MA_OPT_FRAMESKIP,     &currentConfig.Frameskip,    0, -1, 16, 1, 1 },
-       { "Enable sound",              MB_ONOFF, MA_OPT_ENABLE_SOUND,  &currentConfig.EmuOpt,  0x0004,  0,  0, 1, 1 },
-       { NULL,                        MB_NONE,  MA_OPT_SOUND_QUALITY, NULL, 0, 0, 0, 1, 1 },
-       { NULL,                        MB_NONE,  MA_OPT_REGION,        NULL, 0, 0, 0, 1, 1 },
-       { "Use SRAM/BRAM savestates",  MB_ONOFF, MA_OPT_SRAM_STATES,   &currentConfig.EmuOpt,  0x0001, 0, 0, 1, 1 },
-       { NULL,                        MB_NONE,  MA_OPT_CONFIRM_STATES,NULL, 0, 0, 0, 1, 1 },
-       { "Save slot",                 MB_RANGE, MA_OPT_SAVE_SLOT,     &state_slot, 0, 0, 9, 1, 1 },
-       { NULL,                        MB_NONE,  MA_OPT_CPU_CLOCKS,    NULL, 0, 0, 0, 1, 1 },
-       { "[Display options]",         MB_NONE,  MA_OPT_DISP_OPTS,     NULL, 0, 0, 0, 1, 0 },
-       { "[Sega/Mega CD options]",    MB_NONE,  MA_OPT_SCD_OPTS,      NULL, 0, 0, 0, 1, 0 },
-       { "[Advanced options]",        MB_NONE,  MA_OPT_ADV_OPTS,      NULL, 0, 0, 0, 1, 0 },
-       { NULL,                        MB_NONE,  MA_OPT_SAVECFG,       NULL, 0, 0, 0, 1, 0 },
-       { "Save cfg for current game only",MB_NONE,MA_OPT_SAVECFG_GAME,NULL, 0, 0, 0, 1, 0 },
-       { NULL,                        MB_NONE,  MA_OPT_LOADCFG,       NULL, 0, 0, 0, 1, 0 },
-};
-
-#define OPT_ENTRY_COUNT (sizeof(opt_entries) / sizeof(opt_entries[0]))
-const int opt_entry_count = OPT_ENTRY_COUNT;
-
-
-static void menu_opt_cust_draw(const menu_entry *entry, int x, int y, void *param)
-{
-       char *str, str24[24];
-
-       switch (entry->id)
-       {
-               case MA_OPT_RENDERER:
-                       if (PicoIn.opt & 0x10)
-                               str = "fast";
-                       else if (currentConfig.EmuOpt & 0x80)
-                               str = "accurate";
-                       else
-                               str = " 8bit accurate"; // n/a
-                       text_out16(x, y, "Renderer:                  %s", str);
-                       break;
-               case MA_OPT_FRAMESKIP:
-                       if (currentConfig.Frameskip < 0)
-                            strcpy(str24, "Auto");
-                       else sprintf(str24, "%i", currentConfig.Frameskip);
-                       text_out16(x, y, "Frameskip                  %s", str24);
-                       break;
-               case MA_OPT_SOUND_QUALITY:
-                       str = (PicoIn.opt&0x08)?"stereo":"mono";
-                       text_out16(x, y, "Sound Quality:     %5iHz %s", PicoIn.sndRate, str);
-                       break;
-               case MA_OPT_REGION:
-                       text_out16(x, y, "Region:              %s", me_region_name(PicoIn.regionOverride, PicoIn.autoRgnOrder));
-                       break;
-               case MA_OPT_CONFIRM_STATES:
-                       switch ((currentConfig.EmuOpt >> 9) & 5) {
-                               default: str = "OFF";    break;
-                               case 1:  str = "writes"; break;
-                               case 4:  str = "loads";  break;
-                               case 5:  str = "both";   break;
-                       }
-                       text_out16(x, y, "Confirm savestate          %s", str);
-                       break;
-               case MA_OPT_CPU_CLOCKS:
-                       text_out16(x, y, "CPU/bus clock       %3i/%3iMHz", currentConfig.CPUclock, currentConfig.CPUclock/2);
-                       break;
-               case MA_OPT_SAVECFG:
-                       str24[0] = 0;
-                       if (config_slot != 0) sprintf(str24, " (profile: %i)", config_slot);
-                       text_out16(x, y, "Save cfg as default%s", str24);
-                       break;
-               case MA_OPT_LOADCFG:
-                       text_out16(x, y, "Load cfg from profile %i", config_slot);
-                       break;
-               default:
-                       lprintf("%s: unimplemented (%i)\n", __FUNCTION__, entry->id);
-                       break;
-       }
-}
-
-
-static void draw_menu_options(int menu_sel)
-{
-       int tl_x = 80+25, tl_y = 16+24;
 
-       menu_draw_begin();
-
-       menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 284);
-
-       me_draw(opt_entries, OPT_ENTRY_COUNT, tl_x, tl_y, menu_opt_cust_draw, NULL);
-
-       menu_draw_end();
-}
-
-static int sndrate_prevnext(int rate, int dir)
-{
-       int i, rates[] = { 11025, 22050, 44100 };
-
-       for (i = 0; i < 5; i++)
-               if (rates[i] == rate) break;
-
-       i += dir ? 1 : -1;
-       if (i > 2) return dir ? 44100 : 22050;
-       if (i < 0) return dir ? 22050 : 11025;
-       return rates[i];
-}
-
-static void region_prevnext(int right)
-{
-       // jp_ntsc=1, jp_pal=2, usa=4, eu=8
-       static int rgn_orders[] = { 0x148, 0x184, 0x814, 0x418, 0x841, 0x481 };
-       int i;
-       if (right) {
-               if (!PicoIn.regionOverride) {
-                       for (i = 0; i < 6; i++)
-                               if (rgn_orders[i] == PicoIn.autoRgnOrder) break;
-                       if (i < 5) PicoIn.autoRgnOrder = rgn_orders[i+1];
-                       else PicoIn.regionOverride=1;
+               if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
+                       if (g_layer_cx < 0)   g_layer_cx = 0;
+                       if (g_layer_cx > 640) g_layer_cx = 640;
+                       if (g_layer_cy < 0)   g_layer_cy = 0;
+                       if (g_layer_cy > 420) g_layer_cy = 420;
+                       if (g_layer_cw < 160) g_layer_cw = 160;
+                       if (g_layer_ch < 60)  g_layer_ch = 60;
+                       if (g_layer_cx + g_layer_cw > 800)
+                               g_layer_cw = 800 - g_layer_cx;
+                       if (g_layer_cy + g_layer_ch > 480)
+                               g_layer_ch = 480 - g_layer_cy;
+                       pnd_setup_layer(1, g_layer_cx, g_layer_cy, g_layer_cw, g_layer_ch);
                }
-               else PicoIn.regionOverride<<=1;
-               if (PicoIn.regionOverride > 8) PicoIn.regionOverride = 8;
-       } else {
-               if (!PicoIn.regionOverride) {
-                       for (i = 0; i < 6; i++)
-                               if (rgn_orders[i] == PicoIn.autoRgnOrder) break;
-                       if (i > 0) PicoIn.autoRgnOrder = rgn_orders[i-1];
-               }
-               else PicoIn.regionOverride>>=1;
-       }
-}
-
-static void menu_options_save(void)
-{
-       if (PicoIn.regionOverride) {
-               // force setting possibly changed..
-               Pico.m.pal = (PicoIn.regionOverride == 2 || PicoIn.regionOverride == 8) ? 1 : 0;
-       }
-       if (!(PicoIn.opt & POPT_6BTN_PAD)) {
-               // unbind XYZ MODE, just in case
-               unbind_action(0xf00);
        }
-}
 
-static int menu_loop_options(void)
-{
-       static int menu_sel = 0;
-       int menu_sel_max, ret;
-       unsigned long inp = 0;
-       menu_id selected_id;
+       pnd_setup_layer(0, g_layer_cx, g_layer_cy, g_layer_cw, g_layer_ch);
 
-       me_enable(opt_entries, OPT_ENTRY_COUNT, MA_OPT_SAVECFG_GAME, rom_loaded);
-       me_enable(opt_entries, OPT_ENTRY_COUNT, MA_OPT_LOADCFG, config_slot != config_slot_current);
-       menu_sel_max = me_count_enabled(opt_entries, OPT_ENTRY_COUNT) - 1;
-       if (menu_sel > menu_sel_max) menu_sel = menu_sel_max;
-
-       while (1)
-       {
-               draw_menu_options(menu_sel);
-               inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_X|PBTN_CIRCLE, 0);
-               if (inp & PBTN_UP  ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }
-               if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }
-               selected_id = me_index2id(opt_entries, OPT_ENTRY_COUNT, menu_sel);
-               if (inp & (PBTN_LEFT|PBTN_RIGHT)) { // multi choise
-                       if (!me_process(opt_entries, OPT_ENTRY_COUNT, selected_id, (inp&PBTN_RIGHT) ? 1 : 0)) {
-                               switch (selected_id) {
-                                       case MA_OPT_RENDERER:
-                                               if ((PicoIn.opt & 0x10) || !(currentConfig.EmuOpt & 0x80)) {
-                                                       PicoIn.opt &= ~0x10;
-                                                       currentConfig.EmuOpt |=  0x80;
-                                               } else {
-                                                       PicoIn.opt |=  0x10;
-                                                       currentConfig.EmuOpt &= ~0x80;
-                                               }
-                                               break;
-                                       case MA_OPT_SOUND_QUALITY:
-                                               PicoIn.sndRate = sndrate_prevnext(PicoIn.sndRate, inp & PBTN_RIGHT);
-                                               break;
-                                       case MA_OPT_REGION:
-                                               region_prevnext(inp & PBTN_RIGHT);
-                                               break;
-                                       case MA_OPT_CONFIRM_STATES: {
-                                                        int n = ((currentConfig.EmuOpt>>9)&1) | ((currentConfig.EmuOpt>>10)&2);
-                                                        n += (inp & PBTN_LEFT) ? -1 : 1;
-                                                        if (n < 0) n = 0; else if (n > 3) n = 3;
-                                                        n |= n << 1; n &= ~2;
-                                                        currentConfig.EmuOpt &= ~0xa00;
-                                                        currentConfig.EmuOpt |= n << 9;
-                                                        break;
-                                                }
-                                       case MA_OPT_SAVE_SLOT:
-                                                if (inp & PBTN_RIGHT) {
-                                                        state_slot++; if (state_slot > 9) state_slot = 0;
-                                                } else {state_slot--; if (state_slot < 0) state_slot = 9;
-                                                }
-                                                break;
-                                       case MA_OPT_CPU_CLOCKS:
-                                                while ((inp = psp_pad_read(0)) & (PBTN_LEFT|PBTN_RIGHT)) {
-                                                        currentConfig.CPUclock += (inp & PBTN_LEFT) ? -1 : 1;
-                                                        if (currentConfig.CPUclock <  19) currentConfig.CPUclock = 19;
-                                                        if (currentConfig.CPUclock > 333) currentConfig.CPUclock = 333;
-                                                        draw_menu_options(menu_sel); // will wait vsync
-                                                }
-                                                break;
-                                       case MA_OPT_SAVECFG:
-                                       case MA_OPT_SAVECFG_GAME:
-                                       case MA_OPT_LOADCFG:
-                                                config_slot += (inp&PBTN_RIGHT) ? 1 : -1;
-                                                if (config_slot > 9) config_slot = 0;
-                                                if (config_slot < 0) config_slot = 9;
-                                                me_enable(opt_entries, OPT_ENTRY_COUNT, MA_OPT_LOADCFG, config_slot != config_slot_current);
-                                                menu_sel_max = me_count_enabled(opt_entries, OPT_ENTRY_COUNT) - 1;
-                                                if (menu_sel > menu_sel_max) menu_sel = menu_sel_max;
-                                                break;
-                                       default:
-                                               //lprintf("%s: something unknown selected (%i)\n", __FUNCTION__, selected_id);
-                                               break;
-                               }
-                       }
-               }
-               if (inp & PBTN_CIRCLE) {
-                       if (!me_process(opt_entries, OPT_ENTRY_COUNT, selected_id, 1))
-                       {
-                               switch (selected_id)
-                               {
-                                       case MA_OPT_DISP_OPTS:
-                                               dispmenu_loop_options();
-                                               break;
-                                       case MA_OPT_SCD_OPTS:
-                                               cd_menu_loop_options();
-                                               if (engineState == PGS_ReloadRom)
-                                                       return 0; // test BIOS
-                                               break;
-                                       case MA_OPT_ADV_OPTS:
-                                               amenu_loop_options();
-                                               break;
-                                       case MA_OPT_SAVECFG: // done (update and write)
-                                               menu_options_save();
-                                               if (emu_WriteConfig(0)) strcpy(menuErrorMsg, "config saved");
-                                               else strcpy(menuErrorMsg, "failed to write config");
-                                               return 1;
-                                       case MA_OPT_SAVECFG_GAME: // done (update and write for current game)
-                                               menu_options_save();
-                                               if (emu_WriteConfig(1)) strcpy(menuErrorMsg, "config saved");
-                                               else strcpy(menuErrorMsg, "failed to write config");
-                                               return 1;
-                                       case MA_OPT_LOADCFG:
-                                               ret = emu_ReadConfig(1, 1);
-                                               if (!ret) ret = emu_ReadConfig(0, 1);
-                                               if (ret)  strcpy(menuErrorMsg, "config loaded");
-                                               else      strcpy(menuErrorMsg, "failed to load config");
-                                               return 1;
-                                       default:
-                                               //lprintf("%s: something unknown selected (%i)\n", __FUNCTION__, selected_id);
-                                               break;
-                               }
-                       }
-               }
-               if(inp & PBTN_X) {
-                       menu_options_save();
-                       return 0;  // done (update, no write)
-               }
-       }
+       return 0;
 }
+#endif
 
-// -------------- credits --------------
-
-static void draw_menu_credits(void)
-{
-       int tl_x = 80+15, tl_y = 16+64, y;
-       menu_draw_begin();
-
-       text_out16(tl_x, 16+20, "PicoDrive v" VERSION " (c) notaz, 2006-2008");
-
-       y = tl_y;
-       text_out16(tl_x, y, "Credits:");
-       text_out16(tl_x, (y+=10), "fDave: base code of PicoDrive");
-       text_out16(tl_x, (y+=10), "Chui: Fame/C");
-       text_out16(tl_x, (y+=10), "NJ: CZ80");
-       text_out16(tl_x, (y+=10), "MAME devs: YM2612 and SN76496 cores");
-       text_out16(tl_x, (y+=10), "ps2dev.org people: PSP SDK/code");
-       text_out16(tl_x, (y+=10), "ketchupgun: skin design");
-
-       text_out16(tl_x, (y+=20), "special thanks (for docs, ideas):");
-       text_out16(tl_x, (y+=10), " Charles MacDonald, Haze,");
-       text_out16(tl_x, (y+=10), " Stephane Dallongeville,");
-       text_out16(tl_x, (y+=10), " Lordus, Exophase, Rokas,");
-       text_out16(tl_x, (y+=10), " Nemesis, Tasco Deluxe");
-
-       menu_draw_end();
-}
-
-
-// -------------- root menu --------------
-
-menu_entry main_entries[] =
-{
-       { "Resume game",        MB_NONE, MA_MAIN_RESUME_GAME, NULL, 0, 0, 0, 0 },
-       { "Save State",         MB_NONE, MA_MAIN_SAVE_STATE,  NULL, 0, 0, 0, 0 },
-       { "Load State",         MB_NONE, MA_MAIN_LOAD_STATE,  NULL, 0, 0, 0, 0 },
-       { "Reset game",         MB_NONE, MA_MAIN_RESET_GAME,  NULL, 0, 0, 0, 0 },
-       { "Load new ROM/ISO",   MB_NONE, MA_MAIN_LOAD_ROM,    NULL, 0, 0, 0, 1 },
-       { "Change options",     MB_NONE, MA_MAIN_OPTIONS,     NULL, 0, 0, 0, 1 },
-       { "Configure controls", MB_NONE, MA_MAIN_CONTROLS,    NULL, 0, 0, 0, 1 },
-       { "Credits",            MB_NONE, MA_MAIN_CREDITS,     NULL, 0, 0, 0, 1 },
-       { "Patches / GameGenie",MB_NONE, MA_MAIN_PATCHES,     NULL, 0, 0, 0, 0 },
-       { "Exit",               MB_NONE, MA_MAIN_EXIT,        NULL, 0, 0, 0, 1 }
-};
-
-#define MAIN_ENTRY_COUNT (sizeof(main_entries) / sizeof(main_entries[0]))
-
-static void draw_menu_root(int menu_sel)
-{
-       const int tl_x = 86+70, tl_y = 16+70;
-       char *stat = NULL;
-
-       menu_draw_begin();
-
-       if ((currentConfig.EmuOpt&0x20000) && (stat = psp_get_status_line()))
-               text_out16(287, 12, "%s", stat);
-
-       text_out16(tl_x, 48, "PicoDrive v" VERSION);
-
-       menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 146);
-
-       me_draw(main_entries, MAIN_ENTRY_COUNT, tl_x, tl_y, NULL, NULL);
-
-       // error
-       if (menuErrorMsg[0])
-               text_out16(10, 252, menuErrorMsg);
-       menu_draw_end();
-}
-
-
-static void menu_loop_root(void)
-{
-       static int menu_sel = 0;
-       int ret, menu_sel_max;
-       unsigned long inp = 0;
-
-       me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_RESUME_GAME, rom_loaded);
-       me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_SAVE_STATE,  rom_loaded);
-       me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_LOAD_STATE,  rom_loaded);
-       me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_RESET_GAME,  rom_loaded);
-       me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_PATCHES,     PicoPatches != NULL);
-
-       menu_sel_max = me_count_enabled(main_entries, MAIN_ENTRY_COUNT) - 1;
-       if (menu_sel > menu_sel_max) menu_sel = menu_sel_max;
-
-       // mp3 errors?
-       if (mp3_last_error != 0) {
-               if (mp3_last_error == -1)
-                    sprintf(menuErrorMsg, "Unsupported mp3 format, use 44kHz stereo");
-               else sprintf(menuErrorMsg, "mp3 init failed, code %08x", mp3_last_error);
-               mp3_last_error = 0;
-       }
-
-       /* make sure action buttons are not pressed on entering menu */
-       draw_menu_root(menu_sel);
-
-       while (psp_pad_read(1) & (PBTN_X|PBTN_CIRCLE|PBTN_SELECT)) psp_msleep(50);
-
-       for (;;)
-       {
-               draw_menu_root(menu_sel);
-               inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_X|PBTN_CIRCLE|PBTN_SELECT|PBTN_L|PBTN_R, 0);
-               if(inp & PBTN_UP  )  { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }
-               if(inp & PBTN_DOWN)  { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }
-               if((inp & (PBTN_L|PBTN_R)) == (PBTN_L|PBTN_R)) debug_menu_loop();
-               if( inp & (PBTN_SELECT|PBTN_X)) {
-                       if (rom_loaded) {
-                               while (psp_pad_read(1) & (PBTN_SELECT|PBTN_X)) psp_msleep(50); // wait until released
-                               engineState = PGS_Running;
-                               break;
-                       }
-               }
-               if(inp & PBTN_CIRCLE)  {
-                       menuErrorMsg[0] = 0; // clear error msg
-                       switch (me_index2id(main_entries, MAIN_ENTRY_COUNT, menu_sel))
-                       {
-                               case MA_MAIN_RESUME_GAME:
-                                       if (rom_loaded) {
-                                               while (psp_pad_read(1) & PBTN_CIRCLE) psp_msleep(50);
-                                               engineState = PGS_Running;
-                                               return;
-                                       }
-                                       break;
-                               case MA_MAIN_SAVE_STATE:
-                                       if (rom_loaded) {
-                                               if(savestate_menu_loop(0))
-                                                       continue;
-                                               engineState = PGS_Running;
-                                               return;
-                                       }
-                                       break;
-                               case MA_MAIN_LOAD_STATE:
-                                       if (rom_loaded) {
-                                               if(savestate_menu_loop(1))
-                                                       continue;
-                                               while (psp_pad_read(1) & PBTN_CIRCLE) psp_msleep(50);
-                                               engineState = PGS_Running;
-                                               return;
-                                       }
-                                       break;
-                               case MA_MAIN_RESET_GAME:
-                                       if (rom_loaded) {
-                                               emu_ResetGame();
-                                               while (psp_pad_read(1) & PBTN_CIRCLE) psp_msleep(50);
-                                               engineState = PGS_Running;
-                                               return;
-                                       }
-                                       break;
-                               case MA_MAIN_LOAD_ROM:
-                               {
-                                       char curr_path[PATH_MAX], *selfname;
-                                       FILE *tstf;
-                                       if ( (tstf = fopen(loadedRomFName, "rb")) )
-                                       {
-                                               fclose(tstf);
-                                               strcpy(curr_path, loadedRomFName);
-                                       }
-                                       else
-                                               getcwd(curr_path, PATH_MAX);
-                                       selfname = romsel_loop(curr_path);
-                                       if (selfname) {
-                                               lprintf("selected file: %s\n", selfname);
-                                               engineState = PGS_ReloadRom;
-                                               return;
-                                       }
-                                       break;
-                               }
-                               case MA_MAIN_OPTIONS:
-                                       ret = menu_loop_options();
-                                       if (ret == 1) continue; // status update
-                                       if (engineState == PGS_ReloadRom)
-                                               return; // BIOS test
-                                       break;
-                               case MA_MAIN_CONTROLS:
-                                       kc_sel_loop();
-                                       break;
-                               case MA_MAIN_CREDITS:
-                                       draw_menu_credits();
-                                       psp_msleep(500);
-                                       inp = 0;
-                                       while (!(inp & (PBTN_X|PBTN_CIRCLE)))
-                                               inp = in_menu_wait(PBTN_X|PBTN_CIRCLE, 0);
-                                       break;
-                               case MA_MAIN_EXIT:
-                                       engineState = PGS_Quit;
-                                       return;
-                               case MA_MAIN_PATCHES:
-                                       if (rom_loaded && PicoPatches) {
-                                               patches_menu_loop();
-                                               PicoPatchApply();
-                                               strcpy(menuErrorMsg, "Patches applied");
-                                               continue;
-                                       }
-                                       break;
-                               default:
-                                       lprintf("%s: something unknown selected\n", __FUNCTION__);
-                                       break;
-                       }
-               }
-       }
-}
-
-void menu_darken_bg(void *dst, const void *src, int pixels, int darker)
-{
-       unsigned int *dest = dst;
-       const unsigned int *srce = src;
-       pixels /= 2;
-       if (darker)
-       {
-               while (pixels--)
-               {
-                       unsigned int p = *srce++;
-                       *dest++ = ((p&0xf79ef79e)>>1) - ((p&0xc618c618)>>3);
-               }
-       }
-       else
-       {
-               while (pixels--)
-               {
-                       unsigned int p = *srce++;
-                       *dest++ = (p&0xf79ef79e)>>1;
-               }
-       }
-}
-
-static void menu_prepare_bg(int use_game_bg, int use_fg)
-{
-       if (use_game_bg)
-       {
-               // darken the active framebuffer
-               unsigned short *dst = bg_buffer;
-               unsigned short *src = use_fg ? psp_video_get_active_fb() : psp_screen;
-               int i;
-               for (i = 272; i > 0; i--, dst += 480, src += 512)
-                       menu_darken_bg(dst, src, 480, 1);
-               //memset32_uncached((int *)(bg_buffer + 480*264), 0, 480*8*2/4);
-       }
-       else
-       {
-               // should really only happen once, on startup..
-               memset32_uncached((int *)(void *)bg_buffer, 0, sizeof(bg_buffer)/4);
-               readpng(bg_buffer, "skin/background.png", READPNG_BG);
-       }
-       sceKernelDcacheWritebackAll();
-}
-
-static void menu_gfx_prepare(void)
-{
-       menu_prepare_bg(rom_loaded, 1);
-
-       menu_draw_begin();
-       menu_draw_end();
-}
-
-
-void menu_loop(void)
-{
-       menu_gfx_prepare();
-
-       menu_loop_root();
-
-       menuErrorMsg[0] = 0;
-}
-
-
-// --------- CD tray close menu ----------
-
-static void draw_menu_tray(int menu_sel)
-{
-       int tl_x = 70, tl_y = 90, y;
-
-       menu_draw_begin();
-
-       text_out16(tl_x, 20, "The unit is about to");
-       text_out16(tl_x, 30, "close the CD tray.");
-
-       y = tl_y;
-       text_out16(tl_x, y,       "Load new CD image");
-       text_out16(tl_x, (y+=10), "Insert nothing");
-
-       // draw cursor
-       text_out16(tl_x - 16, tl_y + menu_sel*10, ">");
-       // error
-       if (menuErrorMsg[0]) text_out16(5, 226, menuErrorMsg);
-       menu_draw_end();
-}
-
-
-int menu_loop_tray(void)
-{
-       int menu_sel = 0, menu_sel_max = 1;
-       unsigned long inp = 0;
-       char curr_path[PATH_MAX], *selfname;
-       FILE *tstf;
-
-       menu_gfx_prepare();
-
-       if ( (tstf = fopen(loadedRomFName, "rb")) )
-       {
-               fclose(tstf);
-               strcpy(curr_path, loadedRomFName);
-       }
-       else
-       {
-               getcwd(curr_path, PATH_MAX);
-       }
-
-       /* make sure action buttons are not pressed on entering menu */
-       draw_menu_tray(menu_sel);
-       while (psp_pad_read(1) & PBTN_CIRCLE) psp_msleep(50);
-
-       for (;;)
-       {
-               draw_menu_tray(menu_sel);
-               inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_CIRCLE, 0);
-               if(inp & PBTN_UP  )  { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }
-               if(inp & PBTN_DOWN)  { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }
-               if(inp & PBTN_CIRCLE)  {
-                       switch (menu_sel) {
-                               case 0: // select image
-                                       selfname = romsel_loop(curr_path);
-                                       if (selfname) {
-                                               int ret = -1;
-                                               cd_img_type cd_type;
-                                               cd_type = emu_cdCheck(NULL, romFileName);
-                                               if (cd_type != CIT_NOT_CD)
-                                                       ret = Insert_CD(romFileName, cd_type);
-                                               if (ret != 0) {
-                                                       sprintf(menuErrorMsg, "Load failed, invalid CD image?");
-                                                       lprintf("%s\n", menuErrorMsg);
-                                                       continue;
-                                               }
-                                               engineState = PGS_RestartRun;
-                                               return 1;
-                                       }
-                                       break;
-                               case 1: // insert nothing
-                                       engineState = PGS_RestartRun;
-                                       return 0;
-                       }
-               }
-               menuErrorMsg[0] = 0; // clear error msg
-       }
-}
+#define MENU_OPTIONS_GFX \
+       mee_enum      ("Scaler",                   MA_OPT_SCALING,        currentConfig.scaling, \
+                                                                         men_scaler), \
+       mee_onoff     ("Vsync",                    MA_OPT3_VSYNC,         currentConfig.EmuOpt, EOPT_VSYNC), \
+       /* mee_cust_h    ("Setup custom scaler",      MA_NONE,               menu_loop_cscaler, NULL, h_cscaler), \*/
 
+#define MENU_OPTIONS_ADV
 
index eac13ff..5ec8206 100644 (file)
@@ -12,7 +12,6 @@
 #include <pspkernel.h>
 #include <pspsdk.h>
 #include <pspaudiocodec.h>
-#include <kubridge.h>
 
 #include <pico/pico_int.h>
 #include <pico/sound/mix.h>
@@ -136,19 +135,11 @@ static int read_next_frame(int which_buffer)
 
 static SceUID load_start_module(const char *prxname)
 {
-       SceUID mod, mod1;
-       int status, ret;
+       SceUID mod;
 
        mod = pspSdkLoadStartModule(prxname, PSP_MEMORY_PARTITION_KERNEL);
        if (mod < 0) {
                lprintf("failed to load %s (%08x), trying kuKernelLoadModule\n", prxname, mod);
-               mod1 = kuKernelLoadModule(prxname, 0, NULL);
-               if (mod1 < 0) lprintf("kuKernelLoadModule failed with %08x\n", mod1);
-               else {
-                       ret = sceKernelStartModule(mod1, 0, NULL, &status, 0);
-                       if (ret < 0) lprintf("sceKernelStartModule failed with %08x\n", ret);
-                       else mod = mod1;
-               }
        }
        return mod;
 }
@@ -467,7 +458,7 @@ int mp3_get_offset(void) // 0-1023
        int cdda_on;
 
        cdda_on = (PicoIn.AHW & PAHW_MCD) && (PicoIn.opt&0x800) && !(Pico_mcd->s68k_regs[0x36] & 1) &&
-                       (Pico_mcd->scd.Status_CDC & 1) && mp3_handle >= 0;
+                       /* TODO (Pico_mcd->scd.Status_CDC & 1) &&*/ mp3_handle >= 0;
 
        if (cdda_on) {
                offs1024  = mp3_src_pos << 7;
diff --git a/platform/psp/plat.c b/platform/psp/plat.c
new file mode 100644 (file)
index 0000000..9b2277f
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * Platform interface functions for PSP picodrive frontend
+ *
+ * (C) 2020 kub
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+
+#include "../common/emu.h"
+#include "../libpicofe/menu.h"
+#include "../libpicofe/plat.h"
+
+#include <pspiofilemgr.h>
+#include <pspthreadman.h>
+#include <pspdisplay.h>
+#include <psputils.h>
+#include <psppower.h>
+#include <pspgu.h>
+#include <pspaudio.h>
+
+#include "psp.h"
+#include "emu.h"
+#include "asm_utils.h"
+
+#include <pico/pico_int.h>
+
+/* graphics buffer management in VRAM:
+ * -   VRAM_FB0, VRAM_FB1      frame buffers
+ * -   VRAM_DEPTH              Z buffer (unused)
+ * -   VRAM_BUF0, VRAM_BUF1    emulator render buffers
+ * Emulator screen output is using the MD screen resolutions and is rendered
+ * to VRAM_BUFx and subsequently projected (that is, scaled and blitted) into
+ * the associated frame buffer (in PSP output resolution). Additional emulator
+ * output is then directly rendered to that frame buffer.
+ * The emulator menu is rendered directly into the frame buffers, using the
+ * native PSP resolution.
+ * Menu background uses native resolution and is copied and shaded from a frame
+ * buffer, or read in from a file if no emulator screen output is present.
+ */
+
+/* System level intialization */
+int plat_target_init(void)
+{
+       psp_init();
+
+       /* buffer resolutions */
+       g_menuscreen_w = 480, g_menuscreen_h  = 272, g_menuscreen_pp = 512;
+       g_screen_width = 328, g_screen_height = 256, g_screen_ppitch = 512;
+       g_menubg_src_w = 480, g_menubg_src_h  = 272, g_menubg_src_pp = 512;
+
+       /* buffer settings for menu display on startup */
+       g_screen_ptr = VRAM_CACHED_STUFF + (psp_screen - VRAM_FB0);
+       g_menuscreen_ptr = psp_screen;
+       g_menubg_ptr = malloc(512*272*2);
+
+       return 0;
+}
+
+/* System level deinitialization */
+void plat_target_finish(void)
+{
+       psp_finish();
+}
+
+/* display a completed frame buffer and prepare a new render buffer */
+void plat_video_flip(void)
+{
+       g_menubg_src_ptr = psp_screen;
+       psp_video_flip(currentConfig.EmuOpt & EOPT_VSYNC);
+       g_screen_ptr = VRAM_CACHED_STUFF + (psp_screen - VRAM_FB0);
+       plat_video_set_buffer(g_screen_ptr);
+}
+
+/* wait for start of vertical blanking */
+void plat_video_wait_vsync(void)
+{
+       sceDisplayWaitVblankStart();
+}
+
+/* switch from emulation display to menu display */
+void plat_video_menu_enter(int is_rom_loaded)
+{
+}
+
+/* start rendering a menu screen */
+void plat_video_menu_begin(void)
+{
+       g_menuscreen_ptr = psp_screen;
+}
+
+/* display a completed menu screen */
+void plat_video_menu_end(void)
+{
+       plat_video_wait_vsync();
+       plat_video_flip();
+}
+
+/* terminate menu display */
+void plat_video_menu_leave(void)
+{
+}
+
+/* Preliminary initialization needed at program start */
+void plat_early_init(void)
+{
+}
+
+/* base directory for configuration and save files */
+int plat_get_root_dir(char *dst, int len)
+{
+       if (len > 0) *dst = 0;
+       return 0;
+}
+
+/* base directory for emulator resources */
+int plat_get_skin_dir(char *dst, int len)
+{
+       if (len > 0) *dst = 0;
+       return 0;
+}
+
+/* check if path is a directory */
+int plat_is_dir(const char *path)
+{
+       SceIoStat st;
+       int ret = sceIoGetstat(path, &st);
+       return (ret >= 0 && (st.st_mode & FIO_S_IFDIR));
+}
+
+/* current time in ms */
+unsigned int plat_get_ticks_ms(void)
+{
+       /* approximate /= 1000 */
+       unsigned long long v64;
+       v64 = (unsigned long long)plat_get_ticks_us() * 4294968;
+       return v64 >> 32;
+}
+
+/* current time in us */
+unsigned int plat_get_ticks_us(void)
+{
+       return sceKernelGetSystemTimeLow();
+}
+
+/* sleep for some time in ms */
+void plat_sleep_ms(int ms)
+{
+       psp_msleep(ms);
+}
+
+/* sleep for some time in us */
+void plat_wait_till_us(unsigned int us_to)
+{
+       unsigned int tval;
+       int diff;
+
+       tval = sceKernelGetSystemTimeLow();
+       diff = (int)us_to - (int)tval;
+       if (diff >= 512 && diff < 100*1024)
+               sceKernelDelayThread(diff);
+}
+
+/* wait until some event occurs, or timeout */
+int plat_wait_event(int *fds_hnds, int count, int timeout_ms)
+{
+       return 0;       // unused
+}
+
+/* memory mapping functions */
+void *plat_mmap(unsigned long addr, size_t size, int need_exec, int is_fixed)
+{
+       return malloc(size);
+}
+
+void *plat_mremap(void *ptr, size_t oldsize, size_t newsize)
+{
+       return realloc(ptr, newsize);
+}
+
+void plat_munmap(void *ptr, size_t size)
+{
+       free(ptr);
+}
+
+void *plat_mem_get_for_drc(size_t size)
+{
+       return NULL;
+}
+
+int plat_mem_set_exec(void *ptr, size_t size)
+{
+       return 0;
+}
+
+/* get current CPU clock */
+static int plat_cpu_clock_get(void)
+{
+       return scePowerGetCpuClockFrequencyInt();
+}
+
+/* set CPU clock */
+static int plat_cpu_clock_set(int clock)
+{
+       if (clock < 33) clock = 33;
+       if (clock > 333) clock = 333;
+
+       return scePowerSetClockFrequency(clock, clock, clock/2);
+}
+
+/* get battery state in percent */
+static int plat_bat_capacity_get(void)
+{
+       return scePowerGetBatteryLifePercent();
+}
+
+struct plat_target plat_target = {
+       .cpu_clock_get = plat_cpu_clock_get,
+       .cpu_clock_set = plat_cpu_clock_set,
+       .bat_capacity_get = plat_bat_capacity_get,
+//     .gamma_set = plat_gamma_set,
+//     .hwfilter_set = plat_hwfilter_set,
+//     .hwfilters = plat_hwfilters,
+};
+
+
+/* replacement libc stuff */
+
+int alphasort(const struct dirent **a, const struct dirent **b)
+{
+       return strcoll ((*a)->d_name, (*b)->d_name);
+}
+
+int scandir(const char *dir, struct dirent ***namelist_out,
+               int(*filter)(const struct dirent *),
+               int(*compar)(const struct dirent **, const struct dirent **))
+{
+       int ret = -1, dir_uid = -1, name_alloc = 4, name_count = 0;
+       struct dirent **namelist = NULL, *ent;
+       SceIoDirent sce_ent;
+
+       namelist = malloc(sizeof(*namelist) * name_alloc);
+       if (namelist == NULL) { lprintf("%s:%i: OOM\n", __FILE__, __LINE__); goto fail; }
+
+       // try to read first..
+       dir_uid = sceIoDopen(dir);
+       if (dir_uid >= 0)
+       {
+               /* it is very important to clear SceIoDirent to be passed to sceIoDread(), */
+               /* or else it may crash, probably misinterpreting something in it. */
+               memset(&sce_ent, 0, sizeof(sce_ent));
+               ret = sceIoDread(dir_uid, &sce_ent);
+               if (ret < 0)
+               {
+                       lprintf("sceIoDread(\"%s\") failed with %i\n", dir, ret);
+                       goto fail;
+               }
+       }
+       else
+               lprintf("sceIoDopen(\"%s\") failed with %i\n", dir, dir_uid);
+
+       while (ret > 0)
+       {
+               ent = malloc(sizeof(*ent));
+               if (ent == NULL) { lprintf("%s:%i: OOM\n", __FILE__, __LINE__); goto fail; }
+       ent->d_stat = sce_ent.d_stat;
+       ent->d_stat.st_attr &= FIO_SO_IFMT; // serves as d_type
+               strncpy(ent->d_name, sce_ent.d_name, sizeof(ent->d_name));
+               ent->d_name[sizeof(ent->d_name)-1] = 0;
+               if (filter == NULL || filter(ent))
+                    namelist[name_count++] = ent;
+               else free(ent);
+
+               if (name_count >= name_alloc)
+               {
+                       void *tmp;
+                       name_alloc *= 2;
+                       tmp = realloc(namelist, sizeof(*namelist) * name_alloc);
+                       if (tmp == NULL) { lprintf("%s:%i: OOM\n", __FILE__, __LINE__); goto fail; }
+                       namelist = tmp;
+               }
+
+               memset(&sce_ent, 0, sizeof(sce_ent));
+               ret = sceIoDread(dir_uid, &sce_ent);
+       }
+
+       // sort
+       if (compar != NULL && name_count > 3)
+               qsort(&namelist[2], name_count - 2, sizeof(namelist[0]), (int (*)()) compar);
+
+       // all done.
+       ret = name_count;
+       *namelist_out = namelist;
+       goto end;
+
+fail:
+       if (namelist != NULL)
+       {
+               while (name_count--)
+                       free(namelist[name_count]);
+               free(namelist);
+       }
+end:
+       if (dir_uid >= 0) sceIoDclose(dir_uid);
+       return ret;
+}
+
+int _flush_cache (char *addr, const int size, const int op)
+{
+       sceKernelDcacheWritebackRange(addr, size);
+       sceKernelIcacheInvalidateRange(addr, size);
+       return 0;
+}
index a5bfe3a..3273ad3 100644 (file)
 
 #include "psp.h"
 #include "emu.h"
+
 #include <pico/pico_int.h>
+#include "../common/emu.h"
 #include "../common/version.h"
 
-extern int pico_main(void);
+extern int pico_main(int argc, char *argv[]);
 
 #ifndef FW15
 
-PSP_MODULE_INFO("PicoDrive", 0, 1, 51);
+PSP_MODULE_INFO("PicoDrive", 0, 1, 97);
 PSP_HEAP_SIZE_MAX();
 
-int main() { return pico_main(); }     /* just a wrapper */
+int main(int argc, char *argv[]) { return pico_main(argc, argv); }     /* just a wrapper */
 
 #else
 
-PSP_MODULE_INFO("PicoDrive", 0x1000, 1, 51);
+PSP_MODULE_INFO("PicoDrive", 0x1000, 1, 97);
 PSP_MAIN_THREAD_ATTR(0);
 
-int main()
+int main(int argc, char *argv[])
 {
        SceUID thid;
 
@@ -47,7 +49,7 @@ int main()
 
        thid = sceKernelCreateThread("pico_main", (SceKernelThreadEntry) pico_main, 32, 0x2000, PSP_THREAD_ATTR_USER, NULL);
        if (thid >= 0)
-               sceKernelStartThread(thid, 0, 0);
+               sceKernelStartThread(thid, argc, argv);
 #ifndef GCOV
        sceKernelExitDeleteThread(0);
 #else
@@ -133,7 +135,7 @@ void psp_init(void)
        lprintf("\n%s\n", "PicoDrive v" VERSION " " __DATE__ " " __TIME__);
        lprintf("running on %08x kernel\n", sceKernelDevkitVersion()),
        lprintf("entered psp_init, threadId %08x, priority %i\n", main_thread_id,
-               sceKernelGetThreadCurrentPriority());
+       sceKernelGetThreadCurrentPriority());
 
        thid = sceKernelCreateThread("update_thread", callback_thread, 0x11, 0xFA0, 0, NULL);
        if (thid >= 0)
@@ -153,8 +155,8 @@ void psp_init(void)
        sceGuStart(GU_DIRECT, guCmdList);
        sceGuDrawBuffer(GU_PSM_5650, (void *)VRAMOFFS_FB0, 512);
        sceGuDispBuffer(480, 272, (void *)VRAMOFFS_FB1, 512); // don't care
-       sceGuClear(GU_COLOR_BUFFER_BIT | GU_DEPTH_BUFFER_BIT);
        sceGuDepthBuffer((void *)VRAMOFFS_DEPTH, 512);
+       sceGuClear(GU_COLOR_BUFFER_BIT | GU_DEPTH_BUFFER_BIT);
        sceGuOffset(2048 - (480 / 2), 2048 - (272 / 2));
        sceGuViewport(2048, 2048, 480, 272);
        sceGuDepthRange(0xc350, 0x2710);
@@ -226,11 +228,11 @@ unsigned int psp_pad_read(int blocking)
        buttons = pad.Buttons;
 
        // analog..
-       buttons &= ~(PBTN_NUB_UP|PBTN_NUB_DOWN|PBTN_NUB_LEFT|PBTN_NUB_RIGHT);
-       if (pad.Lx < 128 - ANALOG_DEADZONE) buttons |= PBTN_NUB_LEFT;
-       if (pad.Lx > 128 + ANALOG_DEADZONE) buttons |= PBTN_NUB_RIGHT;
-       if (pad.Ly < 128 - ANALOG_DEADZONE) buttons |= PBTN_NUB_UP;
-       if (pad.Ly > 128 + ANALOG_DEADZONE) buttons |= PBTN_NUB_DOWN;
+       buttons &= ~(PSP_NUB_UP|PSP_NUB_DOWN|PSP_NUB_LEFT|PSP_NUB_RIGHT);
+       if (pad.Lx < 128 - ANALOG_DEADZONE) buttons |= PSP_NUB_LEFT;
+       if (pad.Lx > 128 + ANALOG_DEADZONE) buttons |= PSP_NUB_RIGHT;
+       if (pad.Ly < 128 - ANALOG_DEADZONE) buttons |= PSP_NUB_UP;
+       if (pad.Ly > 128 + ANALOG_DEADZONE) buttons |= PSP_NUB_DOWN;
 
        return buttons;
 }
index 7067f05..f33971c 100644 (file)
@@ -50,24 +50,9 @@ char *psp_get_status_line(void);
 void psp_wait_suspend(void);
 void psp_resume_suspend(void);
 
-/* shorter btn names */
-#define PBTN_UP       PSP_CTRL_UP
-#define PBTN_LEFT     PSP_CTRL_LEFT
-#define PBTN_RIGHT    PSP_CTRL_RIGHT
-#define PBTN_DOWN     PSP_CTRL_DOWN
-#define PBTN_L        PSP_CTRL_LTRIGGER
-#define PBTN_R        PSP_CTRL_RTRIGGER
-#define PBTN_TRIANGLE PSP_CTRL_TRIANGLE
-#define PBTN_CIRCLE   PSP_CTRL_CIRCLE
-#define PBTN_X        PSP_CTRL_CROSS
-#define PBTN_SQUARE   PSP_CTRL_SQUARE
-#define PBTN_SELECT   PSP_CTRL_SELECT
-#define PBTN_START    PSP_CTRL_START
-#define PBTN_NOTE     PSP_CTRL_NOTE // doesn't seem to work?
-
-/* fake 'nub' btns */
-#define PBTN_NUB_UP    (1 << 28)
-#define PBTN_NUB_RIGHT (1 << 29)
-#define PBTN_NUB_DOWN  (1 << 30)
-#define PBTN_NUB_LEFT  (1 << 31)
+/* fake 'nub' btns, mapped to the 4 unused upper bits of ctrl buttons */
+#define PSP_NUB_UP    (1 << 28)
+#define PSP_NUB_RIGHT (1 << 29)
+#define PSP_NUB_DOWN  (1 << 30)
+#define PSP_NUB_LEFT  (1 << 31)