drc: arm64 wip
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / new_dynarec.c
index 987892f..1383b2f 100644 (file)
@@ -57,6 +57,9 @@ static int sceBlock;
 #ifdef __arm__
 #include "assem_arm.h"
 #endif
+#ifdef __aarch64__
+#include "assem_arm64.h"
+#endif
 
 #define MAXBLOCK 4096
 #define MAX_OUTPUT_BLOCK_SIZE 262144
@@ -195,8 +198,14 @@ struct link_entry
 
   int new_dynarec_hacks;
   int new_dynarec_did_compile;
+
+  extern int cycle_count; // ... until end of the timeslice, counts -N -> 0
+  extern int last_count;  // last absolute target, often = next_interupt
+  extern int pcaddr;
+  extern int pending_exception;
+  extern int branch_target;
+  extern u_int mini_ht[32][2];
   extern u_char restore_candidate[512];
-  extern int cycle_count;
 
   /* registers that may be allocated */
   /* 1-31 gpr */
@@ -296,6 +305,9 @@ static void add_stub_r(enum stub_type type, void *addr, void *retaddr,
   int i, int addr_reg, struct regstat *i_regs, int ccadj, u_int reglist);
 static void add_to_linker(void *addr, u_int target, int ext);
 static void *emit_fastpath_cmp_jump(int i,int addr,int *addr_reg_override);
+static void *get_direct_memhandler(void *table, u_int addr,
+  enum stub_type type, uintptr_t *addr_host);
+static void pass_args(int a0, int a1);
 
 static void mprotect_w_x(void *start, void *end, int is_x)
 {
@@ -338,6 +350,8 @@ static void end_tcache_write(void *start, void *end)
   __clear_cache(start, end);
   #endif
   (void)len;
+#else
+  __clear_cache(start, end);
 #endif
 
   mprotect_w_x(start, end, 1);
@@ -834,6 +848,9 @@ static const char *func_name(intptr_t a)
 #ifdef __arm__
 #include "assem_arm.c"
 #endif
+#ifdef __aarch64__
+#include "assem_arm64.c"
+#endif
 
 // Add virtual address mapping to linked list
 void ll_add(struct ll_entry **head,int vaddr,void *addr)
@@ -962,7 +979,7 @@ static void ll_kill_pointers(struct ll_entry *head,uintptr_t addr,int shift)
     {
       inv_debug("EXP: Kill pointer at %p (%x)\n",head->addr,head->vaddr);
       void *host_addr=find_extjump_insn(head->addr);
-      #ifdef __arm__
+      #if defined(__arm__) || defined(__aarch64__)
         mark_clear_cache(host_addr);
       #endif
       set_jump_target(host_addr, head->addr);
@@ -990,7 +1007,7 @@ void invalidate_page(u_int page)
   while(head!=NULL) {
     inv_debug("INVALIDATE: kill pointer to %x (%p)\n",head->vaddr,head->addr);
     void *host_addr=find_extjump_insn(head->addr);
-    #ifdef __arm__
+    #if defined(__arm__) || defined(__aarch64__)
       mark_clear_cache(host_addr);
     #endif
     set_jump_target(host_addr, head->addr);
@@ -1015,7 +1032,7 @@ static void invalidate_block_range(u_int block, u_int first, u_int last)
   for(first=page+1;first<last;first++) {
     invalidate_page(first);
   }
-  #ifdef __arm__
+  #if defined(__arm__) || defined(__aarch64__)
     do_clear_cache();
   #endif
 
@@ -1995,7 +2012,24 @@ void rlist()
   printf("\n");
 }
 
-void alu_assemble(int i,struct regstat *i_regs)
+// trashes r2
+static void pass_args(int a0, int a1)
+{
+  if(a0==1&&a1==0) {
+    // must swap
+    emit_mov(a0,2); emit_mov(a1,1); emit_mov(2,0);
+  }
+  else if(a0!=0&&a1==0) {
+    emit_mov(a1,1);
+    if (a0>=0) emit_mov(a0,0);
+  }
+  else {
+    if(a0>=0&&a0!=0) emit_mov(a0,0);
+    if(a1>=0&&a1!=1) emit_mov(a1,1);
+  }
+}
+
+static void alu_assemble(int i,struct regstat *i_regs)
 {
   if(opcode2[i]>=0x20&&opcode2[i]<=0x23) { // ADD/ADDU/SUB/SUBU
     if(rt1[i]) {
@@ -2463,6 +2497,34 @@ static void *emit_fastpath_cmp_jump(int i,int addr,int *addr_reg_override)
   return jaddr;
 }
 
+// return memhandler, or get directly accessable address and return 0
+static void *get_direct_memhandler(void *table, u_int addr,
+  enum stub_type type, uintptr_t *addr_host)
+{
+  uintptr_t l1, l2 = 0;
+  l1 = ((uintptr_t *)table)[addr>>12];
+  if ((l1 & (1ul << (sizeof(l1)*8-1))) == 0) {
+    uintptr_t v = l1 << 1;
+    *addr_host = v + addr;
+    return NULL;
+  }
+  else {
+    l1 <<= 1;
+    if (type == LOADB_STUB || type == LOADBU_STUB || type == STOREB_STUB)
+      l2 = ((uintptr_t *)l1)[0x1000/4 + 0x1000/2 + (addr&0xfff)];
+    else if (type == LOADH_STUB || type == LOADHU_STUB || type == STOREH_STUB)
+      l2=((uintptr_t *)l1)[0x1000/4 + (addr&0xfff)/2];
+    else
+      l2=((uintptr_t *)l1)[(addr&0xfff)/4];
+    if ((l2 & (1<<31)) == 0) {
+      uintptr_t v = l2 << 1;
+      *addr_host = v + (addr&0xfff);
+      return NULL;
+    }
+    return (void *)(l2 << 1);
+  }
+}
+
 static void load_assemble(int i,struct regstat *i_regs)
 {
   int s,th,tl,addr;
@@ -3112,7 +3174,7 @@ static void cop2_put_dreg(u_int copr,signed char sl,signed char temp)
     case 30:
       emit_movs(sl,temp);
       emit_mvnmi(temp,temp);
-#ifdef HAVE_ARMV5
+#if defined(HAVE_ARMV5) || defined(__aarch64__)
       emit_clz(temp,temp);
 #else
       emit_movs(temp,HOST_TEMPREG);
@@ -4193,7 +4255,7 @@ void do_cc(int i,signed char i_regmap[],int *adj,int addr,int taken,int invert)
 static void do_ccstub(int n)
 {
   literal_pool(256);
-  assem_debug("do_ccstub %x\n",start+stubs[n].b*4);
+  assem_debug("do_ccstub %lx\n",start+stubs[n].b*4);
   set_jump_target(stubs[n].addr, out);
   int i=stubs[n].b;
   if(stubs[n].d==NULLDS) {
@@ -6183,25 +6245,39 @@ static void disassemble_inst(int i) {}
 
 #define DRC_TEST_VAL 0x74657374
 
-static int new_dynarec_test(void)
+static void new_dynarec_test(void)
 {
-  int (*testfunc)(void) = (void *)out;
+  int (*testfunc)(void);
   void *beginning;
-  int ret;
+  int ret[2];
+  size_t i;
 
-  beginning = start_block();
-  emit_movimm(DRC_TEST_VAL,0); // test
-  emit_jmpreg(14);
-  literal_pool(0);
-  end_block(beginning);
-  SysPrintf("testing if we can run recompiled code..\n");
-  ret = testfunc();
-  if (ret == DRC_TEST_VAL)
+  // check structure linkage
+  if ((void *)reg != (void *)&psxRegs
+      || (u_char *)rcnts - (u_char *)reg != sizeof(psxRegs))
+  {
+    SysPrintf("linkage_arm miscompilation/breakage detected.\n");
+  }
+
+  SysPrintf("testing if we can run recompiled code...\n");
+  ((volatile u_int *)out)[0]++; // make cache dirty
+
+  for (i = 0; i < ARRAY_SIZE(ret); i++) {
+    out = translation_cache;
+    beginning = start_block();
+    emit_movimm(DRC_TEST_VAL + i, 0); // test
+    emit_ret();
+    literal_pool(0);
+    end_block(beginning);
+    testfunc = beginning;
+    ret[i] = testfunc();
+  }
+
+  if (ret[0] == DRC_TEST_VAL && ret[1] == DRC_TEST_VAL + 1)
     SysPrintf("test passed.\n");
   else
-    SysPrintf("test failed: %08x\n", ret);
+    SysPrintf("test failed, will likely crash soon (r=%08x %08x)\n", ret[0], ret[1]);
   out = translation_cache;
-  return ret == DRC_TEST_VAL;
 }
 
 // clear the state completely, instead of just marking
@@ -6645,7 +6721,7 @@ int new_recompile_block(int addr)
 #endif
       case 0x12: strcpy(insn[i],"COP2"); type=NI;
         op2=(source[i]>>21)&0x1f;
-        //if (op2 & 0x10) {
+        //if (op2 & 0x10)
         if (source[i]&0x3f) { // use this hack to support old savestates with patched gte insns
           if (gte_handlers[source[i]&0x3f]!=NULL) {
             if (gte_regnames[source[i]&0x3f]!=NULL)
@@ -8893,7 +8969,7 @@ int new_recompile_block(int addr)
         break;
       case 3:
         // Clear jump_out
-        #ifdef __arm__
+        #if defined(__arm__) || defined(__aarch64__)
         if((expirep&2047)==0)
           do_clear_cache();
         #endif