drc: merge Ari64's patch: 07_clear_cache
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / assem_arm.c
index c950585..0153bfc 100644 (file)
@@ -68,6 +68,8 @@ const u_int jump_vaddr_reg[16] = {
 
 #include "fpu.h"
 
+unsigned int needs_clear_cache[1<<(TARGET_SIZE_2-17)];
+
 /* Linker */
 
 void set_jump_target(int addr,u_int target)
@@ -914,6 +916,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
@@ -1032,56 +1084,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);
@@ -1202,7 +1204,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)) {
@@ -1236,7 +1240,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{
@@ -1251,7 +1257,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{
@@ -2579,9 +2587,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)
@@ -2659,10 +2665,7 @@ 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);
-  // allow for PCSX dummy reads
-  //assert(rt>=0);
-  if(rs<0)
-    rs=get_reg(regmap,-1);
+  if(rs<0) rs=get_reg(regmap,-1);
   assert(rs>=0);
   int ftable=0;
   if(type==LOADB_STUB||type==LOADBU_STUB)
@@ -3275,57 +3278,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
@@ -3342,19 +3348,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
@@ -4776,6 +4786,38 @@ void wb_invalidate_arm(signed char pre[],signed char entry[],uint64_t dirty,uint
 #define wb_invalidate wb_invalidate_arm
 */
 
+// Clearing the cache is rather slow on ARM Linux, so mark the areas
+// that need to be cleared, and then only clear these areas once.
+void do_clear_cache()
+{
+  int i,j;
+  for (i=0;i<(1<<(TARGET_SIZE_2-17));i++)
+  {
+    u_int bitmap=needs_clear_cache[i];
+    if(bitmap) {
+      u_int start,end;
+      for(j=0;j<32;j++) 
+      {
+        if(bitmap&(1<<j)) {
+          start=BASE_ADDR+i*131072+j*4096;
+          end=start+4095;
+          j++;
+          while(j<32) {
+            if(bitmap&(1<<j)) {
+              end+=4096;
+              j++;
+            }else{
+              __clear_cache((void *)start,(void *)end);
+              break;
+            }
+          }
+        }
+      }
+      needs_clear_cache[i]=0;
+    }
+  }
+}
+
 // CPU-architecture-specific initialization
 void arch_init() {
 #ifndef DISABLE_COP1