drc: merge Ari64's patch: 05_dont_write_r0
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / assem_arm.c
index 56b0c1a..ed89bb0 100644 (file)
@@ -914,6 +914,56 @@ void emit_zeroreg(int rt)
   output_w32(0xe3a00000|rd_rn_rm(rt,0,0));
 }
 
+void emit_loadlp(u_int imm,u_int rt)
+{
+  add_literal((int)out,imm);
+  assem_debug("ldr %s,pc+? [=%x]\n",regname[rt],imm);
+  output_w32(0xe5900000|rd_rn_rm(rt,15,0));
+}
+void emit_movw(u_int imm,u_int rt)
+{
+  assert(imm<65536);
+  assem_debug("movw %s,#%d (0x%x)\n",regname[rt],imm,imm);
+  output_w32(0xe3000000|rd_rn_rm(rt,0,0)|(imm&0xfff)|((imm<<4)&0xf0000));
+}
+void emit_movt(u_int imm,u_int rt)
+{
+  assem_debug("movt %s,#%d (0x%x)\n",regname[rt],imm&0xffff0000,imm&0xffff0000);
+  output_w32(0xe3400000|rd_rn_rm(rt,0,0)|((imm>>16)&0xfff)|((imm>>12)&0xf0000));
+}
+void emit_movimm(u_int imm,u_int rt)
+{
+  u_int armval;
+  if(genimm(imm,&armval)) {
+    assem_debug("mov %s,#%d\n",regname[rt],imm);
+    output_w32(0xe3a00000|rd_rn_rm(rt,0,0)|armval);
+  }else if(genimm(~imm,&armval)) {
+    assem_debug("mvn %s,#%d\n",regname[rt],imm);
+    output_w32(0xe3e00000|rd_rn_rm(rt,0,0)|armval);
+  }else if(imm<65536) {
+    #ifdef ARMv5_ONLY
+    assem_debug("mov %s,#%d\n",regname[rt],imm&0xFF00);
+    output_w32(0xe3a00000|rd_rn_imm_shift(rt,0,imm>>8,8));
+    assem_debug("add %s,%s,#%d\n",regname[rt],regname[rt],imm&0xFF);
+    output_w32(0xe2800000|rd_rn_imm_shift(rt,rt,imm&0xff,0));
+    #else
+    emit_movw(imm,rt);
+    #endif
+  }else{
+    #ifdef ARMv5_ONLY
+    emit_loadlp(imm,rt);
+    #else
+    emit_movw(imm&0x0000FFFF,rt);
+    emit_movt(imm&0xFFFF0000,rt);
+    #endif
+  }
+}
+void emit_pcreladdr(u_int rt)
+{
+  assem_debug("add %s,pc,#?\n",regname[rt]);
+  output_w32(0xe2800000|rd_rn_rm(rt,15,0));
+}
+
 void emit_loadreg(int r, int hr)
 {
 #ifdef FORCE32
@@ -1008,6 +1058,15 @@ void emit_or_and_set_flags(int rs1,int rs2,int rt)
   output_w32(0xe1900000|rd_rn_rm(rt,rs1,rs2));
 }
 
+void emit_orrshl_imm(u_int rs,u_int imm,u_int rt)
+{
+  assert(rs<16);
+  assert(rt<16);
+  assert(imm<32);
+  assem_debug("orr %s,%s,%s,lsl #%d\n",regname[rt],regname[rt],regname[rs],imm);
+  output_w32(0xe1800000|rd_rn_rm(rt,rt,rs)|(imm<<7));
+}
+
 void emit_orrshr_imm(u_int rs,u_int imm,u_int rt)
 {
   assert(rs<16);
@@ -1023,56 +1082,6 @@ void emit_xor(u_int rs1,u_int rs2,u_int rt)
   output_w32(0xe0200000|rd_rn_rm(rt,rs1,rs2));
 }
 
