drc: fix wrong address reg use in c2ls, small refactoring
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / new_dynarec.c
index 6f7c567..88c059a 100644 (file)
@@ -135,7 +135,7 @@ struct ll_entry
 #define CCREG 36 // Cycle count
 #define INVCP 37 // Pointer to invalid_code
 #define TEMPREG 38
-#define FTEMP 38 // FPU temporary register
+#define FTEMP 38 // FPU/LDL/LDR temporary register
 #define PTEMP 39 // Prefetch temporary register
 #define TLREG 40 // TLB mapping offset
 #define RHASH 41 // Return address hash
@@ -175,6 +175,10 @@ struct ll_entry
 #define OTHER 23  // Other
 #define SPAN 24   // Branch/delay slot spans 2 pages
 #define NI 25     // Not implemented
+#define HLECALL 26// PCSX fake opcodes for HLE
+#define COP2 27   // Coprocessor 2 move
+#define C2LS 28   // Coprocessor 2 load/store
+#define C2OP 29   // Coprocessor 2 operation
 
   /* stubs */
 #define CC_STUB 1
@@ -213,7 +217,10 @@ void cc_interrupt();
 void fp_exception();
 void fp_exception_ds();
 void jump_syscall();
+void jump_syscall_hle();
 void jump_eret();
+void jump_hlecall();
+void new_dyna_leave();
 
 // TLB
 void TLBWI_new();
@@ -399,6 +406,9 @@ void *get_addr_ht(u_int vaddr)
 
 void *get_addr_32(u_int vaddr,u_int flags)
 {
+#ifdef FORCE32
+  return get_addr(vaddr);
+#endif
   //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];
@@ -626,7 +636,7 @@ void lsn(u_char hsn[], int i, int *preferred_reg)
     }
     // On some architectures stores need invc_ptr
     #if defined(HOST_IMM8)
-    if(itype[i+j]==STORE || itype[i+j]==STORELR || (opcode[i+j]&0x3b)==0x39) {
+    if(itype[i+j]==STORE || itype[i+j]==STORELR || (opcode[i+j]&0x3b)==0x39 || (opcode[i+j]&0x3b)==0x3a) {
       hsn[INVCP]=j;
     }
     #endif
@@ -663,19 +673,19 @@ void lsn(u_char hsn[], int i, int *preferred_reg)
     hsn[RHTBL]=1;
   }
   // Coprocessor load/store needs FTEMP, even if not declared
-  if(itype[i]==C1LS) {
+  if(itype[i]==C1LS||itype[i]==C2LS) {
     hsn[FTEMP]=0;
   }
   // Load L/R also uses FTEMP as a temporary register
   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
-  if(itype[i]==LOAD || itype[i]==LOADLR || itype[i]==STORE || itype[i]==STORELR || itype[i]==C1LS ) {
+  if(itype[i]==LOAD || itype[i]==LOADLR || itype[i]==STORE || itype[i]==STORELR || itype[i]==C1LS || itype[i]==C2LS) {
     hsn[TLREG]=0;
   }
   // Don't remove the miniht registers
@@ -716,7 +726,7 @@ int needed_again(int r, int i)
       j++;
       break;
     }
-    if(itype[i+j]==SYSCALL||((source[i+j]&0xfc00003f)==0x0d))
+    if(itype[i+j]==SYSCALL||itype[i+j]==HLECALL||((source[i+j]&0xfc00003f)==0x0d))
     {
       break;
     }
@@ -962,14 +972,10 @@ void ll_add(struct ll_entry **head,int vaddr,void *addr)
 // Add virtual address mapping for 32-bit compiled block
 void ll_add_32(struct ll_entry **head,int vaddr,u_int reg32,void *addr)
 {
-  struct ll_entry *new_entry;
-  new_entry=malloc(sizeof(struct ll_entry));
-  assert(new_entry!=NULL);
-  new_entry->vaddr=vaddr;
-  new_entry->reg32=reg32;
-  new_entry->addr=addr;
-  new_entry->next=*head;
-  *head=new_entry;
+  ll_add(head,vaddr,addr);
+#ifndef FORCE32
+  (*head)->reg32=reg32;
+#endif
 }
 
 // Check if an address is already compiled
@@ -1070,25 +1076,37 @@ 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);
     if(((ptr>>shift)==(addr>>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);
+      printf("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)) {
+        #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) {
@@ -1102,17 +1120,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);
@@ -1127,7 +1153,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;
@@ -1145,7 +1171,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
@@ -1171,10 +1197,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
@@ -1243,7 +1266,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];
             }
@@ -1253,7 +1276,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) {
@@ -1615,7 +1638,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
@@ -1643,6 +1666,22 @@ void c1ls_alloc(struct regstat *current,int i)
   alloc_reg_temp(current,i,-1);
 }
 
+void c2ls_alloc(struct regstat *current,int i)
+{
+  clear_const(current,rt1[i]);
+  if(needed_again(rs1[i],i)) alloc_reg(current,i,rs1[i]);
+  alloc_reg(current,i,FTEMP);
+  // If using TLB, need a register for pointer to the mapping table
+  if(using_tlb) alloc_reg(current,i,TLREG);
+  #if defined(HOST_IMM8)
+  // On CPUs without 32-bit immediates we need a pointer to invalid_code
+  else if((opcode[i]&0x3b)==0x3a) // SWC2/SDC2
+    alloc_reg(current,i,INVCP);
+  #endif
+  // We need a temporary register for address generation
+  alloc_reg_temp(current,i,-1);
+}
+
 #ifndef multdiv_alloc
 void multdiv_alloc(struct regstat *current,int i)
 {
@@ -1780,6 +1819,10 @@ void float_alloc(struct regstat *current,int i)
   alloc_reg(current,i,CSREG); // Load status
   alloc_reg_temp(current,i,-1);
 }
