drc: try harder to not compile code as 64bit
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / new_dynarec.c
index 347fd3d..66a5a89 100644 (file)
@@ -179,6 +179,7 @@ struct ll_entry
 #define COP2 27   // Coprocessor 2 move
 #define C2LS 28   // Coprocessor 2 load/store
 #define C2OP 29   // Coprocessor 2 operation
+#define INTCALL 30// Call interpreter to handle rare corner cases
 
   /* stubs */
 #define CC_STUB 1
@@ -220,6 +221,7 @@ void jump_syscall();
 void jump_syscall_hle();
 void jump_eret();
 void jump_hlecall();
+void jump_intcall();
 void new_dyna_leave();
 
 // TLB
@@ -385,9 +387,6 @@ void *get_addr(u_int vaddr)
   //printf("TRACE: count=%d next=%d (get_addr no-match %x)\n",Count,next_interupt,vaddr);
   int r=new_recompile_block(vaddr);
   if(r==0) return get_addr(vaddr);
-#ifdef PCSX
-  return (void *)r;
-#else
   // Execute in unmapped page, generate pagefault execption
   Status|=2;
   Cause=(vaddr<<31)|0x8;
@@ -396,7 +395,6 @@ void *get_addr(u_int vaddr)
   Context=(Context&0xFF80000F)|((BadVAddr>>9)&0x007FFFF0);
   EntryHi=BadVAddr&0xFFFFE000;
   return get_addr_ht(0x80000000);
-#endif
 }
 // Look up address in hash table first
 void *get_addr_ht(u_int vaddr)
@@ -731,7 +729,7 @@ int needed_again(int r, int i)
       j++;
       break;
     }
-    if(itype[i+j]==SYSCALL||itype[i+j]==HLECALL||((source[i+j]&0xfc00003f)==0x0d))
+    if(itype[i+j]==SYSCALL||itype[i+j]==HLECALL||itype[i+j]==INTCALL||((source[i+j]&0xfc00003f)==0x0d))
     {
       break;
     }
@@ -1088,7 +1086,7 @@ void ll_kill_pointers(struct ll_entry *head,int addr,int shift)
     if(((ptr>>shift)==(addr>>shift)) ||
        (((ptr-MAX_OUTPUT_BLOCK_SIZE)>>shift)==(addr>>shift)))
     {
-      printf("EXP: Kill pointer at %x (%x)\n",(int)head->addr,head->vaddr);
+      inv_debug("EXP: Kill pointer at %x (%x)\n",(int)head->addr,head->vaddr);
       u_int host_addr=(u_int)kill_pointer(head->addr);
 
       if((host_addr>>12)!=(old_host_addr>>12)) {
@@ -3696,7 +3694,7 @@ void mov_assemble(int i,struct regstat *i_regs)
 {
   //if(opcode2[i]==0x10||opcode2[i]==0x12) { // MFHI/MFLO
   //if(opcode2[i]==0x11||opcode2[i]==0x13) { // MTHI/MTLO
-  assert(rt1[i]>0);
+  //assert(rt1[i]>0);
   if(rt1[i]) {
     signed char sh,sl,th,tl;
     th=get_reg(i_regs->regmap,rt1[i]|64);
@@ -3752,6 +3750,16 @@ void hlecall_assemble(int i,struct regstat *i_regs)
   emit_jmp((int)jump_hlecall);
 }
 
+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);
+  emit_movimm(start+i*4,0); // Get PC
+  emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG);
+  emit_jmp((int)jump_intcall);
+}
+
 void ds_assemble(int i,struct regstat *i_regs)
 {
   is_delayslot=1;
@@ -3796,6 +3804,7 @@ void ds_assemble(int i,struct regstat *i_regs)
       mov_assemble(i,i_regs);break;
     case SYSCALL:
     case HLECALL:
+    case INTCALL:
     case SPAN:
     case UJUMP:
     case RJUMP:
@@ -4649,6 +4658,7 @@ void ds_assemble_entry(int i)
       mov_assemble(t,&regs[t]);break;
     case SYSCALL:
     case HLECALL:
+    case INTCALL:
     case SPAN:
     case UJUMP:
     case RJUMP:
@@ -6480,6 +6490,7 @@ static void pagespan_ds()
       mov_assemble(0,&regs[0]);break;
     case SYSCALL:
     case HLECALL:
+    case INTCALL:
     case SPAN:
     case UJUMP:
     case RJUMP:
@@ -6703,7 +6714,7 @@ void unneeded_registers(int istart,int iend,int r)
         }
       }
     }
-    else if(itype[i]==SYSCALL||itype[i]==HLECALL)
+    else if(itype[i]==SYSCALL||itype[i]==HLECALL||itype[i]==INTCALL)
     {
       // SYSCALL instruction (software interrupt)
       u=1;
@@ -7069,7 +7080,7 @@ static void provisional_r32()
         if((regs[i].was32>>dep2[i+1])&1) r32|=1LL<<dep2[i+1];
       }
     }
-    else if(itype[i]==SYSCALL||itype[i]==HLECALL)
+    else if(itype[i]==SYSCALL||itype[i]==HLECALL||itype[i]==INTCALL)
     {
       // SYSCALL instruction (software interrupt)
       r32=0;
@@ -7423,7 +7434,7 @@ void clean_registers(int istart,int iend,int wr)
         }
       }
     }
-    else if(itype[i]==SYSCALL||itype[i]==HLECALL)
+    else if(itype[i]==SYSCALL||itype[i]==HLECALL||itype[i]==INTCALL)
     {
       // SYSCALL instruction (software interrupt)
       will_dirty_i=0;
@@ -7625,6 +7636,9 @@ void disassemble_inst(int i)
       case C2LS:
         printf (" %x: %s cpr2[%d],r%d+%x\n",start+i*4,insn[i],(source[i]>>16)&0x1f,rs1[i],imm[i]);
         break;
+      case INTCALL:
+        printf (" %x: %s (INTCALL)\n",start+i*4,insn[i]);
+        break;
       default:
         //printf (" %s %8x\n",insn[i],source[i]);
         printf (" %x: %s\n",start+i*4,insn[i]);
@@ -7747,8 +7761,7 @@ int new_recompile_block(int addr)
   start = (u_int)addr&~3;
   //assert(((u_int)addr&1)==0);
 #ifdef PCSX
-  if ((Config.HLE && start == 0x80001000) || // hlecall
-      (/*psxRegs.pc != 0x80030000 &&*/ start == 0x80030000)) // fastbios thing
+  if (Config.HLE && start == 0x80001000) // hlecall
   {
     // XXX: is this enough? Maybe check hleSoftCall?
     u_int beginning=(u_int)out;
@@ -7760,10 +7773,7 @@ int new_recompile_block(int addr)
 #ifdef __arm__
     __clear_cache((void *)beginning,out);
 #endif
-    if (start == 0x80030000)
-      return beginning;
-    else
-      ll_add(jump_in+page,start,(void *)beginning);
+    ll_add(jump_in+page,start,(void *)beginning);
     return 0;
   }
   else if ((u_int)addr < 0x00200000 ||
@@ -8074,11 +8084,11 @@ int new_recompile_block(int addr)
           break;
         }
         break;
+#ifndef FORCE32
       case 0x14: strcpy(insn[i],"BEQL"); type=CJUMP; break;
       case 0x15: strcpy(insn[i],"BNEL"); type=CJUMP; break;
       case 0x16: strcpy(insn[i],"BLEZL"); type=CJUMP; break;
       case 0x17: strcpy(insn[i],"BGTZL"); type=CJUMP; break;
-#ifndef FORCE32
       case 0x18: strcpy(insn[i],"DADDI"); type=IMM16; break;
       case 0x19: strcpy(insn[i],"DADDIU"); type=IMM16; break;
       case 0x1A: strcpy(insn[i],"LDL"); type=LOADLR; break;
@@ -8118,19 +8128,20 @@ int new_recompile_block(int addr)
 #endif
 #ifdef PCSX
       case 0x12: strcpy(insn[i],"COP2"); type=NI;
+        // note: COP MIPS-1 encoding differs from MIPS32
         op2=(source[i]>>21)&0x1f;
-        switch(op2)
+        if (source[i]&0x3f) {
+          if (gte_handlers[source[i]&0x3f]!=NULL) {
+            snprintf(insn[i], sizeof(insn[i]), "COP2 %x", source[i]&0x3f);
+            type=C2OP;
+          }
+        }
+        else switch(op2)
         {
           case 0x00: strcpy(insn[i],"MFC2"); type=COP2; break;
           case 0x02: strcpy(insn[i],"CFC2"); type=COP2; break;
           case 0x04: strcpy(insn[i],"MTC2"); type=COP2; break;
           case 0x06: strcpy(insn[i],"CTC2"); type=COP2; break;
-          default:
-            if (gte_handlers[source[i]&0x3f]!=NULL) {
-              snprintf(insn[i], sizeof(insn[i]), "COP2 %x", source[i]&0x3f);
-              type=C2OP;
-            }
-            break;
         }
         break;
       case 0x32: strcpy(insn[i],"LWC2"); type=C2LS; break;
@@ -8141,6 +8152,18 @@ int new_recompile_block(int addr)
         printf("NI %08x @%08x (%08x)\n", source[i], addr + i*4, addr);
         break;
     }
