drc: get rid of pass 7/provisional_r32 too
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / new_dynarec.c
index 7495875..fdd5b64 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
@@ -307,7 +309,14 @@ static void tlb_hacks()
 
 static u_int get_page(u_int vaddr)
 {
+#ifndef PCSX
   u_int page=(vaddr^0x80000000)>>12;
+#else
+  u_int page=vaddr&~0xe0000000;
+  if (page < 0x1000000)
+    page &= ~0x0e00000; // RAM mirrors
+  page>>=12;
+#endif
 #ifndef DISABLE_TLB
   if(page>262143&&tlb_LUT_r[vaddr>>12]) page=(tlb_LUT_r[vaddr>>12]^0x80000000)>>12;
 #endif
@@ -408,7 +417,7 @@ void *get_addr_32(u_int vaddr,u_int flags)
 {
 #ifdef FORCE32
   return get_addr(vaddr);
-#endif
+#else
   //printf("TRACE: count=%d next=%d (get_addr_32 %x,flags %x)\n",Count,next_interupt,vaddr,flags);
   int *ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF];
   if(ht_bin[0]==vaddr) return (void *)ht_bin[1];
@@ -488,6 +497,7 @@ void *get_addr_32(u_int vaddr,u_int flags)
   Context=(Context&0xFF80000F)|((BadVAddr>>9)&0x007FFFF0);
   EntryHi=BadVAddr&0xFFFFE000;
   return get_addr_ht(0x80000000);
+#endif
 }
 
 void clear_all_regs(signed char regmap[])
@@ -680,8 +690,8 @@ void lsn(u_char hsn[], int i, int *preferred_reg)
   if(itype[i]==LOADLR) {
     hsn[FTEMP]=0;
   }
-  // Also 64-bit SDL/SDR
-  if(opcode[i]==0x2c||opcode[i]==0x2d) {
+  // Also SWL/SWR/SDL/SDR
+  if(opcode[i]==0x2a||opcode[i]==0x2e||opcode[i]==0x2c||opcode[i]==0x2d) {
     hsn[FTEMP]=0;
   }
   // Don't remove the TLB registers either
@@ -726,7 +736,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;
     }
@@ -1076,6 +1086,7 @@ void ll_clear(struct ll_entry **head)
 // Dereference the pointers and remove if it matches
 void ll_kill_pointers(struct ll_entry *head,int addr,int shift)
 {
+  u_int old_host_addr=0;
   while(head) {
     int ptr=get_pointer(head->addr);
     inv_debug("EXP: Lookup pointer to %x at %x (%x)\n",(int)ptr,(int)head->addr,head->vaddr);
@@ -1083,18 +1094,29 @@ void ll_kill_pointers(struct ll_entry *head,int addr,int shift)
        (((ptr-MAX_OUTPUT_BLOCK_SIZE)>>shift)==(addr>>shift)))
     {
       inv_debug("EXP: Kill pointer at %x (%x)\n",(int)head->addr,head->vaddr);
-      kill_pointer(head->addr);
+      u_int host_addr=(u_int)kill_pointer(head->addr);
+
+      if((host_addr>>12)!=(old_host_addr>>12)) {
+        #ifdef __arm__
+        __clear_cache((void *)(old_host_addr&~0xfff),(void *)(old_host_addr|0xfff));
+        #endif
+        old_host_addr=host_addr;
+      }
     }
     head=head->next;
   }
+  #ifdef __arm__
+  if (old_host_addr)
+    __clear_cache((void *)(old_host_addr&~0xfff),(void *)(old_host_addr|0xfff));
+  #endif
 }
 
 // This is called when we write to a compiled block (see do_invstub)
-int invalidate_page(u_int page)
+void invalidate_page(u_int page)
 {
-  int modified=0;
   struct ll_entry *head;
   struct ll_entry *next;
+  u_int old_host_addr=0;
   head=jump_in[page];
   jump_in[page]=0;
   while(head!=NULL) {
@@ -1108,17 +1130,25 @@ int invalidate_page(u_int page)
   jump_out[page]=0;
   while(head!=NULL) {
     inv_debug("INVALIDATE: kill pointer to %x (%x)\n",head->vaddr,(int)head->addr);
-    kill_pointer(head->addr);
-    modified=1;
+    u_int host_addr=(u_int)kill_pointer(head->addr);
+
+    if((host_addr>>12)!=(old_host_addr>>12)) {
+      #ifdef __arm__
+      __clear_cache((void *)(old_host_addr&~0xfff),(void *)(old_host_addr|0xfff));
+      #endif
+      old_host_addr=host_addr;
+    }
     next=head->next;
     free(head);
     head=next;
   }
-  return modified;
+  #ifdef __arm__
+  if (old_host_addr)
+    __clear_cache((void *)(old_host_addr&~0xfff),(void *)(old_host_addr|0xfff));
+  #endif
 }
 void invalidate_block(u_int block)
 {
-  int modified;
   u_int page=get_page(block<<12);
   u_int vpage=get_vpage(block<<12);
   inv_debug("INVALIDATE: %x (%d)\n",block<<12,page);
@@ -1133,7 +1163,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<0x80800000) {
+      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;
@@ -1151,7 +1181,7 @@ void invalidate_block(u_int block)
     head=head->next;
   }
   //printf("first=%d last=%d\n",first,last);
-  modified=invalidate_page(page);
+  invalidate_page(page);
   assert(first+5>page); // NB: this assumes MAXBLOCK<=4096 (4 pages)
   assert(last<page+5);
   // Invalidate the adjacent pages if a block crosses a 4K boundary
@@ -1177,10 +1207,7 @@ void invalidate_block(u_int block)
   }
   else if(block>=0x80000&&block<0x80800) memory_map[block]=((u_int)rdram-0x80000000)>>2;
 #endif