+void c2op_alloc(struct regstat *current,int i)
+{
+  alloc_reg_temp(current,i,-1);
+}
 void fcomp_alloc(struct regstat *current,int i)
 {
   alloc_reg(current,i,CSREG); // Load status
@@ -1805,6 +1848,7 @@ void delayslot_alloc(struct regstat *current,int i)
     case RJUMP:
     case FJUMP:
     case SYSCALL:
+    case HLECALL:
     case SPAN:
       assem_debug("jump in the delay slot.  this shouldn't happen.\n");//exit(1);
       printf("Disabled speculative precompilation\n");
@@ -1840,11 +1884,15 @@ void delayslot_alloc(struct regstat *current,int i)
       cop0_alloc(current,i);
       break;
     case COP1:
+    case COP2:
       cop1_alloc(current,i);
       break;
     case C1LS:
       c1ls_alloc(current,i);
       break;
+    case C2LS:
+      c2ls_alloc(current,i);
+      break;
     case FCONV:
       fconv_alloc(current,i);
       break;
@@ -1854,6 +1902,9 @@ void delayslot_alloc(struct regstat *current,int i)
     case FCOMP:
       fcomp_alloc(current,i);
       break;
+    case C2OP:
+      c2op_alloc(current,i);
+      break;
   }
 }
 
@@ -1874,9 +1925,9 @@ static void pagespan_alloc(struct regstat *current,int i)
   if(opcode[i]==0&&(opcode2[i]&0x3E)==8) // JR/JALR
   {
     alloc_reg(current,i,rs1[i]);
-    if (rt1[i]==31) {
-      alloc_reg(current,i,31);
-      dirty_reg(current,31);
+    if (rt1[i]!=0) {
+      alloc_reg(current,i,rt1[i]);
+      dirty_reg(current,rt1[i]);
     }
   }
   if((opcode[i]&0x2E)==4) // BEQ/BNE/BEQL/BNEL
@@ -2683,7 +2734,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]);
@@ -2695,14 +2746,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) {
+    if(!c||(((u_int)constmap[i][s]+offset)>>16)==0x1f80) {
+      // could be FIFO, must perform the read
+      assem_debug("(forced read)\n");
+      tl=get_reg(i_regs->regmap,-1);
+      assert(tl>=0);
+    }
+  }
+  if(offset||s<0||c) addr=tl;
+  else addr=s;
+#endif
   if(tl>=0) {
     //assert(tl>=0);
     //assert(rt1[i]);
@@ -2713,10 +2774,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
@@ -2948,7 +3009,7 @@ void store_assemble(int i,struct regstat *i_regs)
   int addr,temp;
   int offset;
   int jaddr=0,jaddr2,type;
-  int memtarget,c=0;
+  int memtarget=0,c=0;
   int agr=AGEN1+(i&1);
   u_int hr,reglist=0;
   th=get_reg(i_regs->regmap,rs2[i]|64);
@@ -2959,7 +3020,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);
@@ -2975,14 +3036,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;
@@ -3064,6 +3125,9 @@ void store_assemble(int i,struct regstat *i_regs)
     }
     type=STORED_STUB;
   }
+  if(!using_tlb&&(!c||memtarget))
+    // addr could be a temp, make sure it survives STORE*_STUB
+    reglist|=1<<addr;
   if(jaddr) {
     add_stub(type,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist);
   } else if(!memtarget) {
@@ -3129,15 +3193,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);
@@ -3148,7 +3214,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);
@@ -3315,7 +3381,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);
@@ -3400,7 +3466,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
   {
@@ -3431,7 +3497,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
     }
@@ -3527,6 +3593,92 @@ void c1ls_assemble(int i,struct regstat *i_regs)
 #endif
 }
 
+void c2ls_assemble(int i,struct regstat *i_regs)
+{
+  int s,tl;
+  int ar;
+  int offset;
+  int memtarget=0,c=0;
+  int jaddr,jaddr2=0,jaddr3,type;
+  int agr=AGEN1+(i&1);
+  u_int hr,reglist=0;
+  u_int copr=(source[i]>>16)&0x1f;
+  s=get_reg(i_regs->regmap,rs1[i]);
+  tl=get_reg(i_regs->regmap,FTEMP);
+  offset=imm[i];
+  assert(rs1[i]>0);
+  assert(tl>=0);
+  assert(!using_tlb);
+
+  for(hr=0;hr<HOST_REGS;hr++) {
+    if(i_regs->regmap[hr]>=0) reglist|=1<<hr;
+  }
+  if(i_regs->regmap[HOST_CCREG]==CCREG)
+    reglist&=~(1<<HOST_CCREG);
+
+  // get the address
+  if (opcode[i]==0x3a) { // SWC2
+    ar=get_reg(i_regs->regmap,agr);
+    if(ar<0) ar=get_reg(i_regs->regmap,-1);
+    reglist|=1<<ar;
+  } 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;
+  }
+  else
+    type=LOADW_STUB;
+
+  if(c&&!memtarget) {
+    jaddr2=(int)out;
+    emit_jmp(0); // inline_readstub/inline_writestub?
+  }
+  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);
+  if (opcode[i]==0x3a) { // SWC2
+#if defined(HOST_IMM8)
+    int ir=get_reg(i_regs->regmap,INVCP);
+    assert(ir>=0);
+    emit_cmpmem_indexedsr12_reg(ir,ar,1);
+#else
+    emit_cmpmem_indexedsr12_imm((int)invalid_code,ar,1);
+#endif
+    jaddr3=(int)out;
+    emit_jne(0);
+    add_stub(INVCODE_STUB,jaddr3,(int)out,reglist|(1<<HOST_CCREG),ar,0,0,0);
+  }
+  if (opcode[i]==0x32) { // LWC2
+    cop2_put_dreg(copr,tl,HOST_TEMPREG);
+  }
+}
+
 #ifndef multdiv_assemble
 void multdiv_assemble(int i,struct regstat *i_regs)
 {
@@ -3581,7 +3733,18 @@ void syscall_assemble(int i,struct regstat *i_regs)
   assert(!is_delayslot);
   emit_movimm(start+i*4,EAX); // Get PC
   emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); // CHECK: is this right?  There should probably be an extra cycle...