-void emit_loadlp(u_int imm,u_int rt)
-{
-  add_literal((int)out,imm);
-  assem_debug("ldr %s,pc+? [=%x]\n",regname[rt],imm);
-  output_w32(0xe5900000|rd_rn_rm(rt,15,0));
-}
-void emit_movw(u_int imm,u_int rt)
-{
-  assert(imm<65536);
-  assem_debug("movw %s,#%d (0x%x)\n",regname[rt],imm,imm);
-  output_w32(0xe3000000|rd_rn_rm(rt,0,0)|(imm&0xfff)|((imm<<4)&0xf0000));
-}
-void emit_movt(u_int imm,u_int rt)
-{
-  assem_debug("movt %s,#%d (0x%x)\n",regname[rt],imm&0xffff0000,imm&0xffff0000);
-  output_w32(0xe3400000|rd_rn_rm(rt,0,0)|((imm>>16)&0xfff)|((imm>>12)&0xf0000));
-}
-void emit_movimm(u_int imm,u_int rt)
-{
-  u_int armval;
-  if(genimm(imm,&armval)) {
-    assem_debug("mov %s,#%d\n",regname[rt],imm);
-    output_w32(0xe3a00000|rd_rn_rm(rt,0,0)|armval);
-  }else if(genimm(~imm,&armval)) {
-    assem_debug("mvn %s,#%d\n",regname[rt],imm);
-    output_w32(0xe3e00000|rd_rn_rm(rt,0,0)|armval);
-  }else if(imm<65536) {
-    #ifdef ARMv5_ONLY
-    assem_debug("mov %s,#%d\n",regname[rt],imm&0xFF00);
-    output_w32(0xe3a00000|rd_rn_imm_shift(rt,0,imm>>8,8));
-    assem_debug("add %s,%s,#%d\n",regname[rt],regname[rt],imm&0xFF);
-    output_w32(0xe2800000|rd_rn_imm_shift(rt,rt,imm&0xff,0));
-    #else
-    emit_movw(imm,rt);
-    #endif
-  }else{
-    #ifdef ARMv5_ONLY
-    emit_loadlp(imm,rt);
-    #else
-    emit_movw(imm&0x0000FFFF,rt);
-    emit_movt(imm&0xFFFF0000,rt);
-    #endif
-  }
-}
-void emit_pcreladdr(u_int rt)
-{
-  assem_debug("add %s,pc,#?\n",regname[rt]);
-  output_w32(0xe2800000|rd_rn_rm(rt,15,0));
-}
-
 void emit_addimm(u_int rs,int imm,u_int rt)
 {
   assert(rs<16);
@@ -1193,7 +1202,9 @@ void emit_sbb(int rs1,int rs2)
 void emit_andimm(int rs,int imm,int rt)
 {
   u_int armval;
-  if(genimm(imm,&armval)) {
+  if(imm==0) {
+    emit_zeroreg(rt);
+  }else if(genimm(imm,&armval)) {
     assem_debug("and %s,%s,#%d\n",regname[rt],regname[rs],imm);
     output_w32(0xe2000000|rd_rn_rm(rt,rs,0)|armval);
   }else if(genimm(~imm,&armval)) {
@@ -1227,7 +1238,9 @@ void emit_andimm(int rs,int imm,int rt)
 void emit_orimm(int rs,int imm,int rt)
 {
   u_int armval;
-  if(genimm(imm,&armval)) {
+  if(imm==0) {
+    if(rs!=rt) emit_mov(rs,rt);
+  }else if(genimm(imm,&armval)) {
     assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm);
     output_w32(0xe3800000|rd_rn_rm(rt,rs,0)|armval);
   }else{
@@ -1242,7 +1255,9 @@ void emit_orimm(int rs,int imm,int rt)
 void emit_xorimm(int rs,int imm,int rt)
 {
   u_int armval;
-  if(genimm(imm,&armval)) {
+  if(imm==0) {
+    if(rs!=rt) emit_mov(rs,rt);
+  }else if(genimm(imm,&armval)) {
     assem_debug("eor %s,%s,#%d\n",regname[rt],regname[rs],imm);
     output_w32(0xe2200000|rd_rn_rm(rt,rs,0)|armval);
   }else{
@@ -2570,9 +2585,7 @@ do_readstub(int n)
   }
   assert(rs>=0);
   if(addr<0) addr=rt;
-  if(addr<0)
-    // assume dummy read, no alloced reg
-    addr=get_reg(i_regmap,-1);
+  if(addr<0&&itype[i]!=C1LS&&itype[i]!=C2LS&&itype[i]!=LOADLR) addr=get_reg(i_regmap,-1);
   assert(addr>=0);
   int ftable=0;
   if(type==LOADB_STUB||type==LOADBU_STUB)
@@ -2650,8 +2663,8 @@ inline_readstub(int type, int i, u_int addr, signed char regmap[], int target, i
   int rs=get_reg(regmap,target);
   int rth=get_reg(regmap,target|64);
   int rt=get_reg(regmap,target);
+  if(rs<0) rs=get_reg(regmap,-1);
   assert(rs>=0);
-  assert(rt>=0);
   int ftable=0;
   if(type==LOADB_STUB||type==LOADBU_STUB)
     ftable=(int)readmemb;
@@ -2664,6 +2677,8 @@ inline_readstub(int type, int i, u_int addr, signed char regmap[], int target, i
     ftable=(int)readmemd;
 #endif
   assert(ftable!=0);
+  if(target==0)
+    emit_movimm(addr,rs);
   emit_writeword(rs,(int)&address);
   //emit_pusha();
   save_regs(reglist);
@@ -2697,19 +2712,21 @@ inline_readstub(int type, int i, u_int addr, signed char regmap[], int target, i
   }
   //emit_popa();
   restore_regs(reglist);
-  if(type==LOADB_STUB)
-    emit_movsbl((int)&readmem_dword,rt);
-  if(type==LOADBU_STUB)
-    emit_movzbl((int)&readmem_dword,rt);
-  if(type==LOADH_STUB)
-    emit_movswl((int)&readmem_dword,rt);
-  if(type==LOADHU_STUB)
-    emit_movzwl((int)&readmem_dword,rt);
-  if(type==LOADW_STUB)
-    emit_readword((int)&readmem_dword,rt);
-  if(type==LOADD_STUB) {
-    emit_readword((int)&readmem_dword,rt);
-    if(rth>=0) emit_readword(((int)&readmem_dword)+4,rth);
+  if(rt>=0) {
+    if(type==LOADB_STUB)
+      emit_movsbl((int)&readmem_dword,rt);
+    if(type==LOADBU_STUB)
+      emit_movzbl((int)&readmem_dword,rt);
+    if(type==LOADH_STUB)
+      emit_movswl((int)&readmem_dword,rt);
+    if(type==LOADHU_STUB)
+      emit_movzwl((int)&readmem_dword,rt);
+    if(type==LOADW_STUB)
+      emit_readword((int)&readmem_dword,rt);
+    if(type==LOADD_STUB) {
+      emit_readword((int)&readmem_dword,rt);
+      if(rth>=0) emit_readword(((int)&readmem_dword)+4,rth);
+    }
   }
 }
 
@@ -3259,57 +3276,60 @@ void loadlr_assemble_arm(int i,struct regstat *i_regs)
     memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80000000+RAM_SIZE;
     if(using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1;
   }
-  if(tl>=0) {
-    //assert(tl>=0);
-    //assert(rt1[i]);
-    if(!using_tlb) {
-      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
-        }
-        emit_cmpimm(addr,RAM_SIZE);
-        jaddr=(int)out;
-        emit_jno(0);
-      }
-      else {
-        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
-        }
-      }
-    }else{ // using tlb
-      int a;
-      if(c) {
-        a=-1;
-      }else if (opcode[i]==0x22||opcode[i]==0x26) {
-        a=0xFFFFFFFC; // LWL/LWR
+  if(!using_tlb) {
+    if(!c) {
+      #ifdef RAM_OFFSET
+      map=get_reg(i_regs->regmap,ROREG);
+      if(map<0) emit_loadreg(ROREG,map=HOST_TEMPREG);
+      #endif
+      emit_shlimm(addr,3,temp);
+      if (opcode[i]==0x22||opcode[i]==0x26) {
+        emit_andimm(addr,0xFFFFFFFC,temp2); // LWL/LWR
       }else{
-        a=0xFFFFFFF8; // LDL/LDR
+        emit_andimm(addr,0xFFFFFFF8,temp2); // LDL/LDR
       }
-      map=get_reg(i_regs->regmap,TLREG);
-      assert(map>=0);
-      map=do_tlb_r(addr,temp2,map,0,a,c?-1:temp,c,constmap[i][s]+offset);
-      if(c) {
-        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
-        }
+      emit_cmpimm(addr,RAM_SIZE);
+      jaddr=(int)out;
+      emit_jno(0);
+    }
+    else {
+      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
       }
-      do_tlb_r_branch(map,c,constmap[i][s]+offset,&jaddr);
     }
-    if (opcode[i]==0x22||opcode[i]==0x26) { // LWL/LWR
-      if(!c||memtarget) {
-        //emit_readword_indexed((int)rdram-0x80000000,temp2,temp2);
-        emit_readword_indexed_tlb((int)rdram-0x80000000,temp2,map,temp2);
-        if(jaddr) add_stub(LOADW_STUB,jaddr,(int)out,i,temp2,(int)i_regs,ccadj[i],reglist);
+  }else{ // using tlb
+    int a;
+    if(c) {
+      a=-1;
+    }else if (opcode[i]==0x22||opcode[i]==0x26) {
+      a=0xFFFFFFFC; // LWL/LWR
+    }else{
+      a=0xFFFFFFF8; // LDL/LDR
+    }
+    map=get_reg(i_regs->regmap,TLREG);
+    assert(map>=0);
+    map=do_tlb_r(addr,temp2,map,0,a,c?-1:temp,c,constmap[i][s]+offset);
+    if(c) {
+      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
       }
-      else
-        inline_readstub(LOADW_STUB,i,(constmap[i][s]+offset)&0xFFFFFFFC,i_regs->regmap,FTEMP,ccadj[i],reglist);
+    }
+    do_tlb_r_branch(map,c,constmap[i][s]+offset,&jaddr);
+  }
+  if (opcode[i]==0x22||opcode[i]==0x26) { // LWL/LWR
+    if(!c||memtarget) {
+      //emit_readword_indexed((int)rdram-0x80000000,temp2,temp2);
+      emit_readword_indexed_tlb(0,temp2,map,temp2);
+      if(jaddr) add_stub(LOADW_STUB,jaddr,(int)out,i,temp2,(int)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
@@ -3326,19 +3346,23 @@ void loadlr_assemble_arm(int i,struct regstat *i_regs)
         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
-      // FIXME: little endian
-      int temp2h=get_reg(i_regs->regmap,FTEMP|64);
-      if(!c||memtarget) {
-        //if(th>=0) emit_readword_indexed((int)rdram-0x80000000,temp2,temp2h);
-        //emit_readword_indexed((int)rdram-0x7FFFFFFC,temp2,temp2);
-        emit_readdword_indexed_tlb((int)rdram-0x80000000,temp2,map,temp2h,temp2);
-        if(jaddr) add_stub(LOADD_STUB,jaddr,(int)out,i,temp2,(int)i_regs,ccadj[i],reglist);
-      }
-      else
-        inline_readstub(LOADD_STUB,i,(constmap[i][s]+offset)&0xFFFFFFF8,i_regs->regmap,FTEMP,ccadj[i],reglist);
+    //emit_storereg(rt1[i],tl); // DEBUG
+  }
+  if (opcode[i]==0x1A||opcode[i]==0x1B) { // LDL/LDR
+    // FIXME: little endian
+    int temp2h=get_reg(i_regs->regmap,FTEMP|64);
+    if(!c||memtarget) {
+      //if(th>=0) emit_readword_indexed((int)rdram-0x80000000,temp2,temp2h);
+      //emit_readword_indexed((int)rdram-0x7FFFFFFC,temp2,temp2);
+      emit_readdword_indexed_tlb(0,temp2,map,temp2h,temp2);
+      if(jaddr) add_stub(LOADD_STUB,jaddr,(int)out,i,temp2,(int)i_regs,ccadj[i],reglist);
+    }
+    else
+      inline_readstub(LOADD_STUB,i,(constmap[i][s]+offset)&0xFFFFFFF8,i_regs->regmap,FTEMP,ccadj[i],reglist);
+    if(rt1[i]) {
+      assert(th>=0);
+      assert(tl>=0);
       emit_testimm(temp,32);
       emit_andimm(temp,24,temp);
       if (opcode[i]==0x1A) { // LDL
@@ -3540,25 +3564,22 @@ static void cop2_get_dreg(u_int copr,signed char tl,signed char temp)
       emit_writeword(tl,(int)&reg_cop2d[copr]);
       break;
     case 28:
-    case 30:
-      emit_movimm(0,tl);
-      break;
     case 29:
       emit_readword((int)&reg_cop2d[9],temp);
       emit_testimm(temp,0x8000); // do we need this?
       emit_andimm(temp,0xf80,temp);
       emit_andne_imm(temp,0,temp);
-      emit_shr(temp,7,tl);
+      emit_shrimm(temp,7,tl);
       emit_readword((int)&reg_cop2d[10],temp);
       emit_testimm(temp,0x8000);
       emit_andimm(temp,0xf80,temp);
       emit_andne_imm(temp,0,temp);
-      emit_orrshr(temp,2,tl);
+      emit_orrshr_imm(temp,2,tl);
       emit_readword((int)&reg_cop2d[11],temp);
       emit_testimm(temp,0x8000);
       emit_andimm(temp,0xf80,temp);
       emit_andne_imm(temp,0,temp);
-      emit_orrshl(temp,3,tl);
+      emit_orrshl_imm(temp,3,tl);
       emit_writeword(tl,(int)&reg_cop2d[copr]);
       break;
     default:
@@ -3580,13 +3601,13 @@ static void cop2_put_dreg(u_int copr,signed char sl,signed char temp)
       break;
     case 28:
       emit_andimm(sl,0x001f,temp);
-      emit_shl(temp,7,temp);
+      emit_shlimm(temp,7,temp);
       emit_writeword(temp,(int)&reg_cop2d[9]);
       emit_andimm(sl,0x03e0,temp);
-      emit_shl(temp,2,temp);
+      emit_shlimm(temp,2,temp);
       emit_writeword(temp,(int)&reg_cop2d[10]);
       emit_andimm(sl,0x7c00,temp);
-      emit_shr(temp,3,temp);
+      emit_shrimm(temp,3,temp);
       emit_writeword(temp,(int)&reg_cop2d[11]);
       emit_writeword(sl,(int)&reg_cop2d[28]);
       break;
@@ -3597,8 +3618,6 @@ static void cop2_put_dreg(u_int copr,signed char sl,signed char temp)
       emit_writeword(sl,(int)&reg_cop2d[30]);
       emit_writeword(temp,(int)&reg_cop2d[31]);
       break;
-    case 7:
-    case 29:
     case 31:
       break;
     default: