drc: something works on arm64
authornotaz <notasas@gmail.com>
Thu, 11 Nov 2021 00:32:02 +0000 (02:32 +0200)
committernotaz <notasas@gmail.com>
Sun, 14 Nov 2021 00:05:06 +0000 (02:05 +0200)
frontend/menu.c
libpcsxcore/gte.c
libpcsxcore/new_dynarec/assem_arm.c
libpcsxcore/new_dynarec/assem_arm64.c
libpcsxcore/new_dynarec/emu_if.c
libpcsxcore/new_dynarec/linkage_arm.S
libpcsxcore/new_dynarec/linkage_arm64.S
libpcsxcore/new_dynarec/new_dynarec.c
libpcsxcore/new_dynarec/patches/trace_drc_chk
libpcsxcore/psxinterpreter.c
libpcsxcore/psxinterpreter.h [new file with mode: 0644]

index 37956ff..0dbaa40 100644 (file)
@@ -1590,8 +1590,10 @@ static const char h_cfg_nodrc[]  = "Disable dynamic recompiler and use interpret
                                   "Might be useful to overcome some dynarec bugs";
 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
                                   "must reload game for any change to take effect";
                                   "Might be useful to overcome some dynarec bugs";
 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
                                   "must reload game for any change to take effect";
+#ifdef ICACHE_EMULATION
 static const char h_cfg_icache[] = "Allows you to play the F1 games.\n"
                                   "Note: This breaks the PAL version of Spyro 2.";
 static const char h_cfg_icache[] = "Allows you to play the F1 games.\n"
                                   "Note: This breaks the PAL version of Spyro 2.";
+#endif
                                   
 static menu_entry e_menu_adv_options[] =
 {
                                   
 static menu_entry e_menu_adv_options[] =
 {
index 97a4ccd..e05f33d 100644 (file)
@@ -322,9 +322,10 @@ static inline void MTC2(u32 value, int reg) {
 
                case 28:
                        gteIRGB = value;
 
                case 28:
                        gteIRGB = value;
-                       gteIR1 = (value & 0x1f) << 7;
-                       gteIR2 = (value & 0x3e0) << 2;
-                       gteIR3 = (value & 0x7c00) >> 3;
+                       // not gteIR1 etc. just to be consistent with dynarec
+                       regs->CP2D.n.ir1 = (value & 0x1f) << 7;
+                       regs->CP2D.n.ir2 = (value & 0x3e0) << 2;
+                       regs->CP2D.n.ir3 = (value & 0x7c00) >> 3;
                        break;
 
                case 30:
                        break;
 
                case 30:
index ed00103..c611456 100644 (file)
@@ -237,7 +237,7 @@ static void *get_clean_addr(void *addr)
   return ptr;
 }
 
   return ptr;
 }
 
-static int verify_dirty(u_int *ptr)
+static int verify_dirty(const u_int *ptr)
 {
   #ifndef HAVE_ARMV7
   u_int offset;
 {
   #ifndef HAVE_ARMV7
   u_int offset;
@@ -601,12 +601,6 @@ static void emit_not(int rs,int rt)
   output_w32(0xe1e00000|rd_rn_rm(rt,0,rs));
 }
 
   output_w32(0xe1e00000|rd_rn_rm(rt,0,rs));
 }
 
-static void emit_mvnmi(int rs,int rt)
-{
-  assem_debug("mvnmi %s,%s\n",regname[rt],regname[rs]);
-  output_w32(0x41e00000|rd_rn_rm(rt,0,rs));
-}
-
 static void emit_and(u_int rs1,u_int rs2,u_int rt)
 {
   assem_debug("and %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
 static void emit_and(u_int rs1,u_int rs2,u_int rt)
 {
   assem_debug("and %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
@@ -643,6 +637,12 @@ static void emit_xor(u_int rs1,u_int rs2,u_int rt)
   output_w32(0xe0200000|rd_rn_rm(rt,rs1,rs2));
 }
 
   output_w32(0xe0200000|rd_rn_rm(rt,rs1,rs2));
 }
 
+static void emit_xorsar_imm(u_int rs1,u_int rs2,u_int imm,u_int rt)
+{
+  assem_debug("eor %s,%s,%s,asr #%d\n",regname[rt],regname[rs1],regname[rs2],imm);
+  output_w32(0xe0200040|rd_rn_rm(rt,rs1,rs2)|(imm<<7));
+}
+
 static void emit_addimm(u_int rs,int imm,u_int rt)
 {
   assert(rs<16);
 static void emit_addimm(u_int rs,int imm,u_int rt)
 {
   assert(rs<16);
@@ -888,7 +888,7 @@ static void emit_sar(u_int rs,u_int shift,u_int rt)
   output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x50|(shift<<8));
 }
 
   output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x50|(shift<<8));
 }
 
-static void emit_orrshl(u_int rs,u_int shift,u_int rt)
+static unused void emit_orrshl(u_int rs,u_int shift,u_int rt)
 {
   assert(rs<16);
   assert(rt<16);
 {
   assert(rs<16);
   assert(rt<16);
@@ -897,7 +897,7 @@ static void emit_orrshl(u_int rs,u_int shift,u_int rt)
   output_w32(0xe1800000|rd_rn_rm(rt,rt,rs)|0x10|(shift<<8));
 }
 
   output_w32(0xe1800000|rd_rn_rm(rt,rt,rs)|0x10|(shift<<8));
 }
 
-static void emit_orrshr(u_int rs,u_int shift,u_int rt)
+static unused void emit_orrshr(u_int rs,u_int shift,u_int rt)
 {
   assert(rs<16);
   assert(rt<16);
 {
   assert(rs<16);
   assert(rt<16);
@@ -952,6 +952,14 @@ static void emit_cmovb_imm(int imm,int rt)
   output_w32(0x33a00000|rd_rn_rm(rt,0,0)|armval);
 }
 
   output_w32(0x33a00000|rd_rn_rm(rt,0,0)|armval);
 }
 
+static void emit_cmovae_imm(int imm,int rt)
+{
+  assem_debug("movcs %s,#%d\n",regname[rt],imm);
+  u_int armval;
+  genimm_checked(imm,&armval);
+  output_w32(0x23a00000|rd_rn_rm(rt,0,0)|armval);
+}
+
 static void emit_cmovne_reg(int rs,int rt)
 {
   assem_debug("movne %s,%s\n",regname[rt],regname[rs]);
 static void emit_cmovne_reg(int rs,int rt)
 {
   assem_debug("movne %s,%s\n",regname[rt],regname[rs]);
@@ -1114,7 +1122,7 @@ static void emit_jcc(const void *a_)
   output_w32(0x3a000000|offset);
 }
 
   output_w32(0x3a000000|offset);
 }
 
-static void emit_callreg(u_int r)
+static unused void emit_callreg(u_int r)
 {
   assert(r<15);
   assem_debug("blx %s\n",regname[r]);
 {
   assert(r<15);
   assem_debug("blx %s\n",regname[r]);
@@ -1379,7 +1387,7 @@ static void emit_teq(int rs, int rt)
   output_w32(0xe1300000|rd_rn_rm(0,rs,rt));
 }
 
   output_w32(0xe1300000|rd_rn_rm(0,rs,rt));
 }
 
-static void emit_rsbimm(int rs, int imm, int rt)
+static unused void emit_rsbimm(int rs, int imm, int rt)
 {
   u_int armval;
   genimm_checked(imm,&armval);
 {
   u_int armval;
   genimm_checked(imm,&armval);
@@ -1940,94 +1948,6 @@ static void inline_writestub(enum stub_type type, int i, u_int addr, signed char
   restore_regs(reglist);
 }
 
   restore_regs(reglist);
 }
 
-static void do_unalignedwritestub(int n)
-{
-  assem_debug("do_unalignedwritestub %x\n",start+stubs[n].a*4);
-  literal_pool(256);
-  set_jump_target(stubs[n].addr, out);
-
-  int i=stubs[n].a;
-  struct regstat *i_regs=(struct regstat *)stubs[n].c;
-  int addr=stubs[n].b;
-  u_int reglist=stubs[n].e;
-  signed char *i_regmap=i_regs->regmap;
-  int temp2=get_reg(i_regmap,FTEMP);
-  int rt;
-  rt=get_reg(i_regmap,rs2[i]);
-  assert(rt>=0);
-  assert(addr>=0);
-  assert(opcode[i]==0x2a||opcode[i]==0x2e); // SWL/SWR only implemented
-  reglist|=(1<<addr);
-  reglist&=~(1<<temp2);
-
-#if 1
-  // don't bother with it and call write handler
-  save_regs(reglist);
-  pass_args(addr,rt);
-  int cc=get_reg(i_regmap,CCREG);
-  if(cc<0)
-    emit_loadreg(CCREG,2);
-  emit_addimm(cc<0?2:cc,CLOCK_ADJUST((int)stubs[n].d+1),2);
-  emit_call((opcode[i]==0x2a?jump_handle_swl:jump_handle_swr));
-  emit_addimm(0,-CLOCK_ADJUST((int)stubs[n].d+1),cc<0?2:cc);
-  if(cc<0)
-    emit_storereg(CCREG,2);
-  restore_regs(reglist);
-  emit_jmp(stubs[n].retaddr); // return address
-#else
-  emit_andimm(addr,0xfffffffc,temp2);
-  emit_writeword(temp2,&address);
-
-  save_regs(reglist);
-  emit_shrimm(addr,16,1);
-  int cc=get_reg(i_regmap,CCREG);
-  if(cc<0) {
-    emit_loadreg(CCREG,2);
-  }
-  emit_movimm((u_int)readmem,0);
-  emit_addimm(cc<0?2:cc,2*stubs[n].d+2,2);
-  emit_call((int)&indirect_jump_indexed);
-  restore_regs(reglist);
-
-  emit_readword(&readmem_dword,temp2);
-  int temp=addr; //hmh
-  emit_shlimm(addr,3,temp);
-  emit_andimm(temp,24,temp);
-#ifdef BIG_ENDIAN_MIPS
-  if (opcode[i]==0x2e) // SWR
-#else
-  if (opcode[i]==0x2a) // SWL
-#endif
-    emit_xorimm(temp,24,temp);
-  emit_movimm(-1,HOST_TEMPREG);
-  if (opcode[i]==0x2a) { // SWL
-    emit_bic_lsr(temp2,HOST_TEMPREG,temp,temp2);
-    emit_orrshr(rt,temp,temp2);
-  }else{
-    emit_bic_lsl(temp2,HOST_TEMPREG,temp,temp2);
-    emit_orrshl(rt,temp,temp2);
-  }
-  emit_readword(&address,addr);
-  emit_writeword(temp2,&word);
-  //save_regs(reglist); // don't need to, no state changes
-  emit_shrimm(addr,16,1);
-  emit_movimm((u_int)writemem,0);
-  //emit_call((int)&indirect_jump_indexed);
-  emit_mov(15,14);
-  emit_readword_dualindexedx4(0,1,15);
-  emit_readword(&Count,HOST_TEMPREG);
-  emit_readword(&next_interupt,2);
-  emit_addimm(HOST_TEMPREG,-2*stubs[n].d-2,HOST_TEMPREG);
-  emit_writeword(2,&last_count);
-  emit_sub(HOST_TEMPREG,2,cc<0?HOST_TEMPREG:cc);
-  if(cc<0) {
-    emit_storereg(CCREG,HOST_TEMPREG);
-  }
-  restore_regs(reglist);
-  emit_jmp(stubs[n].retaddr); // return address
-#endif
-}
-
 // this output is parsed by verify_dirty, get_bounds, isclean, get_clean_addr
 static void do_dirty_stub_emit_args(u_int arg0)
 {
 // this output is parsed by verify_dirty, get_bounds, isclean, get_clean_addr
 static void do_dirty_stub_emit_args(u_int arg0)
 {
@@ -2066,208 +1986,12 @@ static void do_dirty_stub_ds()
 
 /* Special assem */
 
 
 /* Special assem */
 
-static void shift_assemble_arm(int i,struct regstat *i_regs)
-{
-  if(rt1[i]) {
-    if(opcode2[i]<=0x07) // SLLV/SRLV/SRAV
-    {
-      signed char s,t,shift;
-      t=get_reg(i_regs->regmap,rt1[i]);
-      s=get_reg(i_regs->regmap,rs1[i]);
-      shift=get_reg(i_regs->regmap,rs2[i]);
-      if(t>=0){
-        if(rs1[i]==0)
-        {
-          emit_zeroreg(t);
-        }
-        else if(rs2[i]==0)
-        {
-          assert(s>=0);
-          if(s!=t) emit_mov(s,t);
-        }
-        else
-        {
-          emit_andimm(shift,31,HOST_TEMPREG);
-          if(opcode2[i]==4) // SLLV
-          {
-            emit_shl(s,HOST_TEMPREG,t);
-          }
-          if(opcode2[i]==6) // SRLV
-          {
-            emit_shr(s,HOST_TEMPREG,t);
-          }
-          if(opcode2[i]==7) // SRAV
-          {
-            emit_sar(s,HOST_TEMPREG,t);
-          }
-        }
-      }
-    } else { // DSLLV/DSRLV/DSRAV
-      signed char sh,sl,th,tl,shift;
-      th=get_reg(i_regs->regmap,rt1[i]|64);
-      tl=get_reg(i_regs->regmap,rt1[i]);
-      sh=get_reg(i_regs->regmap,rs1[i]|64);
-      sl=get_reg(i_regs->regmap,rs1[i]);
-      shift=get_reg(i_regs->regmap,rs2[i]);
-      if(tl>=0){
-        if(rs1[i]==0)
-        {
-          emit_zeroreg(tl);
-          if(th>=0) emit_zeroreg(th);
-        }
-        else if(rs2[i]==0)
-        {
-          assert(sl>=0);
-          if(sl!=tl) emit_mov(sl,tl);
-          if(th>=0&&sh!=th) emit_mov(sh,th);
-        }
-        else
-        {
-          // FIXME: What if shift==tl ?
-          assert(shift!=tl);
-          int temp=get_reg(i_regs->regmap,-1);
-          int real_th=th;
-          if(th<0&&opcode2[i]!=0x14) {th=temp;} // DSLLV doesn't need a temporary register
-          assert(sl>=0);
-          assert(sh>=0);
-          emit_andimm(shift,31,HOST_TEMPREG);
-          if(opcode2[i]==0x14) // DSLLV
-          {
-            if(th>=0) emit_shl(sh,HOST_TEMPREG,th);
-            emit_rsbimm(HOST_TEMPREG,32,HOST_TEMPREG);
-            emit_orrshr(sl,HOST_TEMPREG,th);
-            emit_andimm(shift,31,HOST_TEMPREG);
-            emit_testimm(shift,32);
-            emit_shl(sl,HOST_TEMPREG,tl);
-            if(th>=0) emit_cmovne_reg(tl,th);
-            emit_cmovne_imm(0,tl);
-          }
-          if(opcode2[i]==0x16) // DSRLV
-          {
-            assert(th>=0);
-            emit_shr(sl,HOST_TEMPREG,tl);
-            emit_rsbimm(HOST_TEMPREG,32,HOST_TEMPREG);
-            emit_orrshl(sh,HOST_TEMPREG,tl);
-            emit_andimm(shift,31,HOST_TEMPREG);
-            emit_testimm(shift,32);
-            emit_shr(sh,HOST_TEMPREG,th);
-            emit_cmovne_reg(th,tl);
-            if(real_th>=0) emit_cmovne_imm(0,th);
-          }
-          if(opcode2[i]==0x17) // DSRAV
-          {
-            assert(th>=0);
-            emit_shr(sl,HOST_TEMPREG,tl);
-            emit_rsbimm(HOST_TEMPREG,32,HOST_TEMPREG);
-            if(real_th>=0) {
-              assert(temp>=0);
-              emit_sarimm(th,31,temp);
-            }
-            emit_orrshl(sh,HOST_TEMPREG,tl);
-            emit_andimm(shift,31,HOST_TEMPREG);
-            emit_testimm(shift,32);
-            emit_sar(sh,HOST_TEMPREG,th);
-            emit_cmovne_reg(th,tl);
-            if(real_th>=0) emit_cmovne_reg(temp,th);
-          }
-        }
-      }
-    }
-  }
-}
-#define shift_assemble shift_assemble_arm
-
-static void loadlr_assemble_arm(int i,struct regstat *i_regs)
-{
-  int s,tl,temp,temp2,addr;
-  int offset;
-  void *jaddr=0;
-  int memtarget=0,c=0;
-  int fastio_reg_override=-1;
-  u_int hr,reglist=0;
-  tl=get_reg(i_regs->regmap,rt1[i]);
-  s=get_reg(i_regs->regmap,rs1[i]);
-  temp=get_reg(i_regs->regmap,-1);
-  temp2=get_reg(i_regs->regmap,FTEMP);
-  addr=get_reg(i_regs->regmap,AGEN1+(i&1));
-  assert(addr<0);
-  offset=imm[i];
-  for(hr=0;hr<HOST_REGS;hr++) {
-    if(i_regs->regmap[hr]>=0) reglist|=1<<hr;
-  }
-  reglist|=1<<temp;
-  if(offset||s<0||c) addr=temp2;
-  else addr=s;
-  if(s>=0) {
-    c=(i_regs->wasconst>>s)&1;
-    if(c) {
-      memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80000000+RAM_SIZE;
-    }
-  }
-  if(!c) {
-    emit_shlimm(addr,3,temp);
-    if (opcode[i]==0x22||opcode[i]==0x26) {
-      emit_andimm(addr,0xFFFFFFFC,temp2); // LWL/LWR
-    }else{
-      emit_andimm(addr,0xFFFFFFF8,temp2); // LDL/LDR
-    }
-    jaddr=emit_fastpath_cmp_jump(i,temp2,&fastio_reg_override);
-  }
-  else {
-    if(ram_offset&&memtarget) {
-      host_tempreg_acquire();
-      emit_addimm(temp2,ram_offset,HOST_TEMPREG);
-      fastio_reg_override=HOST_TEMPREG;
-    }
-    if (opcode[i]==0x22||opcode[i]==0x26) {
-      emit_movimm(((constmap[i][s]+offset)<<3)&24,temp); // LWL/LWR
-    }else{
-      emit_movimm(((constmap[i][s]+offset)<<3)&56,temp); // LDL/LDR
-    }
-  }
-  if (opcode[i]==0x22||opcode[i]==0x26) { // LWL/LWR
-    if(!c||memtarget) {
-      int a=temp2;
-      if(fastio_reg_override>=0) a=fastio_reg_override;
-      emit_readword_indexed(0,a,temp2);
-      if(fastio_reg_override==HOST_TEMPREG) host_tempreg_release();
-      if(jaddr) add_stub_r(LOADW_STUB,jaddr,out,i,temp2,i_regs,ccadj[i],reglist);
-    }
-    else
-      inline_readstub(LOADW_STUB,i,(constmap[i][s]+offset)&0xFFFFFFFC,i_regs->regmap,FTEMP,ccadj[i],reglist);
-    if(rt1[i]) {
-      assert(tl>=0);
-      emit_andimm(temp,24,temp);
-#ifdef BIG_ENDIAN_MIPS
-      if (opcode[i]==0x26) // LWR
-#else
-      if (opcode[i]==0x22) // LWL
-#endif
-        emit_xorimm(temp,24,temp);
-      emit_movimm(-1,HOST_TEMPREG);
-      if (opcode[i]==0x26) {
-        emit_shr(temp2,temp,temp2);
-        emit_bic_lsr(tl,HOST_TEMPREG,temp,tl);
-      }else{
-        emit_shl(temp2,temp,temp2);
-        emit_bic_lsl(tl,HOST_TEMPREG,temp,tl);
-      }
-      emit_or(temp2,tl,tl);
-    }
-    //emit_storereg(rt1[i],tl); // DEBUG
-  }
-  if (opcode[i]==0x1A||opcode[i]==0x1B) { // LDL/LDR
-    assert(0);
-  }
-}
-#define loadlr_assemble loadlr_assemble_arm
-
 static void c2op_prologue(u_int op,u_int reglist)
 {
   save_regs_all(reglist);
 #ifdef PCNT
   emit_movimm(op,0);
 static void c2op_prologue(u_int op,u_int reglist)
 {
   save_regs_all(reglist);
 #ifdef PCNT
   emit_movimm(op,0);
-  emit_call((int)pcnt_gte_start);
+  emit_call(pcnt_gte_start);
 #endif
   emit_addimm(FP,(int)&psxRegs.CP2D.r[0]-(int)&dynarec_local,0); // cop2 regs
 }
 #endif
   emit_addimm(FP,(int)&psxRegs.CP2D.r[0]-(int)&dynarec_local,0); // cop2 regs
 }
@@ -2276,7 +2000,7 @@ static void c2op_epilogue(u_int op,u_int reglist)
 {
 #ifdef PCNT
   emit_movimm(op,0);
 {
 #ifdef PCNT
   emit_movimm(op,0);
-  emit_call((int)pcnt_gte_end);
+  emit_call(pcnt_gte_end);
 #endif
   restore_regs_all(reglist);
 }
 #endif
   restore_regs_all(reglist);
 }
@@ -2419,6 +2143,45 @@ static void c2op_assemble(int i,struct regstat *i_regs)
   }
 }
 
   }
 }
 
+static void c2op_ctc2_31_assemble(signed char sl, signed char temp)
+{
+  //value = value & 0x7ffff000;
+  //if (value & 0x7f87e000) value |= 0x80000000;
+  emit_shrimm(sl,12,temp);
+  emit_shlimm(temp,12,temp);
+  emit_testimm(temp,0x7f000000);
+  emit_testeqimm(temp,0x00870000);
+  emit_testeqimm(temp,0x0000e000);
+  emit_orrne_imm(temp,0x80000000,temp);
+}
+
+static void do_mfc2_31_one(u_int copr,signed char temp)
+{
+  emit_readword(&reg_cop2d[copr],temp);
+  emit_testimm(temp,0x8000); // do we need this?
+  emit_andne_imm(temp,0,temp);
+  emit_cmpimm(temp,0xf80);
+  emit_andimm(temp,0xf80,temp);
+  emit_cmovae_imm(0xf80,temp);
+}
+
+static void c2op_mfc2_29_assemble(signed char tl, signed char temp)
+{
+  if (temp < 0) {
+    host_tempreg_acquire();
+    temp = HOST_TEMPREG;
+  }
+  do_mfc2_31_one(9,temp);
+  emit_shrimm(temp,7,tl);
+  do_mfc2_31_one(10,temp);
+  emit_orrshr_imm(temp,2,tl);
+  do_mfc2_31_one(11,temp);
+  emit_orrshl_imm(temp,3,tl);
+  emit_writeword(tl,&reg_cop2d[29]);
+  if (temp == HOST_TEMPREG)
+    host_tempreg_release();
+}
+
 static void multdiv_assemble_arm(int i,struct regstat *i_regs)
 {
   //  case 0x18: MULT
 static void multdiv_assemble_arm(int i,struct regstat *i_regs)
 {
   //  case 0x18: MULT
index a0c628b..27f9141 100644 (file)
@@ -20,6 +20,7 @@
  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
+#include "pcnt.h"
 #include "arm_features.h"
 
 #if   defined(BASE_ADDR_FIXED)
 #include "arm_features.h"
 
 #if   defined(BASE_ADDR_FIXED)
@@ -43,25 +44,26 @@ static void set_jump_target(void *addr, void *target)
   u_int *ptr = addr;
   intptr_t offset = (u_char *)target - (u_char *)addr;
 
   u_int *ptr = addr;
   intptr_t offset = (u_char *)target - (u_char *)addr;
 
-  if((*ptr&0xFC000000)==0x14000000) {
+  if ((*ptr&0xFC000000) == 0x14000000) { // b
     assert(offset>=-134217728LL&&offset<134217728LL);
     *ptr=(*ptr&0xFC000000)|((offset>>2)&0x3ffffff);
   }
     assert(offset>=-134217728LL&&offset<134217728LL);
     *ptr=(*ptr&0xFC000000)|((offset>>2)&0x3ffffff);
   }
-  else if((*ptr&0xff000000)==0x54000000) {
+  else if ((*ptr&0xff000000) == 0x54000000 // b.cond
+        || (*ptr&0x7e000000) == 0x34000000) { // cbz/cbnz
     // Conditional branch are limited to +/- 1MB
     // block max size is 256k so branching beyond the +/- 1MB limit
     // should only happen when jumping to an already compiled block (see add_link)
     // a workaround would be to do a trampoline jump via a stub at the end of the block
     // Conditional branch are limited to +/- 1MB
     // block max size is 256k so branching beyond the +/- 1MB limit
     // should only happen when jumping to an already compiled block (see add_link)
     // a workaround would be to do a trampoline jump via a stub at the end of the block
-    assert(offset>=-1048576LL&&offset<1048576LL);
+    assert(-1048576 <= offset && offset < 1048576);
     *ptr=(*ptr&0xFF00000F)|(((offset>>2)&0x7ffff)<<5);
   }
     *ptr=(*ptr&0xFF00000F)|(((offset>>2)&0x7ffff)<<5);
   }
-  else if((*ptr&0x9f000000)==0x10000000) { //adr
+  else if((*ptr&0x9f000000)==0x10000000) { // adr
     // generated by do_miniht_insert
     assert(offset>=-1048576LL&&offset<1048576LL);
     *ptr=(*ptr&0x9F00001F)|(offset&0x3)<<29|((offset>>2)&0x7ffff)<<5;
   }
   else
     // generated by do_miniht_insert
     assert(offset>=-1048576LL&&offset<1048576LL);
     *ptr=(*ptr&0x9F00001F)|(offset&0x3)<<29|((offset>>2)&0x7ffff)<<5;
   }
   else
-    assert(0); // should not happen
+    abort(); // should not happen
 }
 
 // from a pointer to external jump stub (which was produced by emit_extjump2)
 }
 
 // from a pointer to external jump stub (which was produced by emit_extjump2)
@@ -75,62 +77,21 @@ static void *find_extjump_insn(void *stub)
 }
 
 // find where external branch is liked to using addr of it's stub:
 }
 
 // find where external branch is liked to using addr of it's stub:
-// get address that insn one after stub loads (dyna_linker arg1),
+// get address that the stub loads (dyna_linker arg1),
 // treat it as a pointer to branch insn,
 // return addr where that branch jumps to
 static void *get_pointer(void *stub)
 {
   int *i_ptr = find_extjump_insn(stub);
 // treat it as a pointer to branch insn,
 // return addr where that branch jumps to
 static void *get_pointer(void *stub)
 {
   int *i_ptr = find_extjump_insn(stub);
-  assert((*i_ptr&0xfc000000) == 0x14000000); // b
-  return (u_char *)i_ptr+(((signed int)(*i_ptr<<6)>>6)<<2);
-}
-
-// Find the "clean" entry point from a "dirty" entry point
-// by skipping past the call to verify_code
-static void *get_clean_addr(void *addr)
-{
+  if ((*i_ptr&0xfc000000) == 0x14000000)  // b
+    return i_ptr + ((signed int)(*i_ptr<<6)>>6);
+  if ((*i_ptr&0xff000000) == 0x54000000     // b.cond
+      || (*i_ptr&0x7e000000) == 0x34000000) // cbz/cbnz
+    return i_ptr + ((signed int)(*i_ptr<<8)>>13);
   assert(0);
   return NULL;
 }
 
   assert(0);
   return NULL;
 }
 
-static int verify_dirty(u_int *ptr)
-{
-  assert(0);
-  return 0;
-}
-
-static int isclean(void *addr)
-{
-  u_int *ptr = addr;
-  return (*ptr >> 24) != 0x58; // the only place ldr (literal) is used
-}
-
-static uint64_t get_from_ldr_literal(const u_int *i)
-{
-  signed int ofs;
-  assert((i[0] & 0xff000000) == 0x58000000);
-  ofs = i[0] << 8;
-  ofs >>= 5+8;
-  return *(uint64_t *)(i + ofs);
-}
-
-static uint64_t get_from_movz(const u_int *i)
-{
-  assert((i[0] & 0x7fe00000) == 0x52800000);
-  return (i[0] >> 5) & 0xffff;
-}
-
-// get source that block at addr was compiled from (host pointers)
-static void get_bounds(void *addr, u_char **start, u_char **end)
-{
-  const u_int *ptr = addr;
-  assert((ptr[0] & 0xff00001f) == 0x58000001); // ldr x1, source
-  assert((ptr[1] & 0xff00001f) == 0x58000002); // ldr x2, copy
-  assert((ptr[2] & 0xffe0001f) == 0x52800003); // movz w3, #slen*4
-  *start = (u_char *)get_from_ldr_literal(&ptr[0]);
-  *end = *start + get_from_movz(&ptr[2]);
-}
-
 // Allocate a specific ARM register.
 static void alloc_arm_reg(struct regstat *cur,int i,signed char reg,int hr)
 {
 // Allocate a specific ARM register.
 static void alloc_arm_reg(struct regstat *cur,int i,signed char reg,int hr)
 {
@@ -208,6 +169,13 @@ static u_int rm_rd(u_int rm, u_int rd)
 }
 */
 
 }
 */
 
+static u_int rn_rd(u_int rn, u_int rd)
+{
+  assert(rn < 31);
+  assert(rd < 31);
+  return (rn << 5) | rd;
+}
+
 static u_int rm_rn_rd(u_int rm, u_int rn, u_int rd)
 {
   assert(rm < 32);
 static u_int rm_rn_rd(u_int rm, u_int rn, u_int rd)
 {
   assert(rm < 32);
@@ -216,6 +184,12 @@ static u_int rm_rn_rd(u_int rm, u_int rn, u_int rd)
   return (rm << 16) | (rn << 5) | rd;
 }
 
   return (rm << 16) | (rn << 5) | rd;
 }
 
+static u_int rm_ra_rn_rd(u_int rm, u_int ra, u_int rn, u_int rd)
+{
+  assert(ra < 32);
+  return rm_rn_rd(rm, rn, rd) | (ra << 10);
+}
+
 static u_int imm7_rt2_rn_rt(u_int imm7, u_int rt2, u_int rn, u_int rt)
 {
   assert(imm7 < 0x80);
 static u_int imm7_rt2_rn_rt(u_int imm7, u_int rt2, u_int rn, u_int rt)
 {
   assert(imm7 < 0x80);
@@ -304,7 +278,7 @@ static uint32_t is_mask(u_int value)
 // non-empty sequence of ones (possibly rotated) with the remainder zero.
 static uint32_t is_rotated_mask(u_int value)
 {
 // non-empty sequence of ones (possibly rotated) with the remainder zero.
 static uint32_t is_rotated_mask(u_int value)
 {
-  if (value == 0)
+  if (value == 0 || value == ~0)
     return 0;
   if (is_mask((value - 1) | value))
     return 1;
     return 0;
   if (is_mask((value - 1) | value))
     return 1;
@@ -328,11 +302,11 @@ static void gen_logical_imm(u_int value, u_int *immr, u_int *imms)
     lzeros = __builtin_clz(value);
     tzeros = __builtin_ctz(value);
     ones = 32 - lzeros - tzeros;
     lzeros = __builtin_clz(value);
     tzeros = __builtin_ctz(value);
     ones = 32 - lzeros - tzeros;
-    *immr = 31 - tzeros;
+    *immr = lzeros;
     *imms = 31 - ones;
     return;
   }
     *imms = 31 - ones;
     return;
   }
-  assert(0);
+  abort();
 }
 
 static void emit_mov(u_int rs, u_int rt)
 }
 
 static void emit_mov(u_int rs, u_int rt)
@@ -347,13 +321,6 @@ static void emit_mov64(u_int rs, u_int rt)
   output_w32(0xaa000000 | rm_rn_rd(rs, WZR, rt));
 }
 
   output_w32(0xaa000000 | rm_rn_rd(rs, WZR, rt));
 }
 
-static void emit_movs(u_int rs, u_int rt)
-{
-  assert(0); // misleading
-  assem_debug("movs %s,%s\n", regname[rt], regname[rs]);
-  output_w32(0x31000000 | imm12_rn_rd(0, rs, rt));
-}
-
 static void emit_add(u_int rs1, u_int rs2, u_int rt)
 {
   assem_debug("add %s,%s,%s\n", regname[rt], regname[rs1], regname[rs2]);
 static void emit_add(u_int rs1, u_int rs2, u_int rt)
 {
   assem_debug("add %s,%s,%s\n", regname[rt], regname[rs1], regname[rs2]);
@@ -366,16 +333,9 @@ static void emit_add64(u_int rs1, u_int rs2, u_int rt)
   output_w32(0x8b000000 | rm_rn_rd(rs2, rs1, rt));
 }
 
   output_w32(0x8b000000 | rm_rn_rd(rs2, rs1, rt));
 }
 
-#pragma GCC diagnostic ignored "-Wunused-function"
-static void emit_adds(u_int rs1, u_int rs2, u_int rt)
-{
-  assem_debug("adds %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
-  output_w32(0x2b000000 | rm_rn_rd(rs2, rs1, rt));
-}
-
 static void emit_adds64(u_int rs1, u_int rs2, u_int rt)
 {
 static void emit_adds64(u_int rs1, u_int rs2, u_int rt)
 {
-  assem_debug("adds %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
+  assem_debug("adds %s,%s,%s\n",regname64[rt],regname64[rs1],regname64[rs2]);
   output_w32(0xab000000 | rm_rn_rd(rs2, rs1, rt));
 }
 
   output_w32(0xab000000 | rm_rn_rd(rs2, rs1, rt));
 }
 
@@ -391,6 +351,12 @@ static void emit_sub(u_int rs1, u_int rs2, u_int rt)
   output_w32(0x4b000000 | rm_imm6_rn_rd(rs2, 0, rs1, rt));
 }
 
   output_w32(0x4b000000 | rm_imm6_rn_rd(rs2, 0, rs1, rt));
 }
 
+static void emit_sub_asrimm(u_int rs1, u_int rs2, u_int shift, u_int rt)
+{
+  assem_debug("sub %s,%s,%s,asr #%u\n",regname[rt],regname[rs1],regname[rs2],shift);
+  output_w32(0x4b800000 | rm_imm6_rn_rd(rs2, shift, rs1, rt));
+}
+
 static void emit_movz(u_int imm, u_int rt)
 {
   assem_debug("movz %s,#%#x\n", regname[rt], imm);
 static void emit_movz(u_int imm, u_int rt)
 {
   assem_debug("movz %s,#%#x\n", regname[rt], imm);
@@ -424,7 +390,7 @@ static void emit_movk(u_int imm,u_int rt)
 static void emit_movk_lsl16(u_int imm,u_int rt)
 {
   assert(imm<65536);
 static void emit_movk_lsl16(u_int imm,u_int rt)
 {
   assert(imm<65536);
-  assem_debug("movk %s, #%#x, lsl #16\n", regname[rt], imm);
+  assem_debug("movk %s,#%#x,lsl #16\n", regname[rt], imm);
   output_w32(0x72a00000 | imm16_rd(imm, rt));
 }
 
   output_w32(0x72a00000 | imm16_rd(imm, rt));
 }
 
@@ -463,7 +429,7 @@ static void emit_readword(void *addr, u_int rt)
     output_w32(0xb9400000 | imm12_rn_rd(offset >> 2, FP, rt));
   }
   else
     output_w32(0xb9400000 | imm12_rn_rd(offset >> 2, FP, rt));
   }
   else
-    assert(0);
+    abort();
 }
 
 static void emit_readdword(void *addr, u_int rt)
 }
 
 static void emit_readdword(void *addr, u_int rt)
@@ -473,6 +439,17 @@ static void emit_readdword(void *addr, u_int rt)
     assem_debug("ldr %s,[x%d+%#lx]\n", regname64[rt], FP, offset);
     output_w32(0xf9400000 | imm12_rn_rd(offset >> 3, FP, rt));
   }
     assem_debug("ldr %s,[x%d+%#lx]\n", regname64[rt], FP, offset);
     output_w32(0xf9400000 | imm12_rn_rd(offset >> 3, FP, rt));
   }
+  else
+    abort();
+}
+
+static void emit_readshword(void *addr, u_int rt)
+{
+  uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local;
+  if (!(offset & 1) && offset <= 8190) {
+    assem_debug("ldrsh %s,[x%d+%#lx]\n", regname[rt], FP, offset);
+    output_w32(0x79c00000 | imm12_rn_rd(offset >> 1, FP, rt));
+  }
   else
     assert(0);
 }
   else
     assert(0);
 }
