allow to disable SH2 dynarec on runtime
[picodrive.git] / platform / libretro.c
index ecf6a29..cc50307 100644 (file)
@@ -17,6 +17,7 @@
 #endif
 
 #include <pico/pico_int.h>
+#include <pico/state.h>
 #include "common/input_pico.h"
 #include "common/version.h"
 #include "libretro.h"
@@ -40,10 +41,6 @@ static int vout_width, vout_height;
 
 static short __attribute__((aligned(4))) sndBuffer[2*44100/50];
 
-// FIXME: these 2 shouldn't be here
-static unsigned char PicoDraw2FB_[(8+320) * (8+240+8)];
-unsigned char *PicoDraw2FB = PicoDraw2FB_;
-
 static void snd_write(int len);
 
 #ifdef _WIN32
@@ -151,7 +148,6 @@ void emu_video_mode_change(int start_line, int line_count, int is_32cols)
 
 void emu_32x_startup(void)
 {
-       PicoDrawSetOutFormat(PDF_RGB555, 1);
 }
 
 #ifndef ANDROID
@@ -187,6 +183,11 @@ void retro_set_environment(retro_environment_t cb)
 {
        static const struct retro_variable vars[] = {
                //{ "region", "Region; Auto|NTSC|PAL" },
+               { "picodrive_input1", "Input device 1; 3 button pad|6 button pad|None" },
+               { "picodrive_input2", "Input device 2; 3 button pad|6 button pad|None" },
+#ifdef DRC_SH2
+               { "picodrive_drc", "Dynamic recompilers; enabled|disabled" },
+#endif
                { NULL, NULL },
        };
 
@@ -231,20 +232,124 @@ void retro_get_system_av_info(struct retro_system_av_info *info)
        info->geometry.aspect_ratio = 4.0 / 3.0;
 }
 
-/* savestates - TODO */
+/* savestates */
+struct savestate_state {
+       const char *load_buf;
+       char *save_buf;
+       size_t size;
+       size_t pos;
+};
+
+size_t state_read(void *p, size_t size, size_t nmemb, void *file)
+{
+       struct savestate_state *state = file;
+       size_t bsize = size * nmemb;
+
+       if (state->pos + bsize > state->size) {
+               lprintf("savestate error: %u/%u\n",
+                       state->pos + bsize, state->size);
+               bsize = state->size - state->pos;
+               if ((int)bsize <= 0)
+                       return 0;
+       }
+
+       memcpy(p, state->load_buf + state->pos, bsize);
+       state->pos += bsize;
+       return bsize;
+}
+
+size_t state_write(void *p, size_t size, size_t nmemb, void *file)
+{
+       struct savestate_state *state = file;
+       size_t bsize = size * nmemb;
+
+       if (state->pos + bsize > state->size) {
+               lprintf("savestate error: %u/%u\n",
+                       state->pos + bsize, state->size);
+               bsize = state->size - state->pos;
+               if ((int)bsize <= 0)
+                       return 0;
+       }
+
+       memcpy(state->save_buf + state->pos, p, bsize);
+       state->pos += bsize;
+       return bsize;
+}
+
+size_t state_skip(void *p, size_t size, size_t nmemb, void *file)
+{
+       struct savestate_state *state = file;
+       size_t bsize = size * nmemb;
+
+       state->pos += bsize;
+       return bsize;
+}
+
+size_t state_eof(void *file)
+{
+       struct savestate_state *state = file;
+
+       return state->pos >= state->size;
+}
+
+int state_fseek(void *file, long offset, int whence)
+{
+       struct savestate_state *state = file;
+
+       switch (whence) {
+       case SEEK_SET:
+               state->pos = offset;
+               break;
+       case SEEK_CUR:
+               state->pos += offset;
+               break;
+       case SEEK_END:
+               state->pos = state->size + offset;
+               break;
+       }
+       return (int)state->pos;
+}
+
+/* savestate sizes vary wildly depending if cd/32x or
+ * carthw is active, so run the whole thing to get size */
 size_t retro_serialize_size(void) 
 { 
-       return 0;
+       struct savestate_state state = { 0, };
+       int ret;
+
+       ret = PicoStateFP(&state, 1, NULL, state_skip, NULL, state_fseek);
+       if (ret != 0)
+               return 0;
+
+       return state.pos;
 }
 
 bool retro_serialize(void *data, size_t size)
 { 
-       return false;
+       struct savestate_state state = { 0, };
+       int ret;
+
+       state.save_buf = data;
+       state.size = size;
+       state.pos = 0;
+
+       ret = PicoStateFP(&state, 1, NULL, state_write,
+               NULL, state_fseek);
+       return ret == 0;
 }
 
 bool retro_unserialize(const void *data, size_t size)
 {
-       return false;
+       struct savestate_state state = { 0, };
+       int ret;
+
+       state.load_buf = data;
+       state.size = size;
+       state.pos = 0;
+
+       ret = PicoStateFP(&state, 0, state_read, NULL,
+               state_eof, state_fseek);
+       return ret == 0;
 }
 
 /* cheats - TODO */
@@ -445,7 +550,7 @@ bool retro_load_game(const struct retro_game_info *info)
 
        enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_RGB565;
        if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt)) {
-               lprintf("RGB565 suppot required, sorry\n");
+               lprintf("RGB565 support required, sorry\n");
                return false;
        }
 
@@ -560,13 +665,52 @@ static void snd_write(int len)
        audio_batch_cb(PsndOut, len / 4);
 }
 
+static enum input_device input_name_to_val(const char *name)
+{
+       if (strcmp(name, "3 button pad") == 0)
+               return PICO_INPUT_PAD_3BTN;
+       if (strcmp(name, "6 button pad") == 0)
+               return PICO_INPUT_PAD_6BTN;
+       if (strcmp(name, "None") == 0)
+               return PICO_INPUT_NOTHING;
+
+       lprintf("invalid picodrive_input: '%s'\n", name);
+       return PICO_INPUT_PAD_3BTN;
+}
+
+static void update_variables(void)
+{
+       struct retro_variable var;
+
+       var.value = NULL;
+       var.key = "picodrive_input1";
+       if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+               PicoSetInputDevice(0, input_name_to_val(var.value));
+
+       var.value = NULL;
+       var.key = "picodrive_input2";
+       if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+               PicoSetInputDevice(1, input_name_to_val(var.value));
+
+#ifdef DRC_SH2
+       var.value = NULL;
+       var.key = "picodrive_drc";
+       if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) {
+               if (strcmp(var.value, "enabled") == 0)
+                       PicoOpt |= POPT_EN_DRC;
+               else
+                       PicoOpt &= ~POPT_EN_DRC;
+       }
+#endif
+}
+
 void retro_run(void) 
 {
        bool updated = false;
        int pad, i;
 
        if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
-               ; //update_variables(true);
+               update_variables();
 
        input_poll_cb();
 
@@ -614,12 +758,14 @@ void retro_init(void)
        vout_buf = malloc(VOUT_MAX_WIDTH * VOUT_MAX_HEIGHT * 2);
 
        PicoInit();
-       PicoDrawSetOutFormat(PDF_RGB555, 1);
+       PicoDrawSetOutFormat(PDF_RGB555, 0);
        PicoDrawSetOutBuf(vout_buf, vout_width * 2);
 
        //PicoMessage = plat_status_msg_busy_next;
        PicoMCDopenTray = disk_tray_open;
        PicoMCDcloseTray = disk_tray_close;
+
+       update_variables();
 }
 
 void retro_deinit(void)