Fix remaining bugs and fix indentation
[picodrive.git] / platform / libretro.c
index d246cad..23f0694 100644 (file)
@@ -13,7 +13,9 @@
 #ifndef _WIN32
 #include <sys/mman.h>
 #else
+#include <io.h>
 #include <windows.h>
+#include <sys/types.h>
 #endif
 #include <errno.h>
 #ifdef __MACH__
 #include "common/version.h"
 #include "libretro.h"
 
-#ifndef MAP_ANONYMOUS
-#define MAP_ANONYMOUS MAP_ANON
-#endif
-
 static retro_video_refresh_t video_cb;
 static retro_input_poll_t input_poll_cb;
 static retro_input_state_t input_state_cb;
@@ -41,7 +39,7 @@ static FILE *emu_log;
 #define VOUT_MAX_WIDTH 320
 #define VOUT_MAX_HEIGHT 240
 static void *vout_buf;
-static int vout_width, vout_height;
+static int vout_width, vout_height, vout_offset;
 
 static short __attribute__((aligned(4))) sndBuffer[2*44100/50];
 
@@ -71,54 +69,107 @@ void cache_flush_d_inval_i(void *start, void *end)
 }
 
 #ifdef _WIN32
-void* mmap(void *desired_addr,
-       size_t len, 
-       int mmap_prot, 
-       int mmap_flags, 
-       HANDLE fd,
-       size_t off)
-{
-    HANDLE fmh;
-       void *base_addr;
-       SECURITY_ATTRIBUTES sa;
-       sa.nLength = sizeof(sa);
-       sa.lpSecurityDescriptor = NULL;
-       sa.bInheritHandle = TRUE;
-       fmh = CreateFileMapping(fd, &sa, PAGE_WRITECOPY , 0, len, NULL);
-       if (fmh == NULL){ return NULL; }
-    base_addr = MapViewOfFileEx(fmh, FILE_MAP_WRITE|FILE_MAP_READ, 0, off, len, desired_addr);
-       CloseHandle(fmh);
-       return base_addr;
-}
-
-void munmap(
-       void *base_addr,
-       size_t len
-)
-{
-       UnmapViewOfFile(base_addr);
-}
-#define MAP_FAILED 0
-#define PROT_READ 0
-#define PROT_WRITE 0
-#define MAP_PRIVATE 0 
-#define MAP_ANONYMOUS 0 
+/* mmap() replacement for Windows
+ *
+ * Author: Mike Frysinger <vapier@gentoo.org>
+ * Placed into the public domain
+ */
+
+/* References:
+ * CreateFileMapping: http://msdn.microsoft.com/en-us/library/aa366537(VS.85).aspx
+ * CloseHandle:       http://msdn.microsoft.com/en-us/library/ms724211(VS.85).aspx
+ * MapViewOfFile:     http://msdn.microsoft.com/en-us/library/aa366761(VS.85).aspx
+ * UnmapViewOfFile:   http://msdn.microsoft.com/en-us/library/aa366882(VS.85).aspx
+ */
+
+#define PROT_READ     0x1
+#define PROT_WRITE    0x2
+/* This flag is only available in WinXP+ */
+#ifdef FILE_MAP_EXECUTE
+#define PROT_EXEC     0x4
+#else
+#define PROT_EXEC        0x0
+#define FILE_MAP_EXECUTE 0
 #endif
