(ctr/3ds) optimize build, add support for 32x/svp dynamic recompilers.
[picodrive.git] / platform / libretro / libretro.c
index 057cd52..8bd6363 100644 (file)
 #include <libkern/OSCacheControl.h>
 #endif
 
+#ifdef _3DS
+#include "3ds/3ds_utils.h"
+#define MEMOP_PROT   6
+int svcDuplicateHandle(unsigned int* out, unsigned int original);
+int svcCloseHandle(unsigned int handle);
+int svcControlProcessMemory(unsigned int process, void* addr0, void* addr1,
+                            unsigned int size, unsigned int type, unsigned int perm);
+#define MEMOP_MAP     4
+#define MEMOP_UNMAP   5
+
+static int ctr_svchack_successful = 0;
+#endif
+
 #include <pico/pico_int.h>
 #include <pico/state.h>
 #include "../common/input_pico.h"
@@ -67,8 +80,10 @@ void cache_flush_d_inval_i(void *start, void *end)
        size_t len = (char *)end - (char *)start;
        sys_dcache_flush(start, len);
        sys_icache_invalidate(start, len);
+#elif defined(_3DS)
+   ctr_flush_invalidate_cache();
 #else
-       __clear_cache(start, end);
+   __clear_cache(start, end);
 #endif
 #endif
 }
@@ -190,7 +205,7 @@ void munmap(void *base_addr, size_t len)
 
 int mprotect(void *addr, size_t len, int prot)
 {
-   /* stub - not really needed at this point since this codepath has no dynarecs */
+   /* stub - not really needed at this point since this codepath has no dynarecs */   
    return 0;
 }
 
@@ -200,6 +215,134 @@ int mprotect(void *addr, size_t len, int prot)
 #define MAP_ANONYMOUS MAP_ANON
 #endif
 
