Merge https://github.com/notaz/pcsx_rearmed
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / new_dynarec.c
index bfe3961..dfa17a7 100644 (file)
 #include <assert.h>
 #include <errno.h>
 #include <sys/mman.h>
+#ifdef __MACH__
+#include <libkern/OSCacheControl.h>
+#endif
+#ifdef _3DS
+#include <3ds_utils.h>
+#endif
+#ifdef VITA
+#include <psp2/kernel/sysmem.h>
+static int sceBlock;
+int getVMBlock();
+#endif
 
-#include "emu_if.h" //emulator interface
+#include "new_dynarec_config.h"
+#include "backends/psx/emu_if.h" //emulator interface
 
 //#define DISASM
 //#define assem_debug printf
 #define inv_debug(...)
 
 #ifdef __i386__
-#include "assem_x86.h"
+#include "x86/assem_x86.h"
 #endif
 #ifdef __x86_64__
-#include "assem_x64.h"
+#include "x64/assem_x64.h"
 #endif
 #ifdef __arm__
-#include "assem_arm.h"
+#include "arm/assem_arm.h"
 #endif
 
-#ifdef __BLACKBERRY_QNX__
-#undef __clear_cache
-#define __clear_cache(start,end) msync(start, (size_t)((void*)end - (void*)start), MS_SYNC | MS_CACHE_ONLY | MS_INVALIDATE_ICACHE);
-#elif defined(__MACH__)
-#include <libkern/OSCacheControl.h>
-#define __clear_cache mach_clear_cache
-static void __clear_cache(void *start, void *end) {
-  size_t len = (char *)end - (char *)start;
-  sys_dcache_flush(start, len);
-  sys_icache_invalidate(start, len);
-}
+#ifdef VITA
+int _newlib_vm_size_user = 1 << TARGET_SIZE_2;
 #endif
 
 #define MAXBLOCK 4096
@@ -271,6 +274,66 @@ static void add_to_linker(int addr,int target,int ext);
 
 static int tracedebug=0;
 
+static void mprotect_w_x(void *start, void *end, int is_x)
+{
+#ifdef NO_WRITE_EXEC
+  #if defined(VITA)
+  // *Open* enables write on all memory that was
+  // allocated by sceKernelAllocMemBlockForVM()?
+  if (is_x)
+    sceKernelCloseVMDomain();
+  else
+    sceKernelOpenVMDomain();
+  #else
+  u_long mstart = (u_long)start & ~4095ul;
+  u_long mend = (u_long)end;
+  if (mprotect((void *)mstart, mend - mstart,
+               PROT_READ | (is_x ? PROT_EXEC : PROT_WRITE)) != 0)
+    SysPrintf("mprotect(%c) failed: %s\n", is_x ? 'x' : 'w', strerror(errno));
+  #endif
+#endif
+}
+
+static void start_tcache_write(void *start, void *end)
+{
+  mprotect_w_x(start, end, 0);
+}
+
+static void end_tcache_write(void *start, void *end)
+{
+#ifdef __arm__
+  size_t len = (char *)end - (char *)start;
+  #if   defined(__BLACKBERRY_QNX__)
+  msync(start, len, MS_SYNC | MS_CACHE_ONLY | MS_INVALIDATE_ICACHE);
+  #elif defined(__MACH__)
+  sys_cache_control(kCacheFunctionPrepareForExecution, start, len);
+  #elif defined(VITA)
+  sceKernelSyncVMDomain(sceBlock, start, len);
+  #elif defined(_3DS)
+  ctr_flush_invalidate_cache();
+  #else
+  __clear_cache(start, end);
+  #endif
+  (void)len;
+#endif
+
+  mprotect_w_x(start, end, 1);
+}
+
+static void *start_block(void)
+{
+  u_char *end = out + MAX_OUTPUT_BLOCK_SIZE;
+  if (end > (u_char *)BASE_ADDR + (1<<TARGET_SIZE_2))
+    end = (u_char *)BASE_ADDR + (1<<TARGET_SIZE_2);
+  start_tcache_write(out, end);
+  return out;
+}
+
+static void end_block(void *start)
+{
+  end_tcache_write(start, out);
+}
+
 //#define DEBUG_CYCLE_COUNT 1
 
 #define NO_CYCLE_PENALTY_THR 12