-void *plat_mmap(unsigned long addr, size_t size, int need_exec, int is_fixed)
-{
-#ifndef _WIN32
-   int flags = 0;
-   void *ret = mmap((void*)addr,size,PROT_READ | PROT_WRITE, flags, -1, 0);
-   if (addr != 0 && ret != (void *)addr) {
-      lprintf("warning: wanted to map @%08lx, got %p\n",
-            addr, ret);
 
-      if (is_fixed) {
-         munmap(ret, size);
-         return NULL;
-      }
-   }
+#define MAP_SHARED    0x01
+#define MAP_PRIVATE   0x02
+#define MAP_ANONYMOUS 0x20
+#define MAP_ANON      MAP_ANONYMOUS
+#define MAP_FAILED    ((void *) -1)
+
+#ifdef __USE_FILE_OFFSET64
+# define DWORD_HI(x) (x >> 32)
+# define DWORD_LO(x) ((x) & 0xffffffff)
 #else
+# define DWORD_HI(x) (0)
+# define DWORD_LO(x) (x)
+#endif
+
+static void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
+{
+       if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
+               return MAP_FAILED;
+       if (fd == -1) {
+               if (!(flags & MAP_ANON) || offset)
+                       return MAP_FAILED;
+       } else if (flags & MAP_ANON)
+               return MAP_FAILED;
+
+       DWORD flProtect;
+       if (prot & PROT_WRITE) {
+               if (prot & PROT_EXEC)
+                       flProtect = PAGE_EXECUTE_READWRITE;
+               else
+                       flProtect = PAGE_READWRITE;
+       } else if (prot & PROT_EXEC) {
+               if (prot & PROT_READ)
+                       flProtect = PAGE_EXECUTE_READ;
+               else if (prot & PROT_EXEC)
+                       flProtect = PAGE_EXECUTE;
+       } else
+               flProtect = PAGE_READONLY;
+
+       off_t end = length + offset;
+       HANDLE mmap_fd, h;
+       if (fd == -1)
+               mmap_fd = INVALID_HANDLE_VALUE;
+       else
+               mmap_fd = (HANDLE)_get_osfhandle(fd);
+       h = CreateFileMapping(mmap_fd, NULL, flProtect, DWORD_HI(end), DWORD_LO(end), NULL);
+       if (h == NULL)
+               return MAP_FAILED;
+
+       DWORD dwDesiredAccess;
+       if (prot & PROT_WRITE)
+               dwDesiredAccess = FILE_MAP_WRITE;
+       else
+               dwDesiredAccess = FILE_MAP_READ;
+       if (prot & PROT_EXEC)
+               dwDesiredAccess |= FILE_MAP_EXECUTE;
+       if (flags & MAP_PRIVATE)
+               dwDesiredAccess |= FILE_MAP_COPY;
+       void *ret = MapViewOfFile(h, dwDesiredAccess, DWORD_HI(offset), DWORD_LO(offset), length);
+       if (ret == NULL) {
+               CloseHandle(h);
+               ret = MAP_FAILED;
+       }
+       return ret;
+}
+
+static void munmap(void *addr, size_t length)
+{
+       UnmapViewOfFile(addr);
+       /* ruh-ro, we leaked handle from CreateFileMapping() ... */
+}
+#endif
+
+#ifndef MAP_ANONYMOUS
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+void *plat_mmap(unsigned long addr, size_t size, int need_exec, int is_fixed)
+{
    int flags = MAP_PRIVATE | MAP_ANONYMOUS;
    void *req, *ret;
 
@@ -138,7 +189,6 @@ void *plat_mmap(unsigned long addr, size_t size, int need_exec, int is_fixed)
          return NULL;
       }
    }
-#endif
 
        return ret;
 }
@@ -201,6 +251,9 @@ void emu_video_mode_change(int start_line, int line_count, int is_32cols)
        memset(vout_buf, 0, 320 * 240 * 2);
        vout_width = is_32cols ? 256 : 320;
        PicoDrawSetOutBuf(vout_buf, vout_width * 2);
+
+       vout_height = line_count;
+       vout_offset = vout_width * start_line;
 }
 
 void emu_32x_startup(void)
@@ -240,6 +293,13 @@ 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" },
+               { "picodrive_sprlim", "No sprite limit; disabled|enabled" },
+               { "picodrive_ramcart", "MegaCD RAM cart; disabled|enabled" },
+#ifdef DRC_SH2
+               { "picodrive_drc", "Dynamic recompilers; enabled|disabled" },
+#endif
                { NULL, NULL },
        };
 
@@ -278,10 +338,10 @@ void retro_get_system_av_info(struct retro_system_av_info *info)
        info->timing.fps            = Pico.m.pal ? 50 : 60;
        info->timing.sample_rate    = 44100;
        info->geometry.base_width   = 320;
-       info->geometry.base_height  = 240;
+       info->geometry.base_height  = vout_height;
        info->geometry.max_width    = VOUT_MAX_WIDTH;
        info->geometry.max_height   = VOUT_MAX_HEIGHT;
-       info->geometry.aspect_ratio = 4.0 / 3.0;
+       info->geometry.aspect_ratio = 0.0f;
 }
 
 /* savestates */