+#ifdef _3DS
+typedef struct
+{
+   unsigned int requested_map;
+   void* buffer;
+}pico_mmap_t;
+
+pico_mmap_t pico_mmaps[] = {
+   {0x02000000, 0},
+   {0x06000000, 0},
+   {NULL,       0}
+};
+
+void *plat_mmap(unsigned long addr, size_t size, int need_exec, int is_fixed)
+{
+   (void)is_fixed;
+
+   if (ctr_svchack_successful)
+   {
+      pico_mmap_t* pico_mmap;
+
+      for (pico_mmap = pico_mmaps; pico_mmap->requested_map; pico_mmap++)
+      {
+         if ((pico_mmap->requested_map == addr))
+         {
+            unsigned int ptr_aligned, tmp;
+            unsigned int currentHandle;
+            unsigned int perm = 0b011;
+
+            if (need_exec)
+               perm = 0b111;
+
+            size = (size + 0xFFF) & ~0xFFF;
+            pico_mmap->buffer = malloc(size + 0x1000);
+            ptr_aligned = (((unsigned int)pico_mmap->buffer) + 0xFFF) & ~0xFFF;
+
+            svcDuplicateHandle(&currentHandle, 0xFFFF8001);
+
+            if(svcControlProcessMemory(currentHandle, pico_mmap->requested_map, ptr_aligned, size, MEMOP_MAP, perm) < 0)
+            {
+               if (log_cb)
+                  log_cb(RETRO_LOG_ERROR, "could not map memory @0x%08X\n", pico_mmap->requested_map);
+               exit(1);
+            }
+
+            svcCloseHandle(currentHandle);
+            return (void*)pico_mmap->requested_map;
+         }
+      }
+   }
+
+   return malloc(size);
+}
+
+void *plat_mremap(void *ptr, size_t oldsize, size_t newsize)
+{
+   if (ctr_svchack_successful)
+   {
+      pico_mmap_t* pico_mmap;
+
+      for (pico_mmap = pico_mmaps; pico_mmap->requested_map; pico_mmap++)
+      {
+         if ((pico_mmap->requested_map == (unsigned int)ptr))
+         {
+            unsigned int ptr_aligned;
+            unsigned int currentHandle;
+            void* tmp;
+
+            oldsize = (oldsize + 0xFFF) & ~0xFFF;
+            newsize = (newsize + 0xFFF) & ~0xFFF;
+            ptr_aligned = (((unsigned int)pico_mmap->buffer) + 0xFFF) & ~0xFFF;
+
+            svcDuplicateHandle(&currentHandle, 0xFFFF8001);
+
+            svcControlProcessMemory(currentHandle, pico_mmap->requested_map, ptr_aligned, oldsize, MEMOP_UNMAP, 0b011);
+
+            tmp = realloc(pico_mmap->buffer, newsize + 0x1000);
+            if(!tmp)
+               return NULL;
+
+            pico_mmap->buffer = tmp;
+            ptr_aligned = (((unsigned int)pico_mmap->buffer) + 0xFFF) & ~0xFFF;
+
+            svcControlProcessMemory(currentHandle, pico_mmap->requested_map, ptr_aligned, newsize, MEMOP_MAP, 0x3);
+
+            svcCloseHandle(currentHandle);
+
+            return ptr;
+         }
+      }
+   }
+
+   return realloc(ptr, newsize);
+
+}
+void plat_munmap(void *ptr, size_t size)
+{
+   if (ctr_svchack_successful)
+   {
+      pico_mmap_t* pico_mmap;
+
+      for (pico_mmap = pico_mmaps; pico_mmap->requested_map; pico_mmap++)
+      {
+         if ((pico_mmap->requested_map == (unsigned int)ptr))
+         {
+            unsigned int ptr_aligned;
+            unsigned int currentHandle;
+
+            size = (size + 0xFFF) & ~0xFFF;
+            ptr_aligned = (((unsigned int)pico_mmap->buffer) + 0xFFF) & ~0xFFF;
+
+            svcDuplicateHandle(&currentHandle, 0xFFFF8001);
+
+            svcControlProcessMemory(currentHandle, (void*)pico_mmap->requested_map, (void*)ptr_aligned, size, MEMOP_UNMAP, 0b011);
+
+            svcCloseHandle(currentHandle);
+
+            free(pico_mmap->buffer);
+            pico_mmap->buffer = NULL;
+            return;
+         }
+      }
+   }
+
+   free(ptr);
+}
+
+#else
 void *plat_mmap(unsigned long addr, size_t size, int need_exec, int is_fixed)
 {
    int flags = MAP_PRIVATE | MAP_ANONYMOUS;
@@ -265,6 +408,7 @@ void plat_munmap(void *ptr, size_t size)
        if (ptr != NULL)
                munmap(ptr, size);
 }
+#endif
 
 int plat_mem_set_exec(void *ptr, size_t size)
 {
@@ -272,6 +416,26 @@ int plat_mem_set_exec(void *ptr, size_t size)
    int ret = VirtualProtect(ptr,size,PAGE_EXECUTE_READWRITE,0);
    if (ret == 0 && log_cb)
       log_cb(RETRO_LOG_ERROR, "mprotect(%p, %zd) failed: %d\n", ptr, size, 0);
+#elif defined(_3DS)
+   int ret = -1;
+   if (ctr_svchack_successful)
+   {
+      unsigned int currentHandle;
+      svcDuplicateHandle(&currentHandle, 0xFFFF8001);
+      ret = svcControlProcessMemory(currentHandle, ptr, 0x0,
+                              size, MEMOP_PROT, 0b111);
+      svcCloseHandle(currentHandle);
+      ctr_flush_invalidate_cache();
+
+   }
+   else
+   {
+      if (log_cb)
+         log_cb(RETRO_LOG_ERROR, "plat_mem_set_exec called with no svcControlProcessMemory access\n");
+      exit(1);
+   }
+
+
 #else
    int ret = mprotect(ptr, size, PROT_READ | PROT_WRITE | PROT_EXEC);
    if (ret != 0 && log_cb)
@@ -302,7 +466,8 @@ void lprintf(const char *fmt, ...)
    vsprintf(buffer, fmt, ap);
    /* TODO - add 'level' param for warning/error messages? */
    if (log_cb)
-      log_cb(RETRO_LOG_INFO, "%s\n", fmt);
+      log_cb(RETRO_LOG_INFO, "%s\n", fmt, ap);
+   va_end(ap);
 }
 
 /* libretro */
