drc: inv: fix ram ofset and mirror handling
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / new_dynarec.c
index 8cf8dfb..59d4208 100644 (file)
@@ -141,6 +141,11 @@ struct ll_entry
   int new_dynarec_did_compile;
   int new_dynarec_hacks;
   u_int stop_after_jal;
+#ifndef RAM_FIXED
+  static u_int ram_offset;
+#else
+  static const u_int ram_offset=0;
+#endif
   extern u_char restore_candidate[512];
   extern int cycle_count;
 
@@ -1211,7 +1216,7 @@ void invalidate_block(u_int block)
     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(page<2048&&start>=(u_int)rdram&&end<(u_int)rdram+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;
@@ -1241,10 +1246,11 @@ void invalidate_addr(u_int addr)
   if(page<2048) { // RAM
     struct ll_entry *head;
     u_int addr_min=~0, addr_max=0;
-    int mask=RAM_SIZE-1;
+    u_int mask=RAM_SIZE-1;
+    u_int addr_main=0x80000000|(addr&mask);
     int pg1;
-    inv_code_start=addr&~0xfff;
-    inv_code_end=addr|0xfff;
+    inv_code_start=addr_main&~0xfff;
+    inv_code_end=addr_main|0xfff;
     pg1=page;
     if (pg1>0) {
       // must check previous page too because of spans..
@@ -1255,11 +1261,15 @@ void invalidate_addr(u_int addr)
       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(ram_offset) {
+          start-=ram_offset;
+          end-=ram_offset;
+        }
+        if(start<=addr_main&&addr_main<end) {
           if(start<addr_min) addr_min=start;
           if(end>addr_max) addr_max=end;
         }
-        else if(addr<start) {
+        else if(addr_main<start) {
           if(start<inv_code_end)
             inv_code_end=start-1;
         }
@@ -1276,6 +1286,8 @@ void invalidate_addr(u_int addr)
       return;
     }
     else {
+      inv_code_start=(addr&~mask)|(inv_code_start&mask);
+      inv_code_end=(addr&~mask)|(inv_code_end&mask);
       inv_debug("INV ADDR: %08x miss, inv %08x-%08x, sk %d\n", addr, inv_code_start, inv_code_end, 0);
       return;
     }
@@ -2917,6 +2929,10 @@ void load_assemble(int i,struct regstat *i_regs)
         jaddr=emit_fastpath_cmp_jump(i,addr,&fastload_reg_override);
       }
     }
+    else if(ram_offset&&memtarget) {
+      emit_addimm(addr,ram_offset,HOST_TEMPREG);
+      fastload_reg_override=HOST_TEMPREG;
+    }
   }else{ // using tlb
     int x=0;
     if (opcode[i]==0x20||opcode[i]==0x24) x=3; // LB/LBU
@@ -2982,7 +2998,7 @@ void load_assemble(int i,struct regstat *i_regs)
             gen_tlb_addr_r(a,map);
             emit_movswl_indexed(x,a,tl);
           }else{
-            #ifdef RAM_OFFSET
+            #if 1 //def RAM_OFFSET
             emit_movswl_indexed(x,a,tl);
             #else
             emit_movswl_indexed((int)rdram-0x80000000+x,a,tl);
@@ -3069,7 +3085,7 @@ void load_assemble(int i,struct regstat *i_regs)
             gen_tlb_addr_r(a,map);
             emit_movzwl_indexed(x,a,tl);
           }else{
-            #ifdef RAM_OFFSET
+            #if 1 //def RAM_OFFSET
             emit_movzwl_indexed(x,a,tl);
             #else
             emit_movzwl_indexed((int)rdram-0x80000000+x,a,tl);
@@ -3226,6 +3242,10 @@ void store_assemble(int i,struct regstat *i_regs)
         jaddr=emit_fastpath_cmp_jump(i,addr,&faststore_reg_override);
       #endif
     }
+    else if(ram_offset&&memtarget) {
+      emit_addimm(addr,ram_offset,HOST_TEMPREG);
+      faststore_reg_override=HOST_TEMPREG;
+    }
   }else{ // using tlb
     int x=0;
     if (opcode[i]==0x28) x=3; // SB
@@ -3270,7 +3290,8 @@ void store_assemble(int i,struct regstat *i_regs)
         gen_tlb_addr_w(a,map);
         emit_writehword_indexed(tl,x,a);
       }else
-        emit_writehword_indexed(tl,(int)rdram-0x80000000+x,a);
+        //emit_writehword_indexed(tl,(int)rdram-0x80000000+x,a);
+        emit_writehword_indexed(tl,x,a);
     }
     type=STOREH_STUB;
   }
@@ -3332,10 +3353,24 @@ void store_assemble(int i,struct regstat *i_regs)
       #endif
     }
   }