@@ -440,7 +500,7 @@ static unsigned int disk_get_image_index(void)
 
 static bool disk_set_image_index(unsigned int index)
 {
-       cd_img_type cd_type;
+       enum cd_img_type cd_type;
        int ret;
 
        if (index >= sizeof(disks) / sizeof(disks[0]))
@@ -461,7 +521,7 @@ static bool disk_set_image_index(unsigned int index)
        ret = -1;
        cd_type = PicoCdCheck(disks[index].fname, NULL);
        if (cd_type != CIT_NOT_CD)
-               ret = Insert_CD(disks[index].fname, cd_type);
+               ret = cdd_load(disks[index].fname, cd_type);
        if (ret != 0) {
                lprintf("Load failed, invalid CD image?\n");
                return 0;
@@ -530,13 +590,13 @@ static void disk_tray_close(void)
 
 
 static const char * const biosfiles_us[] = {
-       "us_scd1_9210", "us_scd2_9306", "SegaCDBIOS9303", "bios_CD_U"
+       "us_scd2_9306", "SegaCDBIOS9303", "us_scd1_9210", "bios_CD_U"
 };
 static const char * const biosfiles_eu[] = {
-       "eu_mcd1_9210", "eu_mcd2_9306", "eu_mcd2_9303", "bios_CD_E"
+       "eu_mcd2_9306", "eu_mcd2_9303", "eu_mcd1_9210", "bios_CD_E"
 };
 static const char * const biosfiles_jp[] = {
-       "jp_mcd1_9112", "jp_mcd1_9111", "bios_CD_J"
+       "jp_mcd2_921222", "jp_mcd1_9112", "jp_mcd1_9111", "bios_CD_J"
 };
 
 static void make_system_path(char *buf, size_t buf_size,
@@ -602,7 +662,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;
        }
 
@@ -649,7 +709,7 @@ bool retro_load_game(const struct retro_game_info *info)
        PicoWriteSound = snd_write;
        memset(sndBuffer, 0, sizeof(sndBuffer));
        PsndOut = sndBuffer;
-       PsndRerate(1);
+       PsndRerate(0);
 
        return true;
 }
@@ -681,14 +741,25 @@ void *retro_get_memory_data(unsigned id)
 
 size_t retro_get_memory_size(unsigned id)
 {
+       unsigned int i;
+       int sum;
+
        if (id != RETRO_MEMORY_SAVE_RAM)
                return 0;
 
        if (PicoAHW & PAHW_MCD)
                // bram
                return 0x2000;
-       else
+
+       if (Pico.m.frame_count == 0)
                return SRam.size;
+
+       // if game doesn't write to sram, don't report it to
+       // libretro so that RA doesn't write out zeroed .srm
+       for (i = 0, sum = 0; i < SRam.size; i++)
+               sum |= SRam.data[i];
+
+       return (sum != 0) ? SRam.size : 0;
 }
 
 void retro_reset(void)
@@ -717,13 +788,70 @@ 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));
+
+       var.value = NULL;
+       var.key = "picodrive_sprlim";
+       if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) {
+               if (strcmp(var.value, "enabled") == 0)
+                       PicoOpt |= POPT_DIS_SPRITE_LIM;
+               else
+                       PicoOpt &= ~POPT_DIS_SPRITE_LIM;
+       }
+
+       var.value = NULL;
+       var.key = "picodrive_ramcart";
+       if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) {
+               if (strcmp(var.value, "enabled") == 0)
+                       PicoOpt |= POPT_EN_MCD_RAMCART;
+               else
+                       PicoOpt &= ~POPT_EN_MCD_RAMCART;
+       }
+
+#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();
 
@@ -735,7 +863,8 @@ void retro_run(void)
 
        PicoFrame();
 
-       video_cb(vout_buf, vout_width, vout_height, vout_width * 2);
+       video_cb((short *)vout_buf + vout_offset,
+               vout_width, vout_height, vout_width * 2);
 }
 
 void retro_init(void)
@@ -760,11 +889,10 @@ void retro_init(void)
                | POPT_EN_32X|POPT_EN_PWM
                | POPT_ACC_SPRITES|POPT_DIS_32C_BORDER;
 #ifdef __arm__
-       PicoOpt |= POPT_EN_SVP_DRC;
+       PicoOpt |= POPT_EN_DRC;
 #endif
        PsndRate = 44100;
        PicoAutoRgnOrder = 0x184; // US, EU, JP
-       PicoCDBuffers = 0;
 
        vout_width = 320;
        vout_height = 240;
@@ -777,6 +905,8 @@ void retro_init(void)
        //PicoMessage = plat_status_msg_busy_next;
        PicoMCDopenTray = disk_tray_open;
        PicoMCDcloseTray = disk_tray_close;
+
+       update_variables();
 }
 
 void retro_deinit(void)