drc: do modification check in smaller than page granularity
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / new_dynarec.c
index 893f258..8ab3128 100644 (file)
@@ -371,6 +371,7 @@ void *get_addr(u_int vaddr)
       if(verify_dirty(head->addr)) {
         //printf("restore candidate: %x (%d) d=%d\n",vaddr,page,invalid_code[vaddr>>12]);
         invalid_code[vaddr>>12]=0;
+        inv_code_start=inv_code_end=~0;
         memory_map[vaddr>>12]|=0x40000000;
         if(vpage<2048) {
 #ifndef DISABLE_TLB
@@ -463,6 +464,7 @@ void *get_addr_32(u_int vaddr,u_int flags)
       if(verify_dirty(head->addr)) {
         //printf("restore candidate: %x (%d) d=%d\n",vaddr,page,invalid_code[vaddr>>12]);
         invalid_code[vaddr>>12]=0;
+        inv_code_start=inv_code_end=~0;
         memory_map[vaddr>>12]|=0x40000000;
         if(vpage<2048) {
 #ifndef DISABLE_TLB
@@ -1127,39 +1129,10 @@ void invalidate_page(u_int page)
     head=next;
   }
 }
-void invalidate_block(u_int block)
+
+static void invalidate_block_range(u_int block, u_int first, u_int last)
 {
   u_int page=get_page(block<<12);
-  u_int vpage=get_vpage(block<<12);
-  inv_debug("INVALIDATE: %x (%d)\n",block<<12,page);
-  //inv_debug("invalid_code[block]=%d\n",invalid_code[block]);
-  u_int first,last;
-  first=last=page;
-  struct ll_entry *head;
-  head=jump_dirty[vpage];
-  //printf("page=%d vpage=%d\n",page,vpage);
-  while(head!=NULL) {
-    u_int start,end;
-    if(vpage>2047||(head->vaddr>>12)==block) { // Ignore vaddr hash collision
-      get_bounds((int)head->addr,&start,&end);
-      //printf("start: %x end: %x\n",start,end);
-      if(page<2048&&start>=0x80000000&&end<0x80000000+RAM_SIZE) {
-        if(((start-(u_int)rdram)>>12)<=page&&((end-1-(u_int)rdram)>>12)>=page) {
-          if((((start-(u_int)rdram)>>12)&2047)<first) first=((start-(u_int)rdram)>>12)&2047;
-          if((((end-1-(u_int)rdram)>>12)&2047)>last) last=((end-1-(u_int)rdram)>>12)&2047;
-        }
-      }
-#ifndef DISABLE_TLB
-      if(page<2048&&(signed int)start>=(signed int)0xC0000000&&(signed int)end>=(signed int)0xC0000000) {
-        if(((start+memory_map[start>>12]-(u_int)rdram)>>12)<=page&&((end-1+memory_map[(end-1)>>12]-(u_int)rdram)>>12)>=page) {
-          if((((start+memory_map[start>>12]-(u_int)rdram)>>12)&2047)<first) first=((start+memory_map[start>>12]-(u_int)rdram)>>12)&2047;
-          if((((end-1+memory_map[(end-1)>>12]-(u_int)rdram)>>12)&2047)>last) last=((end-1+memory_map[(end-1)>>12]-(u_int)rdram)>>12)&2047;
-        }
-      }
-#endif
-    }
-    head=head->next;
-  }
   //printf("first=%d last=%d\n",first,last);
   invalidate_page(page);
   assert(first+5>page); // NB: this assumes MAXBLOCK<=4096 (4 pages)
@@ -1178,9 +1151,6 @@ void invalidate_block(u_int block)
   
   // Don't trap writes
   invalid_code[block]=1;
-#ifdef PCSX
-  invalid_code[((u_int)0x80000000>>12)|page]=1;
-#endif
 #ifndef DISABLE_TLB
   // If there is a valid TLB entry for this page, remove write protect
   if(tlb_LUT_w[block]) {
@@ -1198,10 +1168,98 @@ void invalidate_block(u_int block)
   memset(mini_ht,-1,sizeof(mini_ht));
   #endif
 }
+
+void invalidate_block(u_int block)
+{
+  u_int page=get_page(block<<12);
+  u_int vpage=get_vpage(block<<12);
+  inv_debug("INVALIDATE: %x (%d)\n",block<<12,page);
+  //inv_debug("invalid_code[block]=%d\n",invalid_code[block]);
+  u_int first,last;
+  first=last=page;
+  struct ll_entry *head;
+  head=jump_dirty[vpage];
+  //printf("page=%d vpage=%d\n",page,vpage);
+  while(head!=NULL) {
+    u_int start,end;
+    if(vpage>2047||(head->vaddr>>12)==block) { // Ignore vaddr hash collision
+      get_bounds((int)head->addr,&start,&end);
+      //printf("start: %x end: %x\n",start,end);
+      if(page<2048&&start>=0x80000000&&end<0x80000000+RAM_SIZE) {
+        if(((start-(u_int)rdram)>>12)<=page&&((end-1-(u_int)rdram)>>12)>=page) {
+          if((((start-(u_int)rdram)>>12)&2047)<first) first=((start-(u_int)rdram)>>12)&2047;
+          if((((end-1-(u_int)rdram)>>12)&2047)>last) last=((end-1-(u_int)rdram)>>12)&2047;
+        }
+      }
+#ifndef DISABLE_TLB
+      if(page<2048&&(signed int)start>=(signed int)0xC0000000&&(signed int)end>=(signed int)0xC0000000) {
+        if(((start+memory_map[start>>12]-(u_int)rdram)>>12)<=page&&((end-1+memory_map[(end-1)>>12]-(u_int)rdram)>>12)>=page) {
+          if((((start+memory_map[start>>12]-(u_int)rdram)>>12)&2047)<first) first=((start+memory_map[start>>12]-(u_int)rdram)>>12)&2047;
+          if((((end-1+memory_map[(end-1)>>12]-(u_int)rdram)>>12)&2047)>last) last=((end-1+memory_map[(end-1)>>12]-(u_int)rdram)>>12)&2047;
+        }
+      }
+#endif
+    }
+    head=head->next;
+  }
+  invalidate_block_range(block,first,last);
+}
+
 void invalidate_addr(u_int addr)
 {
+#ifdef PCSX
+  //static int rhits;
+  // this check is done by the caller
+  //if (inv_code_start<=addr&&addr<=inv_code_end) { rhits++; return; }
+  u_int page=get_page(addr);
+  if(page<2048) { // RAM
+    struct ll_entry *head;
+    u_int addr_min=~0, addr_max=0;
+    int mask=RAM_SIZE-1;
+    int pg1;
+    inv_code_start=addr&~0xfff;
+    inv_code_end=addr|0xfff;
+    pg1=page;
+    if (pg1>0) {
+      // must check previous page too because of spans..
+      pg1--;
+      inv_code_start-=0x1000;
+    }
+    for(;pg1<=page;pg1++) {
+      for(head=jump_dirty[pg1];head!=NULL;head=head->next) {
+        u_int start,end;
+        get_bounds((int)head->addr,&start,&end);
+        if((start&mask)<=(addr&mask)&&(addr&mask)<(end&mask)) {
+          if(start<addr_min) addr_min=start;
+          if(end>addr_max) addr_max=end;
+        }
+        else if(addr<start) {
+          if(start<inv_code_end)
+            inv_code_end=start-1;
+        }
+        else {
+          if(end>inv_code_start)
+            inv_code_start=end;
+        }
+      }
+    }
+    if (addr_min!=~0) {
+      inv_debug("INV ADDR: %08x hit %08x-%08x\n", addr, addr_min, addr_max);
+      inv_code_start=inv_code_end=~0;
+      invalidate_block_range(addr>>12,(addr_min&mask)>>12,(addr_max&mask)>>12);
+      return;
+    }
+    else {
+      inv_debug("INV ADDR: %08x miss, inv %08x-%08x, sk %d\n", addr, inv_code_start, inv_code_end, 0);//rhits);
+    }
+    //rhits=0;
+    if(page!=0) // FIXME: don't know what's up with page 0 (Klonoa)
+      return;
+  }
+#endif
   invalidate_block(addr>>12);
 }
+
 // This is called when loading a save state.
 // Anything could have changed, so invalidate everything.
 void invalidate_all_pages()
@@ -1240,6 +1298,8 @@ void add_link(u_int vaddr,void *src)
 {
   u_int page=get_page(vaddr);
   inv_debug("add_link: %x -> %x (%d)\n",(int)src,vaddr,page);
+  int *ptr=(int *)(src+4);
+  assert((*ptr&0x0fff0000)==0x059f0000);
   ll_add(jump_out+page,vaddr,src);
   //int ptr=get_pointer(src);
   //inv_debug("add_link: Pointer is to %x\n",(int)ptr);
@@ -5136,9 +5196,45 @@ add_to_linker(int addr,int target,int ext)
   linkcount++;
 }
 
+static void ujump_assemble_write_ra(int i)
+{
+  int rt;
+  unsigned int return_address;
+  rt=get_reg(branch_regs[i].regmap,31);
+  assem_debug("branch(%d): eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d\n",i,branch_regs[i].regmap[0],branch_regs[i].regmap[1],branch_regs[i].regmap[2],branch_regs[i].regmap[3],branch_regs[i].regmap[5],branch_regs[i].regmap[6],branch_regs[i].regmap[7]);
+  //assert(rt>=0);
+  return_address=start+i*4+8;
+  if(rt>=0) {
+    #ifdef USE_MINI_HT
+    if(internal_branch(branch_regs[i].is32,return_address)&&rt1[i+1]!=31) {
+      int temp=-1; // note: must be ds-safe
+      #ifdef HOST_TEMPREG
+      temp=HOST_TEMPREG;
+      #endif
+      if(temp>=0) do_miniht_insert(return_address,rt,temp);
+      else emit_movimm(return_address,rt);
+    }
+    else
+    #endif
+    {
+      #ifdef REG_PREFETCH
+      if(temp>=0) 
+      {
+        if(i_regmap[temp]!=PTEMP) emit_movimm((int)hash_table[((return_address>>16)^return_address)&0xFFFF],temp);
+      }
+      #endif
+      emit_movimm(return_address,rt); // PC into link register
+      #ifdef IMM_PREFETCH
+      emit_prefetch(hash_table[((return_address>>16)^return_address)&0xFFFF]);
+      #endif
+    }
+  }
+}
+
 void ujump_assemble(int i,struct regstat *i_regs)
 {
   signed char *i_regmap=i_regs->regmap;
+  int ra_done=0;
   if(i==(ba[i]-start)>>2) assem_debug("idle loop\n");
   address_generation(i+1,i_regs,regs[i].regmap_entry);
   #ifdef REG_PREFETCH
@@ -5150,38 +5246,9 @@ void ujump_assemble(int i,struct regstat *i_regs)
     if(i_regmap[temp]==PTEMP) emit_movimm((int)hash_table[((return_address>>16)^return_address)&0xFFFF],temp);
   }
   #endif
-  if(rt1[i]==31) {
-    int rt;
-    unsigned int return_address;
-    rt=get_reg(branch_regs[i].regmap,31);
-    assem_debug("branch(%d): eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d\n",i,branch_regs[i].regmap[0],branch_regs[i].regmap[1],branch_regs[i].regmap[2],branch_regs[i].regmap[3],branch_regs[i].regmap[5],branch_regs[i].regmap[6],branch_regs[i].regmap[7]);
-    //assert(rt>=0);
-    return_address=start+i*4+8;
-    if(rt>=0) {
-      #ifdef USE_MINI_HT
-      if(internal_branch(branch_regs[i].is32,return_address)&&rt1[i+1]!=31) {
-        int temp=-1; // note: must be ds-safe
-        #ifdef HOST_TEMPREG
-        temp=HOST_TEMPREG;
-        #endif
-        if(temp>=0) do_miniht_insert(return_address,rt,temp);
-        else emit_movimm(return_address,rt);
-      }
-      else
-      #endif
-      {
-        #ifdef REG_PREFETCH
-        if(temp>=0) 
-        {
-          if(i_regmap[temp]!=PTEMP) emit_movimm((int)hash_table[((return_address>>16)^return_address)&0xFFFF],temp);
-        }
-        #endif
-        emit_movimm(return_address,rt); // PC into link register
-        #ifdef IMM_PREFETCH
-        emit_prefetch(hash_table[((return_address>>16)^return_address)&0xFFFF]);
-        #endif
-      }
-    }
+  if(rt1[i]==31&&(rt1[i]==rs1[i+1]||rt1[i]==rs2[i+1])) {
+    ujump_assemble_write_ra(i); // writeback ra for DS
+    ra_done=1;
   }
   ds_assemble(i+1,i_regs);
   uint64_t bc_unneeded=branch_regs[i].u;
@@ -5191,6 +5258,8 @@ void ujump_assemble(int i,struct regstat *i_regs)
   wb_invalidate(regs[i].regmap,branch_regs[i].regmap,regs[i].dirty,regs[i].is32,
                 bc_unneeded,bc_unneeded_upper);
   load_regs(regs[i].regmap,branch_regs[i].regmap,regs[i].was32,CCREG,CCREG);
+  if(!ra_done&&rt1[i]==31)
+    ujump_assemble_write_ra(i);
   int cc,adj;
   cc=get_reg(branch_regs[i].regmap,CCREG);
   assert(cc==HOST_CCREG);
@@ -5214,11 +5283,33 @@ void ujump_assemble(int i,struct regstat *i_regs)
   }
 }
 
+static void rjump_assemble_write_ra(int i)
+{
+  int rt,return_address;
+  assert(rt1[i+1]!=rt1[i]);
+  assert(rt2[i+1]!=rt1[i]);
+  rt=get_reg(branch_regs[i].regmap,rt1[i]);
+  assem_debug("branch(%d): eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d\n",i,branch_regs[i].regmap[0],branch_regs[i].regmap[1],branch_regs[i].regmap[2],branch_regs[i].regmap[3],branch_regs[i].regmap[5],branch_regs[i].regmap[6],branch_regs[i].regmap[7]);
+  assert(rt>=0);
+  return_address=start+i*4+8;
+  #ifdef REG_PREFETCH
+  if(temp>=0) 
+  {
+    if(i_regmap[temp]!=PTEMP) emit_movimm((int)hash_table[((return_address>>16)^return_address)&0xFFFF],temp);
+  }
+  #endif
+  emit_movimm(return_address,rt); // PC into link register
+  #ifdef IMM_PREFETCH
+  emit_prefetch(hash_table[((return_address>>16)^return_address)&0xFFFF]);
+  #endif
+}
+
 void rjump_assemble(int i,struct regstat *i_regs)
 {
   signed char *i_regmap=i_regs->regmap;
   int temp;
   int rs,cc,adj;
+  int ra_done=0;
   rs=get_reg(branch_regs[i].regmap,rs1[i]);
   assert(rs>=0);
   if(rs1[i]==rt1[i+1]||rs1[i]==rt2[i+1]) {
@@ -5245,6 +5336,10 @@ void rjump_assemble(int i,struct regstat *i_regs)
     if(rh>=0) do_preload_rhash(rh);
   }
   #endif
+  if(rt1[i]!=0&&(rt1[i]==rs1[i+1]||rt1[i]==rs2[i+1])) {
+    rjump_assemble_write_ra(i);
+    ra_done=1;
+  }
   ds_assemble(i+1,i_regs);
   uint64_t bc_unneeded=branch_regs[i].u;
   uint64_t bc_unneeded_upper=branch_regs[i].uu;
@@ -5254,25 +5349,8 @@ void rjump_assemble(int i,struct regstat *i_regs)
   wb_invalidate(regs[i].regmap,branch_regs[i].regmap,regs[i].dirty,regs[i].is32,
                 bc_unneeded,bc_unneeded_upper);
   load_regs(regs[i].regmap,branch_regs[i].regmap,regs[i].was32,rs1[i],CCREG);
-  if(rt1[i]!=0) {
-    int rt,return_address;
-    assert(rt1[i+1]!=rt1[i]);
-    assert(rt2[i+1]!=rt1[i]);
-    rt=get_reg(branch_regs[i].regmap,rt1[i]);
-    assem_debug("branch(%d): eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d\n",i,branch_regs[i].regmap[0],branch_regs[i].regmap[1],branch_regs[i].regmap[2],branch_regs[i].regmap[3],branch_regs[i].regmap[5],branch_regs[i].regmap[6],branch_regs[i].regmap[7]);
-    assert(rt>=0);
-    return_address=start+i*4+8;
-    #ifdef REG_PREFETCH
-    if(temp>=0) 
-    {
-      if(i_regmap[temp]!=PTEMP) emit_movimm((int)hash_table[((return_address>>16)^return_address)&0xFFFF],temp);
-    }
-    #endif
-    emit_movimm(return_address,rt); // PC into link register
-    #ifdef IMM_PREFETCH
-    emit_prefetch(hash_table[((return_address>>16)^return_address)&0xFFFF]);
-    #endif
-  }
+  if(!ra_done&&rt1[i]!=0)
+    rjump_assemble_write_ra(i);
   cc=get_reg(branch_regs[i].regmap,CCREG);
   assert(cc==HOST_CCREG);
   #ifdef USE_MINI_HT
@@ -7773,6 +7851,7 @@ void new_dynarec_clear_full()
   pending_exception=0;
   literalcount=0;
   stop_after_jal=0;
+  inv_code_start=inv_code_end=~0;
   // TLB
 #ifndef DISABLE_TLB
   using_tlb=0;
@@ -8881,8 +8960,6 @@ int new_recompile_block(int addr)
           clear_const(&current,rt1[i]);
           alloc_cc(&current,i);
           dirty_reg(&current,CCREG);
-          ooo[i]=1;
-          delayslot_alloc(&current,i+1);
           if (rt1[i]==31) {
             alloc_reg(&current,i,31);
             dirty_reg(&current,31);
@@ -8893,6 +8970,8 @@ int new_recompile_block(int addr)
             #endif
             //current.is32|=1LL<<rt1[i];
           }
+          ooo[i]=1;
+          delayslot_alloc(&current,i+1);
           //current.isconst=0; // DEBUG
           ds=1;
           //printf("i=%d, isconst=%x\n",i,current.isconst);
@@ -11305,6 +11384,7 @@ int new_recompile_block(int addr)
     }
 #endif
   }
+  inv_code_start=inv_code_end=~0;
 #ifdef PCSX
   // PCSX maps all RAM mirror invalid_code tests to 0x80000000..0x80000000+RAM_SIZE
   if(get_page(start)<(RAM_SIZE>>12))