+  u_int addr_val=constmap[i][s]+offset;
   if(jaddr) {
     add_stub(type,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist);
   } else if(c&&!memtarget) {
-    inline_writestub(type,i,constmap[i][s]+offset,i_regs->regmap,rs2[i],ccadj[i],reglist);
+    inline_writestub(type,i,addr_val,i_regs->regmap,rs2[i],ccadj[i],reglist);
+  }
+  // basic current block modification detection..
+  // not looking back as that should be in mips cache already
+  if(c&&start+i*4<addr_val&&addr_val<start+slen*4) {
+    printf("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(i_regs->regmap==regs[i].regmap) {
+      load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty,i);
+      wb_dirtys(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty);
+      emit_movimm(start+i*4+4,0);
+      emit_writeword(0,(int)&pcaddr);
+      emit_jmp((int)do_interrupt);
+    }
   }
   //if(opcode[i]==0x2B || opcode[i]==0x3F)
   //if(opcode[i]==0x2B || opcode[i]==0x28)
@@ -3860,6 +3895,10 @@ void c2ls_assemble(int i,struct regstat *i_regs)
     if(!c) {
       jaddr2=emit_fastpath_cmp_jump(i,ar,&fastio_reg_override);
     }
+    else if(ram_offset&&memtarget) {
+      emit_addimm(ar,ram_offset,HOST_TEMPREG);
+      fastio_reg_override=HOST_TEMPREG;
+    }
     if (opcode[i]==0x32) { // LWC2
       #ifdef HOST_IMM_ADDR32
       if(c) emit_readword_tlb(constmap[i][s]+offset,-1,tl);
@@ -7025,7 +7064,7 @@ void unneeded_registers(int istart,int iend,int r)
     uu&=~(1LL<<us2[i]);
     gte_u&=~gte_rs[i];
     if(gte_rs[i]&&rt1[i]&&(unneeded_reg[i+1]&(1ll<<rt1[i])))
-      gte_u|=gte_rs[i] // MFC2/CFC2 to dead register, unneeded
+      gte_u|=gte_rs[i]&gte_unneeded[i+1]; // MFC2/CFC2 to dead register, unneeded
     // Source-target dependencies
     uu&=~(tdep<<dep1[i]);
     uu&=~(tdep<<dep2[i]);
@@ -7979,10 +8018,16 @@ void new_dynarec_init()
 {
   printf("Init new dynarec\n");
   out=(u_char *)BASE_ADDR;
+#if BASE_ADDR_FIXED
   if (mmap (out, 1<<TARGET_SIZE_2,
             PROT_READ | PROT_WRITE | PROT_EXEC,
             MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
             -1, 0) <= 0) {printf("mmap() failed\n");}
+#else
+  // not all systems allow execute in data segment by default
+  if (mprotect(out, 1<<TARGET_SIZE_2, PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
+    printf("mprotect() failed\n");
+#endif
 #ifdef MUPEN64
   rdword=&readmem_dword;
   fake_pc.f.r.rs=&readmem_dword;
@@ -8036,12 +8081,17 @@ void new_dynarec_init()
 #endif
   tlb_hacks();
   arch_init();
+#ifndef RAM_FIXED
+  ram_offset=(u_int)rdram-0x80000000;
+#endif
 }
 
 void new_dynarec_cleanup()
 {
   int n;
+  #if BASE_ADDR_FIXED
   if (munmap ((void *)BASE_ADDR, 1<<TARGET_SIZE_2) < 0) {printf("munmap() failed\n");}
+  #endif
   for(n=0;n<4096;n++) ll_clear(jump_in+n);
   for(n=0;n<4096;n++) ll_clear(jump_out+n);
   for(n=0;n<4096;n++) ll_clear(jump_dirty+n);
@@ -11529,7 +11579,7 @@ int new_recompile_block(int addr)
   
   // If we're within 256K of the end of the buffer,
   // start over from the beginning. (Is 256K enough?)
-  if((int)out>BASE_ADDR+(1<<TARGET_SIZE_2)-MAX_OUTPUT_BLOCK_SIZE) out=(u_char *)BASE_ADDR;
+  if((u_int)out>(u_int)BASE_ADDR+(1<<TARGET_SIZE_2)-MAX_OUTPUT_BLOCK_SIZE) out=(u_char *)BASE_ADDR;
   
   // Trap writes to any of the pages we compiled
   for(i=start>>12;i<=(start+slen*4)>>12;i++) {
@@ -11557,11 +11607,11 @@ int new_recompile_block(int addr)
   
   /* Pass 10 - Free memory by expiring oldest blocks */
   
-  int end=((((int)out-BASE_ADDR)>>(TARGET_SIZE_2-16))+16384)&65535;
+  int end=((((int)out-(int)BASE_ADDR)>>(TARGET_SIZE_2-16))+16384)&65535;
   while(expirep!=end)
   {
     int shift=TARGET_SIZE_2-3; // Divide into 8 blocks
-    int base=BASE_ADDR+((expirep>>13)<<shift); // Base address of this block
+    int base=(int)BASE_ADDR+((expirep>>13)<<shift); // Base address of this block
     inv_debug("EXP: Phase %d\n",expirep);
     switch((expirep>>11)&3)
     {