@@ -516,10 +493,10 @@ static void emit_writedword(u_int rt, void *addr)
   uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local;
   if (!(offset & 7) && offset <= 32760) {
     assem_debug("str %s,[x%d+%#lx]\n", regname64[rt], FP, offset);
   uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local;
   if (!(offset & 7) && offset <= 32760) {
     assem_debug("str %s,[x%d+%#lx]\n", regname64[rt], FP, offset);
-    output_w32(0xf9000000 | imm12_rn_rd(offset >> 2, FP, rt));
+    output_w32(0xf9000000 | imm12_rn_rd(offset >> 3, FP, rt));
   }
   else
   }
   else
-    assert(0);
+    abort();
 }
 
 static void emit_storereg(u_int r, u_int hr)
 }
 
 static void emit_storereg(u_int r, u_int hr)
@@ -547,13 +524,7 @@ static void emit_testimm(u_int rs, u_int imm)
   assem_debug("tst %s,#%#x\n", regname[rs], imm);
   assert(is_rotated_mask(imm)); // good enough for PCSX
   gen_logical_imm(imm, &immr, &imms);
   assem_debug("tst %s,#%#x\n", regname[rs], imm);
   assert(is_rotated_mask(imm)); // good enough for PCSX
   gen_logical_imm(imm, &immr, &imms);
-  output_w32(0xb9000000 | n_immr_imms_rn_rd(0, immr, imms, rs, WZR));
-}
-
-static void emit_testeqimm(u_int rs,int imm)
-{
-  assem_debug("tsteq %s,$%d\n",regname[rs],imm);
-  assert(0); // TODO eliminate emit_testeqimm
+  output_w32(0x72000000 | n_immr_imms_rn_rd(0, immr, imms, rs, WZR));
 }
 
 static void emit_not(u_int rs,u_int rt)
 }
 
 static void emit_not(u_int rs,u_int rt)
@@ -562,12 +533,6 @@ static void emit_not(u_int rs,u_int rt)
   output_w32(0x2a200000 | rm_rn_rd(rs, WZR, rt));
 }
 
   output_w32(0x2a200000 | rm_rn_rd(rs, WZR, rt));
 }
 
-static void emit_mvnmi(u_int rs,u_int rt)
-{
-  assem_debug("mvnmi %s,%s\n",regname[rt],regname[rs]);
-  assert(0); // eliminate
-}
-
 static void emit_and(u_int rs1,u_int rs2,u_int rt)
 {
   assem_debug("and %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
 static void emit_and(u_int rs1,u_int rs2,u_int rt)
 {
   assem_debug("and %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
@@ -580,6 +545,12 @@ static void emit_or(u_int rs1,u_int rs2,u_int rt)
   output_w32(0x2a000000 | rm_rn_rd(rs2, rs1, rt));
 }
 
   output_w32(0x2a000000 | rm_rn_rd(rs2, rs1, rt));
 }
 
+static void emit_bic(u_int rs1,u_int rs2,u_int rt)
+{
+  assem_debug("bic %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
+  output_w32(0x0a200000 | rm_rn_rd(rs2, rs1, rt));
+}
+
 static void emit_orrshl_imm(u_int rs,u_int imm,u_int rt)
 {
   assem_debug("orr %s,%s,%s,lsl #%d\n",regname[rt],regname[rt],regname[rs],imm);
 static void emit_orrshl_imm(u_int rs,u_int imm,u_int rt)
 {
   assem_debug("orr %s,%s,%s,lsl #%d\n",regname[rt],regname[rt],regname[rs],imm);
@@ -592,12 +563,24 @@ static void emit_orrshr_imm(u_int rs,u_int imm,u_int rt)
   output_w32(0x2a400000 | rm_imm6_rn_rd(rs, imm, rt, rt));
 }
 
   output_w32(0x2a400000 | rm_imm6_rn_rd(rs, imm, rt, rt));
 }
 
+static void emit_bicsar_imm(u_int rs,u_int imm,u_int rt)
+{
+  assem_debug("bic %s,%s,%s,asr #%d\n",regname[rt],regname[rt],regname[rs],imm);
+  output_w32(0x0aa00000 | rm_imm6_rn_rd(rs, imm, rt, rt));
+}
+
 static void emit_xor(u_int rs1,u_int rs2,u_int rt)
 {
   assem_debug("eor %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
   output_w32(0x4a000000 | rm_rn_rd(rs2, rs1, rt));
 }
 
 static void emit_xor(u_int rs1,u_int rs2,u_int rt)
 {
   assem_debug("eor %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
   output_w32(0x4a000000 | rm_rn_rd(rs2, rs1, rt));
 }
 
+static void emit_xorsar_imm(u_int rs1, u_int rs2, u_int imm, u_int rt)
+{
+  assem_debug("eor %s,%s,%s,asr #%d\n",regname[rt],regname[rs1],regname[rs2],imm);
+  output_w32(0x4a800000 | rm_imm6_rn_rd(rs2, imm, rs1, rt));
+}
+
 static void emit_addimm_s(u_int s, u_int is64, u_int rs, uintptr_t imm, u_int rt)
 {
   unused const char *st = s ? "s" : "";
 static void emit_addimm_s(u_int s, u_int is64, u_int rs, uintptr_t imm, u_int rt)
 {
   unused const char *st = s ? "s" : "";
@@ -608,7 +591,7 @@ static void emit_addimm_s(u_int s, u_int is64, u_int rs, uintptr_t imm, u_int rt
     output_w32(0x11000000 | is64 | s | imm12_rn_rd(imm, rs, rt));
   }
   else if (-imm < 4096) {
     output_w32(0x11000000 | is64 | s | imm12_rn_rd(imm, rs, rt));
   }
   else if (-imm < 4096) {
-    assem_debug("sub%s %s,%s,%#lx\n", st, regname[rt], regname[rs], imm);
+    assem_debug("sub%s %s,%s,%#lx\n", st, regname[rt], regname[rs], -imm);
     output_w32(0x51000000 | is64 | s | imm12_rn_rd(-imm, rs, rt));
   }
   else if (imm < 16777216) {
     output_w32(0x51000000 | is64 | s | imm12_rn_rd(-imm, rs, rt));
   }
   else if (imm < 16777216) {
@@ -616,7 +599,7 @@ static void emit_addimm_s(u_int s, u_int is64, u_int rs, uintptr_t imm, u_int rt
     output_w32(0x11400000 | is64 | imm12_rn_rd(imm >> 12, rs, rt));
     if ((imm & 0xfff) || s) {
       assem_debug("add%s %s,%s,#%#lx\n",st,regname[rt],regname[rs],imm&0xfff);
     output_w32(0x11400000 | is64 | imm12_rn_rd(imm >> 12, rs, rt));
     if ((imm & 0xfff) || s) {
       assem_debug("add%s %s,%s,#%#lx\n",st,regname[rt],regname[rs],imm&0xfff);
-      output_w32(0x11000000 | is64 | s | imm12_rn_rd(imm, rt, rt));
+      output_w32(0x11000000 | is64 | s | imm12_rn_rd(imm & 0xfff, rt, rt));
     }
   }
   else if (-imm < 16777216) {
     }
   }
   else if (-imm < 16777216) {
@@ -628,7 +611,7 @@ static void emit_addimm_s(u_int s, u_int is64, u_int rs, uintptr_t imm, u_int rt
     }
   }
   else
     }
   }
   else
-    assert(0);
+    abort();
 }
 
 static void emit_addimm(u_int rs, uintptr_t imm, u_int rt)
 }
 
 static void emit_addimm(u_int rs, uintptr_t imm, u_int rt)
@@ -720,15 +703,16 @@ static void emit_shlimm(u_int rs,u_int imm,u_int rt)
   output_w32(0x53000000 | n_immr_imms_rn_rd(0, (31-imm)+1, 31-imm, rs, rt));
 }
 
   output_w32(0x53000000 | n_immr_imms_rn_rd(0, (31-imm)+1, 31-imm, rs, rt));
 }
 
-static unused void emit_lslpls_imm(u_int rs,int imm,u_int rt)
+static void emit_shrimm(u_int rs,u_int imm,u_int rt)
 {
 {
-  assert(0); // eliminate
+  assem_debug("lsr %s,%s,#%d\n",regname[rt],regname[rs],imm);
+  output_w32(0x53000000 | n_immr_imms_rn_rd(0, imm, 31, rs, rt));
 }
 
 }
 
-static void emit_shrimm(u_int rs,u_int imm,u_int rt)
+static void emit_shrimm64(u_int rs,u_int imm,u_int rt)
 {
   assem_debug("lsr %s,%s,#%d\n",regname[rt],regname[rs],imm);
 {
   assem_debug("lsr %s,%s,#%d\n",regname[rt],regname[rs],imm);
-  output_w32(0x53000000 | n_immr_imms_rn_rd(0, imm, 31, rs, rt));
+  output_w32(0xd3400000 | n_immr_imms_rn_rd(0, imm, 63, rs, rt));
 }
 
 static void emit_sarimm(u_int rs,u_int imm,u_int rt)
 }
 
 static void emit_sarimm(u_int rs,u_int imm,u_int rt)
@@ -739,7 +723,7 @@ static void emit_sarimm(u_int rs,u_int imm,u_int rt)
 
 static void emit_rorimm(u_int rs,u_int imm,u_int rt)
 {
 
 static void emit_rorimm(u_int rs,u_int imm,u_int rt)
 {
-  assem_debug("ror %s,%s,#%d",regname[rt],regname[rs],imm);
+  assem_debug("ror %s,%s,#%d\n",regname[rt],regname[rs],imm);
   output_w32(0x13800000 | rm_imm6_rn_rd(rs, imm, rs, rt));
 }
 
   output_w32(0x13800000 | rm_imm6_rn_rd(rs, imm, rs, rt));
 }
 
@@ -751,7 +735,7 @@ static void emit_signextend16(u_int rs, u_int rt)
 
 static void emit_shl(u_int rs,u_int rshift,u_int rt)
 {
 
 static void emit_shl(u_int rs,u_int rshift,u_int rt)
 {
-  assem_debug("lsl %s,%s,%s",regname[rt],regname[rs],regname[rshift]);
+  assem_debug("lsl %s,%s,%s\n",regname[rt],regname[rs],regname[rshift]);
   output_w32(0x1ac02000 | rm_rn_rd(rshift, rs, rt));
 }
 
   output_w32(0x1ac02000 | rm_rn_rd(rshift, rs, rt));
 }
 
@@ -778,7 +762,7 @@ static void emit_cmpimm(u_int rs, u_int imm)
     output_w32(0x31000000 | imm12_rn_rd(-imm, rs, WZR));
   }
   else if (imm < 16777216 && !(imm & 0xfff)) {
     output_w32(0x31000000 | imm12_rn_rd(-imm, rs, WZR));
   }
   else if (imm < 16777216 && !(imm & 0xfff)) {
-    assem_debug("cmp %s,#%#x,lsl #12\n", regname[rs], imm >> 12);
+    assem_debug("cmp %s,#%#x\n", regname[rs], imm);
     output_w32(0x71400000 | imm12_rn_rd(imm >> 12, rs, WZR));
   }
   else {
     output_w32(0x71400000 | imm12_rn_rd(imm >> 12, rs, WZR));
   }
   else {
@@ -819,9 +803,10 @@ static void emit_cmovb_imm(int imm,u_int rt)
   emit_cmov_imm(COND_CC, COND_CS, imm, rt);
 }
 
   emit_cmov_imm(COND_CC, COND_CS, imm, rt);
 }
 
-static void emit_cmovs_imm(int imm,u_int rt)
+static void emit_cmoveq_reg(u_int rs,u_int rt)
 {
 {
-  emit_cmov_imm(COND_MI, COND_PL, imm, rt);
+  assem_debug("csel %s,%s,%s,eq\n",regname[rt],regname[rs],regname[rt]);
+  output_w32(0x1a800000 | (COND_EQ << 12) | rm_rn_rd(rt, rs, rt));
 }
 
 static void emit_cmovne_reg(u_int rs,u_int rt)
 }
 
 static void emit_cmovne_reg(u_int rs,u_int rt)
@@ -842,6 +827,12 @@ static void emit_cmovs_reg(u_int rs,u_int rt)
   output_w32(0x1a800000 | (COND_MI << 12) | rm_rn_rd(rt, rs, rt));
 }
 
   output_w32(0x1a800000 | (COND_MI << 12) | rm_rn_rd(rt, rs, rt));
 }
 
+static void emit_csinvle_reg(u_int rs1,u_int rs2,u_int rt)
+{
+  assem_debug("csinv %s,%s,%s,le\n",regname[rt],regname[rs1],regname[rs2]);
+  output_w32(0x5a800000 | (COND_LE << 12) | rm_rn_rd(rs2, rs1, rt));
+}
+
 static void emit_slti32(u_int rs,int imm,u_int rt)
 {
   if(rs!=rt) emit_zeroreg(rt);
 static void emit_slti32(u_int rs,int imm,u_int rt)
 {
   if(rs!=rt) emit_zeroreg(rt);
@@ -906,7 +897,7 @@ static void emit_call(const void *a)
   if (-134217728 <= diff && diff <= 134217727)
     output_w32(0x94000000 | ((diff >> 2) & 0x03ffffff));
   else
   if (-134217728 <= diff && diff <= 134217727)
     output_w32(0x94000000 | ((diff >> 2) & 0x03ffffff));
   else
-    assert(0);
+    abort();
 }
 
 static void emit_jmp(const void *a)
 }
 
 static void emit_jmp(const void *a)
@@ -972,16 +963,23 @@ static void emit_jc(const void *a)
   output_w32(0x54000000 | (offset << 5) | COND_CS);
 }
 
   output_w32(0x54000000 | (offset << 5) | COND_CS);
 }
 
-static void emit_jcc(const void *a)
+static void emit_cb(u_int isnz, u_int is64, const void *a, u_int r)
 {
 {
-  assem_debug("bcc %p\n", a);
+  assem_debug("cb%sz %s,%p\n", isnz?"n":"", is64?regname64[r]:regname[r], a);
   u_int offset = genjmpcc(a);
   u_int offset = genjmpcc(a);
-  output_w32(0x54000000 | (offset << 5) | COND_CC);
+  is64 = is64 ? 0x80000000 : 0;
+  isnz = isnz ? 0x01000000 : 0;
+  output_w32(0x34000000 | is64 | isnz | imm19_rt(offset, r));
+}
+
+static void emit_cbz(const void *a, u_int r)
+{
+  emit_cb(0, 0, a, r);
 }
 
 static void emit_jmpreg(u_int r)
 {
 }
 
 static void emit_jmpreg(u_int r)
 {
-  assem_debug("br %s", regname64[r]);
+  assem_debug("br %s\n", regname64[r]);
   output_w32(0xd61f0000 | rm_rn_rd(0, r, 0));
 }
 
   output_w32(0xd61f0000 | rm_rn_rd(0, r, 0));
 }
 
@@ -1000,10 +998,21 @@ static void emit_adr(void *addr, u_int rt)
 {
   intptr_t offset = (u_char *)addr - out;
   assert(-1048576 <= offset && offset < 1048576);
 {
   intptr_t offset = (u_char *)addr - out;
   assert(-1048576 <= offset && offset < 1048576);
+  assert(rt < 31);
   assem_debug("adr x%d,#%#lx\n", rt, offset);
   output_w32(0x10000000 | ((offset&0x3) << 29) | (((offset>>2)&0x7ffff) << 5) | rt);
 }
 
   assem_debug("adr x%d,#%#lx\n", rt, offset);
   output_w32(0x10000000 | ((offset&0x3) << 29) | (((offset>>2)&0x7ffff) << 5) | rt);
 }
 
+static void emit_adrp(void *addr, u_int rt)
+{
+  intptr_t offset = ((intptr_t)addr & ~0xfffl) - ((intptr_t)out & ~0xfffl);
+  assert(-4294967296l <= offset && offset < 4294967296l);
+  assert(rt < 31);
+  offset >>= 12;
+  assem_debug("adrp %s,#%#lx(000)\n",regname64[rt],offset);
+  output_w32(0x90000000 | ((offset&0x3)<<29) | (((offset>>2)&0x7ffff)<<5) | rt);
+}
+
 static void emit_readword_indexed(int offset, u_int rs, u_int rt)
 {
   assem_debug("ldur %s,[%s+%#x]\n",regname[rt],regname64[rs],offset);
 static void emit_readword_indexed(int offset, u_int rs, u_int rt)
 {
   assem_debug("ldur %s,[%s+%#x]\n",regname[rt],regname64[rs],offset);
@@ -1095,55 +1104,80 @@ static void emit_movzwl_indexed(int offset, u_int rs, u_int rt)
 
 static void emit_writeword_indexed(u_int rt, int offset, u_int rs)
 {
 
 static void emit_writeword_indexed(u_int rt, int offset, u_int rs)
 {
-  assem_debug("str %s,[%s+%#x]\n", regname[rt], regname[rs], offset);
-  if (!(offset & 3) && offset <= 16380)
+  if (!(offset & 3) && (u_int)offset <= 16380) {
+    assem_debug("str %s,[%s+%#x]\n", regname[rt], regname[rs], offset);
     output_w32(0xb9000000 | imm12_rn_rd(offset >> 2, rs, rt));
     output_w32(0xb9000000 | imm12_rn_rd(offset >> 2, rs, rt));
+  }
+  else if (-256 <= offset && offset < 256) {
+    assem_debug("stur %s,[%s+%#x]\n", regname[rt], regname[rs], offset);
+    output_w32(0xb8000000 | imm9_rn_rt(offset & 0x1ff, rs, rt));
+  }
   else
     assert(0);
 }
 
 static void emit_writehword_indexed(u_int rt, int offset, u_int rs)
 {
   else
     assert(0);
 }
 
 static void emit_writehword_indexed(u_int rt, int offset, u_int rs)
 {
-  assem_debug("strh %s,[%s+%#x]\n", regname[rt], regname[rs], offset);
-  if (!(offset & 1) && offset <= 8190)
+  if (!(offset & 1) && (u_int)offset <= 8190) {
+    assem_debug("strh %s,[%s+%#x]\n", regname[rt], regname64[rs], offset);
     output_w32(0x79000000 | imm12_rn_rd(offset >> 1, rs, rt));
     output_w32(0x79000000 | imm12_rn_rd(offset >> 1, rs, rt));
+  }
+  else if (-256 <= offset && offset < 256) {
+    assem_debug("sturh %s,[%s+%#x]\n", regname[rt], regname64[rs], offset);
+    output_w32(0x78000000 | imm9_rn_rt(offset & 0x1ff, rs, rt));
+  }
   else
     assert(0);
 }
 
 static void emit_writebyte_indexed(u_int rt, int offset, u_int rs)
 {
   else
     assert(0);
 }
 
 static void emit_writebyte_indexed(u_int rt, int offset, u_int rs)
 {
-  assem_debug("strb %s,[%s+%#x]\n", regname[rt], regname[rs], offset);
-  if ((u_int)offset < 4096)
+  if ((u_int)offset < 4096) {
+    assem_debug("strb %s,[%s+%#x]\n", regname[rt], regname64[rs], offset);
     output_w32(0x39000000 | imm12_rn_rd(offset, rs, rt));
     output_w32(0x39000000 | imm12_rn_rd(offset, rs, rt));
+  }
+  else if (-256 <= offset && offset < 256) {
+    assem_debug("sturb %s,[%s+%#x]\n", regname[rt], regname64[rs], offset);
+    output_w32(0x38000000 | imm9_rn_rt(offset & 0x1ff, rs, rt));
+  }
   else
     assert(0);
 }
 
   else
     assert(0);
 }
 
-static void emit_umull(u_int rs1, u_int rs2, u_int hi, u_int lo)
+static void emit_umull(u_int rs1, u_int rs2, u_int rt)
 {
 {
-  assem_debug("umull %s, %s, %s, %s\n",regname[lo],regname[hi],regname[rs1],regname[rs2]);
-  assert(rs1<16);
-  assert(rs2<16);
-  assert(hi<16);
-  assert(lo<16);
-  assert(0);
+  assem_debug("umull %s,%s,%s\n",regname64[rt],regname[rs1],regname[rs2]);
+  output_w32(0x9ba00000 | rm_ra_rn_rd(rs2, WZR, rs1, rt));
 }
 
 }
 
-static void emit_smull(u_int rs1, u_int rs2, u_int hi, u_int lo)
+static void emit_smull(u_int rs1, u_int rs2, u_int rt)
 {
 {
-  assem_debug("smull %s, %s, %s, %s\n",regname[lo],regname[hi],regname[rs1],regname[rs2]);
-  assert(rs1<16);
-  assert(rs2<16);
-  assert(hi<16);
-  assert(lo<16);
-  assert(0);
+  assem_debug("smull %s,%s,%s\n",regname64[rt],regname[rs1],regname[rs2]);
+  output_w32(0x9b200000 | rm_ra_rn_rd(rs2, WZR, rs1, rt));
+}
+
+static void emit_msub(u_int rs1, u_int rs2, u_int rs3, u_int rt)
+{
+  assem_debug("msub %s,%s,%s,%s\n",regname[rt],regname[rs1],regname[rs2],regname[rs3]);
+  output_w32(0x1b008000 | rm_ra_rn_rd(rs2, rs3, rs1, rt));
 }
 
 }
 
-static void emit_clz(u_int rs,u_int rt)
+static void emit_sdiv(u_int rs1, u_int rs2, u_int rt)
+{
+  assem_debug("sdiv %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
+  output_w32(0x1ac00c00 | rm_rn_rd(rs2, rs1, rt));
+}
+
+static void emit_udiv(u_int rs1, u_int rs2, u_int rt)
+{
+  assem_debug("udiv %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
+  output_w32(0x1ac00800 | rm_rn_rd(rs2, rs1, rt));
+}
+
+static void emit_clz(u_int rs, u_int rt)
 {
   assem_debug("clz %s,%s\n",regname[rt],regname[rs]);
 {
   assem_debug("clz %s,%s\n",regname[rt],regname[rs]);
-  assert(0);
+  output_w32(0x5ac01000 | rn_rd(rs, rt));
 }
 
 // special case for checking invalid_code
 }
 
 // special case for checking invalid_code
@@ -1151,28 +1185,23 @@ static void emit_cmpmem_indexedsr12_reg(u_int rbase, u_int r, u_int imm)
 {
   host_tempreg_acquire();
   emit_shrimm(r, 12, HOST_TEMPREG);
 {
   host_tempreg_acquire();
   emit_shrimm(r, 12, HOST_TEMPREG);
-  assem_debug("ldrb %s,[%s,%s]",regname[HOST_TEMPREG],regname64[rbase],regname64[HOST_TEMPREG]);
-  output_w32(0x38606800 | rm_rn_rd(HOST_TEMPREG, rbase, HOST_TEMPREG));
+  assem_debug("ldrb %s,[%s,%s,uxtw]\n",regname[HOST_TEMPREG],regname64[rbase],regname[HOST_TEMPREG]);
+  output_w32(0x38604800 | rm_rn_rd(HOST_TEMPREG, rbase, HOST_TEMPREG));
   emit_cmpimm(HOST_TEMPREG, imm);
   host_tempreg_release();
 }
 
   emit_cmpimm(HOST_TEMPREG, imm);
   host_tempreg_release();
 }
 
-static void emit_orrne_imm(u_int rs,int imm,u_int rt)
+// special for loadlr_assemble, rs2 is destroyed
+static void emit_bic_lsl(u_int rs1,u_int rs2,u_int shift,u_int rt)
 {
 {
-  assem_debug("orrne %s,%s,#%#x\n",regname[rt],regname[rs],imm);
-  assert(0);
+  emit_shl(rs2, shift, rs2);
+  emit_bic(rs1, rs2, rt);
 }
 
 }
 
-static void emit_andne_imm(u_int rs,int imm,u_int rt)
+static void emit_bic_lsr(u_int rs1,u_int rs2,u_int shift,u_int rt)
 {
 {
-  assem_debug("andne %s,%s,#%#x\n",regname[rt],regname[rs],imm);
-  assert(0);
-}
-
-static unused void emit_addpl_imm(u_int rs,int imm,u_int rt)
-{
-  assem_debug("addpl %s,%s,#%#x\n",regname[rt],regname[rs],imm);
-  assert(0);
+  emit_shr(rs2, shift, rs2);
+  emit_bic(rs1, rs2, rt);
 }
 
 static void emit_loadlp_ofs(u_int ofs, u_int rt)
 }
 
 static void emit_loadlp_ofs(u_int ofs, u_int rt)
@@ -1280,9 +1309,11 @@ static void check_extjump2(void *src)
 static void emit_movimm_from(u_int rs_val, u_int rs, u_int rt_val, u_int rt)
 {
   int diff = rt_val - rs_val;
 static void emit_movimm_from(u_int rs_val, u_int rs, u_int rt_val, u_int rt)
 {
   int diff = rt_val - rs_val;
-  if ((-4096 <= diff && diff < 4096)
-      || (-16777216 <= diff && diff < 16777216 && !(diff & 0xfff)))
+  if ((-4096 < diff && diff < 4096)
+      || (-16777216 < diff && diff < 16777216 && !(diff & 0xfff)))
     emit_addimm(rs, diff, rt);
     emit_addimm(rs, diff, rt);
+  else if (rt_val == ~rs_val)
+    emit_not(rs, rt);
   else if (is_rotated_mask(rs_val ^ rt_val))
     emit_xorimm(rs, rs_val ^ rt_val, rt);
   else
   else if (is_rotated_mask(rs_val ^ rt_val))
     emit_xorimm(rs, rs_val ^ rt_val, rt);
   else
@@ -1293,8 +1324,9 @@ static void emit_movimm_from(u_int rs_val, u_int rs, u_int rt_val, u_int rt)
 static int is_similar_value(u_int v1, u_int v2)
 {
   int diff = v1 - v2;
 static int is_similar_value(u_int v1, u_int v2)
 {
   int diff = v1 - v2;
-  return (-4096 <= diff && diff < 4096)
-    || (-16777216 <= diff && diff < 16777216 && !(diff & 0xfff))
+  return (-4096 < diff && diff < 4096)
+    || (-16777216 < diff && diff < 16777216 && !(diff & 0xfff))
+    || v1 == ~v2
     || is_rotated_mask(v1 ^ v2);
 }
 
     || is_rotated_mask(v1 ^ v2);
 }
 
@@ -1326,7 +1358,7 @@ static void loadstore_extend(enum stub_type type, u_int rs, u_int rt)
     case STOREH_STUB: emit_ubfm(rs, 15, rt); break;
     case LOADW_STUB:  
     case STOREW_STUB: if (rs != rt) emit_mov(rs, rt); break;
     case STOREH_STUB: emit_ubfm(rs, 15, rt); break;
     case LOADW_STUB:  
     case STOREW_STUB: if (rs != rt) emit_mov(rs, rt); break;
-    default: assert(0);
+    default:          assert(0);
   }
 }
 
   }
 }
 
@@ -1381,7 +1413,7 @@ static void do_readstub(int n)
       case LOADH_STUB:  emit_ldrsh_dualindexed(temp2,rs,rt); break;
       case LOADHU_STUB: emit_ldrh_dualindexed(temp2,rs,rt); break;
       case LOADW_STUB:  emit_ldr_dualindexed(temp2,rs,rt); break;
       case LOADH_STUB:  emit_ldrsh_dualindexed(temp2,rs,rt); break;
       case LOADHU_STUB: emit_ldrh_dualindexed(temp2,rs,rt); break;
       case LOADW_STUB:  emit_ldr_dualindexed(temp2,rs,rt); break;
-      default: assert(0);
+      default:          assert(0);
     }
   }
   if(regs_saved) {
     }
   }
   if(regs_saved) {
@@ -1470,8 +1502,11 @@ static void inline_readstub(enum stub_type type, int i, u_int addr, signed char
   if(cc<0)
     emit_loadreg(CCREG,2);
   emit_addimm(cc<0?2:cc,CLOCK_ADJUST(adj+1),2);
   if(cc<0)
     emit_loadreg(CCREG,2);
   emit_addimm(cc<0?2:cc,CLOCK_ADJUST(adj+1),2);
-  if(is_dynamic)
-    emit_readdword(&mem_rtab,1);
+  if(is_dynamic) {
+    uintptr_t l1 = ((uintptr_t *)mem_rtab)[addr>>12] << 1;
+    emit_adrp((void *)l1, 1);
+    emit_addimm64(1, l1 & 0xfff, 1);
+  }
   else
     emit_call(do_memhandler_pre);
 
   else
     emit_call(do_memhandler_pre);
 
@@ -1551,7 +1586,7 @@ static void do_writestub(int n)
     case STOREB_STUB: handler=jump_handler_write8; break;
     case STOREH_STUB: handler=jump_handler_write16; break;
     case STOREW_STUB: handler=jump_handler_write32; break;
     case STOREB_STUB: handler=jump_handler_write8; break;
     case STOREH_STUB: handler=jump_handler_write16; break;
     case STOREW_STUB: handler=jump_handler_write32; break;
-    default: assert(0);
+    default:          assert(0);
   }
   assert(handler);
   pass_args(rs,rt);
   }
   assert(handler);
   pass_args(rs,rt);
@@ -1616,10 +1651,36 @@ static void inline_writestub(enum stub_type type, int i, u_int addr, signed char
   restore_regs(reglist);
 }
 
   restore_regs(reglist);
 }
 
-static void do_unalignedwritestub(int n)
+static int verify_code_arm64(const void *source, const void *copy, u_int size)
 {
 {
-  assem_debug("do_unalignedwritestub %x\n",start+stubs[n].a*4);
-  assert(0);
+  int ret = memcmp(source, copy, size);
+  //printf("%s %p,%#x = %d\n", __func__, source, size, ret);
+  return ret;
+}
+
+// this output is parsed by verify_dirty, get_bounds, isclean, get_clean_addr
+static void do_dirty_stub_base(u_int vaddr)
+{
+  assert(slen <= MAXBLOCK);
+  emit_loadlp_ofs(0, 0); // ldr x1, source
+  emit_loadlp_ofs(0, 1); // ldr x2, copy
+  emit_movz(slen*4, 2);
+  emit_call(verify_code_arm64);
+  void *jmp = out;
+  emit_cbz(0, 0);
+  emit_movz(vaddr & 0xffff, 0);
+  emit_movk_lsl16(vaddr >> 16, 0);
+  emit_call(get_addr);
+  emit_jmpreg(0);
+  set_jump_target(jmp, out);
+}
+
+static void assert_dirty_stub(const u_int *ptr)
+{
+  assert((ptr[0] & 0xff00001f) == 0x58000000); // ldr x0, source
+  assert((ptr[1] & 0xff00001f) == 0x58000001); // ldr x1, copy
+  assert((ptr[2] & 0xffe0001f) == 0x52800002); // movz w2, #slen*4
+  assert( ptr[8]               == 0xd61f0000); // br x0
 }
 
 static void set_loadlp(u_int *loadl, void *lit)
 }
 
 static void set_loadlp(u_int *loadl, void *lit)
@@ -1631,17 +1692,6 @@ static void set_loadlp(u_int *loadl, void *lit)
   *loadl |= (ofs >> 2) << 5;
 }
 
   *loadl |= (ofs >> 2) << 5;
 }
 
-// this output is parsed by verify_dirty, get_bounds, isclean, get_clean_addr
-static void do_dirty_stub_emit_args(u_int arg0)
-{
-  assert(slen <= MAXBLOCK);
-  emit_loadlp_ofs(0, 1); // ldr x1, source
-  emit_loadlp_ofs(0, 2); // ldr x2, copy
-  emit_movz(slen*4, 3);
-  emit_movz(arg0 & 0xffff, 0);
-  emit_movk_lsl16(arg0 >> 16, 0);
-}
-
 static void do_dirty_stub_emit_literals(u_int *loadlps)
 {
   set_loadlp(&loadlps[0], out);
 static void do_dirty_stub_emit_literals(u_int *loadlps)
 {
   set_loadlp(&loadlps[0], out);
@@ -1654,8 +1704,7 @@ static void *do_dirty_stub(int i)
 {
   assem_debug("do_dirty_stub %x\n",start+i*4);
   u_int *loadlps = (void *)out;
 {
   assem_debug("do_dirty_stub %x\n",start+i*4);
   u_int *loadlps = (void *)out;
-  do_dirty_stub_emit_args(start + i*4);
-  emit_call(verify_code);
+  do_dirty_stub_base(start + i*4);
   void *entry = out;
   load_regs_entry(i);
   if (entry == out)
   void *entry = out;
   load_regs_entry(i);
   if (entry == out)
@@ -1665,38 +1714,258 @@ static void *do_dirty_stub(int i)
   return entry;
 }
 
   return entry;
 }
 
-static void do_dirty_stub_ds()
+static void do_dirty_stub_ds(void)
 {
 {
-  do_dirty_stub_emit_args(start + 1);
   u_int *loadlps = (void *)out;
   u_int *loadlps = (void *)out;
-  emit_call(verify_code_ds);
+  do_dirty_stub_base(start + 1);
+  void *lit_jumpover = out;
   emit_jmp(out + 8*2);
   do_dirty_stub_emit_literals(loadlps);
   emit_jmp(out + 8*2);
   do_dirty_stub_emit_literals(loadlps);
+  set_jump_target(lit_jumpover, out);
 }
 
 }
 
-/* Special assem */
+static uint64_t get_from_ldr_literal(const u_int *i)
+{
+  signed int ofs;
+  assert((i[0] & 0xff000000) == 0x58000000);
+  ofs = i[0] << 8;
+  ofs >>= 5+8;
+  return *(uint64_t *)(i + ofs);
+}
 
 
-#define shift_assemble shift_assemble_arm64
+static uint64_t get_from_movz(const u_int *i)
+{
+  assert((i[0] & 0x7fe00000) == 0x52800000);
+  return (i[0] >> 5) & 0xffff;
+}
 
 
-static void shift_assemble_arm64(int i,struct regstat *i_regs)
+// Find the "clean" entry point from a "dirty" entry point
+// by skipping past the call to verify_code
+static void *get_clean_addr(u_int *addr)
 {
 {
-  assert(0);
+  assert_dirty_stub(addr);
+  return addr + 9;
 }
 }
-#define loadlr_assemble loadlr_assemble_arm64
 
 
-static void loadlr_assemble_arm64(int i,struct regstat *i_regs)
+static int verify_dirty(const u_int *ptr)
 {
 {
-  assert(0);
+  const void *source, *copy;
+  u_int len;
+  assert_dirty_stub(ptr);
+  source = (void *)get_from_ldr_literal(&ptr[0]); // ldr x1, source
+  copy   = (void *)get_from_ldr_literal(&ptr[1]); // ldr x1, copy
+  len = get_from_movz(&ptr[2]);                   // movz w3, #slen*4
+  return !memcmp(source, copy, len);
+}
+
+static int isclean(void *addr)
+{
+  const u_int *ptr = addr;
+  if ((*ptr >> 24) == 0x58) { // the only place ldr (literal) is used
+    assert_dirty_stub(ptr);
+    return 0;
+  }
+  return 1;
+}
+
+// get source that block at addr was compiled from (host pointers)
+static void get_bounds(void *addr, u_char **start, u_char **end)
+{
+  const u_int *ptr = addr;
+  assert_dirty_stub(ptr);
+  *start = (u_char *)get_from_ldr_literal(&ptr[0]); // ldr x1, source
+  *end = *start + get_from_movz(&ptr[2]);           // movz w3, #slen*4
+}
+
+/* Special assem */
+
+static void c2op_prologue(u_int op,u_int reglist)
+{
+  save_load_regs_all(1, reglist);
+#ifdef PCNT
+  emit_movimm(op, 0);
+  emit_call(pcnt_gte_start);
+#endif
+  // pointer to cop2 regs
+  emit_addimm64(FP, (u_char *)&psxRegs.CP2D.r[0] - (u_char *)&dynarec_local, 0);
+}
+
+static void c2op_epilogue(u_int op,u_int reglist)
+{
+#ifdef PCNT
+  emit_movimm(op, 0);
+  emit_call(pcnt_gte_end);
+#endif
+  save_load_regs_all(0, reglist);
 }
 
 static void c2op_assemble(int i,struct regstat *i_regs)
 {
 }
 
 static void c2op_assemble(int i,struct regstat *i_regs)
 {
-  assert(0);
+  u_int c2op=source[i]&0x3f;
+  u_int hr,reglist_full=0,reglist;
+  int need_flags,need_ir;
+  for(hr=0;hr<HOST_REGS;hr++) {
+    if(i_regs->regmap[hr]>=0) reglist_full|=1<<hr;
+  }
+  reglist=reglist_full&CALLER_SAVE_REGS;
+
+  if (gte_handlers[c2op]!=NULL) {
+    need_flags=!(gte_unneeded[i+1]>>63); // +1 because of how liveness detection works
+    need_ir=(gte_unneeded[i+1]&0xe00)!=0xe00;
+    assem_debug("gte op %08x, unneeded %016lx, need_flags %d, need_ir %d\n",
+      source[i],gte_unneeded[i+1],need_flags,need_ir);
+    if(new_dynarec_hacks&NDHACK_GTE_NO_FLAGS)
+      need_flags=0;
+    //int shift = (source[i] >> 19) & 1;
+    //int lm = (source[i] >> 10) & 1;
+    switch(c2op) {
+      default:
+        (void)need_ir;
+        c2op_prologue(c2op,reglist);
+        emit_movimm(source[i],1); // opcode
+        emit_writeword(1,&psxRegs.code);
+        emit_call(need_flags?gte_handlers[c2op]:gte_handlers_nf[c2op]);
+        break;
+    }
+    c2op_epilogue(c2op,reglist);
+  }
+}
+
+static void c2op_ctc2_31_assemble(signed char sl, signed char temp)
+{
+  //value = value & 0x7ffff000;
+  //if (value & 0x7f87e000) value |= 0x80000000;
+  emit_andimm(sl, 0x7fffe000, temp);
+  emit_testimm(temp, 0xff87ffff);
+  emit_andimm(sl, 0x7ffff000, temp);
+  host_tempreg_acquire();
+  emit_orimm(temp, 0x80000000, HOST_TEMPREG);
+  emit_cmovne_reg(HOST_TEMPREG, temp);
+  host_tempreg_release();
+  assert(0); // testing needed
+}
+
+static void do_mfc2_31_one(u_int copr,signed char temp)
+{
+  emit_readshword(&reg_cop2d[copr],temp);
+  emit_bicsar_imm(temp,31,temp);
+  emit_cmpimm(temp,0xf80);
+  emit_csinvle_reg(temp,WZR,temp); // if (temp > 0xf80) temp = ~0;
+  emit_andimm(temp,0xf80,temp);
+}
+
+static void c2op_mfc2_29_assemble(signed char tl, signed char temp)
+{
+  if (temp < 0) {
+    host_tempreg_acquire();
+    temp = HOST_TEMPREG;
+  }
+  do_mfc2_31_one(9,temp);
+  emit_shrimm(temp,7,tl);
+  do_mfc2_31_one(10,temp);
+  emit_orrshr_imm(temp,2,tl);
+  do_mfc2_31_one(11,temp);
+  emit_orrshl_imm(temp,3,tl);
+  emit_writeword(tl,&reg_cop2d[29]);
+
+  if (temp == HOST_TEMPREG)
+    host_tempreg_release();
 }
 
 static void multdiv_assemble_arm64(int i,struct regstat *i_regs)
 {
 }
 
 static void multdiv_assemble_arm64(int i,struct regstat *i_regs)
 {
-  assert(0);
+  //  case 0x18: MULT
+  //  case 0x19: MULTU
+  //  case 0x1A: DIV
+  //  case 0x1B: DIVU
+  if(rs1[i]&&rs2[i])
+  {
+    switch(opcode2[i])
+    {
+    case 0x18: // MULT
+    case 0x19: // MULTU
+      {
+        signed char m1=get_reg(i_regs->regmap,rs1[i]);
+        signed char m2=get_reg(i_regs->regmap,rs2[i]);
+        signed char hi=get_reg(i_regs->regmap,HIREG);
+        signed char lo=get_reg(i_regs->regmap,LOREG);
+        assert(m1>=0);
+        assert(m2>=0);
+        assert(hi>=0);
+        assert(lo>=0);
+
+        if(opcode2[i]==0x18) // MULT
+          emit_smull(m1,m2,hi);
+        else                 // MULTU
+          emit_umull(m1,m2,hi);
+
+        emit_mov(hi,lo);
+        emit_shrimm64(hi,32,hi);
+        break;
+      }
+    case 0x1A: // DIV
+    case 0x1B: // DIVU
+      {
+        signed char numerator=get_reg(i_regs->regmap,rs1[i]);
+        signed char denominator=get_reg(i_regs->regmap,rs2[i]);
+        signed char quotient=get_reg(i_regs->regmap,LOREG);
+        signed char remainder=get_reg(i_regs->regmap,HIREG);
+        assert(numerator>=0);
+        assert(denominator>=0);
+        assert(quotient>=0);
+        assert(remainder>=0);
+
+        if (opcode2[i] == 0x1A) // DIV
+          emit_sdiv(numerator,denominator,quotient);
+        else                    // DIVU
+          emit_udiv(numerator,denominator,quotient);
+        emit_msub(quotient,denominator,numerator,remainder);
+
+        // div 0 quotient (remainder is already correct)
+        host_tempreg_acquire();
+        if (opcode2[i] == 0x1A) // DIV
+          emit_sub_asrimm(0,numerator,31,HOST_TEMPREG);
+        else
+          emit_movimm(~0,HOST_TEMPREG);
+        emit_test(denominator,denominator);
+        emit_cmoveq_reg(HOST_TEMPREG,quotient);
+        host_tempreg_release();
+        break;
+      }
+    default:
+      assert(0);
+    }
+  }
+  else
+  {
+    signed char hr=get_reg(i_regs->regmap,HIREG);
+    signed char lr=get_reg(i_regs->regmap,LOREG);
+    if ((opcode2[i]==0x1A || opcode2[i]==0x1B) && rs2[i]==0) // div 0
+    {
+      if (rs1[i]) {
+        signed char numerator = get_reg(i_regs->regmap, rs1[i]);
+        assert(numerator >= 0);
+        if (hr >= 0)
+          emit_mov(numerator,hr);
+        if (lr >= 0) {
+          if (opcode2[i] == 0x1A) // DIV
+            emit_sub_asrimm(0,numerator,31,lr);
+          else
+            emit_movimm(~0,lr);
+        }
+      }
+      else {
+        if (hr >= 0) emit_zeroreg(hr);
+        if (lr >= 0) emit_movimm(~0,lr);
+      }
+    }
+    else
+    {
+      // Multiply by zero is zero.
+      if (hr >= 0) emit_zeroreg(hr);
+      if (lr >= 0) emit_zeroreg(lr);
+    }
+  }
 }
 #define multdiv_assemble multdiv_assemble_arm64
 
 }
 #define multdiv_assemble multdiv_assemble_arm64
 
index 62b9176..2df259b 100644 (file)
@@ -338,7 +338,7 @@ static int ari64_init()
        scratch_buf_ptr = scratch_buf;
 
        SysPrintf("Mapped (RAM/scrp/ROM/LUTs/TC):\n");
        scratch_buf_ptr = scratch_buf;
 
        SysPrintf("Mapped (RAM/scrp/ROM/LUTs/TC):\n");
-       SysPrintf("%08x/%08x/%08x/%08x/%08x\n",
+       SysPrintf("%p/%p/%p/%p/%p\n",
                psxM, psxH, psxR, mem_rtab, out);
 
        return 0;
                psxM, psxH, psxR, mem_rtab, out);
 
        return 0;
@@ -657,6 +657,8 @@ void do_insn_cmp(void)
                if (allregs_p[i] != allregs_e[i]) {
                        miss_log_add(i, allregs_p[i], allregs_e[i], psxRegs.pc, psxRegs.cycle);
                        bad++;
                if (allregs_p[i] != allregs_e[i]) {
                        miss_log_add(i, allregs_p[i], allregs_e[i], psxRegs.pc, psxRegs.cycle);
                        bad++;
+                       if (i > 32+2)
+                               goto end;
                }
        }
 
                }
        }
 
index fcb4e1a..bbc52c3 100644 (file)
@@ -32,8 +32,6 @@
 #define get_addr_ht            ESYM(get_addr_ht)
 #define clean_blocks           ESYM(clean_blocks)
 #define gen_interupt           ESYM(gen_interupt)
 #define get_addr_ht            ESYM(get_addr_ht)
 #define clean_blocks           ESYM(clean_blocks)
 #define gen_interupt           ESYM(gen_interupt)
-#define psxException           ESYM(psxException)
-#define execI                  ESYM(execI)
 #define invalidate_addr                ESYM(invalidate_addr)
 #endif
 
 #define invalidate_addr                ESYM(invalidate_addr)
 #endif
 
@@ -393,7 +391,7 @@ FUNCTION(jump_vaddr):
        .align  2
 
 FUNCTION(verify_code_ds):
        .align  2
 
 FUNCTION(verify_code_ds):
-       str     r8, [fp, #LO_branch_target]
+       str     r8, [fp, #LO_branch_target]  @ preserve HOST_BTREG?
 FUNCTION(verify_code):
        /* r1 = source */
        /* r2 = target */
 FUNCTION(verify_code):
        /* r1 = source */
        /* r2 = target */
@@ -512,19 +510,9 @@ FUNCTION(jump_syscall):
        .size   jump_syscall, .-jump_syscall
        .align  2
 
        .size   jump_syscall, .-jump_syscall
        .align  2
 
-       .align  2
-FUNCTION(jump_syscall_hle):
-       str     r0, [fp, #LO_pcaddr] /* PC must be set to EPC for psxException */
-       ldr     r2, [fp, #LO_last_count]
-       mov     r1, #0    /* in delay slot */
-       add     r2, r2, r10
-       mov     r0, #0x20 /* cause */
-       str     r2, [fp, #LO_cycle] /* PCSX cycle counter */
-       bl      psxException
-
        /* note: psxException might do recursive recompiler call from it's HLE code,
         * so be ready for this */
        /* note: psxException might do recursive recompiler call from it's HLE code,
         * so be ready for this */
-pcsx_return:
+FUNCTION(jump_to_new_pc):
        ldr     r1, [fp, #LO_next_interupt]
        ldr     r10, [fp, #LO_cycle]
        ldr     r0, [fp, #LO_pcaddr]
        ldr     r1, [fp, #LO_next_interupt]
        ldr     r10, [fp, #LO_cycle]
        ldr     r0, [fp, #LO_pcaddr]
@@ -532,27 +520,7 @@ pcsx_return:
        str     r1, [fp, #LO_last_count]
        bl      get_addr_ht
        mov     pc, r0
        str     r1, [fp, #LO_last_count]
        bl      get_addr_ht
        mov     pc, r0
-       .size   jump_syscall_hle, .-jump_syscall_hle
-
-       .align  2
-FUNCTION(jump_hlecall):
-       ldr     r2, [fp, #LO_last_count]
-       str     r0, [fp, #LO_pcaddr]
-       add     r2, r2, r10
-       adr     lr, pcsx_return
-       str     r2, [fp, #LO_cycle] /* PCSX cycle counter */
-       bx      r1
-       .size   jump_hlecall, .-jump_hlecall
-
-       .align  2
-FUNCTION(jump_intcall):
-       ldr     r2, [fp, #LO_last_count]
-       str     r0, [fp, #LO_pcaddr]
-       add     r2, r2, r10
-       adr     lr, pcsx_return
-       str     r2, [fp, #LO_cycle] /* PCSX cycle counter */
-       b       execI
-       .size   jump_hlecall, .-jump_hlecall
+       .size   jump_to_new_pc, .-jump_to_new_pc
 
        .align  2
 FUNCTION(new_dyna_leave):
 
        .align  2
 FUNCTION(new_dyna_leave):
index 060ac48..444545c 100644 (file)
@@ -111,18 +111,6 @@ FUNCTION(dyna_linker_ds):
        dyna_linker_main
        .size   dyna_linker_ds, .-dyna_linker_ds
 
        dyna_linker_main
        .size   dyna_linker_ds, .-dyna_linker_ds
 
-       .align  2
-
-FUNCTION(verify_code_ds):
-       bl      abort
-FUNCTION(verify_code):
-       /* r1 = source */
-       /* r2 = target */
-       /* r3 = length */
-       bl      abort
-       .size   verify_code, .-verify_code
-       .size   verify_code_ds, .-verify_code_ds
-
        .align  2
 FUNCTION(cc_interrupt):
        ldr     w0, [rFP, #LO_last_count]
        .align  2
 FUNCTION(cc_interrupt):
        ldr     w0, [rFP, #LO_last_count]
@@ -204,32 +192,17 @@ FUNCTION(jump_syscall):
        .size   jump_syscall, .-jump_syscall
        .align  2
 
        .size   jump_syscall, .-jump_syscall
        .align  2
 
-       .align  2
-FUNCTION(jump_syscall_hle):
-       bl      abort
-
        /* note: psxException might do recursive recompiler call from it's HLE code,
         * so be ready for this */
        /* note: psxException might do recursive recompiler call from it's HLE code,
         * so be ready for this */
-pcsx_return:
-       bl      abort // w10
+FUNCTION(jump_to_new_pc):
        ldr     w1, [fp, #LO_next_interupt]
        ldr     w1, [fp, #LO_next_interupt]
-       ldr     w10, [fp, #LO_cycle]
+       ldr     rCC, [fp, #LO_cycle]
        ldr     w0, [fp, #LO_pcaddr]
        ldr     w0, [fp, #LO_pcaddr]
-       sub     w10, w10, w1
+       sub     rCC, rCC, w1
        str     w1, [fp, #LO_last_count]
        bl      get_addr_ht
        br      x0
        str     w1, [fp, #LO_last_count]
        bl      get_addr_ht
        br      x0
-       .size   jump_syscall_hle, .-jump_syscall_hle
-
-       .align  2
-FUNCTION(jump_hlecall):
-       bl      abort
-       .size   jump_hlecall, .-jump_hlecall
-
-       .align  2
-FUNCTION(jump_intcall):
-       bl      abort
-       .size   jump_intcall, .-jump_intcall
+       .size   jump_to_new_pc, .-jump_to_new_pc
 
        /* stack must be aligned by 16, and include space for save_regs() use */
        .align  2
 
        /* stack must be aligned by 16, and include space for save_regs() use */
        .align  2
@@ -292,7 +265,6 @@ FUNCTION(do_memhandler_post):
 
 .macro pcsx_read_mem readop tab_shift
        /* w0 = address, x1 = handler_tab, w2 = cycles */
 
 .macro pcsx_read_mem readop tab_shift
        /* w0 = address, x1 = handler_tab, w2 = cycles */
-       stp     xzr, x30, [sp, #-16]!
        ubfm    w4, w0, #\tab_shift, #11
        ldr     x3, [x1, w4, uxtw #3]
        adds    x3, x3, x3
        ubfm    w4, w0, #\tab_shift, #11
        ldr     x3, [x1, w4, uxtw #3]
        adds    x3, x3, x3
@@ -300,17 +272,18 @@ FUNCTION(do_memhandler_post):
        \readop w0, [x3, w4, uxtw #\tab_shift]
        ret
 0:
        \readop w0, [x3, w4, uxtw #\tab_shift]
        ret
 0:
+       stp     xzr, x30, [sp, #-16]!
        memhandler_pre
        blr     x3
 .endm
 
 FUNCTION(jump_handler_read8):
        memhandler_pre
        blr     x3
 .endm
 
 FUNCTION(jump_handler_read8):
-       add     x1, x1, #0x1000/4*4 + 0x1000/2*4  /* shift to r8 part */
+       add     x1, x1, #0x1000/4*8 + 0x1000/2*8  /* shift to r8 part */
        pcsx_read_mem ldrb, 0
        b       handler_read_end
 
 FUNCTION(jump_handler_read16):
        pcsx_read_mem ldrb, 0
        b       handler_read_end
 
 FUNCTION(jump_handler_read16):
-       add     x1, x1, #0x1000/4*4               /* shift to r16 part */
+       add     x1, x1, #0x1000/4*8               /* shift to r16 part */
        pcsx_read_mem ldrh, 1
        b       handler_read_end
 
        pcsx_read_mem ldrh, 1
        b       handler_read_end
 
@@ -323,29 +296,28 @@ handler_read_end:
 
 .macro pcsx_write_mem wrtop movop tab_shift
        /* w0 = address, w1 = data, w2 = cycles, x3 = handler_tab */
 
 .macro pcsx_write_mem wrtop movop tab_shift
        /* w0 = address, w1 = data, w2 = cycles, x3 = handler_tab */
-       stp     xzr, x30, [sp, #-16]!
        ubfm    w4, w0, #\tab_shift, #11
        ldr     x3, [x3, w4, uxtw #3]
        ubfm    w4, w0, #\tab_shift, #11
        ldr     x3, [x3, w4, uxtw #3]
-       str     w0, [rFP, #LO_address]    /* some handlers still need it... */
        adds    x3, x3, x3
        adds    x3, x3, x3
-#      str     lr, [rFP, #0]
        bcs     0f
        mov     w0, w2                    /* cycle return */
        \wrtop  w1, [x3, w4, uxtw #\tab_shift]
        ret
 0:
        bcs     0f
        mov     w0, w2                    /* cycle return */
        \wrtop  w1, [x3, w4, uxtw #\tab_shift]
        ret
 0:
+       stp     xzr, x30, [sp, #-16]!
+       str     w0, [rFP, #LO_address]    /* some handlers still need it... */
        \movop  w0, w1
        memhandler_pre
        blr     x3
 .endm
 
 FUNCTION(jump_handler_write8):
        \movop  w0, w1
        memhandler_pre
        blr     x3
 .endm
 
 FUNCTION(jump_handler_write8):
-       add     x3, x3, #0x1000/4*4 + 0x1000/2*4  /* shift to r8 part */
+       add     x3, x3, #0x1000/4*8 + 0x1000/2*8  /* shift to r8 part */
        pcsx_write_mem strb uxtb 0
        b       handler_write_end
 
 FUNCTION(jump_handler_write16):
        pcsx_write_mem strb uxtb 0
        b       handler_write_end
 
 FUNCTION(jump_handler_write16):
-       add     x3, x3, #0x1000/4*4               /* shift to r16 part */
+       add     x3, x3, #0x1000/4*8               /* shift to r16 part */
        pcsx_write_mem strh uxth 1
        b       handler_write_end
 
        pcsx_write_mem strh uxth 1
        b       handler_write_end
 
@@ -358,8 +330,69 @@ handler_write_end:
        ret
 
 FUNCTION(jump_handle_swl):
        ret
 
 FUNCTION(jump_handle_swl):
+       /* w0 = address, w1 = data, w2 = cycles */
+       ldr     x3, [fp, #LO_mem_wtab]
+       mov     w4, w0, lsr #12
+       ldr     x3, [x3, w4, uxtw #3]
+       adds    x3, x3, x3
+       bcs     4f
+       add     x3, x0, x3
+       mov     w0, w2
+       tbz     x3, #1, 10f     // & 2
+       tbz     x3, #0, 2f      // & 1
+3:
+       stur    w1, [x3, #-3]
+       ret
+2:
+       lsr     w2, w1, #8
+       lsr     w1, w1, #24
+       sturh   w2, [x3, #-2]
+       strb    w1, [x3]
+       ret
+10:
+       tbz     x3, #0, 0f      // & 1
+1:
+       lsr     w1, w1, #16
+       sturh   w1, [x3, #-1]
+       ret
+0:
+       lsr     w2, w1, #24
+       strb    w2, [x3]
+       ret
+4:
+       mov     w0, w2          // todo
        bl      abort
        bl      abort
+       ret
 
 FUNCTION(jump_handle_swr):
 
 FUNCTION(jump_handle_swr):
+       /* w0 = address, w1 = data, w2 = cycles */
+       ldr     x3, [fp, #LO_mem_wtab]
+       mov     w4, w0, lsr #12
+       ldr     x3, [x3, w4, uxtw #3]
+       adds    x3, x3, x3
+       bcs     4f
+       add     x3, x0, x3
+       mov     w0, w2
+       tbz     x3, #1, 10f     // & 2
+       tbz     x3, #0, 2f      // & 1
+3:
+       strb    w1, [x3]
+       ret
+2:
+       strh    w1, [x3]
+       ret
+10:
+       tbz     x3, #0, 0f      // & 1
+1:
+       lsr     w2, w1, #8
+       strb    w1, [x3]
+       sturh   w2, [x3, #1]
+       ret
+0:
+       str     w1, [x3]
+       ret
+4:
+       mov     w0, w2          // todo
        bl      abort
        bl      abort
+       ret
 
 
index f2dbb86..9ce1f06 100644 (file)
@@ -35,7 +35,8 @@ static int sceBlock;
 #endif
 
 #include "new_dynarec_config.h"
 #endif
 
 #include "new_dynarec_config.h"
-#include "../psxhle.h" //emulator interface
+#include "../psxhle.h"
+#include "../psxinterpreter.h"
 #include "emu_if.h" //emulator interface
 
 #define noinline __attribute__((noinline,noclone))
 #include "emu_if.h" //emulator interface
 
 #define noinline __attribute__((noinline,noclone))
@@ -272,7 +273,7 @@ struct link_entry
 #define DJT_2 (void *)2l
 
 // asm linkage
 #define DJT_2 (void *)2l
 
 // asm linkage
-int new_recompile_block(int addr);
+int new_recompile_block(u_int addr);
 void *get_addr_ht(u_int vaddr);
 void invalidate_block(u_int block);
 void invalidate_addr(u_int addr);
 void *get_addr_ht(u_int vaddr);
 void invalidate_block(u_int block);
 void invalidate_addr(u_int addr);
@@ -284,9 +285,7 @@ void verify_code_ds();
 void cc_interrupt();
 void fp_exception();
 void fp_exception_ds();
 void cc_interrupt();
 void fp_exception();
 void fp_exception_ds();
-void jump_syscall_hle();
-void jump_hlecall();
-void jump_intcall();
+void jump_to_new_pc();
 void new_dyna_leave();
 
 // Needed by assembler
 void new_dyna_leave();
 
 // Needed by assembler
@@ -298,7 +297,7 @@ static void load_needed_regs(signed char i_regmap[],signed char next_regmap[]);
 static void load_regs_entry(int t);
 static void load_all_consts(signed char regmap[],u_int dirty,int i);
 
 static void load_regs_entry(int t);
 static void load_all_consts(signed char regmap[],u_int dirty,int i);
 
-static int verify_dirty(u_int *ptr);
+static int verify_dirty(const u_int *ptr);
 static int get_final_value(int hr, int i, int *value);
 static void add_stub(enum stub_type type, void *addr, void *retaddr,
   u_int a, uintptr_t b, uintptr_t c, u_int d, u_int e);
 static int get_final_value(int hr, int i, int *value);
 static void add_stub(enum stub_type type, void *addr, void *retaddr,
   u_int a, uintptr_t b, uintptr_t c, u_int d, u_int e);
@@ -832,13 +831,14 @@ static const struct {
   FUNCNAME(jump_handler_write16),
   FUNCNAME(jump_handler_write32),
   FUNCNAME(invalidate_addr),
   FUNCNAME(jump_handler_write16),
   FUNCNAME(jump_handler_write32),
   FUNCNAME(invalidate_addr),
-  FUNCNAME(verify_code),
-  FUNCNAME(jump_hlecall),
-  FUNCNAME(jump_syscall_hle),
+  FUNCNAME(jump_to_new_pc),
   FUNCNAME(new_dyna_leave),
   FUNCNAME(pcsx_mtc0),
   FUNCNAME(pcsx_mtc0_ds),
   FUNCNAME(do_insn_cmp),
   FUNCNAME(new_dyna_leave),
   FUNCNAME(pcsx_mtc0),
   FUNCNAME(pcsx_mtc0_ds),
   FUNCNAME(do_insn_cmp),
+#ifdef __arm__
+  FUNCNAME(verify_code),
+#endif
 };
 
 static const char *func_name(const void *a)
 };
 
 static const char *func_name(const void *a)
@@ -2361,11 +2361,44 @@ void shiftimm_assemble(int i,struct regstat *i_regs)
 }
 
 #ifndef shift_assemble
 }
 
 #ifndef shift_assemble
-void shift_assemble(int i,struct regstat *i_regs)
+static void shift_assemble(int i,struct regstat *i_regs)
 {
 {
-  printf("Need shift_assemble for this architecture.\n");
-  abort();
+  signed char s,t,shift;
+  if (rt1[i] == 0)
+    return;
+  assert(opcode2[i]<=0x07); // SLLV/SRLV/SRAV
+  t = get_reg(i_regs->regmap, rt1[i]);
+  s = get_reg(i_regs->regmap, rs1[i]);
+  shift = get_reg(i_regs->regmap, rs2[i]);
+  if (t < 0)
+    return;
+
+  if(rs1[i]==0)
+    emit_zeroreg(t);
+  else if(rs2[i]==0) {
+    assert(s>=0);
+    if(s!=t) emit_mov(s,t);
+  }
+  else {
+    host_tempreg_acquire();
+    emit_andimm(shift,31,HOST_TEMPREG);
+    switch(opcode2[i]) {
+    case 4: // SLLV
+      emit_shl(s,HOST_TEMPREG,t);
+      break;
+    case 6: // SRLV
+      emit_shr(s,HOST_TEMPREG,t);
+      break;
+    case 7: // SRAV
+      emit_sar(s,HOST_TEMPREG,t);
+      break;
+    default:
+      assert(0);
+    }
+    host_tempreg_release();
+  }
 }
 }
+
 #endif
 
 enum {
 #endif
 
 enum {
@@ -2430,7 +2463,7 @@ static void *emit_fastpath_cmp_jump(int i,int addr,int *addr_reg_override)
   else if(type==MTYPE_1F80) { // scratchpad
     if (psxH == (void *)0x1f800000) {
       host_tempreg_acquire();
   else if(type==MTYPE_1F80) { // scratchpad
     if (psxH == (void *)0x1f800000) {
       host_tempreg_acquire();
-      emit_addimm(addr,-0x1f800000,HOST_TEMPREG);
+      emit_xorimm(addr,0x1f800000,HOST_TEMPREG);
       emit_cmpimm(HOST_TEMPREG,0x1000);
       host_tempreg_release();
       jaddr=out;
       emit_cmpimm(HOST_TEMPREG,0x1000);
       host_tempreg_release();
       jaddr=out;
@@ -2631,10 +2664,86 @@ static void load_assemble(int i,struct regstat *i_regs)
 }
 
 #ifndef loadlr_assemble
 }
 
 #ifndef loadlr_assemble
-void loadlr_assemble(int i,struct regstat *i_regs)
+static void loadlr_assemble(int i,struct regstat *i_regs)
 {
 {
-  printf("Need loadlr_assemble for this architecture.\n");
-  abort();
+  int s,tl,temp,temp2,addr;
+  int offset;
+  void *jaddr=0;
+  int memtarget=0,c=0;
+  int fastio_reg_override=-1;
+  u_int hr,reglist=0;
+  tl=get_reg(i_regs->regmap,rt1[i]);
+  s=get_reg(i_regs->regmap,rs1[i]);
+  temp=get_reg(i_regs->regmap,-1);
+  temp2=get_reg(i_regs->regmap,FTEMP);
+  addr=get_reg(i_regs->regmap,AGEN1+(i&1));
+  assert(addr<0);
+  offset=imm[i];
+  for(hr=0;hr<HOST_REGS;hr++) {
+    if(i_regs->regmap[hr]>=0) reglist|=1<<hr;
+  }
+  reglist|=1<<temp;
+  if(offset||s<0||c) addr=temp2;
+  else addr=s;
+  if(s>=0) {
+    c=(i_regs->wasconst>>s)&1;
+    if(c) {
+      memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80000000+RAM_SIZE;
+    }
+  }
+  if(!c) {
+    emit_shlimm(addr,3,temp);
+    if (opcode[i]==0x22||opcode[i]==0x26) {
+      emit_andimm(addr,0xFFFFFFFC,temp2); // LWL/LWR
+    }else{
+      emit_andimm(addr,0xFFFFFFF8,temp2); // LDL/LDR
+    }
+    jaddr=emit_fastpath_cmp_jump(i,temp2,&fastio_reg_override);
+  }
+  else {
+    if(ram_offset&&memtarget) {
+      host_tempreg_acquire();
+      emit_addimm(temp2,ram_offset,HOST_TEMPREG);
+      fastio_reg_override=HOST_TEMPREG;
+    }
+    if (opcode[i]==0x22||opcode[i]==0x26) {
+      emit_movimm(((constmap[i][s]+offset)<<3)&24,temp); // LWL/LWR
+    }else{
+      emit_movimm(((constmap[i][s]+offset)<<3)&56,temp); // LDL/LDR
+    }
+  }
+  if (opcode[i]==0x22||opcode[i]==0x26) { // LWL/LWR
+    if(!c||memtarget) {
+      int a=temp2;
+      if(fastio_reg_override>=0) a=fastio_reg_override;
+      emit_readword_indexed(0,a,temp2);
+      if(fastio_reg_override==HOST_TEMPREG) host_tempreg_release();
+      if(jaddr) add_stub_r(LOADW_STUB,jaddr,out,i,temp2,i_regs,ccadj[i],reglist);
+    }
+    else
+      inline_readstub(LOADW_STUB,i,(constmap[i][s]+offset)&0xFFFFFFFC,i_regs->regmap,FTEMP,ccadj[i],reglist);
+    if(rt1[i]) {
+      assert(tl>=0);
+      emit_andimm(temp,24,temp);
+      if (opcode[i]==0x22) // LWL
+        emit_xorimm(temp,24,temp);
+      host_tempreg_acquire();
+      emit_movimm(-1,HOST_TEMPREG);
+      if (opcode[i]==0x26) {
+        emit_shr(temp2,temp,temp2);
+        emit_bic_lsr(tl,HOST_TEMPREG,temp,tl);
+      }else{
+        emit_shl(temp2,temp,temp2);
+        emit_bic_lsl(tl,HOST_TEMPREG,temp,tl);
+      }
+      host_tempreg_release();
+      emit_or(temp2,tl,tl);
+    }
+    //emit_storereg(rt1[i],tl); // DEBUG
+  }
+  if (opcode[i]==0x1A||opcode[i]==0x1B) { // LDL/LDR
+    assert(0);
+  }
 }
 #endif
 
 }
 #endif
 
@@ -2746,7 +2855,7 @@ void store_assemble(int i,struct regstat *i_regs)
   }
   // basic current block modification detection..
   // not looking back as that should be in mips cache already
   }
   // basic current block modification detection..
   // not looking back as that should be in mips cache already
-  // (note: doesn't seem to trigger, migh be broken)
+  // (see Spyro2 title->attract mode)
   if(c&&start+i*4<addr_val&&addr_val<start+slen*4) {
     SysPrintf("write to %08x hits block %08x, pc=%08x\n",addr_val,start,start+i*4);
     assert(i_regs->regmap==regs[i].regmap); // not delay slot
   if(c&&start+i*4<addr_val&&addr_val<start+slen*4) {
     SysPrintf("write to %08x hits block %08x, pc=%08x\n",addr_val,start,start+i*4);
     assert(i_regs->regmap==regs[i].regmap); // not delay slot
@@ -2762,7 +2871,7 @@ void store_assemble(int i,struct regstat *i_regs)
   }
 }
 
   }
 }
 
-void storelr_assemble(int i,struct regstat *i_regs)
+static void storelr_assemble(int i,struct regstat *i_regs)
 {
   int s,tl;
   int temp;
 {
   int s,tl;
   int temp;
@@ -2802,7 +2911,8 @@ void storelr_assemble(int i,struct regstat *i_regs)
       emit_jmp(0);
     }
   }
       emit_jmp(0);
     }
   }
-  emit_addimm_no_flags(ram_offset,temp);
+  if(ram_offset)
+    emit_addimm_no_flags(ram_offset,temp);
 
   if (opcode[i]==0x2C||opcode[i]==0x2D) { // SDL/SDR
     assert(0);
 
   if (opcode[i]==0x2C||opcode[i]==0x2D) { // SDL/SDR
     assert(0);
@@ -2819,15 +2929,11 @@ void storelr_assemble(int i,struct regstat *i_regs)
   if (opcode[i]==0x2A) { // SWL
     emit_writeword_indexed(tl,0,temp);
   }
   if (opcode[i]==0x2A) { // SWL
     emit_writeword_indexed(tl,0,temp);
   }
-  if (opcode[i]==0x2E) { // SWR
+  else if (opcode[i]==0x2E) { // SWR
     emit_writebyte_indexed(tl,3,temp);
   }
     emit_writebyte_indexed(tl,3,temp);
   }
-  if (opcode[i]==0x2C) { // SDL
-    assert(0);
-  }
-  if (opcode[i]==0x2D) { // SDR
+  else
     assert(0);
     assert(0);
-  }
   done0=out;
   emit_jmp(0);
   // 1
   done0=out;
   emit_jmp(0);
   // 1
@@ -2840,16 +2946,10 @@ void storelr_assemble(int i,struct regstat *i_regs)
     emit_writebyte_indexed(tl,1,temp);
     if(rs2[i]) emit_rorimm(tl,8,tl);
   }
     emit_writebyte_indexed(tl,1,temp);
     if(rs2[i]) emit_rorimm(tl,8,tl);
   }
-  if (opcode[i]==0x2E) { // SWR
+  else if (opcode[i]==0x2E) { // SWR
     // Write two lsb into two most significant bytes
     emit_writehword_indexed(tl,1,temp);
   }
     // Write two lsb into two most significant bytes
     emit_writehword_indexed(tl,1,temp);
   }
-  if (opcode[i]==0x2C) { // SDL
-    assert(0);
-  }
-  if (opcode[i]==0x2D) { // SDR
-    assert(0);
-  }
   done1=out;
   emit_jmp(0);
   // 2
   done1=out;
   emit_jmp(0);
   // 2
@@ -2863,19 +2963,13 @@ void storelr_assemble(int i,struct regstat *i_regs)
     emit_writehword_indexed(tl,-2,temp);
     if(rs2[i]) emit_rorimm(tl,16,tl);
   }
     emit_writehword_indexed(tl,-2,temp);
     if(rs2[i]) emit_rorimm(tl,16,tl);
   }
-  if (opcode[i]==0x2E) { // SWR
+  else if (opcode[i]==0x2E) { // SWR
     // Write 3 lsb into three most significant bytes
     emit_writebyte_indexed(tl,-1,temp);
     if(rs2[i]) emit_rorimm(tl,8,tl);
     emit_writehword_indexed(tl,0,temp);
     if(rs2[i]) emit_rorimm(tl,24,tl);
   }
     // Write 3 lsb into three most significant bytes
     emit_writebyte_indexed(tl,-1,temp);
     if(rs2[i]) emit_rorimm(tl,8,tl);
     emit_writehword_indexed(tl,0,temp);
     if(rs2[i]) emit_rorimm(tl,24,tl);
   }
-  if (opcode[i]==0x2C) { // SDL
-    assert(0);
-  }
-  if (opcode[i]==0x2D) { // SDR
-    assert(0);
-  }
   done2=out;
   emit_jmp(0);
   // 3
   done2=out;
   emit_jmp(0);
   // 3
@@ -2886,25 +2980,13 @@ void storelr_assemble(int i,struct regstat *i_regs)
     emit_writebyte_indexed(tl,-3,temp);
     if(rs2[i]) emit_rorimm(tl,8,tl);
   }
     emit_writebyte_indexed(tl,-3,temp);
     if(rs2[i]) emit_rorimm(tl,8,tl);
   }
-  if (opcode[i]==0x2E) { // SWR
+  else if (opcode[i]==0x2E) { // SWR
     // Write entire word
     emit_writeword_indexed(tl,-3,temp);
   }
     // Write entire word
     emit_writeword_indexed(tl,-3,temp);
   }
-  if (opcode[i]==0x2C) { // SDL
-    assert(0);
-  }
-  if (opcode[i]==0x2D) { // SDR
-    assert(0);
-  }
   set_jump_target(done0, out);
   set_jump_target(done1, out);
   set_jump_target(done2, out);
   set_jump_target(done0, out);
   set_jump_target(done1, out);
   set_jump_target(done2, out);
-  if (opcode[i]==0x2C) { // SDL
-    assert(0);
-  }
-  if (opcode[i]==0x2D) { // SDR
-    assert(0);
-  }
   if(!c||!memtarget)
     add_stub_r(STORELR_STUB,jaddr,out,i,temp,i_regs,ccadj[i],reglist);
   if(!(i_regs->waswritten&(1<<rs1[i]))&&!(new_dynarec_hacks&NDHACK_NO_SMC_CHECK)) {
   if(!c||!memtarget)
     add_stub_r(STORELR_STUB,jaddr,out,i,temp,i_regs,ccadj[i],reglist);
   if(!(i_regs->waswritten&(1<<rs1[i]))&&!(new_dynarec_hacks&NDHACK_NO_SMC_CHECK)) {
@@ -3089,22 +3171,7 @@ static void cop2_get_dreg(u_int copr,signed char tl,signed char temp)
       break;
     case 28:
     case 29:
       break;
     case 28:
     case 29:
-      emit_readword(&reg_cop2d[9],temp);
-      emit_testimm(temp,0x8000); // do we need this?
-      emit_andimm(temp,0xf80,temp);
-      emit_andne_imm(temp,0,temp);
-      emit_shrimm(temp,7,tl);
-      emit_readword(&reg_cop2d[10],temp);
-      emit_testimm(temp,0x8000);
-      emit_andimm(temp,0xf80,temp);
-      emit_andne_imm(temp,0,temp);
-      emit_orrshr_imm(temp,2,tl);
-      emit_readword(&reg_cop2d[11],temp);
-      emit_testimm(temp,0x8000);
-      emit_andimm(temp,0xf80,temp);
-      emit_andne_imm(temp,0,temp);
-      emit_orrshl_imm(temp,3,tl);
-      emit_writeword(tl,&reg_cop2d[copr]);
+      c2op_mfc2_29_assemble(tl,temp);
       break;
     default:
       emit_readword(&reg_cop2d[copr],tl);
       break;
     default:
       emit_readword(&reg_cop2d[copr],tl);
@@ -3136,8 +3203,7 @@ static void cop2_put_dreg(u_int copr,signed char sl,signed char temp)
       emit_writeword(sl,&reg_cop2d[28]);
       break;
     case 30:
       emit_writeword(sl,&reg_cop2d[28]);
       break;
     case 30:
-      emit_movs(sl,temp);
-      emit_mvnmi(temp,temp);
+      emit_xorsar_imm(sl,sl,31,temp);
 #if defined(HAVE_ARMV5) || defined(__aarch64__)
       emit_clz(temp,temp);
 #else
 #if defined(HAVE_ARMV5) || defined(__aarch64__)
       emit_clz(temp,temp);
 #else
@@ -3197,7 +3263,7 @@ static void c2ls_assemble(int i,struct regstat *i_regs)
   assert(ar>=0);
 
   if (opcode[i]==0x3a) { // SWC2
   assert(ar>=0);
 
   if (opcode[i]==0x3a) { // SWC2
-    cop2_get_dreg(copr,tl,HOST_TEMPREG);
+    cop2_get_dreg(copr,tl,-1);
     type=STOREW_STUB;
   }
   else
     type=STOREW_STUB;
   }
   else
@@ -3291,14 +3357,7 @@ static void cop2_assemble(int i,struct regstat *i_regs)
         emit_signextend16(sl,temp);
         break;
       case 31:
         emit_signextend16(sl,temp);
         break;
       case 31:
-        //value = value & 0x7ffff000;
-        //if (value & 0x7f87e000) value |= 0x80000000;
-        emit_shrimm(sl,12,temp);
-        emit_shlimm(temp,12,temp);
-        emit_testimm(temp,0x7f000000);
-        emit_testeqimm(temp,0x00870000);
-        emit_testeqimm(temp,0x0000e000);
-        emit_orrne_imm(temp,0x80000000,temp);
+        c2op_ctc2_31_assemble(sl,temp);
         break;
       default:
         temp=sl;
         break;
       default:
         temp=sl;
@@ -3309,6 +3368,90 @@ static void cop2_assemble(int i,struct regstat *i_regs)
   }
 }
 
   }
 }
 
+static void do_unalignedwritestub(int n)
+{
+  assem_debug("do_unalignedwritestub %x\n",start+stubs[n].a*4);
+  literal_pool(256);
+  set_jump_target(stubs[n].addr, out);
+
+  int i=stubs[n].a;
+  struct regstat *i_regs=(struct regstat *)stubs[n].c;
+  int addr=stubs[n].b;
+  u_int reglist=stubs[n].e;
+  signed char *i_regmap=i_regs->regmap;
+  int temp2=get_reg(i_regmap,FTEMP);
+  int rt;
+  rt=get_reg(i_regmap,rs2[i]);
+  assert(rt>=0);
+  assert(addr>=0);
+  assert(opcode[i]==0x2a||opcode[i]==0x2e); // SWL/SWR only implemented
+  reglist|=(1<<addr);
+  reglist&=~(1<<temp2);
+
+#if 1
+  // don't bother with it and call write handler
+  save_regs(reglist);
+  pass_args(addr,rt);
+  int cc=get_reg(i_regmap,CCREG);
+  if(cc<0)
+    emit_loadreg(CCREG,2);
+  emit_addimm(cc<0?2:cc,CLOCK_ADJUST((int)stubs[n].d+1),2);
+  emit_call((opcode[i]==0x2a?jump_handle_swl:jump_handle_swr));
+  emit_addimm(0,-CLOCK_ADJUST((int)stubs[n].d+1),cc<0?2:cc);
+  if(cc<0)
+    emit_storereg(CCREG,2);
+  restore_regs(reglist);
+  emit_jmp(stubs[n].retaddr); // return address
+#else
+  emit_andimm(addr,0xfffffffc,temp2);
+  emit_writeword(temp2,&address);
+
+  save_regs(reglist);
+  emit_shrimm(addr,16,1);
+  int cc=get_reg(i_regmap,CCREG);
+  if(cc<0) {
+    emit_loadreg(CCREG,2);
+  }
+  emit_movimm((u_int)readmem,0);
+  emit_addimm(cc<0?2:cc,2*stubs[n].d+2,2);
+  emit_call((int)&indirect_jump_indexed);
+  restore_regs(reglist);
+
+  emit_readword(&readmem_dword,temp2);
+  int temp=addr; //hmh
+  emit_shlimm(addr,3,temp);
+  emit_andimm(temp,24,temp);
+  if (opcode[i]==0x2a) // SWL
+    emit_xorimm(temp,24,temp);
+  emit_movimm(-1,HOST_TEMPREG);
+  if (opcode[i]==0x2a) { // SWL
+    emit_bic_lsr(temp2,HOST_TEMPREG,temp,temp2);
+    emit_orrshr(rt,temp,temp2);
+  }else{
+    emit_bic_lsl(temp2,HOST_TEMPREG,temp,temp2);
+    emit_orrshl(rt,temp,temp2);
+  }
+  emit_readword(&address,addr);
+  emit_writeword(temp2,&word);
+  //save_regs(reglist); // don't need to, no state changes
+  emit_shrimm(addr,16,1);
+  emit_movimm((u_int)writemem,0);
+  //emit_call((int)&indirect_jump_indexed);
+  emit_mov(15,14);
+  emit_readword_dualindexedx4(0,1,15);
+  emit_readword(&Count,HOST_TEMPREG);
+  emit_readword(&next_interupt,2);
+  emit_addimm(HOST_TEMPREG,-2*stubs[n].d-2,HOST_TEMPREG);
+  emit_writeword(2,&last_count);
+  emit_sub(HOST_TEMPREG,2,cc<0?HOST_TEMPREG:cc);
+  if(cc<0) {
+    emit_storereg(CCREG,HOST_TEMPREG);
+  }
+  restore_regs(reglist);
+  emit_jmp(stubs[n].retaddr); // return address
+#endif
+}
+
 #ifndef multdiv_assemble
 void multdiv_assemble(int i,struct regstat *i_regs)
 {
 #ifndef multdiv_assemble
 void multdiv_assemble(int i,struct regstat *i_regs)
 {
@@ -3333,43 +3476,44 @@ static void mov_assemble(int i,struct regstat *i_regs)
   }
 }
 
   }
 }
 
-static void syscall_assemble(int i,struct regstat *i_regs)
+// call interpreter, exception handler, things that change pc/regs/cycles ...
+static void call_c_cpu_handler(int i, const struct regstat *i_regs, u_int pc, void *func)
 {
   signed char ccreg=get_reg(i_regs->regmap,CCREG);
   assert(ccreg==HOST_CCREG);
   assert(!is_delayslot);
   (void)ccreg;
 {
   signed char ccreg=get_reg(i_regs->regmap,CCREG);
   assert(ccreg==HOST_CCREG);
   assert(!is_delayslot);
   (void)ccreg;
-  emit_movimm(start+i*4,EAX); // Get PC
-  emit_addimm(HOST_CCREG,CLOCK_ADJUST(ccadj[i]),HOST_CCREG); // CHECK: is this right?  There should probably be an extra cycle...
-  emit_jmp(jump_syscall_hle); // XXX
+
+  emit_movimm(pc,3); // Get PC
+  emit_readword(&last_count,2);
+  emit_writeword(3,&psxRegs.pc);
+  emit_addimm(HOST_CCREG,CLOCK_ADJUST(ccadj[i]),HOST_CCREG); // XXX
+  emit_add(2,HOST_CCREG,2);
+  emit_writeword(2,&psxRegs.cycle);
+  emit_call(func);
+  emit_jmp(jump_to_new_pc);
+}
+
+static void syscall_assemble(int i,struct regstat *i_regs)
+{
+  emit_movimm(0x20,0); // cause code
+  emit_movimm(0,1);    // not in delay slot
+  call_c_cpu_handler(i,i_regs,start+i*4,psxException);
 }
 
 static void hlecall_assemble(int i,struct regstat *i_regs)
 {
 }
 
 static void hlecall_assemble(int i,struct regstat *i_regs)
 {
-  extern void psxNULL();
-  signed char ccreg=get_reg(i_regs->regmap,CCREG);
-  assert(ccreg==HOST_CCREG);
-  assert(!is_delayslot);
-  (void)ccreg;
-  emit_movimm(start+i*4+4,0); // Get PC
+  void *hlefunc = psxNULL;
   uint32_t hleCode = source[i] & 0x03ffffff;
   uint32_t hleCode = source[i] & 0x03ffffff;
-  if (hleCode >= ARRAY_SIZE(psxHLEt))
-    emit_movimm((uintptr_t)psxNULL,1);
-  else
-    emit_movimm((uintptr_t)psxHLEt[hleCode],1);
-  emit_addimm(HOST_CCREG,CLOCK_ADJUST(ccadj[i]),HOST_CCREG); // XXX
-  emit_jmp(jump_hlecall);
+  if (hleCode < ARRAY_SIZE(psxHLEt))
+    hlefunc = psxHLEt[hleCode];
+
+  call_c_cpu_handler(i,i_regs,start+i*4+4,hlefunc);
 }
 
 static void intcall_assemble(int i,struct regstat *i_regs)
 {
 }
 
 static void intcall_assemble(int i,struct regstat *i_regs)
 {
-  signed char ccreg=get_reg(i_regs->regmap,CCREG);
-  assert(ccreg==HOST_CCREG);
-  assert(!is_delayslot);
-  (void)ccreg;
-  emit_movimm(start+i*4,0); // Get PC
-  emit_addimm(HOST_CCREG,CLOCK_ADJUST(ccadj[i]),HOST_CCREG);
-  emit_jmp(jump_intcall);
+  call_c_cpu_handler(i,i_regs,start+i*4,execI);
 }
 
 static void speculate_mov(int rs,int rt)
 }
 
 static void speculate_mov(int rs,int rt)
@@ -4075,7 +4219,7 @@ static int match_bt(signed char i_regmap[],uint64_t i_dirty,int addr)
 static void drc_dbg_emit_do_cmp(int i)
 {
   extern void do_insn_cmp();
 static void drc_dbg_emit_do_cmp(int i)
 {
   extern void do_insn_cmp();
-  extern int cycle;
+  //extern int cycle;
   u_int hr,reglist=0;
 
   for(hr=0;hr<HOST_REGS;hr++)
   u_int hr,reglist=0;
 
   for(hr=0;hr<HOST_REGS;hr++)
@@ -4087,6 +4231,7 @@ static void drc_dbg_emit_do_cmp(int i)
   //emit_readword(&cycle,0);
   //emit_addimm(0,2,0);
   //emit_writeword(0,&cycle);
   //emit_readword(&cycle,0);
   //emit_addimm(0,2,0);
   //emit_writeword(0,&cycle);
+  (void)get_reg2;
   restore_regs(reglist);
 }
 #else
   restore_regs(reglist);
 }
 #else
@@ -4667,6 +4812,9 @@ static void cjump_assemble(int i,struct regstat *i_regs)
   #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK
   if(i>(ba[i]-start)>>2) invert=1;
   #endif
   #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK
   if(i>(ba[i]-start)>>2) invert=1;
   #endif
+  #ifdef __aarch64__
+  invert=1; // because of near cond. branches
+  #endif
 
   if(ooo[i]) {
     s1l=get_reg(branch_regs[i].regmap,rs1[i]);
 
   if(ooo[i]) {
     s1l=get_reg(branch_regs[i].regmap,rs1[i]);
@@ -4956,6 +5104,9 @@ static void sjump_assemble(int i,struct regstat *i_regs)
   #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK
   if(i>(ba[i]-start)>>2) invert=1;
   #endif
   #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK
   if(i>(ba[i]-start)>>2) invert=1;
   #endif
+  #ifdef __aarch64__
+  invert=1; // because of near cond. branches
+  #endif
 
   //if(opcode2[i]>=0x10) return; // FIXME (BxxZAL)
   //assert(opcode2[i]<0x10||rs1[i]==0); // FIXME (BxxZAL)
 
   //if(opcode2[i]>=0x10) return; // FIXME (BxxZAL)
   //assert(opcode2[i]<0x10||rs1[i]==0); // FIXME (BxxZAL)
@@ -6484,7 +6635,7 @@ void new_dynarec_load_blocks(const void *save, int size)
   memcpy(&psxRegs.GPR, regs_save, sizeof(regs_save));
 }
 
   memcpy(&psxRegs.GPR, regs_save, sizeof(regs_save));
 }
 
-int new_recompile_block(int addr)
+int new_recompile_block(u_int addr)
 {
   u_int pagelimit = 0;
   u_int state_rflags = 0;
 {
   u_int pagelimit = 0;
   u_int state_rflags = 0;
@@ -7906,8 +8057,8 @@ int new_recompile_block(int addr)
             }
           }
         }
             }
           }
         }
-      }
-    }
+      } // if needed
+    } // for hr
   }
 
   /* Pass 5 - Pre-allocate registers */
   }
 
   /* Pass 5 - Pre-allocate registers */
@@ -8533,7 +8684,7 @@ int new_recompile_block(int addr)
   void *instr_addr0_override = NULL;
 
   if (start == 0x80030000) {
   void *instr_addr0_override = NULL;
 
   if (start == 0x80030000) {
-    // nasty hack for fastbios thing
+    // nasty hack for the fastbios thing
     // override block entry to this code
     instr_addr0_override = out;
     emit_movimm(start,0);
     // override block entry to this code
     instr_addr0_override = out;
     emit_movimm(start,0);
@@ -8543,7 +8694,12 @@ int new_recompile_block(int addr)
     emit_writeword(0,&pcaddr);
     emit_writeword(0,&address);
     emit_cmp(0,1);
     emit_writeword(0,&pcaddr);
     emit_writeword(0,&address);
     emit_cmp(0,1);
+    #ifdef __aarch64__
+    emit_jeq(out + 4*2);
+    emit_jmp(new_dyna_leave);
+    #else
     emit_jne(new_dyna_leave);
     emit_jne(new_dyna_leave);
+    #endif
   }
   for(i=0;i<slen;i++)
   {
   }
   for(i=0;i<slen;i++)
   {
index b63855a..e09af7a 100644 (file)
@@ -1,8 +1,8 @@
 diff --git a/libpcsxcore/new_dynarec/linkage_arm.S b/libpcsxcore/new_dynarec/linkage_arm.S
 diff --git a/libpcsxcore/new_dynarec/linkage_arm.S b/libpcsxcore/new_dynarec/linkage_arm.S
-index fcb4e1a..e2547c4 100644
+index bbc52c3..83c5b08 100644
 --- a/libpcsxcore/new_dynarec/linkage_arm.S
 +++ b/libpcsxcore/new_dynarec/linkage_arm.S
 --- a/libpcsxcore/new_dynarec/linkage_arm.S
 +++ b/libpcsxcore/new_dynarec/linkage_arm.S
-@@ -439,7 +439,7 @@ FUNCTION(cc_interrupt):
+@@ -437,7 +437,7 @@ FUNCTION(cc_interrupt):
        str     r1, [fp, #LO_pending_exception]
        and     r2, r2, r10, lsr #17
        add     r3, fp, #LO_restore_candidate
        str     r1, [fp, #LO_pending_exception]
        and     r2, r2, r10, lsr #17
        add     r3, fp, #LO_restore_candidate
@@ -11,34 +11,7 @@ index fcb4e1a..e2547c4 100644
  @@    str     r10, [fp, #LO_reg_cop0+36]      /* Count */
        ldr     r4, [r2, r3]
        mov     r10, lr
  @@    str     r10, [fp, #LO_reg_cop0+36]      /* Count */
        ldr     r4, [r2, r3]
        mov     r10, lr
-@@ -519,7 +519,7 @@ FUNCTION(jump_syscall_hle):
-       mov     r1, #0    /* in delay slot */
-       add     r2, r2, r10
-       mov     r0, #0x20 /* cause */
--      str     r2, [fp, #LO_cycle] /* PCSX cycle counter */
-+@@@   str     r2, [fp, #LO_cycle] /* PCSX cycle counter */
-       bl      psxException
-       /* note: psxException might do recursive recompiler call from it's HLE code,
-@@ -540,7 +540,7 @@ FUNCTION(jump_hlecall):
-       str     r0, [fp, #LO_pcaddr]
-       add     r2, r2, r10
-       adr     lr, pcsx_return
--      str     r2, [fp, #LO_cycle] /* PCSX cycle counter */
-+@@@   str     r2, [fp, #LO_cycle] /* PCSX cycle counter */
-       bx      r1
-       .size   jump_hlecall, .-jump_hlecall
-@@ -550,7 +550,7 @@ FUNCTION(jump_intcall):
-       str     r0, [fp, #LO_pcaddr]
-       add     r2, r2, r10
-       adr     lr, pcsx_return
--      str     r2, [fp, #LO_cycle] /* PCSX cycle counter */
-+@@@   str     r2, [fp, #LO_cycle] /* PCSX cycle counter */
-       b       execI
-       .size   jump_hlecall, .-jump_hlecall
-@@ -559,7 +559,7 @@ FUNCTION(new_dyna_leave):
+@@ -527,7 +527,7 @@ FUNCTION(new_dyna_leave):
        ldr     r0, [fp, #LO_last_count]
        add     r12, fp, #28
        add     r10, r0, r10
        ldr     r0, [fp, #LO_last_count]
        add     r12, fp, #28
        add     r10, r0, r10
@@ -47,7 +20,7 @@ index fcb4e1a..e2547c4 100644
        ldmfd   sp!, {r4, r5, r6, r7, r8, r9, sl, fp, ip, pc}
        .size   new_dyna_leave, .-new_dyna_leave
  
        ldmfd   sp!, {r4, r5, r6, r7, r8, r9, sl, fp, ip, pc}
        .size   new_dyna_leave, .-new_dyna_leave
  
-@@ -676,7 +676,7 @@ FUNCTION(new_dyna_start):
+@@ -644,7 +644,7 @@ FUNCTION(new_dyna_start):
        \readop r0, [r1, r3, lsl #\tab_shift]
  .endif
        movcc   pc, lr
        \readop r0, [r1, r3, lsl #\tab_shift]
  .endif
        movcc   pc, lr
@@ -56,7 +29,7 @@ index fcb4e1a..e2547c4 100644
        bx      r1
  .endm
  
        bx      r1
  .endm
  
-@@ -711,7 +711,7 @@ FUNCTION(jump_handler_read32):
+@@ -679,7 +679,7 @@ FUNCTION(jump_handler_read32):
        mov     r0, r1
        add     r2, r2, r12
        push    {r2, lr}
        mov     r0, r1
        add     r2, r2, r12
        push    {r2, lr}
@@ -65,7 +38,7 @@ index fcb4e1a..e2547c4 100644
        blx     r3
  
        ldr     r0, [fp, #LO_next_interupt]
        blx     r3
  
        ldr     r0, [fp, #LO_next_interupt]
-@@ -739,7 +739,7 @@ FUNCTION(jump_handler_write_h):
+@@ -707,7 +707,7 @@ FUNCTION(jump_handler_write_h):
        add     r2, r2, r12
        mov     r0, r1
        push    {r2, lr}
        add     r2, r2, r12
        mov     r0, r1
        push    {r2, lr}
@@ -75,10 +48,10 @@ index fcb4e1a..e2547c4 100644
  
        ldr     r0, [fp, #LO_next_interupt]
 diff --git a/libpcsxcore/new_dynarec/linkage_arm64.S b/libpcsxcore/new_dynarec/linkage_arm64.S
  
        ldr     r0, [fp, #LO_next_interupt]
 diff --git a/libpcsxcore/new_dynarec/linkage_arm64.S b/libpcsxcore/new_dynarec/linkage_arm64.S
-index 060ac48..e3007d3 100644
+index 698bd78..798abea 100644
 --- a/libpcsxcore/new_dynarec/linkage_arm64.S
 +++ b/libpcsxcore/new_dynarec/linkage_arm64.S
 --- a/libpcsxcore/new_dynarec/linkage_arm64.S
 +++ b/libpcsxcore/new_dynarec/linkage_arm64.S
-@@ -131,7 +131,7 @@ FUNCTION(cc_interrupt):
+@@ -119,7 +119,7 @@ FUNCTION(cc_interrupt):
        str     wzr, [rFP, #LO_pending_exception]
        and     w2, w2, rCC, lsr #17
        add     x3, rFP, #LO_restore_candidate
        str     wzr, [rFP, #LO_pending_exception]
        and     w2, w2, rCC, lsr #17
        add     x3, rFP, #LO_restore_candidate
@@ -87,7 +60,7 @@ index 060ac48..e3007d3 100644
  #     str     rCC, [rFP, #LO_reg_cop0+36]     /* Count */
        ldr     w19, [x3, w2, uxtw]
        mov     x21, lr
  #     str     rCC, [rFP, #LO_reg_cop0+36]     /* Count */
        ldr     w19, [x3, w2, uxtw]
        mov     x21, lr
-@@ -254,7 +254,7 @@ FUNCTION(new_dyna_start):
+@@ -227,7 +227,7 @@ FUNCTION(new_dyna_start):
  FUNCTION(new_dyna_leave):
        ldr     w0,  [rFP, #LO_last_count]
        add     rCC, rCC, w0
  FUNCTION(new_dyna_leave):
        ldr     w0,  [rFP, #LO_last_count]
        add     rCC, rCC, w0
@@ -96,7 +69,7 @@ index 060ac48..e3007d3 100644
        ldp     x19, x20, [sp, #16*1]
        ldp     x21, x22, [sp, #16*2]
        ldp     x23, x24, [sp, #16*3]
        ldp     x19, x20, [sp, #16*1]
        ldp     x21, x22, [sp, #16*2]
        ldp     x23, x24, [sp, #16*3]
-@@ -272,7 +272,7 @@ FUNCTION(new_dyna_leave):
+@@ -245,7 +245,7 @@ FUNCTION(new_dyna_leave):
        /* w0 = adddr/data, x1 = rhandler, w2 = cycles, x3 = whandler */
        ldr     w4, [rFP, #LO_last_count]
        add     w4, w4, w2
        /* w0 = adddr/data, x1 = rhandler, w2 = cycles, x3 = whandler */
        ldr     w4, [rFP, #LO_last_count]
        add     w4, w4, w2
@@ -106,10 +79,10 @@ index 060ac48..e3007d3 100644
  
  .macro memhandler_post
 diff --git a/libpcsxcore/new_dynarec/new_dynarec.c b/libpcsxcore/new_dynarec/new_dynarec.c
  
  .macro memhandler_post
 diff --git a/libpcsxcore/new_dynarec/new_dynarec.c b/libpcsxcore/new_dynarec/new_dynarec.c
-index e7b55b6..caa06d0 100644
+index 1452db3..8200e44 100644
 --- a/libpcsxcore/new_dynarec/new_dynarec.c
 +++ b/libpcsxcore/new_dynarec/new_dynarec.c
 --- a/libpcsxcore/new_dynarec/new_dynarec.c
 +++ b/libpcsxcore/new_dynarec/new_dynarec.c
-@@ -43,10 +43,10 @@ static int sceBlock;
+@@ -44,10 +44,10 @@ static int sceBlock;
  #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
  #endif
  
  #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
  #endif
  
@@ -123,7 +96,7 @@ index e7b55b6..caa06d0 100644
  #define inv_debug(...)
  
  #ifdef __i386__
  #define inv_debug(...)
  
  #ifdef __i386__
-@@ -424,6 +424,9 @@ static int doesnt_expire_soon(void *tcaddr)
+@@ -423,6 +423,9 @@ static int doesnt_expire_soon(void *tcaddr)
  // This is called from the recompiled JR/JALR instructions
  void noinline *get_addr(u_int vaddr)
  {
  // This is called from the recompiled JR/JALR instructions
  void noinline *get_addr(u_int vaddr)
  {
@@ -133,7 +106,7 @@ index e7b55b6..caa06d0 100644
    u_int page=get_page(vaddr);
    u_int vpage=get_vpage(vaddr);
    struct ll_entry *head;
    u_int page=get_page(vaddr);
    u_int vpage=get_vpage(vaddr);
    struct ll_entry *head;
-@@ -4221,13 +4224,15 @@ void do_cc(int i,signed char i_regmap[],int *adj,int addr,int taken,int invert)
+@@ -4393,13 +4396,15 @@ void do_cc(int i,signed char i_regmap[],int *adj,int addr,int taken,int invert)
      }
      emit_addimm_and_set_flags(cycles,HOST_CCREG);
      jaddr=out;
      }
      emit_addimm_and_set_flags(cycles,HOST_CCREG);
      jaddr=out;
@@ -151,7 +124,7 @@ index e7b55b6..caa06d0 100644
    }
    add_stub(CC_STUB,jaddr,idle?idle:out,(*adj==0||invert||idle)?0:(count+2),i,addr,taken,0);
  }
    }
    add_stub(CC_STUB,jaddr,idle?idle:out,(*adj==0||invert||idle)?0:(count+2),i,addr,taken,0);
  }
-@@ -4635,7 +4640,8 @@ static void rjump_assemble(int i,struct regstat *i_regs)
+@@ -4807,7 +4812,8 @@ static void rjump_assemble(int i,struct regstat *i_regs)
      // special case for RFE
      emit_jmp(0);
    else
      // special case for RFE
      emit_jmp(0);
    else
@@ -161,7 +134,7 @@ index e7b55b6..caa06d0 100644
    //load_regs_bt(branch_regs[i].regmap,branch_regs[i].dirty,-1);
    #ifdef USE_MINI_HT
    if(rs1[i]==31) {
    //load_regs_bt(branch_regs[i].regmap,branch_regs[i].dirty,-1);
    #ifdef USE_MINI_HT
    if(rs1[i]==31) {
-@@ -4737,7 +4743,8 @@ static void cjump_assemble(int i,struct regstat *i_regs)
+@@ -4912,7 +4918,8 @@ static void cjump_assemble(int i,struct regstat *i_regs)
      else if(nop) {
        emit_addimm_and_set_flags(CLOCK_ADJUST(ccadj[i]+2),cc);
        void *jaddr=out;
      else if(nop) {
        emit_addimm_and_set_flags(CLOCK_ADJUST(ccadj[i]+2),cc);
        void *jaddr=out;
@@ -171,7 +144,7 @@ index e7b55b6..caa06d0 100644
        add_stub(CC_STUB,jaddr,out,0,i,start+i*4+8,NOTTAKEN,0);
      }
      else {
        add_stub(CC_STUB,jaddr,out,0,i,start+i*4+8,NOTTAKEN,0);
      }
      else {
-@@ -4924,7 +4931,8 @@ static void cjump_assemble(int i,struct regstat *i_regs)
+@@ -5099,7 +5106,8 @@ static void cjump_assemble(int i,struct regstat *i_regs)
          emit_loadreg(CCREG,HOST_CCREG);
          emit_addimm_and_set_flags(CLOCK_ADJUST(ccadj[i]+2),HOST_CCREG);
          void *jaddr=out;
          emit_loadreg(CCREG,HOST_CCREG);
          emit_addimm_and_set_flags(CLOCK_ADJUST(ccadj[i]+2),HOST_CCREG);
          void *jaddr=out;
@@ -181,7 +154,7 @@ index e7b55b6..caa06d0 100644
          add_stub(CC_STUB,jaddr,out,0,i,start+i*4+8,NOTTAKEN,0);
          emit_storereg(CCREG,HOST_CCREG);
        }
          add_stub(CC_STUB,jaddr,out,0,i,start+i*4+8,NOTTAKEN,0);
          emit_storereg(CCREG,HOST_CCREG);
        }
-@@ -4933,7 +4941,8 @@ static void cjump_assemble(int i,struct regstat *i_regs)
+@@ -5108,7 +5116,8 @@ static void cjump_assemble(int i,struct regstat *i_regs)
          assert(cc==HOST_CCREG);
          emit_addimm_and_set_flags(CLOCK_ADJUST(ccadj[i]+2),cc);
          void *jaddr=out;
          assert(cc==HOST_CCREG);
          emit_addimm_and_set_flags(CLOCK_ADJUST(ccadj[i]+2),cc);
          void *jaddr=out;
@@ -191,7 +164,7 @@ index e7b55b6..caa06d0 100644
          add_stub(CC_STUB,jaddr,out,0,i,start+i*4+8,likely[i]?NULLDS:NOTTAKEN,0);
        }
      }
          add_stub(CC_STUB,jaddr,out,0,i,start+i*4+8,likely[i]?NULLDS:NOTTAKEN,0);
        }
      }
-@@ -5032,7 +5041,8 @@ static void sjump_assemble(int i,struct regstat *i_regs)
+@@ -5210,7 +5219,8 @@ static void sjump_assemble(int i,struct regstat *i_regs)
      else if(nevertaken) {
        emit_addimm_and_set_flags(CLOCK_ADJUST(ccadj[i]+2),cc);
        void *jaddr=out;
      else if(nevertaken) {
        emit_addimm_and_set_flags(CLOCK_ADJUST(ccadj[i]+2),cc);
        void *jaddr=out;
@@ -201,7 +174,7 @@ index e7b55b6..caa06d0 100644
        add_stub(CC_STUB,jaddr,out,0,i,start+i*4+8,NOTTAKEN,0);
      }
      else {
        add_stub(CC_STUB,jaddr,out,0,i,start+i*4+8,NOTTAKEN,0);
      }
      else {
-@@ -5188,7 +5198,8 @@ static void sjump_assemble(int i,struct regstat *i_regs)
+@@ -5366,7 +5376,8 @@ static void sjump_assemble(int i,struct regstat *i_regs)
          emit_loadreg(CCREG,HOST_CCREG);
          emit_addimm_and_set_flags(CLOCK_ADJUST(ccadj[i]+2),HOST_CCREG);
          void *jaddr=out;
          emit_loadreg(CCREG,HOST_CCREG);
          emit_addimm_and_set_flags(CLOCK_ADJUST(ccadj[i]+2),HOST_CCREG);
          void *jaddr=out;
@@ -211,7 +184,7 @@ index e7b55b6..caa06d0 100644
          add_stub(CC_STUB,jaddr,out,0,i,start+i*4+8,NOTTAKEN,0);
          emit_storereg(CCREG,HOST_CCREG);
        }
          add_stub(CC_STUB,jaddr,out,0,i,start+i*4+8,NOTTAKEN,0);
          emit_storereg(CCREG,HOST_CCREG);
        }
-@@ -5197,7 +5208,8 @@ static void sjump_assemble(int i,struct regstat *i_regs)
+@@ -5375,7 +5386,8 @@ static void sjump_assemble(int i,struct regstat *i_regs)
          assert(cc==HOST_CCREG);
          emit_addimm_and_set_flags(CLOCK_ADJUST(ccadj[i]+2),cc);
          void *jaddr=out;
          assert(cc==HOST_CCREG);
          emit_addimm_and_set_flags(CLOCK_ADJUST(ccadj[i]+2),cc);
          void *jaddr=out;
@@ -221,7 +194,7 @@ index e7b55b6..caa06d0 100644
          add_stub(CC_STUB,jaddr,out,0,i,start+i*4+8,likely[i]?NULLDS:NOTTAKEN,0);
        }
      }
          add_stub(CC_STUB,jaddr,out,0,i,start+i*4+8,likely[i]?NULLDS:NOTTAKEN,0);
        }
      }
-@@ -5685,7 +5697,7 @@ void unneeded_registers(int istart,int iend,int r)
+@@ -5863,7 +5875,7 @@ void unneeded_registers(int istart,int iend,int r)
      // R0 is always unneeded
      u|=1;
      // Save it
      // R0 is always unneeded
      u|=1;
      // Save it
@@ -230,7 +203,7 @@ index e7b55b6..caa06d0 100644
      gte_unneeded[i]=gte_u;
      /*
      printf("ur (%d,%d) %x: ",istart,iend,start+i*4);
      gte_unneeded[i]=gte_u;
      /*
      printf("ur (%d,%d) %x: ",istart,iend,start+i*4);
-@@ -8209,6 +8221,7 @@ int new_recompile_block(int addr)
+@@ -8387,6 +8399,7 @@ int new_recompile_block(int addr)
  
    // This allocates registers (if possible) one instruction prior
    // to use, which can avoid a load-use penalty on certain CPUs.
  
    // This allocates registers (if possible) one instruction prior
    // to use, which can avoid a load-use penalty on certain CPUs.
@@ -238,7 +211,7 @@ index e7b55b6..caa06d0 100644
    for(i=0;i<slen-1;i++)
    {
      if(!i||(itype[i-1]!=UJUMP&&itype[i-1]!=CJUMP&&itype[i-1]!=SJUMP&&itype[i-1]!=RJUMP))
    for(i=0;i<slen-1;i++)
    {
      if(!i||(itype[i-1]!=UJUMP&&itype[i-1]!=CJUMP&&itype[i-1]!=SJUMP&&itype[i-1]!=RJUMP))
-@@ -8365,6 +8378,7 @@ int new_recompile_block(int addr)
+@@ -8543,6 +8556,7 @@ int new_recompile_block(int addr)
        }
      }
    }
        }
      }
    }
@@ -246,7 +219,7 @@ index e7b55b6..caa06d0 100644
  
    /* Pass 6 - Optimize clean/dirty state */
    clean_registers(0,slen-1,1);
  
    /* Pass 6 - Optimize clean/dirty state */
    clean_registers(0,slen-1,1);
-@@ -8659,6 +8673,11 @@ int new_recompile_block(int addr)
+@@ -8842,6 +8856,11 @@ int new_recompile_block(int addr)
          case SPAN:
            pagespan_assemble(i,&regs[i]);break;
        }
          case SPAN:
            pagespan_assemble(i,&regs[i]);break;
        }
@@ -258,7 +231,7 @@ index e7b55b6..caa06d0 100644
        if(itype[i]==UJUMP||itype[i]==RJUMP||(source[i]>>16)==0x1000)
          literal_pool(1024);
        else
        if(itype[i]==UJUMP||itype[i]==RJUMP||(source[i]>>16)==0x1000)
          literal_pool(1024);
        else
-@@ -8767,7 +8786,7 @@ int new_recompile_block(int addr)
+@@ -8950,7 +8969,7 @@ int new_recompile_block(int addr)
      }
    }
    // External Branch Targets (jump_in)
      }
    }
    // External Branch Targets (jump_in)
@@ -267,7 +240,7 @@ index e7b55b6..caa06d0 100644
    for(i=0;i<slen;i++)
    {
      if(bt[i]||i==0)
    for(i=0;i<slen;i++)
    {
      if(bt[i]||i==0)
-@@ -8882,6 +8901,10 @@ int new_recompile_block(int addr)
+@@ -9065,6 +9084,10 @@ int new_recompile_block(int addr)
      }
      expirep=(expirep+1)&65535;
    }
      }
      expirep=(expirep+1)&65535;
    }
index 02e00a9..61c60ed 100644 (file)
@@ -26,6 +26,7 @@
 #include "gte.h"
 #include "psxhle.h"
 #include "debug.h"
 #include "gte.h"
 #include "psxhle.h"
 #include "debug.h"
+#include "psxinterpreter.h"
 
 static int branch = 0;
 static int branch2 = 0;
 
 static int branch = 0;
 static int branch2 = 0;
@@ -39,8 +40,6 @@ static u32 branchPC;
 #define debugI()
 #endif
 
 #define debugI()
 #endif
 
-void execI();
-
 // Subsets
 void (*psxBSC[64])();
 void (*psxSPC[64])();
 // Subsets
 void (*psxBSC[64])();
 void (*psxSPC[64])();
diff --git a/libpcsxcore/psxinterpreter.h b/libpcsxcore/psxinterpreter.h
new file mode 100644 (file)
index 0000000..1c97689
--- /dev/null
@@ -0,0 +1,4 @@
+
+// called by "new_dynarec"
+void execI();
+void psxNULL();