-  emit_jmp((int)jump_syscall);
+  emit_jmp((int)jump_syscall_hle); // XXX
+}
+
+void hlecall_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+4,0); // Get PC
+  emit_movimm((int)psxHLEt[source[i]&7],1);
+  emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); // XXX
+  emit_jmp((int)jump_hlecall);
 }
 
 void ds_assemble(int i,struct regstat *i_regs)
@@ -3610,6 +3773,12 @@ void ds_assemble(int i,struct regstat *i_regs)
       cop1_assemble(i,i_regs);break;
     case C1LS:
       c1ls_assemble(i,i_regs);break;
+    case COP2:
+      cop2_assemble(i,i_regs);break;
+    case C2LS:
+      c2ls_assemble(i,i_regs);break;
+    case C2OP:
+      c2op_assemble(i,i_regs);break;
     case FCONV:
       fconv_assemble(i,i_regs);break;
     case FLOAT:
@@ -3621,6 +3790,7 @@ void ds_assemble(int i,struct regstat *i_regs)
     case MOV:
       mov_assemble(i,i_regs);break;
     case SYSCALL:
+    case HLECALL:
     case SPAN:
     case UJUMP:
     case RJUMP:
@@ -3778,9 +3948,10 @@ static void loop_preload(signed char pre[],signed char entry[])
 }
 
 // Generate address for load/store instruction
+// goes to AGEN for writes, FTEMP for LOADLR and cop1/2 loads
 void address_generation(int i,struct regstat *i_regs,signed char entry[])
 {
-  if(itype[i]==LOAD||itype[i]==LOADLR||itype[i]==STORE||itype[i]==STORELR||itype[i]==C1LS) {
+  if(itype[i]==LOAD||itype[i]==LOADLR||itype[i]==STORE||itype[i]==STORELR||itype[i]==C1LS||itype[i]==C2LS) {
     int ra;
     int agr=AGEN1+(i&1);
     int mgr=MGEN1+(i&1);
@@ -3795,10 +3966,10 @@ void address_generation(int i,struct regstat *i_regs,signed char entry[])
       ra=get_reg(i_regs->regmap,agr);
       if(ra<0) ra=get_reg(i_regs->regmap,-1);
     }
-    if(itype[i]==C1LS) {
-      if (opcode[i]==0x31||opcode[i]==0x35) // LWC1/LDC1
+    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);
       }
@@ -3834,11 +4005,11 @@ void address_generation(int i,struct regstat *i_regs,signed char entry[])
       else if(c) {
         if(rm>=0) {
           if(!entry||entry[rm]!=mgr) {
-            if(itype[i]==STORE||itype[i]==STORELR||opcode[i]==0x39||opcode[i]==0x3D) {
+            if(itype[i]==STORE||itype[i]==STORELR||(opcode[i]&0x3b)==0x39||(opcode[i]&0x3b)==0x3a) {
               // 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)
@@ -3854,7 +4025,7 @@ void address_generation(int i,struct regstat *i_regs,signed char entry[])
               emit_movimm((constmap[i][rs]+offset)&0xFFFFFFF8,ra); // LDL/LDR
             }else{
               #ifdef HOST_IMM_ADDR32
-              if((itype[i]!=LOAD&&opcode[i]!=0x31&&opcode[i]!=0x35) ||
+              if((itype[i]!=LOAD&&(opcode[i]&0x3b)!=0x31&&(opcode[i]&0x3b)!=0x32) || // LWC1/LDC1/LWC2/LDC2
                  (using_tlb&&((signed int)constmap[i][rs]+offset)>=(signed int)0xC0000000))
               #endif
               emit_movimm(constmap[i][rs]+offset,ra);
@@ -3872,7 +4043,7 @@ void address_generation(int i,struct regstat *i_regs,signed char entry[])
     }
   }
   // Preload constants for next instruction
-  if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR||itype[i+1]==C1LS) {
+  if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR||itype[i+1]==C1LS||itype[i+1]==C2LS) {
     int agr,ra;
     #ifndef HOST_IMM_ADDR32
     // Mapper entry
@@ -3883,11 +4054,12 @@ void address_generation(int i,struct regstat *i_regs,signed char entry[])
       int offset=imm[i+1];
       int c=(regs[i+1].wasconst>>rs)&1;
       if(c) {
-        if(itype[i+1]==STORE||itype[i+1]==STORELR||opcode[i+1]==0x39||opcode[i+1]==0x3D) {
+        if(itype[i+1]==STORE||itype[i+1]==STORELR
+           ||(opcode[i+1]&0x3b)==0x39||(opcode[i+1]&0x3b)==0x3a) { // SWC1/SDC1, SWC2/SDC2
           // 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)
@@ -3913,7 +4085,7 @@ void address_generation(int i,struct regstat *i_regs,signed char entry[])
           emit_movimm((constmap[i+1][rs]+offset)&0xFFFFFFF8,ra); // LDL/LDR
         }else{
           #ifdef HOST_IMM_ADDR32
-          if((itype[i+1]!=LOAD&&opcode[i+1]!=0x31&&opcode[i+1]!=0x35) ||
+          if((itype[i+1]!=LOAD&&(opcode[i+1]&0x3b)!=0x31&&(opcode[i+1]&0x3b)!=0x32) || // LWC1/LDC1/LWC2/LDC2
              (using_tlb&&((signed int)constmap[i+1][rs]+offset)>=(signed int)0xC0000000))
           #endif
           emit_movimm(constmap[i+1][rs]+offset,ra);
@@ -4427,7 +4599,7 @@ void ds_assemble_entry(int i)
     wb_register(CCREG,regs[t].regmap_entry,regs[t].wasdirty,regs[t].was32);
   load_regs(regs[t].regmap_entry,regs[t].regmap,regs[t].was32,rs1[t],rs2[t]);
   address_generation(t,&regs[t],regs[t].regmap_entry);
-  if(itype[t]==STORE||itype[t]==STORELR||(opcode[t]&0x3b)==0x39)
+  if(itype[t]==STORE||itype[t]==STORELR||(opcode[t]&0x3b)==0x39||(opcode[t]&0x3b)==0x3a)
     load_regs(regs[t].regmap_entry,regs[t].regmap,regs[t].was32,INVCP,INVCP);
   cop1_usable=0;
   is_delayslot=0;
@@ -4454,6 +4626,12 @@ void ds_assemble_entry(int i)
       cop1_assemble(t,&regs[t]);break;
     case C1LS:
       c1ls_assemble(t,&regs[t]);break;
+    case COP2:
+      cop2_assemble(t,&regs[t]);break;
+    case C2LS:
+      c2ls_assemble(t,&regs[t]);break;
+    case C2OP:
+      c2op_assemble(t,&regs[t]);break;
     case FCONV:
       fconv_assemble(t,&regs[t]);break;
     case FLOAT:
@@ -4465,6 +4643,7 @@ void ds_assemble_entry(int i)
     case MOV:
       mov_assemble(t,&regs[t]);break;
     case SYSCALL:
+    case HLECALL:
     case SPAN:
     case UJUMP:
     case RJUMP:
@@ -4931,11 +5110,11 @@ 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]==31) {
+  if(rt1[i]!=0) {
     int rt,return_address;
-    assert(rt1[i+1]!=31);
-    assert(rt2[i+1]!=31);
-    rt=get_reg(branch_regs[i].regmap,31);
+    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;
@@ -5447,7 +5626,7 @@ 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(rs1[i]&&(rs1[i]==rt1[i+1]||rs1[i]==rt2[i+1]))
@@ -5456,8 +5635,7 @@ void sjump_assemble(int i,struct regstat *i_regs)
     // First test branch condition, then execute delay slot, then branch
     ooo=0;
   }
-  // TODO: Conditional branches w/link must execute in-order so that
-  // condition test and write to r31 occur before cycle count test
+  assert(opcode2[i]<0x10||ooo); // FIXME (BxxZALL)
 
   if(ooo) {
     s1l=get_reg(branch_regs[i].regmap,rs1[i]);
@@ -5552,7 +5730,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){
@@ -5563,7 +5741,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){
@@ -5578,7 +5756,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){
@@ -5589,7 +5767,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){
@@ -6051,7 +6229,7 @@ static void pagespan_assemble(int i,struct regstat *i_regs)
     emit_mov(s1l,addr);
     if(opcode2[i]==9) // JALR
     {
-      int rt=get_reg(i_regs->regmap,31);
+      int rt=get_reg(i_regs->regmap,rt1[i]);
       emit_movimm(start+i*4+8,rt);
     }
   }
@@ -6252,7 +6430,7 @@ static void pagespan_ds()
     emit_writeword(HOST_BTREG,(int)&branch_target);
   load_regs(regs[0].regmap_entry,regs[0].regmap,regs[0].was32,rs1[0],rs2[0]);
   address_generation(0,&regs[0],regs[0].regmap_entry);
-  if(itype[0]==STORE||itype[0]==STORELR||(opcode[0]&0x3b)==0x39)
+  if(itype[0]==STORE||itype[0]==STORELR||(opcode[0]&0x3b)==0x39||(opcode[0]&0x3b)==0x3a)
     load_regs(regs[0].regmap_entry,regs[0].regmap,regs[0].was32,INVCP,INVCP);
   cop1_usable=0;
   is_delayslot=0;
@@ -6279,6 +6457,12 @@ static void pagespan_ds()
       cop1_assemble(0,&regs[0]);break;
     case C1LS:
       c1ls_assemble(0,&regs[0]);break;
+    case COP2:
+      cop2_assemble(0,&regs[0]);break;
+    case C2LS:
+      c2ls_assemble(0,&regs[0]);break;
+    case C2OP:
+      c2op_assemble(0,&regs[0]);break;
     case FCONV:
       fconv_assemble(0,&regs[0]);break;
     case FLOAT:
@@ -6290,6 +6474,7 @@ static void pagespan_ds()
     case MOV:
       mov_assemble(0,&regs[0]);break;
     case SYSCALL:
+    case HLECALL:
     case SPAN:
     case UJUMP:
     case RJUMP:
@@ -6356,7 +6541,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
@@ -6513,7 +6698,7 @@ void unneeded_registers(int istart,int iend,int r)
         }
       }
     }
-    else if(itype[i]==SYSCALL)
+    else if(itype[i]==SYSCALL||itype[i]==HLECALL)
     {
       // SYSCALL instruction (software interrupt)
       u=1;
@@ -6545,9 +6730,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:");
@@ -6569,6 +6751,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
@@ -6759,18 +6947,22 @@ static void provisional_32bit()
         if(op2==0) is32|=1LL<<rt; // MFC0
         break;
       case COP1:
+      case COP2:
         if(op2==0) is32|=1LL<<rt; // MFC1
         if(op2==1) is32&=~(1LL<<rt); // DMFC1
         if(op2==2) is32|=1LL<<rt; // CFC1
         break;
       case C1LS:
+      case C2LS:
         break;
       case FLOAT:
       case FCONV:
         break;
       case FCOMP:
         break;
+      case C2OP:
       case SYSCALL:
+      case HLECALL:
         break;
       default:
         break;
@@ -6872,7 +7064,7 @@ static void provisional_r32()
         if((regs[i].was32>>dep2[i+1])&1) r32|=1LL<<dep2[i+1];
       }
     }
-    else if(itype[i]==SYSCALL)
+    else if(itype[i]==SYSCALL||itype[i]==HLECALL)
     {
       // SYSCALL instruction (software interrupt)
       r32=0;
@@ -7226,7 +7418,7 @@ void clean_registers(int istart,int iend,int wr)
         }
       }
     }
-    else if(itype[i]==SYSCALL)
+    else if(itype[i]==SYSCALL||itype[i]==HLECALL)
     {
       // SYSCALL instruction (software interrupt)
       will_dirty_i=0;
@@ -7362,7 +7554,11 @@ void disassemble_inst(int i)
       case FJUMP:
         printf (" %x: %s %8x\n",start+i*4,insn[i],ba[i]);break;
       case RJUMP:
-        printf (" %x: %s r%d\n",start+i*4,insn[i],rs1[i]);break;
+        if (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]);
+        break;
       case SPAN:
         printf (" %x: %s (pagespan) r%d,r%d,%8x\n",start+i*4,insn[i],rs1[i],rs2[i],ba[i]);break;
       case IMM16:
@@ -7411,9 +7607,19 @@ void disassemble_inst(int i)
           printf (" %x: %s r%d,cpr1[%d]\n",start+i*4,insn[i],rs1[i],(source[i]>>11)&0x1f); // MTC1
         else printf (" %x: %s\n",start+i*4,insn[i]);
         break;
+      case COP2:
+        if(opcode2[i]<3)
+          printf (" %x: %s r%d,cpr2[%d]\n",start+i*4,insn[i],rt1[i],(source[i]>>11)&0x1f); // MFC2
+        else if(opcode2[i]>3)
+          printf (" %x: %s r%d,cpr2[%d]\n",start+i*4,insn[i],rs1[i],(source[i]>>11)&0x1f); // MTC2
+        else printf (" %x: %s\n",start+i*4,insn[i]);
+        break;
       case C1LS:
         printf (" %x: %s cpr1[%d],r%d+%x\n",start+i*4,insn[i],(source[i]>>16)&0x1f,rs1[i],imm[i]);
         break;
+      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;
       default:
         //printf (" %s %8x\n",insn[i],source[i]);
         printf (" %x: %s\n",start+i*4,insn[i]);
@@ -7535,6 +7741,28 @@ int new_recompile_block(int addr)
   //rlist();
   start = (u_int)addr&~3;
   //assert(((u_int)addr&1)==0);
+#ifdef PCSX
+  if (Config.HLE && start == 0x80001000) {
+    // 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);
+#ifdef __arm__
+    __clear_cache((void *)beginning,out);
+#endif
+    return 0;
+  }
+  else if ((u_int)addr < 0x00200000) {
+    // used for BIOS calls mostly?
+    source = (u_int *)((u_int)rdram+start-0);
+    pagelimit = 0x00200000;
+  }
+  else
+#endif
 #ifdef MUPEN64
   if ((int)addr >= 0xa4000000 && (int)addr < 0xa4001000) {
     source = (u_int *)((u_int)SP_DMEM+start-0xa4000000);
@@ -7542,9 +7770,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) {
@@ -7828,10 +8056,12 @@ int new_recompile_block(int addr)
       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;
       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;
@@ -7844,22 +8074,49 @@ 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;
+        op2=(source[i]>>21)&0x1f;
+        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;
+      case 0x3A: strcpy(insn[i],"SWC2"); type=C2LS; break;
+      case 0x3B: strcpy(insn[i],"HLECALL"); type=HLECALL; break;
+#endif
       default: strcpy(insn[i],"???"); type=NI;
-        assem_debug("NI %08x @%08x\n", source[i], addr + i*4);
+        printf("NI %08x @%08x (%08x)\n", source[i], addr + i*4, addr);
         break;
     }
     itype[i]=type;
@@ -7929,9 +8186,9 @@ int new_recompile_block(int addr)
         rs2[i]=0;
         rt1[i]=0;
         rt2[i]=0;
-        // The JALR instruction writes to r31.
+        // The JALR instruction writes to rd.
         if (op2&1) {
-          rt1[i]=31;   
+          rt1[i]=(source[i]>>11)&0x1f;
         }
         rs2[i]=CCREG;
         break;
@@ -8033,6 +8290,7 @@ int new_recompile_block(int addr)
         if(op2==16) if((source[i]&0x3f)==0x18) rs2[i]=CCREG; // ERET
         break;
       case COP1:
+      case COP2:
         rs1[i]=0;
         rs2[i]=0;
         rt1[i]=0;
@@ -8049,6 +8307,13 @@ int new_recompile_block(int addr)
         rt2[i]=0;
         imm[i]=(short)source[i];
         break;
+      case C2LS:
+        rs1[i]=(source[i]>>21)&0x1F;
+        rs2[i]=0;
+        rt1[i]=0;
+        rt2[i]=0;
+        imm[i]=(short)source[i];
+        break;
       case FLOAT:
       case FCONV:
         rs1[i]=0;
@@ -8063,6 +8328,7 @@ int new_recompile_block(int addr)
         rt2[i]=0;
         break;
       case SYSCALL:
+      case HLECALL:
         rs1[i]=CCREG;
         rs2[i]=0;
         rt1[i]=0;
@@ -8086,7 +8352,7 @@ 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)) {
-      if(rt1[i-1]!=31) { // Continue past subroutine call (JAL)
+      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--)
@@ -8105,8 +8371,9 @@ 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;
-    assert(i<MAXBLOCK-1);
+    if(itype[i]==SYSCALL&&stop_after_jal) done=1;
+    if(itype[i]==HLECALL) done=1;
+    //assert(i<MAXBLOCK-1);
     if(start+i*4==pagelimit-4) done=1;
     assert(start+i*4<pagelimit);
     if (i==MAXBLOCK-1) done=1;
@@ -8428,9 +8695,9 @@ int new_recompile_block(int addr)
           dirty_reg(&current,CCREG);
           if(rs1[i]!=rt1[i+1]&&rs1[i]!=rt2[i+1]) {
             alloc_reg(&current,i,rs1[i]);
-            if (rt1[i]==31) {
-              alloc_reg(&current,i,31);
-              dirty_reg(&current,31);
+            if (rt1[i]!=0) {
+              alloc_reg(&current,i,rt1[i]);
+              dirty_reg(&current,rt1[i]);
               assert(rs1[i+1]!=31&&rs2[i+1]!=31);
               #ifdef REG_PREFETCH
               alloc_reg(&current,i,PTEMP);
@@ -8689,11 +8956,18 @@ int new_recompile_block(int addr)
           cop0_alloc(&current,i);
           break;
         case COP1:
+        case COP2:
           cop1_alloc(&current,i);
           break;
         case C1LS:
           c1ls_alloc(&current,i);
           break;
+        case C2LS:
+          c2ls_alloc(&current,i);
+          break;
+        case C2OP:
+          c2op_alloc(&current,i);
+          break;
         case FCONV:
           fconv_alloc(&current,i);
           break;
@@ -8704,6 +8978,7 @@ int new_recompile_block(int addr)
           fcomp_alloc(&current,i);
           break;
         case SYSCALL:
+        case HLECALL:
           syscall_alloc(&current,i);
           break;
         case SPAN:
@@ -8810,10 +9085,10 @@ int new_recompile_block(int addr)
           alloc_cc(&branch_regs[i-1],i-1);
           dirty_reg(&branch_regs[i-1],CCREG);
           alloc_reg(&branch_regs[i-1],i-1,rs1[i-1]);
-          if(rt1[i-1]==31) { // JALR
-            alloc_reg(&branch_regs[i-1],i-1,31);
-            dirty_reg(&branch_regs[i-1],31);
-            branch_regs[i-1].is32|=1LL<<31;
+          if(rt1[i-1]!=0) { // JALR
+            alloc_reg(&branch_regs[i-1],i-1,rt1[i-1]);
+            dirty_reg(&branch_regs[i-1],rt1[i-1]);
+            branch_regs[i-1].is32|=1LL<<rt1[i-1];
           }
           #ifdef USE_MINI_HT
           if(rs1[i-1]==31) { // JALR
@@ -9069,7 +9344,7 @@ int new_recompile_block(int addr)
 
     // Count cycles in between branches
     ccadj[i]=cc;
-    if(i>0&&(itype[i-1]==RJUMP||itype[i-1]==UJUMP||itype[i-1]==CJUMP||itype[i-1]==SJUMP||itype[i-1]==FJUMP||itype[i]==SYSCALL))
+    if(i>0&&(itype[i-1]==RJUMP||itype[i-1]==UJUMP||itype[i-1]==CJUMP||itype[i-1]==SJUMP||itype[i-1]==FJUMP||itype[i]==SYSCALL||itype[i]==HLECALL))
     {
       cc=0;
     }
@@ -9162,13 +9437,13 @@ int new_recompile_block(int addr)
           if(dep1[i+1]==(regs[i].regmap_entry[hr]&63)) nr|=1<<hr;
           if(dep2[i+1]==(regs[i].regmap_entry[hr]&63)) nr|=1<<hr;
         }
-        if(itype[i+1]==STORE || itype[i+1]==STORELR || (opcode[i+1]&0x3b)==0x39) {
+        if(itype[i+1]==STORE || itype[i+1]==STORELR || (opcode[i+1]&0x3b)==0x39 || (opcode[i+1]&0x3b)==0x3a) {
           if(regmap_pre[i][hr]==INVCP) nr|=1<<hr;
           if(regs[i].regmap_entry[hr]==INVCP) nr|=1<<hr;
         }
       }
     }
-    else if(itype[i]==SYSCALL)
+    else if(itype[i]==SYSCALL||itype[i]==HLECALL)
     {
       // SYSCALL instruction (software interrupt)
       nr=0;
@@ -9212,7 +9487,7 @@ int new_recompile_block(int addr)
         if(dep2[i]==(regmap_pre[i][hr]&63)) nr|=1<<hr;
         if(dep2[i]==(regs[i].regmap_entry[hr]&63)) nr|=1<<hr;
       }
-      if(itype[i]==STORE || itype[i]==STORELR || (opcode[i]&0x3b)==0x39) {
+      if(itype[i]==STORE || itype[i]==STORELR || (opcode[i]&0x3b)==0x39 || (opcode[i]&0x3b)==0x3a) {
         if(regmap_pre[i][hr]==INVCP) nr|=1<<hr;
         if(regs[i].regmap_entry[hr]==INVCP) nr|=1<<hr;
       }
@@ -9270,14 +9545,15 @@ int new_recompile_block(int addr)
           if(using_tlb) {
             if(itype[i+1]==LOAD || itype[i+1]==LOADLR ||
                itype[i+1]==STORE || itype[i+1]==STORELR ||
-               itype[i+1]==C1LS )
+               itype[i+1]==C1LS || itype[i+1]==C2LS)
             map=TLREG;
           } else
-          if(itype[i+1]==STORE || itype[i+1]==STORELR || (opcode[i+1]&0x3b)==0x39) {
+          if(itype[i+1]==STORE || itype[i+1]==STORELR ||
+             (opcode[i+1]&0x3b)==0x39 || (opcode[i+1]&0x3b)==0x3a) { // SWC1/SDC1 || SWC2/SDC2
             map=INVCP;
           }
           if(itype[i+1]==LOADLR || itype[i+1]==STORELR ||
-             itype[i+1]==C1LS )
+             itype[i+1]==C1LS || itype[i+1]==C2LS)
             temp=FTEMP;
           if((regs[i].regmap[hr]&63)!=rs1[i] && (regs[i].regmap[hr]&63)!=rs2[i] &&
              (regs[i].regmap[hr]&63)!=rt1[i] && (regs[i].regmap[hr]&63)!=rt2[i] &&
@@ -9328,13 +9604,14 @@ int new_recompile_block(int addr)
             if(using_tlb) {
               if(itype[i]==LOAD || itype[i]==LOADLR ||
                  itype[i]==STORE || itype[i]==STORELR ||
-                 itype[i]==C1LS )
+                 itype[i]==C1LS || itype[i]==C2LS)
               map=TLREG;
-            } else if(itype[i]==STORE || itype[i]==STORELR || (opcode[i]&0x3b)==0x39) {
+            } else if(itype[i]==STORE || itype[i]==STORELR ||
+                      (opcode[i]&0x3b)==0x39 || (opcode[i]&0x3b)==0x3a) { // SWC1/SDC1 || SWC2/SDC2
               map=INVCP;
             }
             if(itype[i]==LOADLR || itype[i]==STORELR ||
-               itype[i]==C1LS )
+               itype[i]==C1LS || itype[i]==C2LS)
               temp=FTEMP;
             if((regs[i].regmap[hr]&63)!=rt1[i] && (regs[i].regmap[hr]&63)!=rt2[i] &&
                (regs[i].regmap[hr]^64)!=us1[i] && (regs[i].regmap[hr]^64)!=us2[i] &&
@@ -9380,7 +9657,8 @@ int new_recompile_block(int addr)
       ||itype[i+1]==SHIFTIMM||itype[i+1]==IMM16||itype[i+1]==LOAD
       ||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)
+      ||itype[i+1]==FCOMP||itype[i+1]==FCONV
+      ||itype[i+1]==COP2||itype[i+1]==C2LS||itype[i+1]==C2OP)
       {
         int t=(ba[i]-start)>>2;
         if(t>0&&(itype[t-1]!=UJUMP&&itype[t-1]!=RJUMP&&itype[t-1]!=CJUMP&&itype[t-1]!=SJUMP&&itype[t-1]!=FJUMP)) // loop_preload can't handle jumps into delay slots
@@ -9401,7 +9679,8 @@ int new_recompile_block(int addr)
           else if(branch_regs[i].regmap[hr]>=0) 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)
+          ||itype[i+1]==FCOMP||itype[i+1]==FCONV
+          ||itype[i+1]==COP2||itype[i+1]==C2LS||itype[i+1]==C2OP)
           {
             // Test both in case the delay slot is ooo,
             // could be done better...
@@ -9440,8 +9719,8 @@ int new_recompile_block(int addr)
                     while(k>1&&regs[k-1].regmap[hr]==-1) {
                       if(itype[k-1]==STORE||itype[k-1]==STORELR
                       ||itype[k-1]==C1LS||itype[k-1]==SHIFT||itype[k-1]==COP1
-                      ||itype[k-1]==FLOAT||itype[k-1]==FCONV
-                      ||itype[k-1]==FCOMP) {
+                      ||itype[k-1]==FLOAT||itype[k-1]==FCONV||itype[k-1]==FCOMP
+                      ||itype[k-1]==COP2||itype[k-1]==C2LS||itype[k-1]==C2OP) {
                         if(count_free_regs(regs[k-1].regmap)<2) {
                           //printf("no free regs for store %x\n",start+(k-1)*4);
                           break;
@@ -9550,7 +9829,8 @@ int new_recompile_block(int addr)
                 }
                 if(itype[j]==STORE||itype[j]==STORELR||itype[j]==C1LS
                 ||itype[j]==SHIFT||itype[j]==COP1||itype[j]==FLOAT
-                ||itype[j]==FCOMP||itype[j]==FCONV) {
+                ||itype[j]==FCOMP||itype[j]==FCONV
+                ||itype[j]==COP2||itype[j]==C2LS||itype[j]==C2OP) {
                   if(count_free_regs(regs[j].regmap)<2) {
                     //printf("No free regs for store %x\n",start+j*4);
                     break;
@@ -9592,7 +9872,8 @@ int new_recompile_block(int addr)
           if(regs[j].regmap[HOST_CCREG]!=-1) break;
           if(itype[j]==STORE||itype[j]==STORELR||itype[j]==C1LS
           ||itype[j]==SHIFT||itype[j]==COP1||itype[j]==FLOAT
-          ||itype[j]==FCOMP||itype[j]==FCONV) {
+          ||itype[j]==FCOMP||itype[j]==FCONV
+          ||itype[j]==COP2||itype[j]==C2LS||itype[j]==C2OP) {
             if(count_free_regs(regs[j].regmap)<2) {
               //printf("no free regs for store %x\n",start+j*4);
               break;
@@ -9625,7 +9906,8 @@ int new_recompile_block(int addr)
           while(regs[k-1].regmap[HOST_CCREG]==-1) {
             if(itype[k-1]==STORE||itype[k-1]==STORELR||itype[k-1]==C1LS
             ||itype[k-1]==SHIFT||itype[k-1]==COP1||itype[k-1]==FLOAT
-            ||itype[k-1]==FCONV||itype[k-1]==FCOMP) {
+            ||itype[k-1]==FCONV||itype[k-1]==FCOMP
+            ||itype[k-1]==COP2||itype[k-1]==C2LS||itype[k-1]==C2OP) {
               if(count_free_regs(regs[k-1].regmap)<2) {
                 //printf("no free regs for store %x\n",start+(k-1)*4);
                 break;
@@ -9656,7 +9938,8 @@ int new_recompile_block(int addr)
       if(itype[i]!=STORE&&itype[i]!=STORELR&&itype[i]!=C1LS&&itype[i]!=SHIFT&&
          itype[i]!=NOP&&itype[i]!=MOV&&itype[i]!=ALU&&itype[i]!=SHIFTIMM&&
          itype[i]!=IMM16&&itype[i]!=LOAD&&itype[i]!=COP1&&itype[i]!=FLOAT&&
-         itype[i]!=FCONV&&itype[i]!=FCOMP)
+         itype[i]!=FCONV&&itype[i]!=FCOMP&&
+         itype[i]!=COP2&&itype[i]!=C2LS&&itype[i]!=C2OP)
       {
         memcpy(f_regmap,regs[i].regmap,sizeof(f_regmap));
       }
@@ -9671,7 +9954,8 @@ int new_recompile_block(int addr)
     {
       if(!bt[i+1])
       {
-        if(itype[i]==ALU||itype[i]==MOV||itype[i]==LOAD||itype[i]==SHIFTIMM||itype[i]==IMM16||(itype[i]==COP1&&opcode2[i]<3))
+        if(itype[i]==ALU||itype[i]==MOV||itype[i]==LOAD||itype[i]==SHIFTIMM||itype[i]==IMM16
+           ||((itype[i]==COP1||itype[i]==COP2)&&opcode2[i]<3))
         {
           if(rs1[i+1]) {
             if((hr=get_reg(regs[i+1].regmap,rs1[i+1]))>=0)
@@ -9738,7 +10022,7 @@ int new_recompile_block(int addr)
             }
           }
           #ifndef HOST_IMM_ADDR32
-          if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR||itype[i+1]==C1LS) {
+          if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR||itype[i+1]==C1LS||itype[i+1]==C2LS) {
             hr=get_reg(regs[i+1].regmap,TLREG);
             if(hr>=0) {
               int sr=get_reg(regs[i+1].regmap,rs1[i+1]);
@@ -9776,7 +10060,8 @@ int new_recompile_block(int addr)
             }
           }
           #endif
-          if(itype[i+1]==STORE||itype[i+1]==STORELR||opcode[i+1]==0x39||opcode[i+1]==0x3D) { // SB/SH/SW/SD/SWC1/SDC1
+          if(itype[i+1]==STORE||itype[i+1]==STORELR
+             ||(opcode[i+1]&0x3b)==0x39||(opcode[i+1]&0x3b)==0x3a) { // SB/SH/SW/SD/SWC1/SDC1/SWC2/SDC2
             if(get_reg(regs[i+1].regmap,rs1[i+1])<0) {
               hr=get_reg2(regs[i].regmap,regs[i+1].regmap,-1);
               if(hr<0) hr=get_reg(regs[i+1].regmap,-1);
@@ -9795,7 +10080,7 @@ int new_recompile_block(int addr)
               }
             }
           }
-          if(itype[i+1]==LOADLR||opcode[i+1]==0x31||opcode[i+1]==0x35) { // LWC1/LDC1
+          if(itype[i+1]==LOADLR||(opcode[i+1]&0x3b)==0x31||(opcode[i+1]&0x3b)==0x32) { // LWC1/LDC1, LWC2/LDC2
             if(get_reg(regs[i+1].regmap,rs1[i+1])<0) {
               int nr;
               hr=get_reg(regs[i+1].regmap,FTEMP);
@@ -9830,12 +10115,12 @@ int new_recompile_block(int addr)
               }
             }
           }
-          if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR/*||itype[i+1]==C1LS*/) {
+          if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR/*||itype[i+1]==C1LS||||itype[i+1]==C2LS*/) {
             if(itype[i+1]==LOAD) 
               hr=get_reg(regs[i+1].regmap,rt1[i+1]);
-            if(itype[i+1]==LOADLR||opcode[i+1]==0x31||opcode[i+1]==0x35) // LWC1/LDC1
+            if(itype[i+1]==LOADLR||(opcode[i+1]&0x3b)==0x31||(opcode[i+1]&0x3b)==0x32) // LWC1/LDC1, LWC2/LDC2
               hr=get_reg(regs[i+1].regmap,FTEMP);
-            if(itype[i+1]==STORE||itype[i+1]==STORELR||opcode[i+1]==0x39||opcode[i+1]==0x3D) { // SWC1/SDC1
+            if(itype[i+1]==STORE||itype[i+1]==STORELR||(opcode[i+1]&0x3b)==0x39||(opcode[i+1]&0x3b)==0x3a) { // SWC1/SDC1/SWC2/SDC2
               hr=get_reg(regs[i+1].regmap,AGEN1+((i+1)&1));
               if(hr<0) hr=get_reg(regs[i+1].regmap,-1);
             }
@@ -9930,7 +10215,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)
+    else if(itype[i]==SYSCALL||itype[i]==HLECALL)
     {
       // SYSCALL instruction (software interrupt)
       r32=0;
@@ -10251,7 +10536,7 @@ int new_recompile_block(int addr)
           load_regs(regs[i].regmap_entry,regs[i].regmap,regs[i].was32,rs1[i+1],rs1[i+1]);
         if(rs2[i+1]!=rs1[i+1]&&rs2[i+1]!=rs1[i]&&rs2[i+1]!=rs2[i])
           load_regs(regs[i].regmap_entry,regs[i].regmap,regs[i].was32,rs2[i+1],rs2[i+1]);
-        if(itype[i+1]==STORE||itype[i+1]==STORELR||(opcode[i+1]&0x3b)==0x39)
+        if(itype[i+1]==STORE||itype[i+1]==STORELR||(opcode[i+1]&0x3b)==0x39||(opcode[i+1]&0x3b)==0x3a)
           load_regs(regs[i].regmap_entry,regs[i].regmap,regs[i].was32,INVCP,INVCP);
       }
       else if(i+1<slen)
@@ -10267,7 +10552,7 @@ int new_recompile_block(int addr)
       // TODO: if(is_ooo(i)) address_generation(i+1);
       if(itype[i]==CJUMP||itype[i]==FJUMP)
         load_regs(regs[i].regmap_entry,regs[i].regmap,regs[i].was32,CCREG,CCREG);
-      if(itype[i]==STORE||itype[i]==STORELR||(opcode[i]&0x3b)==0x39)
+      if(itype[i]==STORE||itype[i]==STORELR||(opcode[i]&0x3b)==0x39||(opcode[i]&0x3b)==0x3a)
         load_regs(regs[i].regmap_entry,regs[i].regmap,regs[i].was32,INVCP,INVCP);
       if(bt[i]) cop1_usable=0;
       // assemble
@@ -10294,6 +10579,12 @@ int new_recompile_block(int addr)
           cop1_assemble(i,&regs[i]);break;
         case C1LS:
           c1ls_assemble(i,&regs[i]);break;
+        case COP2:
+          cop2_assemble(i,&regs[i]);break;
+        case C2LS:
+          c2ls_assemble(i,&regs[i]);break;
+        case C2OP:
+          c2op_assemble(i,&regs[i]);break;
         case FCONV:
           fconv_assemble(i,&regs[i]);break;
         case FLOAT:
@@ -10306,6 +10597,8 @@ int new_recompile_block(int addr)
           mov_assemble(i,&regs[i]);break;
         case SYSCALL:
           syscall_assemble(i,&regs[i]);break;
+        case HLECALL:
+          hlecall_assemble(i,&regs[i]);break;
         case UJUMP:
           ujump_assemble(i,&regs[i]);ds=1;break;
         case RJUMP:
@@ -10550,10 +10843,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;
@@ -10562,3 +10851,5 @@ int new_recompile_block(int addr)
   }
   return 0;
 }
+
+// vim:shiftwidth=2:expandtab