@@ -303,14 +366,16 @@ static u_int get_vpage(u_int vaddr)
 // This is called from the recompiled JR/JALR instructions
 void *get_addr(u_int vaddr)
 {
-  u_int page=get_page(vaddr);
-  u_int vpage=get_vpage(vaddr);
-  struct ll_entry *head;
+  struct ll_entry *head = NULL;
+  u_int page            = get_page(vaddr);
+  u_int vpage           = get_vpage(vaddr);
   //printf("TRACE: count=%d next=%d (get_addr %x,page %d)\n",Count,next_interupt,vaddr,page);
   head=jump_in[page];
-  while(head!=NULL) {
-    if(head->vaddr==vaddr) {
-  //printf("TRACE: count=%d next=%d (get_addr match %x: %x)\n",Count,next_interupt,vaddr,(int)head->addr);
+  while(head!=NULL)
+  {
+    if(head->vaddr==vaddr)
+    {
+      //printf("TRACE: count=%d next=%d (get_addr match %x: %x)\n",Count,next_interupt,vaddr,(int)head->addr);
       u_int *ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF];
       ht_bin[3]=ht_bin[1];
       ht_bin[2]=ht_bin[0];
@@ -321,39 +386,47 @@ void *get_addr(u_int vaddr)
     head=head->next;
   }
   head=jump_dirty[vpage];
-  while(head!=NULL) {
-    if(head->vaddr==vaddr) {
+  while(head!=NULL)
+  {
+    if(head->vaddr==vaddr)
+    {
       //printf("TRACE: count=%d next=%d (get_addr match dirty %x: %x)\n",Count,next_interupt,vaddr,(int)head->addr);
       // Don't restore blocks which are about to expire from the cache
       if((((u_int)head->addr-(u_int)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2)))
-      if(verify_dirty(head->addr)) {
-        //printf("restore candidate: %x (%d) d=%d\n",vaddr,page,invalid_code[vaddr>>12]);
-        invalid_code[vaddr>>12]=0;
-        inv_code_start=inv_code_end=~0;
-        if(vpage<2048) {
-          restore_candidate[vpage>>3]|=1<<(vpage&7);
-        }
-        else restore_candidate[page>>3]|=1<<(page&7);
-        u_int *ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF];
-        if(ht_bin[0]==vaddr) {
-          ht_bin[1]=(u_int)head->addr; // Replace existing entry
-        }
-        else
+        if(verify_dirty(head->addr))
         {
-          ht_bin[3]=ht_bin[1];
-          ht_bin[2]=ht_bin[0];
-          ht_bin[1]=(int)head->addr;
-          ht_bin[0]=vaddr;
+          //printf("restore candidate: %x (%d) d=%d\n",vaddr,page,invalid_code[vaddr>>12]);
+          invalid_code[vaddr>>12]=0;
+          inv_code_start=inv_code_end=~0;
+          if(vpage<2048)
+          {
+            restore_candidate[vpage>>3]|=1<<(vpage&7);
+          }
+          else
+          {
+            restore_candidate[page>>3]|=1<<(page&7);
+          }
+          u_int *ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF];
+
+          if(ht_bin[0]==vaddr)
+            ht_bin[1]=(u_int)head->addr; // Replace existing entry
+          else
+          {
+            ht_bin[3]=ht_bin[1];
+            ht_bin[2]=ht_bin[0];
+            ht_bin[1]=(int)head->addr;
+            ht_bin[0]=vaddr;
+          }
+          return head->addr;
         }
-        return head->addr;
-      }
     }
     head=head->next;
   }
   //printf("TRACE: count=%d next=%d (get_addr no-match %x)\n",Count,next_interupt,vaddr);
   int r=new_recompile_block(vaddr);
-  if(r==0) return get_addr(vaddr);
-  // Execute in unmapped page, generate pagefault execption
+  if(r==0)
+    return get_addr(vaddr);
+  // Execute in unmapped page, generate pagefault exception
   Status|=2;
   Cause=(vaddr<<31)|0x8;
   EPC=(vaddr&1)?vaddr-5:vaddr;
@@ -362,6 +435,7 @@ void *get_addr(u_int vaddr)
   EntryHi=BadVAddr&0xFFFFE000;
   return get_addr_ht(0x80000000);
 }
+
 // Look up address in hash table first
 void *get_addr_ht(u_int vaddr)
 {
@@ -705,13 +779,13 @@ void alloc_all(struct regstat *cur,int i)
 }
 
 #ifdef __i386__
-#include "assem_x86.c"
+#include "x86/assem_x86.c"
 #endif
 #ifdef __x86_64__
-#include "assem_x64.c"
+#include "x64/assem_x64.c"
 #endif
 #ifdef __arm__
-#include "assem_arm.c"
+#include "arm/assem_arm.c"
 #endif
 
 // Add virtual address mapping to linked list
@@ -829,7 +903,7 @@ void ll_clear(struct ll_entry **head)
 }
 
 // Dereference the pointers and remove if it matches
-void ll_kill_pointers(struct ll_entry *head,int addr,int shift)
+static void ll_kill_pointers(struct ll_entry *head,int addr,int shift)
 {
   while(head) {
     int ptr=get_pointer(head->addr);
@@ -838,10 +912,11 @@ void ll_kill_pointers(struct ll_entry *head,int addr,int shift)
        (((ptr-MAX_OUTPUT_BLOCK_SIZE)>>shift)==(addr>>shift)))
     {
       inv_debug("EXP: Kill pointer at %x (%x)\n",(int)head->addr,head->vaddr);
-      u_int host_addr=(u_int)kill_pointer(head->addr);
+      void *host_addr=find_extjump_insn(head->addr);
       #ifdef __arm__
-        needs_clear_cache[(host_addr-(u_int)BASE_ADDR)>>17]|=1<<(((host_addr-(u_int)BASE_ADDR)>>12)&31);
+        mark_clear_cache(host_addr);
       #endif
+      set_jump_target((int)host_addr,(int)head->addr);
     }
     head=head->next;
   }
@@ -865,10 +940,11 @@ void invalidate_page(u_int page)
   jump_out[page]=0;
   while(head!=NULL) {
     inv_debug("INVALIDATE: kill pointer to %x (%x)\n",head->vaddr,(int)head->addr);
-    u_int host_addr=(u_int)kill_pointer(head->addr);
+    void *host_addr=find_extjump_insn(head->addr);
     #ifdef __arm__
-      needs_clear_cache[(host_addr-(u_int)BASE_ADDR)>>17]|=1<<(((host_addr-(u_int)BASE_ADDR)>>12)&31);
+      mark_clear_cache(host_addr);
     #endif
+    set_jump_target((int)host_addr,(int)head->addr);
     next=head->next;
     free(head);
     head=next;
@@ -883,23 +959,26 @@ static void invalidate_block_range(u_int block, u_int first, u_int last)
   assert(first+5>page); // NB: this assumes MAXBLOCK<=4096 (4 pages)
   assert(last<page+5);
   // Invalidate the adjacent pages if a block crosses a 4K boundary
-  while(first<page) {
+  while(first<page)
+  {
     invalidate_page(first);
     first++;
   }
-  for(first=page+1;first<last;first++) {
+  for(first=page+1;first<last;first++)
+  {
     invalidate_page(first);
   }
-  #ifdef __arm__
-    do_clear_cache();
-  #endif
+
+#ifdef __arm__
+  do_clear_cache();
+#endif
 
   // Don't trap writes
   invalid_code[block]=1;
 
-  #ifdef USE_MINI_HT
+#ifdef USE_MINI_HT
   memset(mini_ht,-1,sizeof(mini_ht));
-  #endif
+#endif
 }
 
 void invalidate_block(u_int block)
@@ -907,19 +986,22 @@ void invalidate_block(u_int block)
   u_int page=get_page(block<<12);
   u_int vpage=get_vpage(block<<12);
   inv_debug("INVALIDATE: %x (%d)\n",block<<12,page);
-  //inv_debug("invalid_code[block]=%d\n",invalid_code[block]);
   u_int first,last;
   first=last=page;
   struct ll_entry *head;
   head=jump_dirty[vpage];
   //printf("page=%d vpage=%d\n",page,vpage);
-  while(head!=NULL) {
+  while(head!=NULL)
+  {
     u_int start,end;
-    if(vpage>2047||(head->vaddr>>12)==block) { // Ignore vaddr hash collision
+    if(vpage>2047||(head->vaddr>>12)==block)
+    { // Ignore vaddr hash collision
       get_bounds((int)head->addr,&start,&end);
       //printf("start: %x end: %x\n",start,end);
-      if(page<2048&&start>=(u_int)rdram&&end<(u_int)rdram+RAM_SIZE) {
-        if(((start-(u_int)rdram)>>12)<=page&&((end-1-(u_int)rdram)>>12)>=page) {
+      if(page<2048&&start>=(u_int)rdram&&end<(u_int)rdram+RAM_SIZE)
+      {
+        if(((start-(u_int)rdram)>>12)<=page&&((end-1-(u_int)rdram)>>12)>=page)
+        {
           if((((start-(u_int)rdram)>>12)&2047)<first) first=((start-(u_int)rdram)>>12)&2047;
           if((((end-1-(u_int)rdram)>>12)&2047)>last) last=((end-1-(u_int)rdram)>>12)&2047;
         }
@@ -990,19 +1072,23 @@ void invalidate_addr(u_int addr)
 
 // This is called when loading a save state.
 // Anything could have changed, so invalidate everything.
-void invalidate_all_pages()
+void invalidate_all_pages(void)
 {
   u_int page;
   for(page=0;page<4096;page++)
     invalidate_page(page);
   for(page=0;page<1048576;page++)
-    if(!invalid_code[page]) {
+  {
+    if(!invalid_code[page])
+    {
       restore_candidate[(page&2047)>>3]|=1<<(page&7);
       restore_candidate[((page&2047)>>3)+256]|=1<<(page&7);
     }
-  #ifdef USE_MINI_HT
+  }
+
+#ifdef USE_MINI_HT
   memset(mini_ht,-1,sizeof(mini_ht));
-  #endif
+#endif
 }
 
 // Add an entry to jump_out after making a link
@@ -1027,37 +1113,48 @@ void clean_blocks(u_int page)
   struct ll_entry *head;
   inv_debug("INV: clean_blocks page=%d\n",page);
   head=jump_dirty[page];
-  while(head!=NULL) {
-    if(!invalid_code[head->vaddr>>12]) {
+  while(head!=NULL)
+  {
+    if(!invalid_code[head->vaddr>>12])
+    {
       // Don't restore blocks which are about to expire from the cache
-      if((((u_int)head->addr-(u_int)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2))) {
+      if((((u_int)head->addr-(u_int)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2)))
+      {
         u_int start,end;
-        if(verify_dirty(head->addr)) {
+        if(verify_dirty(head->addr))
+        {
           //printf("Possibly Restore %x (%x)\n",head->vaddr, (int)head->addr);
           u_int i;
           u_int inv=0;
           get_bounds((int)head->addr,&start,&end);
-          if(start-(u_int)rdram<RAM_SIZE) {
-            for(i=(start-(u_int)rdram+0x80000000)>>12;i<=(end-1-(u_int)rdram+0x80000000)>>12;i++) {
+          if(start-(u_int)rdram<RAM_SIZE)
+          {
+            for(i=(start-(u_int)rdram+0x80000000)>>12;i<=(end-1-(u_int)rdram+0x80000000)>>12;i++)
+            {
               inv|=invalid_code[i];
             }
           }
-          else if((signed int)head->vaddr>=(signed int)0x80000000+RAM_SIZE) {
+          else if((signed int)head->vaddr>=(signed int)0x80000000+RAM_SIZE)
+          {
             inv=1;
           }
-          if(!inv) {
+          if(!inv)
+          {
             void * clean_addr=(void *)get_clean_addr((int)head->addr);
-            if((((u_int)clean_addr-(u_int)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2))) {
+            if((((u_int)clean_addr-(u_int)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2)))
+            {
               u_int ppage=page;
               inv_debug("INV: Restored %x (%x/%x)\n",head->vaddr, (int)head->addr, (int)clean_addr);
               //printf("page=%x, addr=%x\n",page,head->vaddr);
               //assert(head->vaddr>>12==(page|0x80000));
               ll_add_flags(jump_in+ppage,head->vaddr,head->reg_sv_flags,clean_addr);
               u_int *ht_bin=hash_table[((head->vaddr>>16)^head->vaddr)&0xFFFF];
-              if(ht_bin[0]==head->vaddr) {
+              if(ht_bin[0]==head->vaddr)
+              {
                 ht_bin[1]=(u_int)clean_addr; // Replace existing entry
               }
-              if(ht_bin[2]==head->vaddr) {
+              if(ht_bin[2]==head->vaddr)
+              {
                 ht_bin[3]=(u_int)clean_addr; // Replace existing entry
               }
             }
@@ -1069,15 +1166,17 @@ void clean_blocks(u_int page)
   }
 }
 
-
-void mov_alloc(struct regstat *current,int i)
+static void mov_alloc(struct regstat *current,int i)
 {
   // Note: Don't need to actually alloc the source registers
-  if((~current->is32>>rs1[i])&1) {
+  if((~current->is32>>rs1[i])&1)
+  {
     //alloc_reg64(current,i,rs1[i]);
     alloc_reg64(current,i,rt1[i]);
     current->is32&=~(1LL<<rt1[i]);
-  } else {
+  }
+  else
+  {
     //alloc_reg(current,i,rs1[i]);
     alloc_reg(current,i,rt1[i]);
     current->is32|=(1LL<<rt1[i]);
@@ -1635,7 +1734,8 @@ void syscall_alloc(struct regstat *current,int i)
 
 void delayslot_alloc(struct regstat *current,int i)
 {
-  switch(itype[i]) {
+  switch(itype[i])
+  {
     case UJUMP:
     case CJUMP:
     case SJUMP:
@@ -1785,7 +1885,8 @@ void wb_register(signed char r,signed char regmap[],uint64_t dirty,uint64_t is32
   }
 }
 
-int mchecksum()
+#if 0
+static int mchecksum(void)
 {
   //if(!tracedebug) return 0;
   int i;
@@ -1798,7 +1899,8 @@ int mchecksum()
   }
   return sum;
 }
-int rchecksum()
+
+static int rchecksum(void)
 {
   int i;
   int sum=0;
@@ -1806,7 +1908,8 @@ int rchecksum()
     sum^=((u_int *)reg)[i];
   return sum;
 }
-void rlist()
+
+static void rlist(void)
 {
   int i;
   printf("TRACE: ");
@@ -1815,12 +1918,12 @@ void rlist()
   printf("\n");
 }
 
-void enabletrace()
+static void enabletrace(void)
 {
   tracedebug=1;
 }
 
-void memdebug(int i)
+static void memdebug(int i)
 {
   //printf("TRACE: count=%d next=%d (checksum %x) lo=%8x%8x\n",Count,next_interupt,mchecksum(),(int)(reg[LOREG]>>32),(int)reg[LOREG]);
   //printf("TRACE: count=%d next=%d (rchecksum %x)\n",Count,next_interupt,rchecksum());
@@ -1845,6 +1948,7 @@ void memdebug(int i)
   }
   //printf("TRACE: %x\n",(&i)[-1]);
 }
+#endif
 
 void alu_assemble(int i,struct regstat *i_regs)
 {
@@ -6936,13 +7040,14 @@ static void disassemble_inst(int i) {}
 static int new_dynarec_test(void)
 {
   int (*testfunc)(void) = (void *)out;
+  void *beginning;
   int ret;
+
+  beginning = start_block();
   emit_movimm(DRC_TEST_VAL,0); // test
   emit_jmpreg(14);
   literal_pool(0);
-#ifdef __arm__
-  __clear_cache((void *)testfunc, out);
-#endif
+  end_block(beginning);
   SysPrintf("testing if we can run recompiled code..\n");
   ret = testfunc();
   if (ret == DRC_TEST_VAL)
@@ -6955,7 +7060,7 @@ static int new_dynarec_test(void)
 
 // clear the state completely, instead of just marking
 // things invalid like invalidate_all_pages() does
-void new_dynarec_clear_full()
+void new_dynarec_clear_full(void)
 {
   int n;
   out=(u_char *)BASE_ADDR;
@@ -6976,22 +7081,54 @@ void new_dynarec_clear_full()
   for(n=0;n<4096;n++) ll_clear(jump_dirty+n);
 }
 
-void new_dynarec_init()
+void new_dynarec_init(void)
 {
   SysPrintf("Init new dynarec\n");
-  out=(u_char *)BASE_ADDR;
-#if BASE_ADDR_FIXED
-  if (mmap (out, 1<<TARGET_SIZE_2,
-            PROT_READ | PROT_WRITE | PROT_EXEC,
-            MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
-            -1, 0) <= 0) {
+
+  // allocate/prepare a buffer for translation cache
+  // see assem_arm.h for some explanation
+#if   defined(BASE_ADDR_FIXED)
+  if (mmap (translation_cache, 1 << TARGET_SIZE_2,
+        PROT_READ | PROT_WRITE | PROT_EXEC,
+        MAP_PRIVATE | MAP_ANONYMOUS,
+        -1, 0) != translation_cache)
+  {
     SysPrintf("mmap() failed: %s\n", strerror(errno));
+    SysPrintf("disable BASE_ADDR_FIXED and recompile\n");
+    abort();
+  }
+#elif defined(BASE_ADDR_DYNAMIC)
+#ifdef VITA
+  sceBlock = getVMBlock();//sceKernelAllocMemBlockForVM("code", 1 << TARGET_SIZE_2);
+  if (sceBlock < 0)
+    SysPrintf("sceKernelAllocMemBlockForVM failed\n");
+  int ret = sceKernelGetMemBlockBase(sceBlock, (void **)&translation_cache);
+  if (ret < 0)
+    SysPrintf("sceKernelGetMemBlockBase failed\n");
+    
+  sceKernelOpenVMDomain();
+  sceClibPrintf("translation_cache = 0x%08X \n ", translation_cache);
+#elif defined(_MSC_VER)
+  base_addr = VirtualAlloc(NULL, 1<<TARGET_SIZE_2, MEM_COMMIT | MEM_RESERVE,
+      PAGE_EXECUTE_READWRITE);
+#else
+  translation_cache = mmap (NULL, 1 << TARGET_SIZE_2,
+      PROT_READ | PROT_WRITE | PROT_EXEC,
+      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  if (translation_cache == MAP_FAILED) {
+    SysPrintf("mmap() failed: %s\n", strerror(errno));
+    abort();
   }
+#endif
 #else
+#ifndef NO_WRITE_EXEC
   // not all systems allow execute in data segment by default
-  if (mprotect(out, 1<<TARGET_SIZE_2, PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
+  if (mprotect((void *)BASE_ADDR, 1<<TARGET_SIZE_2, PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
     SysPrintf("mprotect() failed: %s\n", strerror(errno));
 #endif
+#endif
+
+  out=(u_char *)BASE_ADDR;
   cycle_multiplier=200;
   new_dynarec_clear_full();
 #ifdef HOST_IMM8
@@ -7007,18 +7144,28 @@ void new_dynarec_init()
     SysPrintf("warning: RAM is not directly mapped, performance will suffer\n");
 }
 
-void new_dynarec_cleanup()
+void new_dynarec_cleanup(void)
 {
   int n;
-  #if BASE_ADDR_FIXED
-  if (munmap ((void *)BASE_ADDR, 1<<TARGET_SIZE_2) < 0) {SysPrintf("munmap() failed\n");}
-  #endif
-  for(n=0;n<4096;n++) ll_clear(jump_in+n);
-  for(n=0;n<4096;n++) ll_clear(jump_out+n);
-  for(n=0;n<4096;n++) ll_clear(jump_dirty+n);
-  #ifdef ROM_COPY
+#if defined(BASE_ADDR_FIXED) || defined(BASE_ADDR_DYNAMIC)
+#ifndef VITA
+#if defined(_MSC_VER)
+  VirtualFree(base_addr, 0, MEM_RELEASE);
+#else
+  if (munmap ((void *)BASE_ADDR, 1<<TARGET_SIZE_2) < 0)
+    SysPrintf("munmap() failed\n");
+#endif
+#endif
+#endif
+  for(n=0;n<4096;n++)
+    ll_clear(jump_in+n);
+  for(n=0;n<4096;n++)
+    ll_clear(jump_out+n);
+  for(n=0;n<4096;n++)
+    ll_clear(jump_dirty+n);
+#ifdef ROM_COPY
   if (munmap (ROM_COPY, 67108864) < 0) {SysPrintf("munmap() failed\n");}
-  #endif
+#endif
 }
 
 static u_int *get_source_start(u_int addr, u_int *limit)
@@ -7172,16 +7319,15 @@ int new_recompile_block(int addr)
   if (Config.HLE && start == 0x80001000) // hlecall
   {
     // XXX: is this enough? Maybe check hleSoftCall?
-    u_int beginning=(u_int)out;
+    void *beginning=start_block();
     u_int page=get_page(start);
+
     invalid_code[start>>12]=0;
     emit_movimm(start,0);
     emit_writeword(0,(int)&pcaddr);
     emit_jmp((int)new_dyna_leave);
     literal_pool(0);
-#ifdef __arm__
-    __clear_cache((void *)beginning,out);
-#endif
+    end_block(beginning);
     ll_add_flags(jump_in+page,start,state_rflags,(void *)beginning);
     return 0;
   }
@@ -9883,7 +10029,7 @@ int new_recompile_block(int addr)
   cop1_usable=0;
   uint64_t is32_pre=0;
   u_int dirty_pre=0;
-  u_int beginning=(u_int)out;
+  void *beginning=start_block();
   if((u_int)addr&1) {
     ds=1;
     pagespan_ds();
@@ -10173,14 +10319,12 @@ int new_recompile_block(int addr)
   // Align code
   if(((u_int)out)&7) emit_addnop(13);
   #endif
-  assert((u_int)out-beginning<MAX_OUTPUT_BLOCK_SIZE);
+  assert((u_int)out-(u_int)beginning<MAX_OUTPUT_BLOCK_SIZE);
   //printf("shadow buffer: %x-%x\n",(int)copy,(int)copy+slen*4);
   memcpy(copy,source,slen*4);
   copy+=slen*4;
 
-  #ifdef __arm__
-  __clear_cache((void *)beginning,out);
-  #endif
+  end_block(beginning);
 
   // If we're within 256K of the end of the buffer,
   // start over from the beginning. (Is 256K enough?)