use actual mmap implementation on windows
[picodrive.git] / platform / libretro.c
index a6bc50f..a059157 100644 (file)
 #include <stdio.h>
 #include <stdarg.h>
 #include <string.h>
+#ifndef _WIN32
 #include <sys/mman.h>
+#else
+#include <io.h>
+#include <windows.h>
+#include <sys/types.h>
+#endif
 #include <errno.h>
 #ifdef __MACH__
 #include <libkern/OSCacheControl.h>
 #endif
 
 #include <pico/pico_int.h>
+#include <pico/state.h>
 #include "common/input_pico.h"
 #include "common/version.h"
 #include "libretro.h"
@@ -40,10 +47,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
@@ -69,27 +72,136 @@ void cache_flush_d_inval_i(void *start, void *end)
 #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;
+#ifdef _WIN32
+/* mmap() replacement for Windows
+ *
+ * Author: Mike Frysinger <vapier@gentoo.org>
+ * Placed into the public domain
+ */
 
-       req = (void *)addr;
-       ret = mmap(req, size, PROT_READ | PROT_WRITE, flags, -1, 0);
-       if (ret == MAP_FAILED) {
-               lprintf("mmap(%08lx, %zd) failed: %d\n", addr, size, errno);
-               return NULL;
-       }
+/* 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
+ */
 
-       if (addr != 0 && ret != (void *)addr) {
-               lprintf("warning: wanted to map @%08lx, got %p\n",
-                       addr, ret);
+#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
 
-               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
+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;
+      }
+   }
+#else
+   int flags = MAP_PRIVATE | MAP_ANONYMOUS;
+   void *req, *ret;
+
+   req = (void *)addr;
+   ret = mmap(req, size, PROT_READ | PROT_WRITE, flags, -1, 0);
+   if (ret == MAP_FAILED) {
+      lprintf("mmap(%08lx, %zd) failed: %d\n", addr, size, errno);
+      return NULL;
+   }
+
+   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;
+      }
+   }
+#endif
 
        return ret;
 }
@@ -135,10 +247,15 @@ void plat_munmap(void *ptr, size_t size)
 
 int plat_mem_set_exec(void *ptr, size_t size)
 {
-       int ret = mprotect(ptr, size, PROT_READ | PROT_WRITE | PROT_EXEC);
-       if (ret != 0)
-               lprintf("mprotect(%p, %zd) failed: %d\n", ptr, size, errno);
-
+#ifdef _WIN32
+   int ret = VirtualProtect(ptr,size,PAGE_EXECUTE_READWRITE,0);
+   if (ret == 0)
+      lprintf("mprotect(%p, %zd) failed: %d\n", ptr, size, 0);
+#else
+   int ret = mprotect(ptr, size, PROT_READ | PROT_WRITE | PROT_EXEC);
+   if (ret != 0)
+      lprintf("mprotect(%p, %zd) failed: %d\n", ptr, size, errno);
+#endif
        return ret;
 }
 
@@ -151,7 +268,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
@@ -231,20 +347,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 */
@@ -609,15 +829,12 @@ void retro_init(void)
        PicoAutoRgnOrder = 0x184; // US, EU, JP
        PicoCDBuffers = 0;
 
-       p32x_msh2_multiplier = MSH2_MULTI_DEFAULT;
-       p32x_ssh2_multiplier = SSH2_MULTI_DEFAULT;
-
        vout_width = 320;
        vout_height = 240;
        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;