+#ifdef PCSX
+    /* detect branch in delay slot early */
+    if(type==RJUMP||type==UJUMP||type==CJUMP||type==SJUMP||type==FJUMP) {
+      opcode[i+1]=source[i+1]>>26;
+      opcode2[i+1]=source[i+1]&0x3f;
+      if((0<opcode[i+1]&&opcode[i+1]<8)||(opcode[i+1]==0&&(opcode2[i+1]==8||opcode2[i+1]==9))) {
+        printf("branch in delay slot @%08x (%08x)\n", addr + i*4+4, addr);
+        // don't handle first branch and call interpreter if it's hit
+        type=INTCALL;
+      }
+    }
+#endif
     itype[i]=type;
     opcode2[i]=op2;
     /* Get registers/immediates */
@@ -8351,6 +8374,7 @@ int new_recompile_block(int addr)
         break;
       case SYSCALL:
       case HLECALL:
+      case INTCALL:
         rs1[i]=CCREG;
         rs2[i]=0;
         rt1[i]=0;
@@ -8375,13 +8399,7 @@ int new_recompile_block(int addr)
     /* Is this the end of the block? */
     if(i>0&&(itype[i-1]==UJUMP||itype[i-1]==RJUMP||(source[i-1]>>16)==0x1000)) {
       if(rt1[i-1]==0) { // Continue past subroutine call (JAL)
-        done=1;
-        // Does the block continue due to a branch?
-        for(j=i-1;j>=0;j--)
-        {
-          if(ba[j]==start+i*4+4) done=j=0;
-          if(ba[j]==start+i*4+8) done=j=0;
-        }
+        done=2;
       }
       else {
         if(stop_after_jal) done=1;
@@ -8394,7 +8412,15 @@ int new_recompile_block(int addr)
       if(i>MAXBLOCK/2) done=1;
     }
     if(itype[i]==SYSCALL&&stop_after_jal) done=1;
-    if(itype[i]==HLECALL) done=1;
+    if(itype[i]==HLECALL||itype[i]==INTCALL) done=2;
+    if(done==2) {
+      // Does the block continue due to a branch?
+      for(j=i-1;j>=0;j--)
+      {
+        if(ba[j]==start+i*4+4) done=j=0;
+        if(ba[j]==start+i*4+8) done=j=0;
+      }
+    }
     //assert(i<MAXBLOCK-1);
     if(start+i*4==pagelimit-4) done=1;
     assert(start+i*4<pagelimit);
@@ -8696,7 +8722,8 @@ int new_recompile_block(int addr)
           if (rt1[i]==31) {
             alloc_reg(&current,i,31);
             dirty_reg(&current,31);
-            assert(rs1[i+1]!=31&&rs2[i+1]!=31);
+            //assert(rs1[i+1]!=31&&rs2[i+1]!=31);
+            assert(rt1[i+1]!=rt1[i]);
             #ifdef REG_PREFETCH
             alloc_reg(&current,i,PTEMP);
             #endif
@@ -8720,7 +8747,8 @@ int new_recompile_block(int addr)
             if (rt1[i]!=0) {
               alloc_reg(&current,i,rt1[i]);
               dirty_reg(&current,rt1[i]);
-              assert(rs1[i+1]!=31&&rs2[i+1]!=31);
+              //assert(rs1[i+1]!=31&&rs2[i+1]!=31);
+              assert(rt1[i+1]!=rt1[i]);
               #ifdef REG_PREFETCH
               alloc_reg(&current,i,PTEMP);
               #endif
@@ -9001,6 +9029,7 @@ int new_recompile_block(int addr)
           break;
         case SYSCALL:
         case HLECALL:
+        case INTCALL:
           syscall_alloc(&current,i);
           break;
         case SPAN:
@@ -9465,7 +9494,7 @@ int new_recompile_block(int addr)
         }
       }
     }
-    else if(itype[i]==SYSCALL||itype[i]==HLECALL)
+    else if(itype[i]==SYSCALL||itype[i]==HLECALL||itype[i]==INTCALL)
     {
       // SYSCALL instruction (software interrupt)
       nr=0;
@@ -9692,13 +9721,35 @@ int new_recompile_block(int addr)
               f_regmap[hr]=regs[i].regmap[hr];
             else f_regmap[hr]=-1;
           }
-          else if(regs[i].regmap[hr]>=0) f_regmap[hr]=regs[i].regmap[hr];
+          else if(regs[i].regmap[hr]>=0) {
+            if(f_regmap[hr]!=regs[i].regmap[hr]) {
+              // dealloc old register
+              int n;
+              for(n=0;n<HOST_REGS;n++)
+              {
+                if(f_regmap[n]==regs[i].regmap[hr]) {f_regmap[n]=-1;}
+              }
+              // and alloc new one
+              f_regmap[hr]=regs[i].regmap[hr];
+            }
+          }
           if(branch_regs[i].regmap[hr]>64) {
             if(!((branch_regs[i].dirty>>hr)&1))
               f_regmap[hr]=branch_regs[i].regmap[hr];
             else f_regmap[hr]=-1;
           }
-          else if(branch_regs[i].regmap[hr]>=0) f_regmap[hr]=branch_regs[i].regmap[hr];
+          else if(branch_regs[i].regmap[hr]>=0) {
+            if(f_regmap[hr]!=branch_regs[i].regmap[hr]) {
+              // dealloc old register
+              int n;
+              for(n=0;n<HOST_REGS;n++)
+              {
+                if(f_regmap[n]==branch_regs[i].regmap[hr]) {f_regmap[n]=-1;}
+              }
+              // and alloc new one
+              f_regmap[hr]=branch_regs[i].regmap[hr];
+            }
+          }
           if(itype[i+1]==STORE||itype[i+1]==STORELR||itype[i+1]==C1LS
           ||itype[i+1]==SHIFT||itype[i+1]==COP1||itype[i+1]==FLOAT
           ||itype[i+1]==FCOMP||itype[i+1]==FCONV
@@ -9884,7 +9935,18 @@ int new_recompile_block(int addr)
             if(!((regs[i].dirty>>hr)&1))
               f_regmap[hr]=regs[i].regmap[hr];
           }
-          else if(regs[i].regmap[hr]>=0) f_regmap[hr]=regs[i].regmap[hr];
+          else if(regs[i].regmap[hr]>=0) {
+            if(f_regmap[hr]!=regs[i].regmap[hr]) {
+              // dealloc old register
+              int n;
+              for(n=0;n<HOST_REGS;n++)
+              {
+                if(f_regmap[n]==regs[i].regmap[hr]) {f_regmap[n]=-1;}
+              }
+              // and alloc new one
+              f_regmap[hr]=regs[i].regmap[hr];
+            }
+          }
           else if(regs[i].regmap[hr]<0) count++;
         }
       }
@@ -10237,7 +10299,7 @@ int new_recompile_block(int addr)
         if((regs[i].was32>>dep2[i+1])&1) r32|=1LL<<dep2[i+1];
       }
     }
-    else if(itype[i]==SYSCALL||itype[i]==HLECALL)
+    else if(itype[i]==SYSCALL||itype[i]==HLECALL||itype[i]==INTCALL)
     {
       // SYSCALL instruction (software interrupt)
       r32=0;
@@ -10515,6 +10577,19 @@ int new_recompile_block(int addr)
     ds=1;
     pagespan_ds();
   }
+  u_int instr_addr0_override=0;
+
+#ifdef PCSX
+  if (start == 0x80030000) {
+    // nasty hack for fastbios thing
+    instr_addr0_override=(u_int)out;
+    emit_movimm(start,0);
+    emit_readword((int)&pcaddr,1);
+    emit_writeword(0,(int)&pcaddr);
+    emit_cmp(0,1);
+    emit_jne((int)new_dyna_leave);
+  }
+#endif
   for(i=0;i<slen;i++)
   {
     //if(ds) printf("ds: ");
@@ -10621,6 +10696,8 @@ int new_recompile_block(int addr)
           syscall_assemble(i,&regs[i]);break;
         case HLECALL:
           hlecall_assemble(i,&regs[i]);break;
+        case INTCALL:
+          intcall_assemble(i,&regs[i]);break;
         case UJUMP:
           ujump_assemble(i,&regs[i]);ds=1;break;
         case RJUMP:
@@ -10708,6 +10785,9 @@ int new_recompile_block(int addr)
     }
   }
 
+  if (instr_addr0_override)
+    instr_addr[0] = instr_addr0_override;
+
   /* Pass 9 - Linker */
   for(i=0;i<linkcount;i++)
   {