@@ -314,6 +479,7 @@ void retro_set_environment(retro_environment_t cb)
                { "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" },
+               { "picodrive_region", "Region; Auto|Japan NTSC|Japan PAL|US|Europe" },
 #ifdef DRC_SH2
                { "picodrive_drc", "Dynamic recompilers; enabled|disabled" },
 #endif
@@ -358,7 +524,7 @@ void retro_get_system_av_info(struct retro_system_av_info *info)
        info->geometry.base_height  = vout_height;
        info->geometry.max_width    = VOUT_MAX_WIDTH;
        info->geometry.max_height   = VOUT_MAX_HEIGHT;
-       info->geometry.aspect_ratio = 0.0f;
+       info->geometry.aspect_ratio = 4.0f / 3.0f;
 }
 
 /* savestates */
@@ -975,6 +1141,21 @@ static void update_variables(void)
                        PicoOpt &= ~POPT_EN_MCD_RAMCART;
        }
 
+       var.value = NULL;
+       var.key = "picodrive_region";
+       if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) {
+               if (strcmp(var.value, "Auto") == 0)
+                       PicoRegionOverride = 0;
+               else if (strcmp(var.value, "Japan NTSC") == 0)
+                       PicoRegionOverride = 1;
+               else if (strcmp(var.value, "Japan PAL") == 0)
+                       PicoRegionOverride = 2;
+               else if (strcmp(var.value, "US") == 0)
+                       PicoRegionOverride = 4;
+               else if (strcmp(var.value, "Europe") == 0)
+                       PicoRegionOverride = 8;
+       }
+
 #ifdef DRC_SH2
        var.value = NULL;
        var.key = "picodrive_drc";
@@ -985,6 +1166,10 @@ static void update_variables(void)
                        PicoOpt &= ~POPT_EN_DRC;
        }
 #endif
+#ifdef _3DS
+   if(!ctr_svchack_successful)
+      PicoOpt &= ~POPT_EN_DRC;
+#endif
 }
 
 void retro_run(void) 
@@ -995,7 +1180,7 @@ void retro_run(void)
        if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
                update_variables();
 
-       input_poll_cb();
+   input_poll_cb();
 
        PicoPad[0] = PicoPad[1] = 0;
        for (pad = 0; pad < 2; pad++)
@@ -1031,29 +1216,36 @@ void retro_init(void)
 
        environ_cb(RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE, &disk_control);
 
+#ifdef _3DS
+   ctr_svchack_successful = ctr_svchack_init();
+#endif
+
        PicoOpt = POPT_EN_STEREO|POPT_EN_FM|POPT_EN_PSG|POPT_EN_Z80
                | POPT_EN_MCD_PCM|POPT_EN_MCD_CDDA|POPT_EN_MCD_GFX
                | POPT_EN_32X|POPT_EN_PWM
                | POPT_ACC_SPRITES|POPT_DIS_32C_BORDER;
 #ifdef __arm__
-       PicoOpt |= POPT_EN_DRC;
+#ifdef _3DS
+   if (ctr_svchack_successful)
+#endif
+      PicoOpt |= POPT_EN_DRC;
 #endif
        PsndRate = 44100;
        PicoAutoRgnOrder = 0x184; // US, EU, JP
 
        vout_width = 320;
-       vout_height = 240;
-       vout_buf = malloc(VOUT_MAX_WIDTH * VOUT_MAX_HEIGHT * 2);
+   vout_height = 240;
+   vout_buf = malloc(VOUT_MAX_WIDTH * VOUT_MAX_HEIGHT * 2);
 
-       PicoInit();
-       PicoDrawSetOutFormat(PDF_RGB555, 0);
-       PicoDrawSetOutBuf(vout_buf, vout_width * 2);
+   PicoInit();
+   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();
+   update_variables();
 }
 
 void retro_deinit(void)