-  #ifdef __arm__
-  if(modified)
-    __clear_cache((void *)BASE_ADDR,(void *)BASE_ADDR+(1<<TARGET_SIZE_2));
-  #endif
+
   #ifdef USE_MINI_HT
   memset(mini_ht,-1,sizeof(mini_ht));
   #endif
@@ -1249,7 +1276,7 @@ void clean_blocks(u_int page)
           u_int i;
           u_int inv=0;
           get_bounds((int)head->addr,&start,&end);
-          if(start-(u_int)rdram<0x800000) {
+          if(start-(u_int)rdram<RAM_SIZE) {
             for(i=(start-(u_int)rdram+0x80000000)>>12;i<=(end-1-(u_int)rdram+0x80000000)>>12;i++) {
               inv|=invalid_code[i];
             }
@@ -1259,7 +1286,7 @@ void clean_blocks(u_int page)
             //printf("addr=%x start=%x end=%x\n",addr,start,end);
             if(addr<start||addr>=end) inv=1;
           }
-          else if((signed int)head->vaddr>=(signed int)0x80800000) {
+          else if((signed int)head->vaddr>=(signed int)0x80000000+RAM_SIZE) {
             inv=1;
           }
           if(!inv) {
@@ -1621,7 +1648,7 @@ void store_alloc(struct regstat *current,int i)
   // On CPUs without 32-bit immediates we need a pointer to invalid_code
   else alloc_reg(current,i,INVCP);
   #endif
-  if(opcode[i]==0x2c||opcode[i]==0x2d) { // 64-bit SDL/SDR
+  if(opcode[i]==0x2a||opcode[i]==0x2e||opcode[i]==0x2c||opcode[i]==0x2d) { // SWL/SWL/SDL/SDR
     alloc_reg(current,i,FTEMP);
   }
   // We need a temporary register for address generation
@@ -1763,16 +1790,17 @@ void cop1_alloc(struct regstat *current,int i)
   alloc_reg(current,i,CSREG); // Load status
   if(opcode2[i]<3) // MFC1/DMFC1/CFC1
   {
-    assert(rt1[i]);
-    clear_const(current,rt1[i]);
-    if(opcode2[i]==1) {
-      alloc_reg64(current,i,rt1[i]); // DMFC1
-      current->is32&=~(1LL<<rt1[i]);
-    }else{
-      alloc_reg(current,i,rt1[i]); // MFC1/CFC1
-      current->is32|=1LL<<rt1[i];
+    if(rt1[i]){
+      clear_const(current,rt1[i]);
+      if(opcode2[i]==1) {
+        alloc_reg64(current,i,rt1[i]); // DMFC1
+        current->is32&=~(1LL<<rt1[i]);
+      }else{
+        alloc_reg(current,i,rt1[i]); // MFC1/CFC1
+        current->is32|=1LL<<rt1[i];
+      }
+      dirty_reg(current,rt1[i]);
     }
-    dirty_reg(current,rt1[i]);
     alloc_reg_temp(current,i,-1);
   }
   else if(opcode2[i]>3) // MTC1/DMTC1/CTC1
@@ -2717,7 +2745,7 @@ void load_assemble(int i,struct regstat *i_regs)
   int s,th,tl,addr,map=-1;
   int offset;
   int jaddr=0;
-  int memtarget,c=0;
+  int memtarget=0,c=0;
   u_int hr,reglist=0;
   th=get_reg(i_regs->regmap,rt1[i]|64);
   tl=get_reg(i_regs->regmap,rt1[i]);
@@ -2729,14 +2757,24 @@ void load_assemble(int i,struct regstat *i_regs)
   if(i_regs->regmap[HOST_CCREG]==CCREG) reglist&=~(1<<HOST_CCREG);
   if(s>=0) {
     c=(i_regs->wasconst>>s)&1;
-    memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80800000;
+    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(offset||s<0||c) addr=tl;
-  else addr=s;
   //printf("load_assemble: c=%d\n",c);
   //if(c) printf("load_assemble: const=%x\n",(int)constmap[i][s]+offset);
   // FIXME: Even if the load is a NOP, we should check for pagefaults...
+#ifdef PCSX
+  if(tl<0&&(!c||(((u_int)constmap[i][s]+offset)>>16)==0x1f80)
+    ||rt1[i]==0) {
+      // could be FIFO, must perform the read
+      // ||dummy read
+      assem_debug("(forced read)\n");
+      tl=get_reg(i_regs->regmap,-1);
+      assert(tl>=0);
+  }
+#endif
+  if(offset||s<0||c) addr=tl;
+  else addr=s;
   if(tl>=0) {
     //assert(tl>=0);
     //assert(rt1[i]);
@@ -2747,10 +2785,10 @@ void load_assemble(int i,struct regstat *i_regs)
 //#define R29_HACK 1
         #ifdef R29_HACK
         // Strmnnrmn's speed hack
-        if(rs1[i]!=29||start<0x80001000||start>=0x80800000)
+        if(rs1[i]!=29||start<0x80001000||start>=0x80000000+RAM_SIZE)
         #endif
         {
-          emit_cmpimm(addr,0x800000);
+          emit_cmpimm(addr,RAM_SIZE);
           jaddr=(int)out;
           #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK
           // Hint to branch predictor that the branch is unlikely to be taken
@@ -2993,7 +3031,7 @@ void store_assemble(int i,struct regstat *i_regs)
   offset=imm[i];
   if(s>=0) {
     c=(i_regs->wasconst>>s)&1;
-    memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80800000;
+    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;
   }
   assert(tl>=0);
@@ -3009,14 +3047,14 @@ void store_assemble(int i,struct regstat *i_regs)
       #ifdef R29_HACK
       // Strmnnrmn's speed hack
       memtarget=1;
-      if(rs1[i]!=29||start<0x80001000||start>=0x80800000)
+      if(rs1[i]!=29||start<0x80001000||start>=0x80000000+RAM_SIZE)
       #endif
-      emit_cmpimm(addr,0x800000);
+      emit_cmpimm(addr,RAM_SIZE);
       #ifdef DESTRUCTIVE_SHIFT
       if(s==addr) emit_mov(s,temp);
       #endif
       #ifdef R29_HACK
-      if(rs1[i]!=29||start<0x80001000||start>=0x80800000)
+      if(rs1[i]!=29||start<0x80001000||start>=0x80000000+RAM_SIZE)
       #endif
       {
         jaddr=(int)out;
@@ -3166,15 +3204,17 @@ void storelr_assemble(int i,struct regstat *i_regs)
   int case1,case2,case3;
   int done0,done1,done2;
   int memtarget,c=0;
+  int agr=AGEN1+(i&1);
   u_int hr,reglist=0;
   th=get_reg(i_regs->regmap,rs2[i]|64);
   tl=get_reg(i_regs->regmap,rs2[i]);
   s=get_reg(i_regs->regmap,rs1[i]);
-  temp=get_reg(i_regs->regmap,-1);
+  temp=get_reg(i_regs->regmap,agr);
+  if(temp<0) temp=get_reg(i_regs->regmap,-1);
   offset=imm[i];
   if(s>=0) {
     c=(i_regs->isconst>>s)&1;
-    memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80800000;
+    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;
   }
   assert(tl>=0);
@@ -3185,7 +3225,7 @@ void storelr_assemble(int i,struct regstat *i_regs)
     assert(temp>=0);
     if(!using_tlb) {
       if(!c) {
-        emit_cmpimm(s<0||offset?temp:s,0x800000);
+        emit_cmpimm(s<0||offset?temp:s,RAM_SIZE);
         if(!offset&&s!=temp) emit_mov(s,temp);
         jaddr=(int)out;
         emit_jno(0);
@@ -3352,7 +3392,7 @@ void storelr_assemble(int i,struct regstat *i_regs)
       set_jump_target(done0,(int)out);
     }
     if(!c||!memtarget)
-      add_stub(STORELR_STUB,jaddr,(int)out,0,(int)i_regs,rs2[i],ccadj[i],reglist);
+      add_stub(STORELR_STUB,jaddr,(int)out,i,(int)i_regs,temp,ccadj[i],reglist);
   }
   if(!using_tlb) {
     emit_addimm_no_flags((u_int)0x80000000-(u_int)rdram,temp);
@@ -3437,7 +3477,7 @@ void c1ls_assemble(int i,struct regstat *i_regs)
   // Generate address + offset
   if(!using_tlb) {
     if(!c)
-      emit_cmpimm(offset||c||s<0?ar:s,0x800000);
+      emit_cmpimm(offset||c||s<0?ar:s,RAM_SIZE);
   }
   else
   {
@@ -3468,7 +3508,7 @@ void c1ls_assemble(int i,struct regstat *i_regs)
       jaddr2=(int)out;
       emit_jno(0);
     }
-    else if(((signed int)(constmap[i][s]+offset))>=(signed int)0x80800000) {
+    else if(((signed int)(constmap[i][s]+offset))>=(signed int)0x80000000+RAM_SIZE) {
       jaddr2=(int)out;
       emit_jmp(0); // inline_readstub/inline_writestub?  Very rare case
     }
@@ -3569,7 +3609,7 @@ void c2ls_assemble(int i,struct regstat *i_regs)
   int s,tl;
   int ar;
   int offset;
-  int c=0;
+  int memtarget=0,c=0;
   int jaddr,jaddr2=0,jaddr3,type;
   int agr=AGEN1+(i&1);
   u_int hr,reglist=0;
@@ -3595,36 +3635,41 @@ void c2ls_assemble(int i,struct regstat *i_regs)
   } else { // LWC2
     ar=tl;
   }
+  if(s>=0) c=(i_regs->wasconst>>s)&1;
+  memtarget=c&&(((signed int)(constmap[i][s]+offset))<(signed int)0x80000000+RAM_SIZE);
   if (!offset&&!c&&s>=0) ar=s;
   assert(ar>=0);
 
   if (opcode[i]==0x3a) { // SWC2
     cop2_get_dreg(copr,tl,HOST_TEMPREG);
+    type=STOREW_STUB;
   }
-  if(s>=0) c=(i_regs->wasconst>>s)&1;
-  if(!c) {
-    emit_cmpimm(offset||c||s<0?ar:s,0x800000);
-    jaddr2=(int)out;
-    emit_jno(0);
-  }
-  else if(((signed int)(constmap[i][s]+offset))>=(signed int)0x80800000) {
-    jaddr2=(int)out;
-    emit_jmp(0); // inline_readstub/inline_writestub?  Very rare case
-  }
-  if (opcode[i]==0x32) { // LWC2
-    #ifdef HOST_IMM_ADDR32
-    if(c) emit_readword_tlb(constmap[i][s]+offset,-1,tl);
-    else
-    #endif
-    emit_readword_indexed(0,ar,tl);
+  else
     type=LOADW_STUB;
+
+  if(c&&!memtarget) {
+    jaddr2=(int)out;
+    emit_jmp(0); // inline_readstub/inline_writestub?
   }
-  if (opcode[i]==0x3a) { // SWC2
-#ifdef DESTRUCTIVE_SHIFT
-    if(!offset&&!c&&s>=0) emit_mov(s,ar);
-#endif
-    emit_writeword_indexed(tl,0,ar);
-    type=STOREW_STUB;
+  else {
+    if(!c) {
+      emit_cmpimm(offset||c||s<0?ar:s,RAM_SIZE);
+      jaddr2=(int)out;
+      emit_jno(0);
+    }
+    if (opcode[i]==0x32) { // LWC2
+      #ifdef HOST_IMM_ADDR32
+      if(c) emit_readword_tlb(constmap[i][s]+offset,-1,tl);
+      else
+      #endif
+      emit_readword_indexed(0,ar,tl);
+    }
+    if (opcode[i]==0x3a) { // SWC2
+      #ifdef DESTRUCTIVE_SHIFT
+      if(!offset&&!c&&s>=0) emit_mov(s,ar);
+      #endif
+      emit_writeword_indexed(tl,0,ar);
+    }
   }
   if(jaddr2)
     add_stub(type,jaddr2,(int)out,i,ar,(int)i_regs,ccadj[i],reglist);
@@ -3657,7 +3702,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);
@@ -3713,6 +3758,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;
@@ -3757,6 +3812,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:
@@ -3784,8 +3840,11 @@ int internal_branch(uint64_t i_is32,int addr)
       else printf("optimizable: yes\n");
     }*/
     //if(is32[t]&~unneeded_reg_upper[t]&~i_is32) return 0;
+#ifndef FORCE32
     if(requires_32bit[t]&~i_is32) return 0;
-    else return 1;
+    else
+#endif
+      return 1;
   }
   return 0;
 }
@@ -3935,7 +3994,7 @@ void address_generation(int i,struct regstat *i_regs,signed char entry[])
     if(itype[i]==C1LS||itype[i]==C2LS) {
       if ((opcode[i]&0x3b)==0x31||(opcode[i]&0x3b)==0x32) // LWC1/LDC1/LWC2/LDC2
         ra=get_reg(i_regs->regmap,FTEMP);
-      else { // SWC1/SDC1
+      else { // SWC1/SDC1/SWC2/SDC2
         ra=get_reg(i_regs->regmap,agr);
         if(ra<0) ra=get_reg(i_regs->regmap,-1);
       }
@@ -3975,7 +4034,7 @@ void address_generation(int i,struct regstat *i_regs,signed char entry[])
               // Stores to memory go thru the mapper to detect self-modifying
               // code, loads don't.
               if((unsigned int)(constmap[i][rs]+offset)>=0xC0000000 ||
-                 (unsigned int)(constmap[i][rs]+offset)<0x80800000 )
+                 (unsigned int)(constmap[i][rs]+offset)<0x80000000+RAM_SIZE )
                 generate_map_const(constmap[i][rs]+offset,rm);
             }else{
               if((signed int)(constmap[i][rs]+offset)>=(signed int)0xC0000000)
@@ -4025,7 +4084,7 @@ void address_generation(int i,struct regstat *i_regs,signed char entry[])
           // Stores to memory go thru the mapper to detect self-modifying
           // code, loads don't.
           if((unsigned int)(constmap[i+1][rs]+offset)>=0xC0000000 ||
-             (unsigned int)(constmap[i+1][rs]+offset)<0x80800000 )
+             (unsigned int)(constmap[i+1][rs]+offset)<0x80000000+RAM_SIZE )
             generate_map_const(constmap[i+1][rs]+offset,ra);
         }else{
           if((signed int)(constmap[i+1][rs]+offset)>=(signed int)0xC0000000)
@@ -4525,7 +4584,9 @@ int match_bt(signed char i_regmap[],uint64_t i_is32,uint64_t i_dirty,int addr)
       }
     }
     //if(is32[t]&~unneeded_reg_upper[t]&~i_is32) return 0;
+#ifndef FORCE32
     if(requires_32bit[t]&~i_is32) return 0;
+#endif
     // Delay slots are not valid branch targets
     //if(t>0&&(itype[t-1]==RJUMP||itype[t-1]==UJUMP||itype[t-1]==CJUMP||itype[t-1]==SJUMP||itype[t-1]==FJUMP)) return 0;
     // Delay slots require additional processing, so do not match
@@ -4610,6 +4671,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:
@@ -5592,17 +5654,19 @@ void sjump_assemble(int i,struct regstat *i_regs)
   #endif
 
   //if(opcode2[i]>=0x10) return; // FIXME (BxxZAL)
-  assert(opcode2[i]<0x10||rs1[i]==0); // FIXME (BxxZAL)
+  //assert(opcode2[i]<0x10||rs1[i]==0); // FIXME (BxxZAL)
 
-  if(ooo)
+  if(ooo) {
     if(rs1[i]&&(rs1[i]==rt1[i+1]||rs1[i]==rt2[i+1]))
-  {
-    // Write-after-read dependency prevents out of order execution
-    // First test branch condition, then execute delay slot, then branch
-    ooo=0;
+    {
+      // Write-after-read dependency prevents out of order execution
+      // First test branch condition, then execute delay slot, then branch
+      ooo=0;
+    }
+    if(rt1[i]==31&&(rs1[i+1]==31||rs2[i+1]==31||rt1[i+1]==31||rt2[i+1]==31))
+      // BxxZAL $ra is available to delay insn, so do it in order
+      ooo=0;
   }
-  // TODO: Conditional branches w/link must execute in-order so that
-  // condition test and write to r31 occur before cycle count test
 
   if(ooo) {
     s1l=get_reg(branch_regs[i].regmap,rs1[i]);
@@ -5644,8 +5708,6 @@ void sjump_assemble(int i,struct regstat *i_regs)
     load_regs(regs[i].regmap,branch_regs[i].regmap,regs[i].was32,CCREG,CCREG);
     if(rt1[i]==31) {
       int rt,return_address;
-      assert(rt1[i+1]!=31);
-      assert(rt2[i+1]!=31);
       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]);
       if(rt>=0) {
@@ -5697,7 +5759,7 @@ void sjump_assemble(int i,struct regstat *i_regs)
       if(!only32)
       {
         assert(s1h>=0);
-        if(opcode2[i]==0) // BLTZ
+        if((opcode2[i]&0xf)==0) // BLTZ/BLTZAL
         {
           emit_test(s1h,s1h);
           if(invert){
@@ -5708,7 +5770,7 @@ void sjump_assemble(int i,struct regstat *i_regs)
             emit_js(0);
           }
         }
-        if(opcode2[i]==1) // BGEZ
+        if((opcode2[i]&0xf)==1) // BGEZ/BLTZAL
         {
           emit_test(s1h,s1h);
           if(invert){
@@ -5723,7 +5785,7 @@ void sjump_assemble(int i,struct regstat *i_regs)
       else
       {
         assert(s1l>=0);
-        if(opcode2[i]==0) // BLTZ
+        if((opcode2[i]&0xf)==0) // BLTZ/BLTZAL
         {
           emit_test(s1l,s1l);
           if(invert){
@@ -5734,7 +5796,7 @@ void sjump_assemble(int i,struct regstat *i_regs)
             emit_js(0);
           }
         }
-        if(opcode2[i]==1) // BGEZ
+        if((opcode2[i]&0xf)==1) // BGEZ/BLTZAL
         {
           emit_test(s1l,s1l);
           if(invert){
@@ -5789,18 +5851,30 @@ void sjump_assemble(int i,struct regstat *i_regs)
     // In-order execution (branch first)
     //printf("IOE\n");
     int nottaken=0;
+    if(rt1[i]==31) {
+      int rt,return_address;
+      rt=get_reg(branch_regs[i].regmap,31);
+      if(rt>=0) {
+        // Save the PC even if the branch is not taken
+        return_address=start+i*4+8;
+        emit_movimm(return_address,rt); // PC into link register
+        #ifdef IMM_PREFETCH
+        emit_prefetch(hash_table[((return_address>>16)^return_address)&0xFFFF]);
+        #endif
+      }
+    }
     if(!unconditional) {
       //printf("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]);
       if(!only32)
       {
         assert(s1h>=0);
-        if((opcode2[i]&0x1d)==0) // BLTZ/BLTZL
+        if((opcode2[i]&0x0d)==0) // BLTZ/BLTZL/BLTZAL/BLTZALL
         {
           emit_test(s1h,s1h);
           nottaken=(int)out;
           emit_jns(1);
         }
-        if((opcode2[i]&0x1d)==1) // BGEZ/BGEZL
+        if((opcode2[i]&0x0d)==1) // BGEZ/BGEZL/BGEZAL/BGEZALL
         {
           emit_test(s1h,s1h);
           nottaken=(int)out;
@@ -5810,13 +5884,13 @@ void sjump_assemble(int i,struct regstat *i_regs)
       else
       {
         assert(s1l>=0);
-        if((opcode2[i]&0x1d)==0) // BLTZ/BLTZL
+        if((opcode2[i]&0x0d)==0) // BLTZ/BLTZL/BLTZAL/BLTZALL
         {
           emit_test(s1l,s1l);
           nottaken=(int)out;
           emit_jns(1);
         }
-        if((opcode2[i]&0x1d)==1) // BGEZ/BGEZL
+        if((opcode2[i]&0x0d)==1) // BGEZ/BGEZL/BGEZAL/BGEZALL
         {
           emit_test(s1l,s1l);
           nottaken=(int)out;
@@ -6442,6 +6516,7 @@ static void pagespan_ds()
       mov_assemble(0,&regs[0]);break;
     case SYSCALL:
     case HLECALL:
+    case INTCALL:
     case SPAN:
     case UJUMP:
     case RJUMP:
@@ -6508,7 +6583,7 @@ void unneeded_registers(int istart,int iend,int r)
         {
           uu=u=0x300C0F3; // Discard at, a0-a3, t6-t9
         }
-        if(start>0x80000400&&start<0x80800000) {
+        if(start>0x80000400&&start<0x80000000+RAM_SIZE) {
           if(itype[i]==UJUMP&&rt1[i]==31)
           {
             //uu=u=0x30300FF0FLL; // Discard at, v0-v1, t0-t9, lo, hi
@@ -6665,7 +6740,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;
@@ -6697,9 +6772,6 @@ void unneeded_registers(int istart,int iend,int r)
     // Save it
     unneeded_reg[i]=u;
     unneeded_reg_upper[i]=uu;
-#ifdef FORCE32
-    unneeded_reg_upper[i]=-1LL;
-#endif
     /*
     printf("ur (%d,%d) %x: ",istart,iend,start+i*4);
     printf("U:");
@@ -6721,6 +6793,12 @@ void unneeded_registers(int istart,int iend,int r)
     }
     printf("\n");*/
   }
+#ifdef FORCE32
+  for (i=iend;i>=istart;i--)
+  {
+    unneeded_reg_upper[i]=branch_unneeded_reg_upper[i]=-1LL;
+  }
+#endif
 }
 
 // Identify registers which are likely to contain 32-bit values
@@ -7028,7 +7106,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;
@@ -7382,7 +7460,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;
@@ -7518,7 +7596,7 @@ void disassemble_inst(int i)
       case FJUMP:
         printf (" %x: %s %8x\n",start+i*4,insn[i],ba[i]);break;
       case RJUMP:
-        if (rt1[i]!=31)
+        if (opcode[i]==0x9&&rt1[i]!=31)
           printf (" %x: %s r%d,r%d\n",start+i*4,insn[i],rt1[i],rs1[i]);
         else
           printf (" %x: %s r%d\n",start+i*4,insn[i],rs1[i]);
@@ -7584,6 +7662,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]);
@@ -7706,20 +7787,33 @@ int new_recompile_block(int addr)
   start = (u_int)addr&~3;
   //assert(((u_int)addr&1)==0);
 #ifdef PCSX
-  if (Config.HLE && start == 0x80001000) {
+  if (Config.HLE && start == 0x80001000) // hlecall
+  {
     // XXX: is this enough? Maybe check hleSoftCall?
+    u_int beginning=(u_int)out;
     u_int page=get_page(start);
-    ll_add(jump_in+page,start,out);
     invalid_code[start>>12]=0;
     emit_movimm(start,0);
     emit_writeword(0,(int)&pcaddr);
-    emit_jmp((int)new_dyna_leave); // enough??
+    emit_jmp((int)new_dyna_leave);
+#ifdef __arm__
+    __clear_cache((void *)beginning,out);
+#endif
+    ll_add(jump_in+page,start,(void *)beginning);
     return 0;
   }
-  else if ((u_int)addr < 0x00200000) {
+  else if ((u_int)addr < 0x00200000 ||
+    (0xa0000000 <= addr && addr < 0xa0200000)) {
     // used for BIOS calls mostly?
-    source = (u_int *)((u_int)rdram+start-0);
-    pagelimit = 0x00200000;
+    source = (u_int *)((u_int)rdram+(start&0x1fffff));
+    pagelimit = (addr&0xa0000000)|0x00200000;
+  }
+  else if (!Config.HLE && (
+/*    (0x9fc00000 <= addr && addr < 0x9fc80000) ||*/
+    (0xbfc00000 <= addr && addr < 0xbfc80000))) {
+    // BIOS
+    source = (u_int *)((u_int)psxR+(start&0x7ffff));
+    pagelimit = (addr&0xfff00000)|0x80000;
   }
   else
 #endif
@@ -7730,9 +7824,9 @@ int new_recompile_block(int addr)
   }
   else
 #endif
-  if ((int)addr >= 0x80000000 && (int)addr < 0x80800000) {
+  if ((int)addr >= 0x80000000 && (int)addr < 0x80000000+RAM_SIZE) {
     source = (u_int *)((u_int)rdram+start-0x80000000);
-    pagelimit = 0x80800000;
+    pagelimit = 0x80000000+RAM_SIZE;
   }
 #ifndef DISABLE_TLB
   else if ((signed int)addr >= (signed int)0xC0000000) {
@@ -7754,7 +7848,7 @@ int new_recompile_block(int addr)
     else {
       assem_debug("Compile at unmapped memory address: %x \n", (int)addr);
       //assem_debug("start: %x next: %x\n",memory_map[start>>12],memory_map[(start+4096)>>12]);
-      return 1; // Caller will invoke exception handler
+      return -1; // Caller will invoke exception handler
     }
     //printf("source= %x\n",(int)source);
   }
@@ -7893,7 +7987,11 @@ int new_recompile_block(int addr)
             case 0x02: strcpy(insn[i],"TLBWI"); type=COP0; break;
             case 0x06: strcpy(insn[i],"TLBWR"); type=COP0; break;
             case 0x08: strcpy(insn[i],"TLBP"); type=COP0; break;
+#ifdef PCSX
+            case 0x10: strcpy(insn[i],"RFE"); type=COP0; break;
+#else
             case 0x18: strcpy(insn[i],"ERET"); type=COP0; break;
+#endif
           }
         }
         break;
@@ -8012,6 +8110,7 @@ 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;
@@ -8020,6 +8119,7 @@ int new_recompile_block(int addr)
       case 0x19: strcpy(insn[i],"DADDIU"); type=IMM16; break;
       case 0x1A: strcpy(insn[i],"LDL"); type=LOADLR; break;
       case 0x1B: strcpy(insn[i],"LDR"); type=LOADLR; break;
+#endif
       case 0x20: strcpy(insn[i],"LB"); type=LOAD; break;
       case 0x21: strcpy(insn[i],"LH"); type=LOAD; break;
       case 0x22: strcpy(insn[i],"LWL"); type=LOADLR; break;
@@ -8032,35 +8132,42 @@ int new_recompile_block(int addr)
       case 0x29: strcpy(insn[i],"SH"); type=STORE; break;
       case 0x2A: strcpy(insn[i],"SWL"); type=STORELR; break;
       case 0x2B: strcpy(insn[i],"SW"); type=STORE; break;
+#ifndef FORCE32
       case 0x2C: strcpy(insn[i],"SDL"); type=STORELR; break;
       case 0x2D: strcpy(insn[i],"SDR"); type=STORELR; break;
+#endif
       case 0x2E: strcpy(insn[i],"SWR"); type=STORELR; break;
       case 0x2F: strcpy(insn[i],"CACHE"); type=NOP; break;
       case 0x30: strcpy(insn[i],"LL"); type=NI; break;
       case 0x31: strcpy(insn[i],"LWC1"); type=C1LS; break;
+#ifndef FORCE32
       case 0x34: strcpy(insn[i],"LLD"); type=NI; break;
       case 0x35: strcpy(insn[i],"LDC1"); type=C1LS; break;
       case 0x37: strcpy(insn[i],"LD"); type=LOAD; break;
+#endif
       case 0x38: strcpy(insn[i],"SC"); type=NI; break;
       case 0x39: strcpy(insn[i],"SWC1"); type=C1LS; break;
+#ifndef FORCE32
       case 0x3C: strcpy(insn[i],"SCD"); type=NI; break;
       case 0x3D: strcpy(insn[i],"SDC1"); type=C1LS; break;
       case 0x3F: strcpy(insn[i],"SD"); type=STORE; break;
+#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;
@@ -8068,9 +8175,21 @@ int new_recompile_block(int addr)
       case 0x3B: strcpy(insn[i],"HLECALL"); type=HLECALL; break;
 #endif
       default: strcpy(insn[i],"???"); type=NI;
-        printf("NI %08x @%08x\n", source[i], addr + i*4);
+        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 */
@@ -8281,6 +8400,7 @@ int new_recompile_block(int addr)
         break;
       case SYSCALL:
       case HLECALL:
+      case INTCALL:
         rs1[i]=CCREG;
         rs2[i]=0;
         rt1[i]=0;
@@ -8304,14 +8424,19 @@ int new_recompile_block(int addr)
     else ba[i]=-1;
     /* Is this the end of the block? */
     if(i>0&&(itype[i-1]==UJUMP||itype[i-1]==RJUMP||(source[i-1]>>16)==0x1000)) {
+#ifdef PCSX
+      // check for link register access in delay slot
+      int rt1_=rt1[i-1];
+      if(rt1_!=0&&(rs1[i]==rt1_||rs2[i]==rt1_||rt1[i]==rt1_||rt2[i]==rt1_)) {
+        printf("link access in delay slot @%08x (%08x)\n", addr + i*4, addr);
+        ba[i-1]=-1;
+        itype[i-1]=INTCALL;
+        done=2;
+      }
+      else
+#endif
       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;
@@ -8323,9 +8448,17 @@ int new_recompile_block(int addr)
       // Don't get too close to the limit
       if(i>MAXBLOCK/2) done=1;
     }
-    if(i>0&&itype[i-1]==SYSCALL&&stop_after_jal) done=1;
-    if(itype[i-1]==HLECALL) done=1;
-    assert(i<MAXBLOCK-1);
+    if(itype[i]==SYSCALL&&stop_after_jal) 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);
     if (i==MAXBLOCK-1) done=1;
@@ -8362,9 +8495,10 @@ int new_recompile_block(int addr)
   int ds=0;
   int cc=0;
   int hr;
-  
+
+#ifndef FORCE32
   provisional_32bit();
-  
+#endif
   if((u_int)addr&1) {
     // First instruction is delay slot
     cc=-1;
@@ -8406,6 +8540,7 @@ int new_recompile_block(int addr)
         }
       }
     }
+#ifndef FORCE32
     // If something jumps here with 64-bit values
     // then promote those registers to 64 bits
     if(bt[i])
@@ -8440,8 +8575,7 @@ int new_recompile_block(int addr)
         current.is32=temp_is32;
       }
     }
-#ifdef FORCE32
-    memset(p32, 0xff, sizeof(p32));
+#else
     current.is32=-1LL;
 #endif
 
@@ -8449,7 +8583,7 @@ int new_recompile_block(int addr)
     regs[i].wasconst=current.isconst;
     regs[i].was32=current.is32;
     regs[i].wasdirty=current.dirty;
-    #ifdef DESTRUCTIVE_WRITEBACK
+    #if defined(DESTRUCTIVE_WRITEBACK) && !defined(FORCE32)
     // To change a dirty register from 32 to 64 bits, we must write
     // it out during the previous cycle (for branches, 2 cycles)
     if(i<slen-1&&bt[i+1]&&itype[i-1]!=UJUMP&&itype[i-1]!=CJUMP&&itype[i-1]!=SJUMP&&itype[i-1]!=RJUMP&&itype[i-1]!=FJUMP)
@@ -8627,6 +8761,7 @@ int new_recompile_block(int addr)
             alloc_reg(&current,i,31);
             dirty_reg(&current,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
@@ -8650,7 +8785,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]!=rt1[i]&&rs2[i+1]!=rt1[i]);
+              assert(rt1[i+1]!=rt1[i]);
               #ifdef REG_PREFETCH
               alloc_reg(&current,i,PTEMP);
               #endif
@@ -8794,7 +8930,6 @@ int new_recompile_block(int addr)
             if (rt1[i]==31) { // BLTZAL/BGEZAL
               alloc_reg(&current,i,31);
               dirty_reg(&current,31);
-              assert(rs1[i+1]!=31&&rs2[i+1]!=31);
               //#ifdef REG_PREFETCH
               //alloc_reg(&current,i,PTEMP);
               //#endif
@@ -8931,6 +9066,7 @@ int new_recompile_block(int addr)
           break;
         case SYSCALL:
         case HLECALL:
+        case INTCALL:
           syscall_alloc(&current,i);
           break;
         case SPAN:
@@ -9395,7 +9531,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;
@@ -9622,13 +9758,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
@@ -9814,7 +9972,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++;
         }
       }
@@ -10097,7 +10266,7 @@ int new_recompile_block(int addr)
   clean_registers(0,slen-1,1);
   
   /* Pass 7 - Identify 32-bit registers */
-  
+#ifndef FORCE32
   provisional_r32();
 
   u_int r32=0;
@@ -10167,7 +10336,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;
@@ -10211,6 +10380,7 @@ int new_recompile_block(int addr)
     }
     //requires_32bit[i]=is32[i]&~unneeded_reg_upper[i]; // DEBUG
   }
+#endif
 
   if(itype[slen-1]==SPAN) {
     bt[slen-1]=1; // Mark as a branch target so instruction can restart after exception
@@ -10445,6 +10615,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: ");
@@ -10551,6 +10734,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:
@@ -10638,6 +10823,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++)
   {
@@ -10680,7 +10868,11 @@ int new_recompile_block(int addr)
         u_int vpage=get_vpage(vaddr);
         literal_pool(256);
         //if(!(is32[i]&(~unneeded_reg_upper[i])&~(1LL<<CCREG)))
+#ifndef FORCE32
         if(!requires_32bit[i])
+#else
+        if(1)
+#endif
         {
           assem_debug("%8x (%d) <- %8x\n",instr_addr[i],i,start+i*4);
           assem_debug("jump_in: %x\n",start+i*4);
@@ -10795,10 +10987,6 @@ int new_recompile_block(int addr)
         break;
       case 3:
         // Clear jump_out
-        #ifdef __arm__
-        if((expirep&2047)==0)
-          __clear_cache((void *)BASE_ADDR,(void *)BASE_ADDR+(1<<TARGET_SIZE_2));
-        #endif
         ll_remove_matching_addrs(jump_out+(expirep&2047),base,shift);
         ll_remove_matching_addrs(jump_out+2048+(expirep&2047),base,shift);
         break;