drc: rm unneeded &63 masking
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / new_dynarec.c
index f1005db..abb0d07 100644 (file)
 #ifdef _3DS
 #include <3ds_utils.h>
 #endif
-#ifdef VITA
-#include <psp2/kernel/sysmem.h>
-static int sceBlock;
-#endif
 
 #include "new_dynarec_config.h"
 #include "../psxhle.h"
@@ -53,6 +49,7 @@ static int sceBlock;
 
 //#define DISASM
 //#define ASSEM_PRINT
+//#define REG_ALLOC_PRINT
 
 #ifdef ASSEM_PRINT
 #define assem_debug printf
@@ -79,9 +76,17 @@ static int sceBlock;
 #define MAXBLOCK 4096
 #define MAX_OUTPUT_BLOCK_SIZE 262144
 
+#ifdef VITA
+// apparently Vita has a 16MB limit, so either we cut tc in half,
+// or use this hack (it's a hack because tc size was designed to be power-of-2)
+#define TC_REDUCE_BYTES 4096
+#else
+#define TC_REDUCE_BYTES 0
+#endif
+
 struct ndrc_mem
 {
-  u_char translation_cache[1 << TARGET_SIZE_2];
+  u_char translation_cache[(1 << TARGET_SIZE_2) - TC_REDUCE_BYTES];
   struct
   {
     struct tramp_insns ops[2048 / sizeof(struct tramp_insns)];
@@ -114,15 +119,20 @@ enum stub_type {
   INVCODE_STUB = 14,
 };
 
+// regmap_pre[i]    - regs before [i] insn starts; dirty things here that
+//                    don't match .regmap will be written back
+// [i].regmap_entry - regs that must be set up if someone jumps here
+// [i].regmap       - regs [i] insn will read/(over)write
+// branch_regs[i].* - same as above but for branches, takes delay slot into account
 struct regstat
 {
-  signed char regmap_entry[HOST_REGS]; // pre-insn + loop preloaded regs?
+  signed char regmap_entry[HOST_REGS];
   signed char regmap[HOST_REGS];
   uint64_t wasdirty;
   uint64_t dirty;
   uint64_t u;
-  u_int wasconst;
-  u_int isconst;
+  u_int wasconst;                // before; for example 'lw r2, (r2)' wasconst is true
+  u_int isconst;                 //  ... but isconst is false when r2 is known
   u_int loadedconst;             // host regs that have constants loaded
   u_int waswritten;              // MIPS regs that were used as store base before
 };
@@ -202,7 +212,7 @@ static struct decoded_insn
   static u_int ba[MAXBLOCK];
   static uint64_t unneeded_reg[MAXBLOCK];
   static uint64_t branch_unneeded_reg[MAXBLOCK];
-  // pre-instruction [i], excluding loop-preload regs?
+  // see 'struct regstat' for a description
   static signed char regmap_pre[MAXBLOCK][HOST_REGS];
   // contains 'real' consts at [i] insn, but may differ from what's actually
   // loaded in host reg as 'final' value is always loaded, see get_final_value()
@@ -228,7 +238,7 @@ static struct decoded_insn
   static void *copy;
   static int expirep;
   static u_int stop_after_jal;
-  static u_int f1_hack; // 0 - off, ~0 - capture address, else addr
+  static u_int f1_hack;
 
   int new_dynarec_hacks;
   int new_dynarec_hacks_pergame;
@@ -293,7 +303,7 @@ static struct decoded_insn
 //#define FLOAT 19  // Floating point unit
 //#define FCONV 20  // Convert integer to float
 //#define FCOMP 21  // Floating point compare (sets FSREG)
-#define SYSCALL 22// SYSCALL
+#define SYSCALL 22// SYSCALL,BREAK
 #define OTHER 23  // Other
 #define SPAN 24   // Branch/delay slot spans 2 pages
 #define NI 25     // Not implemented
@@ -324,6 +334,10 @@ void verify_code_ds();
 void cc_interrupt();
 void fp_exception();
 void fp_exception_ds();
+void jump_syscall   (u_int u0, u_int u1, u_int pc);
+void jump_syscall_ds(u_int u0, u_int u1, u_int pc);
+void jump_break   (u_int u0, u_int u1, u_int pc);
+void jump_break_ds(u_int u0, u_int u1, u_int pc);
 void jump_to_new_pc();
 void call_gteStall();
 void new_dyna_leave();
@@ -354,6 +368,14 @@ static void pass_args(int a0, int a1);
 static void emit_far_jump(const void *f);
 static void emit_far_call(const void *f);
 
+#ifdef VITA
+#include <psp2/kernel/sysmem.h>
+static int sceBlock;
+// note: this interacts with RetroArch's Vita bootstrap code: bootstrap/vita/sbrk.c
+extern int getVMBlock();
+int _newlib_vm_size_user = sizeof(*ndrc);
+#endif
+
 static void mprotect_w_x(void *start, void *end, int is_x)
 {
 #ifdef NO_WRITE_EXEC
@@ -468,12 +490,12 @@ static void do_clear_cache(void)
 int cycle_multiplier = CYCLE_MULT_DEFAULT; // 100 for 1.0
 int cycle_multiplier_override;
 int cycle_multiplier_old;
+static int cycle_multiplier_active;
 
 static int CLOCK_ADJUST(int x)
 {
-  int m = cycle_multiplier_override && cycle_multiplier == CYCLE_MULT_DEFAULT
-        ? cycle_multiplier_override : cycle_multiplier;
-  int s=(x>>31)|1;
+  int m = cycle_multiplier_active;
+  int s = (x >> 31) | 1;
   return (x * m + s * 50) / 100;
 }
 
@@ -563,14 +585,12 @@ void noinline *get_addr(u_int vaddr)
   //printf("TRACE: count=%d next=%d (get_addr no-match %x)\n",Count,next_interupt,vaddr);
   int r=new_recompile_block(vaddr);
   if(r==0) return get_addr(vaddr);
-  // Execute in unmapped page, generate pagefault execption
+  // generate an address error
   Status|=2;
-  Cause=(vaddr<<31)|0x8;
+  Cause=(vaddr<<31)|(4<<2);
   EPC=(vaddr&1)?vaddr-5:vaddr;
   BadVAddr=(vaddr&~1);
-  Context=(Context&0xFF80000F)|((BadVAddr>>9)&0x007FFFF0);
-  EntryHi=BadVAddr&0xFFFFE000;
-  return get_addr_ht(0x80000000);
+  return get_addr_ht(0x80000080);
 }
 // Look up address in hash table first
 void *get_addr_ht(u_int vaddr)
@@ -582,16 +602,32 @@ void *get_addr_ht(u_int vaddr)
   return get_addr(vaddr);
 }
 
-void clear_all_regs(signed char regmap[])
+static void clear_all_regs(signed char regmap[])
+{
+  memset(regmap, -1, sizeof(regmap[0]) * HOST_REGS);
+}
+
+static signed char get_reg(const signed char regmap[], signed char r)
 {
   int hr;
-  for (hr=0;hr<HOST_REGS;hr++) regmap[hr]=-1;
+  for (hr = 0; hr < HOST_REGS; hr++) {
+    if (hr == EXCLUDE_REG)
+      continue;
+    if (regmap[hr] == r)
+      return hr;
+  }
+  return -1;
 }
 
-static signed char get_reg(const signed char regmap[],int r)
+static signed char get_reg_temp(const signed char regmap[])
 {
   int hr;
-  for (hr=0;hr<HOST_REGS;hr++) if(hr!=EXCLUDE_REG&&regmap[hr]==r) return hr;
+  for (hr = 0; hr < HOST_REGS; hr++) {
+    if (hr == EXCLUDE_REG)
+      continue;
+    if (regmap[hr] == (signed char)-1)
+      return hr;
+  }
   return -1;
 }
 
@@ -603,7 +639,7 @@ static signed char get_reg2(signed char regmap1[], const signed char regmap2[],
   return -1;
 }
 
-int count_free_regs(signed char regmap[])
+static int count_free_regs(const signed char regmap[])
 {
   int count=0;
   int hr;
@@ -616,63 +652,55 @@ int count_free_regs(signed char regmap[])
   return count;
 }
 
-void dirty_reg(struct regstat *cur,signed char reg)
+static void dirty_reg(struct regstat *cur, signed char reg)
 {
   int hr;
-  if(!reg) return;
-  for (hr=0;hr<HOST_REGS;hr++) {
-    if((cur->regmap[hr]&63)==reg) {
-      cur->dirty|=1<<hr;
-    }
-  }
+  if (!reg) return;
+  hr = get_reg(cur->regmap, reg);
+  if (hr >= 0)
+    cur->dirty |= 1<<hr;
 }
 
 static void set_const(struct regstat *cur, signed char reg, uint32_t value)
 {
   int hr;
-  if(!reg) return;
-  for (hr=0;hr<HOST_REGS;hr++) {
-    if(cur->regmap[hr]==reg) {
-      cur->isconst|=1<<hr;
-      current_constmap[hr]=value;
-    }
+  if (!reg) return;
+  hr = get_reg(cur->regmap, reg);
+  if (hr >= 0) {
+    cur->isconst |= 1<<hr;
+    current_constmap[hr] = value;
   }
 }
 
 static void clear_const(struct regstat *cur, signed char reg)
 {
   int hr;
-  if(!reg) return;
-  for (hr=0;hr<HOST_REGS;hr++) {
-    if((cur->regmap[hr]&63)==reg) {
-      cur->isconst&=~(1<<hr);
-    }
-  }
+  if (!reg) return;
+  hr = get_reg(cur->regmap, reg);
+  if (hr >= 0)
+    cur->isconst &= ~(1<<hr);
 }
 
-static int is_const(struct regstat *cur, signed char reg)
+static int is_const(const struct regstat *cur, signed char reg)
 {
   int hr;
-  if(reg<0) return 0;
-  if(!reg) return 1;
-  for (hr=0;hr<HOST_REGS;hr++) {
-    if((cur->regmap[hr]&63)==reg) {
-      return (cur->isconst>>hr)&1;
-    }
-  }
+  if (reg < 0) return 0;
+  if (!reg) return 1;
+  hr = get_reg(cur->regmap, reg);
+  if (hr >= 0)
+    return (cur->isconst>>hr)&1;
   return 0;
 }
 
-static uint32_t get_const(struct regstat *cur, signed char reg)
+static uint32_t get_const(const struct regstat *cur, signed char reg)
 {
   int hr;
-  if(!reg) return 0;
-  for (hr=0;hr<HOST_REGS;hr++) {
-    if(cur->regmap[hr]==reg) {
-      return current_constmap[hr];
-    }
-  }
-  SysPrintf("Unknown constant in r%d\n",reg);
+  if (!reg) return 0;
+  hr = get_reg(cur->regmap, reg);
+  if (hr >= 0)
+    return current_constmap[hr];
+
+  SysPrintf("Unknown constant in r%d\n", reg);
   abort();
 }
 
@@ -860,14 +888,14 @@ void alloc_all(struct regstat *cur,int i)
 
   for(hr=0;hr<HOST_REGS;hr++) {
     if(hr!=EXCLUDE_REG) {
-      if(((cur->regmap[hr]&63)!=dops[i].rs1)&&((cur->regmap[hr]&63)!=dops[i].rs2)&&
-         ((cur->regmap[hr]&63)!=dops[i].rt1)&&((cur->regmap[hr]&63)!=dops[i].rt2))
+      if((cur->regmap[hr]!=dops[i].rs1)&&(cur->regmap[hr]!=dops[i].rs2)&&
+         (cur->regmap[hr]!=dops[i].rt1)&&(cur->regmap[hr]!=dops[i].rt2))
       {
         cur->regmap[hr]=-1;
         cur->dirty&=~(1<<hr);
       }
       // Don't need zeros
-      if((cur->regmap[hr]&63)==0)
+      if(cur->regmap[hr]==0)
       {
         cur->regmap[hr]=-1;
         cur->dirty&=~(1<<hr);
@@ -914,6 +942,10 @@ static const struct {
   FUNCNAME(jump_handler_write32),
   FUNCNAME(invalidate_addr),
   FUNCNAME(jump_to_new_pc),
+  FUNCNAME(jump_break),
+  FUNCNAME(jump_break_ds),
+  FUNCNAME(jump_syscall),
+  FUNCNAME(jump_syscall_ds),
   FUNCNAME(call_gteStall),
   FUNCNAME(new_dyna_leave),
   FUNCNAME(pcsx_mtc0),
@@ -1475,7 +1507,7 @@ static void alloc_reg(struct regstat *cur,int i,signed char reg)
       if(hsn[r=cur->regmap[preferred_reg]&63]==j) {
         for(hr=0;hr<HOST_REGS;hr++) {
           // Evict both parts of a 64-bit register
-          if((cur->regmap[hr]&63)==r) {
+          if(cur->regmap[hr]==r) {
             cur->regmap[hr]=-1;
             cur->dirty&=~(1<<hr);
             cur->isconst&=~(1<<hr);
@@ -2108,7 +2140,7 @@ static void wb_register(signed char r, const signed char regmap[], uint64_t dirt
   int hr;
   for(hr=0;hr<HOST_REGS;hr++) {
     if(hr!=EXCLUDE_REG) {
-      if((regmap[hr]&63)==r) {
+      if(regmap[hr]==r) {
         if((dirty>>hr)&1) {
           assert(regmap[hr]<64);
           emit_storereg(r,hr);
@@ -2125,7 +2157,7 @@ static void wb_valid(signed char pre[],signed char entry[],u_int dirty_pre,u_int
   for(hr=0;hr<HOST_REGS;hr++) {
     if(hr!=EXCLUDE_REG) {
       reg=pre[hr];
-      if(((~u)>>(reg&63))&1) {
+      if(((~u)>>reg)&1) {
         if(reg>0) {
           if(((dirty_pre&~dirty)>>hr)&1) {
             if(reg>0&&reg<34) {
@@ -2783,12 +2815,12 @@ static void load_assemble(int i, const struct regstat *i_regs, int ccadj_)
       // could be FIFO, must perform the read
       // ||dummy read
       assem_debug("(forced read)\n");
-      tl=get_reg(i_regs->regmap,-1);
+      tl=get_reg_temp(i_regs->regmap);
       assert(tl>=0);
   }
   if(offset||s<0||c) addr=tl;
   else addr=s;
-  //if(tl<0) tl=get_reg(i_regs->regmap,-1);
+  //if(tl<0) tl=get_reg_temp(i_regs->regmap);
  if(tl>=0) {
   //printf("load_assemble: c=%d\n",c);
   //if(c) printf("load_assemble: const=%lx\n",(long)constmap[i][s]+offset);
@@ -2919,7 +2951,7 @@ static void loadlr_assemble(int i, const struct regstat *i_regs, int ccadj_)
   u_int reglist=get_host_reglist(i_regs->regmap);
   tl=get_reg(i_regs->regmap,dops[i].rt1);
   s=get_reg(i_regs->regmap,dops[i].rs1);
-  temp=get_reg(i_regs->regmap,-1);
+  temp=get_reg_temp(i_regs->regmap);
   temp2=get_reg(i_regs->regmap,FTEMP);
   addr=get_reg(i_regs->regmap,AGEN1+(i&1));
   assert(addr<0);
@@ -3005,7 +3037,7 @@ static void store_assemble(int i, const struct regstat *i_regs, int ccadj_)
   tl=get_reg(i_regs->regmap,dops[i].rs2);
   s=get_reg(i_regs->regmap,dops[i].rs1);
   temp=get_reg(i_regs->regmap,agr);
-  if(temp<0) temp=get_reg(i_regs->regmap,-1);
+  if(temp<0) temp=get_reg_temp(i_regs->regmap);
   offset=imm[i];
   if(s>=0) {
     c=(i_regs->wasconst>>s)&1;
@@ -3130,7 +3162,7 @@ static void storelr_assemble(int i, const struct regstat *i_regs, int ccadj_)
   tl=get_reg(i_regs->regmap,dops[i].rs2);
   s=get_reg(i_regs->regmap,dops[i].rs1);
   temp=get_reg(i_regs->regmap,agr);
-  if(temp<0) temp=get_reg(i_regs->regmap,-1);
+  if(temp<0) temp=get_reg_temp(i_regs->regmap);
   offset=imm[i];
   if(s>=0) {
     c=(i_regs->isconst>>s)&1;
@@ -3559,7 +3591,7 @@ static void multdiv_do_stall(int i, const struct regstat *i_regs)
 {
   int j, known_cycles = 0;
   u_int reglist = get_host_reglist(i_regs->regmap);
-  int rtmp = get_reg(i_regs->regmap, -1);
+  int rtmp = get_reg_temp(i_regs->regmap);
   if (rtmp < 0)
     rtmp = reglist_find_free(reglist);
   if (HACK_ENABLED(NDHACK_NO_STALLS))
@@ -3708,7 +3740,7 @@ static void c2ls_assemble(int i, const struct regstat *i_regs, int ccadj_)
   // get the address
   if (dops[i].opcode==0x3a) { // SWC2
     ar=get_reg(i_regs->regmap,agr);
-    if(ar<0) ar=get_reg(i_regs->regmap,-1);
+    if(ar<0) ar=get_reg_temp(i_regs->regmap);
     reglist|=1<<ar;
   } else { // LWC2
     ar=tl;
@@ -3792,7 +3824,7 @@ static void c2ls_assemble(int i, const struct regstat *i_regs, int ccadj_)
 static void cop2_assemble(int i, const struct regstat *i_regs)
 {
   u_int copr = (source[i]>>11) & 0x1f;
-  signed char temp = get_reg(i_regs->regmap, -1);
+  signed char temp = get_reg_temp(i_regs->regmap);
 
   if (!HACK_ENABLED(NDHACK_NO_STALLS)) {
     u_int reglist = reglist_exclude(get_host_reglist(i_regs->regmap), temp, -1);
@@ -3923,9 +3955,15 @@ static void call_c_cpu_handler(int i, const struct regstat *i_regs, int ccadj_,
 
 static void syscall_assemble(int i, const struct regstat *i_regs, int ccadj_)
 {
-  emit_movimm(0x20,0); // cause code
-  emit_movimm(0,1);    // not in delay slot
-  call_c_cpu_handler(i, i_regs, ccadj_, start+i*4, psxException);
+  // 'break' tends to be littered around to catch things like
+  // division by 0 and is almost never executed, so don't emit much code here
+  void *func = (dops[i].opcode2 == 0x0C)
+    ? (is_delayslot ? jump_syscall_ds : jump_syscall)
+    : (is_delayslot ? jump_break_ds : jump_break);
+  assert(get_reg(i_regs->regmap, CCREG) == HOST_CCREG);
+  emit_movimm(start + i*4, 2); // pc
+  emit_addimm(HOST_CCREG, ccadj_ + CLOCK_ADJUST(1), HOST_CCREG);
+  emit_far_jump(func);
 }
 
 static void hlecall_assemble(int i, const struct regstat *i_regs, int ccadj_)
@@ -4122,6 +4160,7 @@ static int assemble(int i, const struct regstat *i_regs, int ccadj_)
     case SPAN:
       pagespan_assemble(i, i_regs);
       break;
+    case NOP:
     case OTHER:
     case NI:
       // not handled, just skip
@@ -4186,7 +4225,7 @@ static void wb_invalidate(signed char pre[],signed char entry[],uint64_t dirty,u
   for(hr=0;hr<HOST_REGS;hr++) {
     if(hr!=EXCLUDE_REG) {
       if(pre[hr]!=entry[hr]) {
-        if(pre[hr]>=0&&(pre[hr]&63)<TEMPREG) {
+        if(pre[hr]>=0&&pre[hr]<TEMPREG) {
           int nr;
           if((nr=get_reg(entry,pre[hr]))>=0) {
             emit_mov(hr,nr);
@@ -4261,7 +4300,7 @@ void address_generation(int i, const struct regstat *i_regs, signed char entry[]
     int agr=AGEN1+(i&1);
     if(dops[i].itype==LOAD) {
       ra=get_reg(i_regs->regmap,dops[i].rt1);
-      if(ra<0) ra=get_reg(i_regs->regmap,-1);
+      if(ra<0) ra=get_reg_temp(i_regs->regmap);
       assert(ra>=0);
     }
     if(dops[i].itype==LOADLR) {
@@ -4269,14 +4308,14 @@ void address_generation(int i, const struct regstat *i_regs, signed char entry[]
     }
     if(dops[i].itype==STORE||dops[i].itype==STORELR) {
       ra=get_reg(i_regs->regmap,agr);
-      if(ra<0) ra=get_reg(i_regs->regmap,-1);
+      if(ra<0) ra=get_reg_temp(i_regs->regmap);
     }
     if(dops[i].itype==C2LS) {
       if ((dops[i].opcode&0x3b)==0x31||(dops[i].opcode&0x3b)==0x32) // LWC1/LDC1/LWC2/LDC2
         ra=get_reg(i_regs->regmap,FTEMP);
       else { // SWC1/SDC1/SWC2/SDC2
         ra=get_reg(i_regs->regmap,agr);
-        if(ra<0) ra=get_reg(i_regs->regmap,-1);
+        if(ra<0) ra=get_reg_temp(i_regs->regmap);
       }
     }
     int rs=get_reg(i_regs->regmap,dops[i].rs1);
@@ -4523,7 +4562,7 @@ static void load_all_regs(const signed char i_regmap[])
         emit_zeroreg(hr);
       }
       else
-      if(i_regmap[hr]>0 && (i_regmap[hr]&63)<TEMPREG && i_regmap[hr]!=CCREG)
+      if(i_regmap[hr]>0 && i_regmap[hr]<TEMPREG && i_regmap[hr]!=CCREG)
       {
         emit_loadreg(i_regmap[hr],hr);
       }
@@ -4542,7 +4581,7 @@ static void load_needed_regs(const signed char i_regmap[], const signed char nex
           emit_zeroreg(hr);
         }
         else
-        if(i_regmap[hr]>0 && (i_regmap[hr]&63)<TEMPREG && i_regmap[hr]!=CCREG)
+        if(i_regmap[hr]>0 && i_regmap[hr]<TEMPREG && i_regmap[hr]!=CCREG)
         {
           emit_loadreg(i_regmap[hr],hr);
         }
@@ -4927,8 +4966,8 @@ static void do_ccstub(int n)
       while(hr<HOST_REGS)
       {
         if(hr!=EXCLUDE_REG && hr!=HOST_CCREG &&
-           (branch_regs[i].regmap[hr]&63)!=dops[i].rs1 &&
-           (branch_regs[i].regmap[hr]&63)!=dops[i].rs2 )
+           branch_regs[i].regmap[hr]!=dops[i].rs1 &&
+           branch_regs[i].regmap[hr]!=dops[i].rs2 )
         {
           addr=hr++;break;
         }
@@ -4937,8 +4976,8 @@ static void do_ccstub(int n)
       while(hr<HOST_REGS)
       {
         if(hr!=EXCLUDE_REG && hr!=HOST_CCREG &&
-           (branch_regs[i].regmap[hr]&63)!=dops[i].rs1 &&
-           (branch_regs[i].regmap[hr]&63)!=dops[i].rs2 )
+           branch_regs[i].regmap[hr]!=dops[i].rs1 &&
+           branch_regs[i].regmap[hr]!=dops[i].rs2 )
         {
           alt=hr++;break;
         }
@@ -4949,8 +4988,8 @@ static void do_ccstub(int n)
         while(hr<HOST_REGS)
         {
           if(hr!=EXCLUDE_REG && hr!=HOST_CCREG &&
-             (branch_regs[i].regmap[hr]&63)!=dops[i].rs1 &&
-             (branch_regs[i].regmap[hr]&63)!=dops[i].rs2 )
+             branch_regs[i].regmap[hr]!=dops[i].rs1 &&
+             branch_regs[i].regmap[hr]!=dops[i].rs2 )
           {
             ntaddr=hr;break;
           }
@@ -5586,7 +5625,7 @@ static void sjump_assemble(int i, const struct regstat *i_regs)
   int cc;
   int match;
   match=match_bt(branch_regs[i].regmap,branch_regs[i].dirty,ba[i]);
-  assem_debug("smatch=%d\n",match);
+  assem_debug("smatch=%d ooo=%d\n", match, dops[i].ooo);
   int s1l;
   int unconditional=0,nevertaken=0;
   int invert=0;
@@ -5823,7 +5862,9 @@ static void sjump_assemble(int i, const struct regstat *i_regs)
       wb_invalidate(regs[i].regmap,branch_regs[i].regmap,regs[i].dirty,ds_unneeded);
       load_regs(regs[i].regmap,branch_regs[i].regmap,dops[i+1].rs1,dops[i+1].rs2);
       address_generation(i+1,&branch_regs[i],0);
-      load_regs(regs[i].regmap,branch_regs[i].regmap,CCREG,CCREG);
+      if (ram_offset)
+        load_regs(regs[i].regmap,branch_regs[i].regmap,ROREG,ROREG);
+      load_regs(regs[i].regmap,branch_regs[i].regmap,CCREG,INVCP);
       ds_assemble(i+1,&branch_regs[i]);
       cc=get_reg(branch_regs[i].regmap,CCREG);
       if (cc == -1) {
@@ -5870,8 +5911,8 @@ static void pagespan_assemble(int i, const struct regstat *i_regs)
     while(hr<HOST_REGS)
     {
       if(hr!=EXCLUDE_REG && hr!=HOST_CCREG &&
-         (i_regs->regmap[hr]&63)!=dops[i].rs1 &&
-         (i_regs->regmap[hr]&63)!=dops[i].rs2 )
+         i_regs->regmap[hr]!=dops[i].rs1 &&
+         i_regs->regmap[hr]!=dops[i].rs2 )
       {
         addr=hr++;break;
       }
@@ -5881,8 +5922,8 @@ static void pagespan_assemble(int i, const struct regstat *i_regs)
   while(hr<HOST_REGS)
   {
     if(hr!=EXCLUDE_REG && hr!=HOST_CCREG && hr!=HOST_BTREG &&
-       (i_regs->regmap[hr]&63)!=dops[i].rs1 &&
-       (i_regs->regmap[hr]&63)!=dops[i].rs2 )
+       i_regs->regmap[hr]!=dops[i].rs1 &&
+       i_regs->regmap[hr]!=dops[i].rs2 )
     {
       alt=hr++;break;
     }
@@ -5893,8 +5934,8 @@ static void pagespan_assemble(int i, const struct regstat *i_regs)
     while(hr<HOST_REGS)
     {
       if(hr!=EXCLUDE_REG && hr!=HOST_CCREG && hr!=HOST_BTREG &&
-         (i_regs->regmap[hr]&63)!=dops[i].rs1 &&
-         (i_regs->regmap[hr]&63)!=dops[i].rs2 )
+         i_regs->regmap[hr]!=dops[i].rs1 &&
+         i_regs->regmap[hr]!=dops[i].rs2 )
       {
         ntaddr=hr;break;
       }
@@ -6090,7 +6131,7 @@ static void pagespan_ds()
   }
   int btaddr=get_reg(regs[0].regmap,BTREG);
   if(btaddr<0) {
-    btaddr=get_reg(regs[0].regmap,-1);
+    btaddr=get_reg_temp(regs[0].regmap);
     emit_readword(&branch_target,btaddr);
   }
   assert(btaddr!=HOST_CCREG);
@@ -6112,8 +6153,21 @@ static void pagespan_ds()
   load_regs_bt(regs[0].regmap,regs[0].dirty,start+4);
 }
 
+static void check_regmap(signed char *regmap)
+{
+#ifndef NDEBUG
+  int i,j;
+  for (i = 0; i < HOST_REGS; i++) {
+    if (regmap[i] < 0)
+      continue;
+    for (j = i + 1; j < HOST_REGS; j++)
+      assert(regmap[i] != regmap[j]);
+  }
+#endif
+}
+
 // Basic liveness analysis for MIPS registers
-void unneeded_registers(int istart,int iend,int r)
+static void unneeded_registers(int istart,int iend,int r)
 {
   int i;
   uint64_t u,gte_u,b,gte_b;
@@ -6283,6 +6337,7 @@ void clean_registers(int istart,int iend,int wr)
   }
   for (i=iend;i>=istart;i--)
   {
+    __builtin_prefetch(regs[i-1].regmap);
     if(dops[i].is_jump)
     {
       if(ba[i]<start || ba[i]>=(start+slen*4))
@@ -6296,18 +6351,18 @@ void clean_registers(int istart,int iend,int wr)
           // Merge in delay slot (will dirty)
           for(r=0;r<HOST_REGS;r++) {
             if(r!=EXCLUDE_REG) {
-              if((branch_regs[i].regmap[r]&63)==dops[i].rt1) will_dirty_i|=1<<r;
-              if((branch_regs[i].regmap[r]&63)==dops[i].rt2) will_dirty_i|=1<<r;
-              if((branch_regs[i].regmap[r]&63)==dops[i+1].rt1) will_dirty_i|=1<<r;
-              if((branch_regs[i].regmap[r]&63)==dops[i+1].rt2) will_dirty_i|=1<<r;
-              if((branch_regs[i].regmap[r]&63)>33) will_dirty_i&=~(1<<r);
+              if(branch_regs[i].regmap[r]==dops[i].rt1) will_dirty_i|=1<<r;
+              if(branch_regs[i].regmap[r]==dops[i].rt2) will_dirty_i|=1<<r;
+              if(branch_regs[i].regmap[r]==dops[i+1].rt1) will_dirty_i|=1<<r;
+              if(branch_regs[i].regmap[r]==dops[i+1].rt2) will_dirty_i|=1<<r;
+              if(branch_regs[i].regmap[r]>33) will_dirty_i&=~(1<<r);
               if(branch_regs[i].regmap[r]<=0) will_dirty_i&=~(1<<r);
               if(branch_regs[i].regmap[r]==CCREG) will_dirty_i|=1<<r;
-              if((regs[i].regmap[r]&63)==dops[i].rt1) will_dirty_i|=1<<r;
-              if((regs[i].regmap[r]&63)==dops[i].rt2) will_dirty_i|=1<<r;
-              if((regs[i].regmap[r]&63)==dops[i+1].rt1) will_dirty_i|=1<<r;
-              if((regs[i].regmap[r]&63)==dops[i+1].rt2) will_dirty_i|=1<<r;
-              if((regs[i].regmap[r]&63)>33) will_dirty_i&=~(1<<r);
+              if(regs[i].regmap[r]==dops[i].rt1) will_dirty_i|=1<<r;
+              if(regs[i].regmap[r]==dops[i].rt2) will_dirty_i|=1<<r;
+              if(regs[i].regmap[r]==dops[i+1].rt1) will_dirty_i|=1<<r;
+              if(regs[i].regmap[r]==dops[i+1].rt2) will_dirty_i|=1<<r;
+              if(regs[i].regmap[r]>33) will_dirty_i&=~(1<<r);
               if(regs[i].regmap[r]<=0) will_dirty_i&=~(1<<r);
               if(regs[i].regmap[r]==CCREG) will_dirty_i|=1<<r;
             }
@@ -6321,20 +6376,20 @@ void clean_registers(int istart,int iend,int wr)
           // Merge in delay slot (will dirty)
           for(r=0;r<HOST_REGS;r++) {
             if(r!=EXCLUDE_REG) {
-              if (1) { // !dops[i].likely) {
+              if (1) { // !dops[i].likely)
                 // Might not dirty if likely branch is not taken
-                if((branch_regs[i].regmap[r]&63)==dops[i].rt1) will_dirty_i|=1<<r;
-                if((branch_regs[i].regmap[r]&63)==dops[i].rt2) will_dirty_i|=1<<r;
-                if((branch_regs[i].regmap[r]&63)==dops[i+1].rt1) will_dirty_i|=1<<r;
-                if((branch_regs[i].regmap[r]&63)==dops[i+1].rt2) will_dirty_i|=1<<r;
-                if((branch_regs[i].regmap[r]&63)>33) will_dirty_i&=~(1<<r);
+                if(branch_regs[i].regmap[r]==dops[i].rt1) will_dirty_i|=1<<r;
+                if(branch_regs[i].regmap[r]==dops[i].rt2) will_dirty_i|=1<<r;
+                if(branch_regs[i].regmap[r]==dops[i+1].rt1) will_dirty_i|=1<<r;
+                if(branch_regs[i].regmap[r]==dops[i+1].rt2) will_dirty_i|=1<<r;
+                if(branch_regs[i].regmap[r]>33) will_dirty_i&=~(1<<r);
                 if(branch_regs[i].regmap[r]==0) will_dirty_i&=~(1<<r);
                 if(branch_regs[i].regmap[r]==CCREG) will_dirty_i|=1<<r;
-                //if((regs[i].regmap[r]&63)==dops[i].rt1) will_dirty_i|=1<<r;
-                //if((regs[i].regmap[r]&63)==dops[i].rt2) will_dirty_i|=1<<r;
-                if((regs[i].regmap[r]&63)==dops[i+1].rt1) will_dirty_i|=1<<r;
-                if((regs[i].regmap[r]&63)==dops[i+1].rt2) will_dirty_i|=1<<r;
-                if((regs[i].regmap[r]&63)>33) will_dirty_i&=~(1<<r);
+                //if(regs[i].regmap[r]==dops[i].rt1) will_dirty_i|=1<<r;
+                //if(regs[i].regmap[r]==dops[i].rt2) will_dirty_i|=1<<r;
+                if(regs[i].regmap[r]==dops[i+1].rt1) will_dirty_i|=1<<r;
+                if(regs[i].regmap[r]==dops[i+1].rt2) will_dirty_i|=1<<r;
+                if(regs[i].regmap[r]>33) will_dirty_i&=~(1<<r);
                 if(regs[i].regmap[r]<=0) will_dirty_i&=~(1<<r);
                 if(regs[i].regmap[r]==CCREG) will_dirty_i|=1<<r;
               }
@@ -6344,15 +6399,15 @@ void clean_registers(int istart,int iend,int wr)
         // Merge in delay slot (wont dirty)
         for(r=0;r<HOST_REGS;r++) {
           if(r!=EXCLUDE_REG) {
-            if((regs[i].regmap[r]&63)==dops[i].rt1) wont_dirty_i|=1<<r;
-            if((regs[i].regmap[r]&63)==dops[i].rt2) wont_dirty_i|=1<<r;
-            if((regs[i].regmap[r]&63)==dops[i+1].rt1) wont_dirty_i|=1<<r;
-            if((regs[i].regmap[r]&63)==dops[i+1].rt2) wont_dirty_i|=1<<r;
+            if(regs[i].regmap[r]==dops[i].rt1) wont_dirty_i|=1<<r;
+            if(regs[i].regmap[r]==dops[i].rt2) wont_dirty_i|=1<<r;
+            if(regs[i].regmap[r]==dops[i+1].rt1) wont_dirty_i|=1<<r;
+            if(regs[i].regmap[r]==dops[i+1].rt2) wont_dirty_i|=1<<r;
             if(regs[i].regmap[r]==CCREG) wont_dirty_i|=1<<r;
-            if((branch_regs[i].regmap[r]&63)==dops[i].rt1) wont_dirty_i|=1<<r;
-            if((branch_regs[i].regmap[r]&63)==dops[i].rt2) wont_dirty_i|=1<<r;
-            if((branch_regs[i].regmap[r]&63)==dops[i+1].rt1) wont_dirty_i|=1<<r;
-            if((branch_regs[i].regmap[r]&63)==dops[i+1].rt2) wont_dirty_i|=1<<r;
+            if(branch_regs[i].regmap[r]==dops[i].rt1) wont_dirty_i|=1<<r;
+            if(branch_regs[i].regmap[r]==dops[i].rt2) wont_dirty_i|=1<<r;
+            if(branch_regs[i].regmap[r]==dops[i+1].rt1) wont_dirty_i|=1<<r;
+            if(branch_regs[i].regmap[r]==dops[i+1].rt2) wont_dirty_i|=1<<r;
             if(branch_regs[i].regmap[r]==CCREG) wont_dirty_i|=1<<r;
           }
         }
@@ -6376,18 +6431,18 @@ void clean_registers(int istart,int iend,int wr)
             // Merge in delay slot (will dirty)
             for(r=0;r<HOST_REGS;r++) {
               if(r!=EXCLUDE_REG) {
-                if((branch_regs[i].regmap[r]&63)==dops[i].rt1) temp_will_dirty|=1<<r;
-                if((branch_regs[i].regmap[r]&63)==dops[i].rt2) temp_will_dirty|=1<<r;
-                if((branch_regs[i].regmap[r]&63)==dops[i+1].rt1) temp_will_dirty|=1<<r;
-                if((branch_regs[i].regmap[r]&63)==dops[i+1].rt2) temp_will_dirty|=1<<r;
-                if((branch_regs[i].regmap[r]&63)>33) temp_will_dirty&=~(1<<r);
+                if(branch_regs[i].regmap[r]==dops[i].rt1) temp_will_dirty|=1<<r;
+                if(branch_regs[i].regmap[r]==dops[i].rt2) temp_will_dirty|=1<<r;
+                if(branch_regs[i].regmap[r]==dops[i+1].rt1) temp_will_dirty|=1<<r;
+                if(branch_regs[i].regmap[r]==dops[i+1].rt2) temp_will_dirty|=1<<r;
+                if(branch_regs[i].regmap[r]>33) temp_will_dirty&=~(1<<r);
                 if(branch_regs[i].regmap[r]<=0) temp_will_dirty&=~(1<<r);
                 if(branch_regs[i].regmap[r]==CCREG) temp_will_dirty|=1<<r;
-                if((regs[i].regmap[r]&63)==dops[i].rt1) temp_will_dirty|=1<<r;
-                if((regs[i].regmap[r]&63)==dops[i].rt2) temp_will_dirty|=1<<r;
-                if((regs[i].regmap[r]&63)==dops[i+1].rt1) temp_will_dirty|=1<<r;
-                if((regs[i].regmap[r]&63)==dops[i+1].rt2) temp_will_dirty|=1<<r;
-                if((regs[i].regmap[r]&63)>33) temp_will_dirty&=~(1<<r);
+                if(regs[i].regmap[r]==dops[i].rt1) temp_will_dirty|=1<<r;
+                if(regs[i].regmap[r]==dops[i].rt2) temp_will_dirty|=1<<r;
+                if(regs[i].regmap[r]==dops[i+1].rt1) temp_will_dirty|=1<<r;
+                if(regs[i].regmap[r]==dops[i+1].rt2) temp_will_dirty|=1<<r;
+                if(regs[i].regmap[r]>33) temp_will_dirty&=~(1<<r);
                 if(regs[i].regmap[r]<=0) temp_will_dirty&=~(1<<r);
                 if(regs[i].regmap[r]==CCREG) temp_will_dirty|=1<<r;
               }
@@ -6399,20 +6454,20 @@ void clean_registers(int istart,int iend,int wr)
             // Merge in delay slot (will dirty)
             for(r=0;r<HOST_REGS;r++) {
               if(r!=EXCLUDE_REG) {
-                if (1) { // !dops[i].likely) {
+                if (1) { // !dops[i].likely)
                   // Will not dirty if likely branch is not taken
-                  if((branch_regs[i].regmap[r]&63)==dops[i].rt1) temp_will_dirty|=1<<r;
-                  if((branch_regs[i].regmap[r]&63)==dops[i].rt2) temp_will_dirty|=1<<r;
-                  if((branch_regs[i].regmap[r]&63)==dops[i+1].rt1) temp_will_dirty|=1<<r;
-                  if((branch_regs[i].regmap[r]&63)==dops[i+1].rt2) temp_will_dirty|=1<<r;
-                  if((branch_regs[i].regmap[r]&63)>33) temp_will_dirty&=~(1<<r);
+                  if(branch_regs[i].regmap[r]==dops[i].rt1) temp_will_dirty|=1<<r;
+                  if(branch_regs[i].regmap[r]==dops[i].rt2) temp_will_dirty|=1<<r;
+                  if(branch_regs[i].regmap[r]==dops[i+1].rt1) temp_will_dirty|=1<<r;
+                  if(branch_regs[i].regmap[r]==dops[i+1].rt2) temp_will_dirty|=1<<r;
+                  if(branch_regs[i].regmap[r]>33) temp_will_dirty&=~(1<<r);
                   if(branch_regs[i].regmap[r]==0) temp_will_dirty&=~(1<<r);
                   if(branch_regs[i].regmap[r]==CCREG) temp_will_dirty|=1<<r;
-                  //if((regs[i].regmap[r]&63)==dops[i].rt1) temp_will_dirty|=1<<r;
-                  //if((regs[i].regmap[r]&63)==dops[i].rt2) temp_will_dirty|=1<<r;
-                  if((regs[i].regmap[r]&63)==dops[i+1].rt1) temp_will_dirty|=1<<r;
-                  if((regs[i].regmap[r]&63)==dops[i+1].rt2) temp_will_dirty|=1<<r;
-                  if((regs[i].regmap[r]&63)>33) temp_will_dirty&=~(1<<r);
+                  //if(regs[i].regmap[r]==dops[i].rt1) temp_will_dirty|=1<<r;
+                  //if(regs[i].regmap[r]==dops[i].rt2) temp_will_dirty|=1<<r;
+                  if(regs[i].regmap[r]==dops[i+1].rt1) temp_will_dirty|=1<<r;
+                  if(regs[i].regmap[r]==dops[i+1].rt2) temp_will_dirty|=1<<r;
+                  if(regs[i].regmap[r]>33) temp_will_dirty&=~(1<<r);
                   if(regs[i].regmap[r]<=0) temp_will_dirty&=~(1<<r);
                   if(regs[i].regmap[r]==CCREG) temp_will_dirty|=1<<r;
                 }
@@ -6422,15 +6477,15 @@ void clean_registers(int istart,int iend,int wr)
           // Merge in delay slot (wont dirty)
           for(r=0;r<HOST_REGS;r++) {
             if(r!=EXCLUDE_REG) {
-              if((regs[i].regmap[r]&63)==dops[i].rt1) temp_wont_dirty|=1<<r;
-              if((regs[i].regmap[r]&63)==dops[i].rt2) temp_wont_dirty|=1<<r;
-              if((regs[i].regmap[r]&63)==dops[i+1].rt1) temp_wont_dirty|=1<<r;
-              if((regs[i].regmap[r]&63)==dops[i+1].rt2) temp_wont_dirty|=1<<r;
+              if(regs[i].regmap[r]==dops[i].rt1) temp_wont_dirty|=1<<r;
+              if(regs[i].regmap[r]==dops[i].rt2) temp_wont_dirty|=1<<r;
+              if(regs[i].regmap[r]==dops[i+1].rt1) temp_wont_dirty|=1<<r;
+              if(regs[i].regmap[r]==dops[i+1].rt2) temp_wont_dirty|=1<<r;
               if(regs[i].regmap[r]==CCREG) temp_wont_dirty|=1<<r;
-              if((branch_regs[i].regmap[r]&63)==dops[i].rt1) temp_wont_dirty|=1<<r;
-              if((branch_regs[i].regmap[r]&63)==dops[i].rt2) temp_wont_dirty|=1<<r;
-              if((branch_regs[i].regmap[r]&63)==dops[i+1].rt1) temp_wont_dirty|=1<<r;
-              if((branch_regs[i].regmap[r]&63)==dops[i+1].rt2) temp_wont_dirty|=1<<r;
+              if(branch_regs[i].regmap[r]==dops[i].rt1) temp_wont_dirty|=1<<r;
+              if(branch_regs[i].regmap[r]==dops[i].rt2) temp_wont_dirty|=1<<r;
+              if(branch_regs[i].regmap[r]==dops[i+1].rt1) temp_wont_dirty|=1<<r;
+              if(branch_regs[i].regmap[r]==dops[i+1].rt2) temp_wont_dirty|=1<<r;
               if(branch_regs[i].regmap[r]==CCREG) temp_wont_dirty|=1<<r;
             }
           }
@@ -6441,9 +6496,9 @@ void clean_registers(int istart,int iend,int wr)
                 if(regs[i].regmap[r]!=regmap_pre[i][r]) {
                   temp_will_dirty&=~(1<<r);
                   temp_wont_dirty&=~(1<<r);
-                  if((regmap_pre[i][r]&63)>0 && (regmap_pre[i][r]&63)<34) {
-                    temp_will_dirty|=((unneeded_reg[i]>>(regmap_pre[i][r]&63))&1)<<r;
-                    temp_wont_dirty|=((unneeded_reg[i]>>(regmap_pre[i][r]&63))&1)<<r;
+                  if(regmap_pre[i][r]>0 && regmap_pre[i][r]<34) {
+                    temp_will_dirty|=((unneeded_reg[i]>>regmap_pre[i][r])&1)<<r;
+                    temp_wont_dirty|=((unneeded_reg[i]>>regmap_pre[i][r])&1)<<r;
                   } else {
                     temp_will_dirty|=1<<r;
                     temp_wont_dirty|=1<<r;
@@ -6478,8 +6533,8 @@ void clean_registers(int istart,int iend,int wr)
                   wont_dirty_i|=wont_dirty[(ba[i]-start)>>2]&(1<<r);
                 }
                 if(branch_regs[i].regmap[r]>=0) {
-                  will_dirty_i|=((unneeded_reg[(ba[i]-start)>>2]>>(branch_regs[i].regmap[r]&63))&1)<<r;
-                  wont_dirty_i|=((unneeded_reg[(ba[i]-start)>>2]>>(branch_regs[i].regmap[r]&63))&1)<<r;
+                  will_dirty_i|=((unneeded_reg[(ba[i]-start)>>2]>>branch_regs[i].regmap[r])&1)<<r;
+                  wont_dirty_i|=((unneeded_reg[(ba[i]-start)>>2]>>branch_regs[i].regmap[r])&1)<<r;
                 }
               }
             }
@@ -6487,18 +6542,18 @@ void clean_registers(int istart,int iend,int wr)
             // Merge in delay slot
             for(r=0;r<HOST_REGS;r++) {
               if(r!=EXCLUDE_REG) {
-                if((branch_regs[i].regmap[r]&63)==dops[i].rt1) will_dirty_i|=1<<r;
-                if((branch_regs[i].regmap[r]&63)==dops[i].rt2) will_dirty_i|=1<<r;
-                if((branch_regs[i].regmap[r]&63)==dops[i+1].rt1) will_dirty_i|=1<<r;
-                if((branch_regs[i].regmap[r]&63)==dops[i+1].rt2) will_dirty_i|=1<<r;
-                if((branch_regs[i].regmap[r]&63)>33) will_dirty_i&=~(1<<r);
+                if(branch_regs[i].regmap[r]==dops[i].rt1) will_dirty_i|=1<<r;
+                if(branch_regs[i].regmap[r]==dops[i].rt2) will_dirty_i|=1<<r;
+                if(branch_regs[i].regmap[r]==dops[i+1].rt1) will_dirty_i|=1<<r;
+                if(branch_regs[i].regmap[r]==dops[i+1].rt2) will_dirty_i|=1<<r;
+                if(branch_regs[i].regmap[r]>33) will_dirty_i&=~(1<<r);
                 if(branch_regs[i].regmap[r]<=0) will_dirty_i&=~(1<<r);
                 if(branch_regs[i].regmap[r]==CCREG) will_dirty_i|=1<<r;
-                if((regs[i].regmap[r]&63)==dops[i].rt1) will_dirty_i|=1<<r;
-                if((regs[i].regmap[r]&63)==dops[i].rt2) will_dirty_i|=1<<r;
-                if((regs[i].regmap[r]&63)==dops[i+1].rt1) will_dirty_i|=1<<r;
-                if((regs[i].regmap[r]&63)==dops[i+1].rt2) will_dirty_i|=1<<r;
-                if((regs[i].regmap[r]&63)>33) will_dirty_i&=~(1<<r);
+                if(regs[i].regmap[r]==dops[i].rt1) will_dirty_i|=1<<r;
+                if(regs[i].regmap[r]==dops[i].rt2) will_dirty_i|=1<<r;
+                if(regs[i].regmap[r]==dops[i+1].rt1) will_dirty_i|=1<<r;
+                if(regs[i].regmap[r]==dops[i+1].rt2) will_dirty_i|=1<<r;
+                if(regs[i].regmap[r]>33) will_dirty_i&=~(1<<r);
                 if(regs[i].regmap[r]<=0) will_dirty_i&=~(1<<r);
                 if(regs[i].regmap[r]==CCREG) will_dirty_i|=1<<r;
               }
@@ -6507,7 +6562,7 @@ void clean_registers(int istart,int iend,int wr)
             // Conditional branch
             will_dirty_i=will_dirty_next;
             wont_dirty_i=wont_dirty_next;
-          //if(ba[i]>start+i*4) // Disable recursion (for debugging)
+          //if(ba[i]>start+i*4) // Disable recursion (for debugging)
             for(r=0;r<HOST_REGS;r++) {
               if(r!=EXCLUDE_REG) {
                 signed char target_reg=branch_regs[i].regmap[r];
@@ -6516,29 +6571,28 @@ void clean_registers(int istart,int iend,int wr)
                   wont_dirty_i|=wont_dirty[(ba[i]-start)>>2]&(1<<r);
                 }
                 else if(target_reg>=0) {
-                  will_dirty_i&=((unneeded_reg[(ba[i]-start)>>2]>>(target_reg&63))&1)<<r;
-                  wont_dirty_i|=((unneeded_reg[(ba[i]-start)>>2]>>(target_reg&63))&1)<<r;
+                  will_dirty_i&=((unneeded_reg[(ba[i]-start)>>2]>>target_reg)&1)<<r;
+                  wont_dirty_i|=((unneeded_reg[(ba[i]-start)>>2]>>target_reg)&1)<<r;
                 }
               }
             }
-          //}
             // Merge in delay slot
             for(r=0;r<HOST_REGS;r++) {
               if(r!=EXCLUDE_REG) {
-                if (1) { // !dops[i].likely) {
+                if (1) { // !dops[i].likely)
                   // Might not dirty if likely branch is not taken
-                  if((branch_regs[i].regmap[r]&63)==dops[i].rt1) will_dirty_i|=1<<r;
-                  if((branch_regs[i].regmap[r]&63)==dops[i].rt2) will_dirty_i|=1<<r;
-                  if((branch_regs[i].regmap[r]&63)==dops[i+1].rt1) will_dirty_i|=1<<r;
-                  if((branch_regs[i].regmap[r]&63)==dops[i+1].rt2) will_dirty_i|=1<<r;
-                  if((branch_regs[i].regmap[r]&63)>33) will_dirty_i&=~(1<<r);
+                  if(branch_regs[i].regmap[r]==dops[i].rt1) will_dirty_i|=1<<r;
+                  if(branch_regs[i].regmap[r]==dops[i].rt2) will_dirty_i|=1<<r;
+                  if(branch_regs[i].regmap[r]==dops[i+1].rt1) will_dirty_i|=1<<r;
+                  if(branch_regs[i].regmap[r]==dops[i+1].rt2) will_dirty_i|=1<<r;
+                  if(branch_regs[i].regmap[r]>33) will_dirty_i&=~(1<<r);
                   if(branch_regs[i].regmap[r]<=0) will_dirty_i&=~(1<<r);
                   if(branch_regs[i].regmap[r]==CCREG) will_dirty_i|=1<<r;
-                  //if((regs[i].regmap[r]&63)==dops[i].rt1) will_dirty_i|=1<<r;
-                  //if((regs[i].regmap[r]&63)==dops[i].rt2) will_dirty_i|=1<<r;
-                  if((regs[i].regmap[r]&63)==dops[i+1].rt1) will_dirty_i|=1<<r;
-                  if((regs[i].regmap[r]&63)==dops[i+1].rt2) will_dirty_i|=1<<r;
-                  if((regs[i].regmap[r]&63)>33) will_dirty_i&=~(1<<r);
+                  //if(regs[i].regmap[r]==dops[i].rt1) will_dirty_i|=1<<r;
+                  //if(regs[i].regmap[r]==dops[i].rt2) will_dirty_i|=1<<r;
+                  if(regs[i].regmap[r]==dops[i+1].rt1) will_dirty_i|=1<<r;
+                  if(regs[i].regmap[r]==dops[i+1].rt2) will_dirty_i|=1<<r;
+                  if(regs[i].regmap[r]>33) will_dirty_i&=~(1<<r);
                   if(regs[i].regmap[r]<=0) will_dirty_i&=~(1<<r);
                   if(regs[i].regmap[r]==CCREG) will_dirty_i|=1<<r;
                 }
@@ -6548,15 +6602,15 @@ void clean_registers(int istart,int iend,int wr)
           // Merge in delay slot (won't dirty)
           for(r=0;r<HOST_REGS;r++) {
             if(r!=EXCLUDE_REG) {
-              if((regs[i].regmap[r]&63)==dops[i].rt1) wont_dirty_i|=1<<r;
-              if((regs[i].regmap[r]&63)==dops[i].rt2) wont_dirty_i|=1<<r;
-              if((regs[i].regmap[r]&63)==dops[i+1].rt1) wont_dirty_i|=1<<r;
-              if((regs[i].regmap[r]&63)==dops[i+1].rt2) wont_dirty_i|=1<<r;
+              if(regs[i].regmap[r]==dops[i].rt1) wont_dirty_i|=1<<r;
+              if(regs[i].regmap[r]==dops[i].rt2) wont_dirty_i|=1<<r;
+              if(regs[i].regmap[r]==dops[i+1].rt1) wont_dirty_i|=1<<r;
+              if(regs[i].regmap[r]==dops[i+1].rt2) wont_dirty_i|=1<<r;
               if(regs[i].regmap[r]==CCREG) wont_dirty_i|=1<<r;
-              if((branch_regs[i].regmap[r]&63)==dops[i].rt1) wont_dirty_i|=1<<r;
-              if((branch_regs[i].regmap[r]&63)==dops[i].rt2) wont_dirty_i|=1<<r;
-              if((branch_regs[i].regmap[r]&63)==dops[i+1].rt1) wont_dirty_i|=1<<r;
-              if((branch_regs[i].regmap[r]&63)==dops[i+1].rt2) wont_dirty_i|=1<<r;
+              if(branch_regs[i].regmap[r]==dops[i].rt1) wont_dirty_i|=1<<r;
+              if(branch_regs[i].regmap[r]==dops[i].rt2) wont_dirty_i|=1<<r;
+              if(branch_regs[i].regmap[r]==dops[i+1].rt1) wont_dirty_i|=1<<r;
+              if(branch_regs[i].regmap[r]==dops[i+1].rt2) wont_dirty_i|=1<<r;
               if(branch_regs[i].regmap[r]==CCREG) wont_dirty_i|=1<<r;
             }
           }
@@ -6585,21 +6639,21 @@ void clean_registers(int istart,int iend,int wr)
     wont_dirty_next=wont_dirty_i;
     for(r=0;r<HOST_REGS;r++) {
       if(r!=EXCLUDE_REG) {
-        if((regs[i].regmap[r]&63)==dops[i].rt1) will_dirty_i|=1<<r;
-        if((regs[i].regmap[r]&63)==dops[i].rt2) will_dirty_i|=1<<r;
-        if((regs[i].regmap[r]&63)>33) will_dirty_i&=~(1<<r);
+        if(regs[i].regmap[r]==dops[i].rt1) will_dirty_i|=1<<r;
+        if(regs[i].regmap[r]==dops[i].rt2) will_dirty_i|=1<<r;
+        if(regs[i].regmap[r]>33) will_dirty_i&=~(1<<r);
         if(regs[i].regmap[r]<=0) will_dirty_i&=~(1<<r);
         if(regs[i].regmap[r]==CCREG) will_dirty_i|=1<<r;
-        if((regs[i].regmap[r]&63)==dops[i].rt1) wont_dirty_i|=1<<r;
-        if((regs[i].regmap[r]&63)==dops[i].rt2) wont_dirty_i|=1<<r;
+        if(regs[i].regmap[r]==dops[i].rt1) wont_dirty_i|=1<<r;
+        if(regs[i].regmap[r]==dops[i].rt2) wont_dirty_i|=1<<r;
         if(regs[i].regmap[r]==CCREG) wont_dirty_i|=1<<r;
         if(i>istart) {
           if (!dops[i].is_jump)
           {
             // Don't store a register immediately after writing it,
             // may prevent dual-issue.
-            if((regs[i].regmap[r]&63)==dops[i-1].rt1) wont_dirty_i|=1<<r;
-            if((regs[i].regmap[r]&63)==dops[i-1].rt2) wont_dirty_i|=1<<r;
+            if(regs[i].regmap[r]==dops[i-1].rt1) wont_dirty_i|=1<<r;
+            if(regs[i].regmap[r]==dops[i-1].rt2) wont_dirty_i|=1<<r;
           }
         }
       }
@@ -6637,7 +6691,6 @@ void clean_registers(int istart,int iend,int wr)
           }
         }
         #endif
-      //}
     }
     // Deal with changed mappings
     temp_will_dirty=will_dirty_i;
@@ -6669,9 +6722,9 @@ void clean_registers(int istart,int iend,int wr)
         else {
           will_dirty_i&=~(1<<r);
           wont_dirty_i&=~(1<<r);
-          if((regmap_pre[i][r]&63)>0 && (regmap_pre[i][r]&63)<34) {
-            will_dirty_i|=((unneeded_reg[i]>>(regmap_pre[i][r]&63))&1)<<r;
-            wont_dirty_i|=((unneeded_reg[i]>>(regmap_pre[i][r]&63))&1)<<r;
+          if(regmap_pre[i][r]>0 && regmap_pre[i][r]<34) {
+            will_dirty_i|=((unneeded_reg[i]>>regmap_pre[i][r])&1)<<r;
+            wont_dirty_i|=((unneeded_reg[i]>>regmap_pre[i][r])&1)<<r;
           } else {
             wont_dirty_i|=1<<r;
             /*printf("i: %x (%d) mismatch: %d\n",start+i*4,i,r);assert(!((will_dirty>>r)&1));*/
@@ -6683,6 +6736,24 @@ void clean_registers(int istart,int iend,int wr)
 }
 
 #ifdef DISASM
+#include <inttypes.h>
+void print_regmap(const char *name, const signed char *regmap)
+{
+  char buf[5];
+  int i, l;
+  fputs(name, stdout);
+  for (i = 0; i < HOST_REGS; i++) {
+    l = 0;
+    if (regmap[i] >= 0)
+      l = snprintf(buf, sizeof(buf), "$%d", regmap[i]);
+    for (; l < 3; l++)
+      buf[l] = ' ';
+    buf[l] = 0;
+    printf(" r%d=%s", i, buf);
+  }
+  fputs("\n", stdout);
+}
+
   /* disassembly */
 void disassemble_inst(int i)
 {
@@ -6768,6 +6839,16 @@ void disassemble_inst(int i)
         //printf (" %s %8x\n",insn[i],source[i]);
         printf (" %x: %s\n",start+i*4,insn[i]);
     }
+    return;
+    printf("D: %"PRIu64"  WD: %"PRIu64"  U: %"PRIu64"\n",
+      regs[i].dirty, regs[i].wasdirty, unneeded_reg[i]);
+    print_regmap("pre:   ", regmap_pre[i]);
+    print_regmap("entry: ", regs[i].regmap_entry);
+    print_regmap("map:   ", regs[i].regmap);
+    if (dops[i].is_jump) {
+      print_regmap("bentry:", branch_regs[i].regmap_entry);
+      print_regmap("bmap:  ", branch_regs[i].regmap);
+    }
 }
 #else
 static void disassemble_inst(int i) {}
@@ -6788,7 +6869,7 @@ static void new_dynarec_test(void)
     SysPrintf("linkage_arm* miscompilation/breakage detected.\n");
   }
 
-  SysPrintf("testing if we can run recompiled code...\n");
+  SysPrintf("testing if we can run recompiled code @%p...\n", out);
   ((volatile u_int *)out)[0]++; // make cache dirty
 
   for (i = 0; i < ARRAY_SIZE(ret); i++) {
@@ -6826,6 +6907,7 @@ void new_dynarec_clear_full(void)
   literalcount=0;
   stop_after_jal=0;
   inv_code_start=inv_code_end=~0;
+  hack_addr=0;
   f1_hack=0;
   // TLB
   for(n=0;n<4096;n++) ll_clear(jump_in+n);
@@ -6838,16 +6920,24 @@ void new_dynarec_clear_full(void)
 
 void new_dynarec_init(void)
 {
-  SysPrintf("Init new dynarec\n");
+  SysPrintf("Init new dynarec, ndrc size %x\n", (int)sizeof(*ndrc));
 
+#ifdef _3DS
+  check_rosalina();
+#endif
 #ifdef BASE_ADDR_DYNAMIC
   #ifdef VITA
-  sceBlock = sceKernelAllocMemBlockForVM("code", 1 << TARGET_SIZE_2);
-  if (sceBlock < 0)
-    SysPrintf("sceKernelAllocMemBlockForVM failed\n");
+  sceBlock = getVMBlock(); //sceKernelAllocMemBlockForVM("code", sizeof(*ndrc));
+  if (sceBlock <= 0)
+    SysPrintf("sceKernelAllocMemBlockForVM failed: %x\n", sceBlock);
   int ret = sceKernelGetMemBlockBase(sceBlock, (void **)&ndrc);
   if (ret < 0)
-    SysPrintf("sceKernelGetMemBlockBase failed\n");
+    SysPrintf("sceKernelGetMemBlockBase failed: %x\n", ret);
+  sceKernelOpenVMDomain();
+  sceClibPrintf("translation_cache = 0x%08lx\n ", (long)ndrc->translation_cache);
+  #elif defined(_MSC_VER)
+  ndrc = VirtualAlloc(NULL, sizeof(*ndrc), MEM_COMMIT | MEM_RESERVE,
+    PAGE_EXECUTE_READWRITE);
   #else
   uintptr_t desired_addr = 0;
   #ifdef __ELF__
@@ -6865,7 +6955,8 @@ void new_dynarec_init(void)
 #else
   #ifndef NO_WRITE_EXEC
   // not all systems allow execute in data segment by default
-  if (mprotect(ndrc, sizeof(ndrc->translation_cache) + sizeof(ndrc->tramp.ops),
+  // size must be 4K aligned for 3DS?
+  if (mprotect(ndrc, sizeof(*ndrc),
                PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
     SysPrintf("mprotect() failed: %s\n", strerror(errno));
   #endif
@@ -6889,8 +6980,9 @@ void new_dynarec_cleanup(void)
   int n;
 #ifdef BASE_ADDR_DYNAMIC
   #ifdef VITA
-  sceKernelFreeMemBlock(sceBlock);
-  sceBlock = -1;
+  // sceBlock is managed by retroarch's bootstrap code
+  //sceKernelFreeMemBlock(sceBlock);
+  //sceBlock = -1;
   #else
   if (munmap(ndrc, sizeof(*ndrc)) < 0)
     SysPrintf("munmap() failed\n");
@@ -6906,9 +6998,6 @@ void new_dynarec_cleanup(void)
 
 static u_int *get_source_start(u_int addr, u_int *limit)
 {
-  if (!HACK_ENABLED(NDHACK_OVERRIDE_CYCLE_M))
-    cycle_multiplier_override = 0;
-
   if (addr < 0x00200000 ||
     (0xa0000000 <= addr && addr < 0xa0200000))
   {
@@ -6923,7 +7012,7 @@ static u_int *get_source_start(u_int addr, u_int *limit)
     // BIOS. The multiplier should be much higher as it's uncached 8bit mem,
     // but timings in PCSX are too tied to the interpreter's BIAS
     if (!HACK_ENABLED(NDHACK_OVERRIDE_CYCLE_M))
-      cycle_multiplier_override = 200;
+      cycle_multiplier_active = 200;
 
     *limit = (addr & 0xfff00000) | 0x80000;
     return (u_int *)((u_char *)psxR + (addr&0x7ffff));
@@ -7035,6 +7124,43 @@ void new_dynarec_load_blocks(const void *save, int size)
   memcpy(&psxRegs.GPR, regs_save, sizeof(regs_save));
 }
 
+static int apply_hacks(void)
+{
+  int i;
+  if (HACK_ENABLED(NDHACK_NO_COMPAT_HACKS))
+    return 0;
+  /* special hack(s) */
+  for (i = 0; i < slen - 4; i++)
+  {
+    // lui a4, 0xf200; jal <rcnt_read>; addu a0, 2; slti v0, 28224
+    if (source[i] == 0x3c04f200 && dops[i+1].itype == UJUMP
+        && source[i+2] == 0x34840002 && dops[i+3].opcode == 0x0a
+        && imm[i+3] == 0x6e40 && dops[i+3].rs1 == 2)
+    {
+      SysPrintf("PE2 hack @%08x\n", start + (i+3)*4);
+      dops[i + 3].itype = NOP;
+    }
+  }
+  i = slen;
+  if (i > 10 && source[i-1] == 0 && source[i-2] == 0x03e00008
+      && source[i-4] == 0x8fbf0018 && source[i-6] == 0x00c0f809
+      && dops[i-7].itype == STORE)
+  {
+    i = i-8;
+    if (dops[i].itype == IMM16)
+      i--;
+    // swl r2, 15(r6); swr r2, 12(r6); sw r6, *; jalr r6
+    if (dops[i].itype == STORELR && dops[i].rs1 == 6
+      && dops[i-1].itype == STORELR && dops[i-1].rs1 == 6)
+    {
+      SysPrintf("F1 hack from %08x, old dst %08x\n", start, hack_addr);
+      f1_hack = 1;
+      return 1;
+    }
+  }
+  return 0;
+}
+
 int new_recompile_block(u_int addr)
 {
   u_int pagelimit = 0;
@@ -7070,9 +7196,11 @@ int new_recompile_block(u_int addr)
     ll_add_flags(jump_in+page,start,state_rflags,(void *)beginning);
     return 0;
   }
-  else if (f1_hack == ~0u || (f1_hack != 0 && start == f1_hack)) {
+  else if (f1_hack && hack_addr == 0) {
     void *beginning = start_block();
     u_int page = get_page(start);
+    emit_movimm(start, 0);
+    emit_writeword(0, &hack_addr);
     emit_readword(&psxRegs.GPR.n.sp, 0);
     emit_readptr(&mem_rtab, 1);
     emit_shrimm(0, 12, 2);
@@ -7088,14 +7216,20 @@ int new_recompile_block(u_int addr)
 
     ll_add_flags(jump_in + page, start, state_rflags, beginning);
     SysPrintf("F1 hack to   %08x\n", start);
-    f1_hack = start;
     return 0;
   }
 
+  cycle_multiplier_active = cycle_multiplier_override && cycle_multiplier == CYCLE_MULT_DEFAULT
+    ? cycle_multiplier_override : cycle_multiplier;
+
   source = get_source_start(start, &pagelimit);
   if (source == NULL) {
-    SysPrintf("Compile at bogus memory address: %08x\n", addr);
-    abort();
+    if (addr != hack_addr) {
+      SysPrintf("Compile at bogus memory address: %08x\n", addr);
+      hack_addr = addr;
+    }
+    //abort();
+    return -1;
   }
 
   /* Pass 1: disassemble */
@@ -7110,16 +7244,16 @@ int new_recompile_block(u_int addr)
   /* Pass 10: garbage collection / free memory */
 
   int j;
-  int done=0;
+  int done = 0, ni_count = 0;
   unsigned int type,op,op2;
 
   //printf("addr = %x source = %x %x\n", addr,source,source[0]);
 
   /* Pass 1 disassembly */
 
-  for(i=0;!done;i++) {
-    dops[i].bt=0;
-    dops[i].ooo=0;
+  for (i = 0; !done; i++)
+  {
+    memset(&dops[i], 0, sizeof(dops[i]));
     op2=0;
     minimum_free_regs[i]=0;
     dops[i].opcode=op=source[i]>>26;
@@ -7138,7 +7272,7 @@ int new_recompile_block(u_int addr)
           case 0x08: strcpy(insn[i],"JR"); type=RJUMP; break;
           case 0x09: strcpy(insn[i],"JALR"); type=RJUMP; break;
           case 0x0C: strcpy(insn[i],"SYSCALL"); type=SYSCALL; break;
-          case 0x0D: strcpy(insn[i],"BREAK"); type=OTHER; break;
+          case 0x0D: strcpy(insn[i],"BREAK"); type=SYSCALL; break;
           case 0x0F: strcpy(insn[i],"SYNC"); type=OTHER; break;
           case 0x10: strcpy(insn[i],"MFHI"); type=MOV; break;
           case 0x11: strcpy(insn[i],"MTHI"); type=MOV; break;
@@ -7559,12 +7693,12 @@ int new_recompile_block(u_int addr)
           do_in_intrp=1;
         }
       }
-      if(do_in_intrp) {
-        dops[i-1].rs1=CCREG;
-        dops[i-1].rs2=dops[i-1].rt1=dops[i-1].rt2=0;
-        ba[i-1]=-1;
-        dops[i-1].itype=INTCALL;
-        done=2;
+      if (do_in_intrp) {
+        memset(&dops[i-1], 0, sizeof(dops[i-1]));
+        dops[i-1].itype = INTCALL;
+        dops[i-1].rs1 = CCREG;
+        ba[i-1] = -1;
+        done = 2;
         i--; // don't compile the DS
       }
     }
@@ -7584,9 +7718,9 @@ int new_recompile_block(u_int addr)
       // Don't get too close to the limit
       if(i>MAXBLOCK/2) done=1;
     }
-    if(dops[i].itype==SYSCALL&&stop_after_jal) done=1;
-    if(dops[i].itype==HLECALL||dops[i].itype==INTCALL) done=2;
-    if(done==2) {
+    if (dops[i].itype == SYSCALL || dops[i].itype == HLECALL || dops[i].itype == INTCALL)
+      done = stop_after_jal ? 1 : 2;
+    if (done == 2) {
       // Does the block continue due to a branch?
       for(j=i-1;j>=0;j--)
       {
@@ -7600,7 +7734,7 @@ int new_recompile_block(u_int addr)
     assert(start+i*4<pagelimit);
     if (i==MAXBLOCK-1) done=1;
     // Stop if we're compiling junk
-    if(dops[i].itype==NI&&dops[i].opcode==0x11) {
+    if(dops[i].itype == NI && (++ni_count > 8 || dops[i].opcode == 0x11)) {
       done=stop_after_jal=1;
       SysPrintf("Disabled speculative precompilation\n");
     }
@@ -7613,23 +7747,7 @@ int new_recompile_block(u_int addr)
   }
   assert(slen>0);
 
-  /* spacial hack(s) */
-  if (i > 10 && source[i-1] == 0 && source[i-2] == 0x03e00008
-      && source[i-4] == 0x8fbf0018 && source[i-6] == 0x00c0f809
-      && dops[i-7].itype == STORE)
-  {
-    i = i-8;
-    if (dops[i].itype == IMM16)
-      i--;
-    // swl r2, 15(r6); swr r2, 12(r6); sw r6, *; jalr r6
-    if (dops[i].itype == STORELR && dops[i].rs1 == 6
-      && dops[i-1].itype == STORELR && dops[i-1].rs1 == 6)
-    {
-      SysPrintf("F1 hack from %08x\n", start);
-      if (f1_hack == 0)
-        f1_hack = ~0u;
-    }
-  }
+  int clear_hack_addr = apply_hacks();
 
   /* Pass 2 - Register dependencies and branch targets */
 
@@ -7638,14 +7756,16 @@ int new_recompile_block(u_int addr)
   /* Pass 3 - Register allocation */
 
   struct regstat current; // Current register allocations/status
-  current.dirty=0;
-  current.u=unneeded_reg[0];
+  clear_all_regs(current.regmap_entry);
   clear_all_regs(current.regmap);
-  alloc_reg(&current,0,CCREG);
-  dirty_reg(&current,CCREG);
-  current.isconst=0;
-  current.wasconst=0;
-  current.waswritten=0;
+  current.wasdirty = current.dirty = 0;
+  current.u = unneeded_reg[0];
+  alloc_reg(&current, 0, CCREG);
+  dirty_reg(&current, CCREG);
+  current.wasconst = 0;
+  current.isconst = 0;
+  current.loadedconst = 0;
+  current.waswritten = 0;
   int ds=0;
   int cc=0;
   int hr=-1;
@@ -7676,6 +7796,9 @@ int new_recompile_block(u_int addr)
     memcpy(regmap_pre[i],current.regmap,sizeof(current.regmap));
     regs[i].wasconst=current.isconst;
     regs[i].wasdirty=current.dirty;
+    regs[i].dirty=0;
+    regs[i].u=0;
+    regs[i].isconst=0;
     regs[i].loadedconst=0;
     if (!dops[i].is_jump) {
       if(i+1<slen) {
@@ -7689,7 +7812,10 @@ int new_recompile_block(u_int addr)
         current.u=branch_unneeded_reg[i]&~((1LL<<dops[i+1].rs1)|(1LL<<dops[i+1].rs2));
         current.u&=~((1LL<<dops[i].rs1)|(1LL<<dops[i].rs2));
         current.u|=1;
-      } else { SysPrintf("oops, branch at end of block with no delay slot\n");abort(); }
+      } else {
+        SysPrintf("oops, branch at end of block with no delay slot @%08x\n", start + i*4);
+        abort();
+      }
     }
     dops[i].is_ds=ds;
     if(ds) {
@@ -7987,7 +8113,7 @@ int new_recompile_block(u_int addr)
           if(r!=regmap_pre[i][hr]) {
             // TODO: delay slot (?)
             or=get_reg(regmap_pre[i],r); // Get old mapping for this register
-            if(or<0||(r&63)>=TEMPREG){
+            if(or<0||r>=TEMPREG){
               regs[i].regmap_entry[hr]=-1;
             }
             else
@@ -7995,7 +8121,7 @@ int new_recompile_block(u_int addr)
               // Just move it to a different register
               regs[i].regmap_entry[hr]=r;
               // If it was dirty before, it's still dirty
-              if((regs[i].wasdirty>>or)&1) dirty_reg(&current,r&63);
+              if((regs[i].wasdirty>>or)&1) dirty_reg(&current,r);
             }
           }
           else
@@ -8331,8 +8457,8 @@ int new_recompile_block(u_int addr)
       // Merge in delay slot
       for(hr=0;hr<HOST_REGS;hr++)
       {
-        if(dops[i+1].rt1&&dops[i+1].rt1==(regs[i].regmap[hr]&63)) nr&=~(1<<hr);
-        if(dops[i+1].rt2&&dops[i+1].rt2==(regs[i].regmap[hr]&63)) nr&=~(1<<hr);
+        if(dops[i+1].rt1&&dops[i+1].rt1==regs[i].regmap[hr]) nr&=~(1<<hr);
+        if(dops[i+1].rt2&&dops[i+1].rt2==regs[i].regmap[hr]) nr&=~(1<<hr);
         if(dops[i+1].rs1==regmap_pre[i][hr]) nr|=1<<hr;
         if(dops[i+1].rs2==regmap_pre[i][hr]) nr|=1<<hr;
         if(dops[i+1].rs1==regs[i].regmap_entry[hr]) nr|=1<<hr;
@@ -8371,9 +8497,9 @@ int new_recompile_block(u_int addr)
     for(hr=0;hr<HOST_REGS;hr++)
     {
       // Overwritten registers are not needed
-      if(dops[i].rt1&&dops[i].rt1==(regs[i].regmap[hr]&63)) nr&=~(1<<hr);
-      if(dops[i].rt2&&dops[i].rt2==(regs[i].regmap[hr]&63)) nr&=~(1<<hr);
-      if(FTEMP==(regs[i].regmap[hr]&63)) nr&=~(1<<hr);
+      if(dops[i].rt1&&dops[i].rt1==regs[i].regmap[hr]) nr&=~(1<<hr);
+      if(dops[i].rt2&&dops[i].rt2==regs[i].regmap[hr]) nr&=~(1<<hr);
+      if(FTEMP==regs[i].regmap[hr]) nr&=~(1<<hr);
       // Source registers are needed
       if(dops[i].rs1==regmap_pre[i][hr]) nr|=1<<hr;
       if(dops[i].rs2==regmap_pre[i][hr]) nr|=1<<hr;
@@ -8393,12 +8519,12 @@ int new_recompile_block(u_int addr)
       // might have to load the register before the branch.
       if(i>0&&!dops[i].bt&&((regs[i].wasdirty>>hr)&1)) {
         if((regmap_pre[i][hr]>0&&!((unneeded_reg[i]>>regmap_pre[i][hr])&1))) {
-          if(dops[i-1].rt1==(regmap_pre[i][hr]&63)) nr|=1<<hr;
-          if(dops[i-1].rt2==(regmap_pre[i][hr]&63)) nr|=1<<hr;
+          if(dops[i-1].rt1==regmap_pre[i][hr]) nr|=1<<hr;
+          if(dops[i-1].rt2==regmap_pre[i][hr]) nr|=1<<hr;
         }
         if((regs[i].regmap_entry[hr]>0&&!((unneeded_reg[i]>>regs[i].regmap_entry[hr])&1))) {
-          if(dops[i-1].rt1==(regs[i].regmap_entry[hr]&63)) nr|=1<<hr;
-          if(dops[i-1].rt2==(regs[i].regmap_entry[hr]&63)) nr|=1<<hr;
+          if(dops[i-1].rt1==regs[i].regmap_entry[hr]) nr|=1<<hr;
+          if(dops[i-1].rt2==regs[i].regmap_entry[hr]) nr|=1<<hr;
         }
       }
     }
@@ -8424,22 +8550,24 @@ int new_recompile_block(u_int addr)
             map2 = INVCP;
           if(dops[i+1].itype==LOADLR || dops[i+1].itype==STORELR || dops[i+1].itype==C2LS)
             temp = FTEMP;
-          if((regs[i].regmap[hr]&63)!=dops[i].rs1 && (regs[i].regmap[hr]&63)!=dops[i].rs2 &&
-             (regs[i].regmap[hr]&63)!=dops[i].rt1 && (regs[i].regmap[hr]&63)!=dops[i].rt2 &&
-             (regs[i].regmap[hr]&63)!=dops[i+1].rt1 && (regs[i].regmap[hr]&63)!=dops[i+1].rt2 &&
+          if(regs[i].regmap[hr]!=dops[i].rs1 && regs[i].regmap[hr]!=dops[i].rs2 &&
+             regs[i].regmap[hr]!=dops[i].rt1 && regs[i].regmap[hr]!=dops[i].rt2 &&
+             regs[i].regmap[hr]!=dops[i+1].rt1 && regs[i].regmap[hr]!=dops[i+1].rt2 &&
              regs[i].regmap[hr]!=dops[i+1].rs1 && regs[i].regmap[hr]!=dops[i+1].rs2 &&
-             (regs[i].regmap[hr]&63)!=temp && regs[i].regmap[hr]!=PTEMP &&
+             regs[i].regmap[hr]!=temp && regs[i].regmap[hr]!=PTEMP &&
              regs[i].regmap[hr]!=RHASH && regs[i].regmap[hr]!=RHTBL &&
              regs[i].regmap[hr]!=RTEMP && regs[i].regmap[hr]!=CCREG &&
              regs[i].regmap[hr]!=map1 && regs[i].regmap[hr]!=map2)
           {
             regs[i].regmap[hr]=-1;
             regs[i].isconst&=~(1<<hr);
-            if((branch_regs[i].regmap[hr]&63)!=dops[i].rs1 && (branch_regs[i].regmap[hr]&63)!=dops[i].rs2 &&
-               (branch_regs[i].regmap[hr]&63)!=dops[i].rt1 && (branch_regs[i].regmap[hr]&63)!=dops[i].rt2 &&
-               (branch_regs[i].regmap[hr]&63)!=dops[i+1].rt1 && (branch_regs[i].regmap[hr]&63)!=dops[i+1].rt2 &&
+            regs[i].dirty&=~(1<<hr);
+            regs[i+1].wasdirty&=~(1<<hr);
+            if(branch_regs[i].regmap[hr]!=dops[i].rs1 && branch_regs[i].regmap[hr]!=dops[i].rs2 &&
+               branch_regs[i].regmap[hr]!=dops[i].rt1 && branch_regs[i].regmap[hr]!=dops[i].rt2 &&
+               branch_regs[i].regmap[hr]!=dops[i+1].rt1 && branch_regs[i].regmap[hr]!=dops[i+1].rt2 &&
                branch_regs[i].regmap[hr]!=dops[i+1].rs1 && branch_regs[i].regmap[hr]!=dops[i+1].rs2 &&
-               (branch_regs[i].regmap[hr]&63)!=temp && branch_regs[i].regmap[hr]!=PTEMP &&
+               branch_regs[i].regmap[hr]!=temp && branch_regs[i].regmap[hr]!=PTEMP &&
                branch_regs[i].regmap[hr]!=RHASH && branch_regs[i].regmap[hr]!=RHTBL &&
                branch_regs[i].regmap[hr]!=RTEMP && branch_regs[i].regmap[hr]!=CCREG &&
                branch_regs[i].regmap[hr]!=map1 && branch_regs[i].regmap[hr]!=map2)
@@ -8468,9 +8596,9 @@ int new_recompile_block(u_int addr)
               map2 = INVCP;
             if (dops[i].itype==LOADLR || dops[i].itype==STORELR || dops[i].itype==C2LS)
               temp = FTEMP;
-            if((regs[i].regmap[hr]&63)!=dops[i].rt1 && (regs[i].regmap[hr]&63)!=dops[i].rt2 &&
+            if(regs[i].regmap[hr]!=dops[i].rt1 && regs[i].regmap[hr]!=dops[i].rt2 &&
                regs[i].regmap[hr]!=dops[i].rs1 && regs[i].regmap[hr]!=dops[i].rs2 &&
-               (regs[i].regmap[hr]&63)!=temp && regs[i].regmap[hr]!=map1 && regs[i].regmap[hr]!=map2 &&
+               regs[i].regmap[hr]!=temp && regs[i].regmap[hr]!=map1 && regs[i].regmap[hr]!=map2 &&
                //(dops[i].itype!=SPAN||regs[i].regmap[hr]!=CCREG)
                regs[i].regmap[hr] != CCREG)
             {
@@ -8488,6 +8616,8 @@ int new_recompile_block(u_int addr)
               }
               regs[i].regmap[hr]=-1;
               regs[i].isconst&=~(1<<hr);
+              regs[i].dirty&=~(1<<hr);
+              regs[i+1].wasdirty&=~(1<<hr);
             }
           }
         }
@@ -8569,15 +8699,12 @@ int new_recompile_block(u_int addr)
                 //printf("Test %x -> %x, %x %d/%d\n",start+i*4,ba[i],start+j*4,hr,r);
                 if(r<34&&((unneeded_reg[j]>>r)&1)) break;
                 assert(r < 64);
-                if(regs[j].regmap[hr]==f_regmap[hr]&&(f_regmap[hr]&63)<TEMPREG) {
+                if(regs[j].regmap[hr]==f_regmap[hr]&&f_regmap[hr]<TEMPREG) {
                   //printf("Hit %x -> %x, %x %d/%d\n",start+i*4,ba[i],start+j*4,hr,r);
                   int k;
                   if(regs[i].regmap[hr]==-1&&branch_regs[i].regmap[hr]==-1) {
+                    if(get_reg(regs[i].regmap,f_regmap[hr])>=0) break;
                     if(get_reg(regs[i+2].regmap,f_regmap[hr])>=0) break;
-                    if(r>63) {
-                      if(get_reg(regs[i].regmap,r&63)<0) break;
-                      if(get_reg(branch_regs[i].regmap,r&63)<0) break;
-                    }
                     k=i;
                     while(k>1&&regs[k-1].regmap[hr]==-1) {
                       if(count_free_regs(regs[k-1].regmap)<=minimum_free_regs[k-1]) {
@@ -8596,7 +8723,6 @@ int new_recompile_block(u_int addr)
                       if(k>2&&(dops[k-3].itype==UJUMP||dops[k-3].itype==RJUMP)&&dops[k-3].rt1==31) {
                         break;
                       }
-                      assert(r < 64);
                       k--;
                     }
                     if(regs[k-1].regmap[hr]==f_regmap[hr]&&regmap_pre[k][hr]==f_regmap[hr]) {
@@ -8874,8 +9000,11 @@ int new_recompile_block(u_int addr)
              ||(dops[i+1].opcode&0x3b)==0x39||(dops[i+1].opcode&0x3b)==0x3a) { // SB/SH/SW/SD/SWC1/SDC1/SWC2/SDC2
             if(get_reg(regs[i+1].regmap,dops[i+1].rs1)<0) {
               hr=get_reg2(regs[i].regmap,regs[i+1].regmap,-1);
-              if(hr<0) hr=get_reg(regs[i+1].regmap,-1);
-              else {regs[i+1].regmap[hr]=AGEN1+((i+1)&1);regs[i+1].isconst&=~(1<<hr);}
+              if(hr<0) hr=get_reg_temp(regs[i+1].regmap);
+              else {
+                regs[i+1].regmap[hr]=AGEN1+((i+1)&1);
+                regs[i+1].isconst&=~(1<<hr);
+              }
               assert(hr>=0);
               if(regs[i].regmap[hr]<0&&regs[i+1].regmap_entry[hr]<0)
               {
@@ -8932,7 +9061,7 @@ int new_recompile_block(u_int addr)
               hr=get_reg(regs[i+1].regmap,FTEMP);
             if(dops[i+1].itype==STORE||dops[i+1].itype==STORELR||(dops[i+1].opcode&0x3b)==0x39||(dops[i+1].opcode&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);
+              if(hr<0) hr=get_reg_temp(regs[i+1].regmap);
             }
             if(hr>=0&&regs[i].regmap[hr]<0) {
               int rs=get_reg(regs[i+1].regmap,dops[i+1].rs1);
@@ -8972,7 +9101,7 @@ int new_recompile_block(u_int addr)
     dops[slen-1].bt=1; // Mark as a branch target so instruction can restart after exception
   }
 
-#ifdef DISASM
+#ifdef REG_ALLOC_PRINT
   /* Debug/disassembly */
   for(i=0;i<slen;i++)
   {
@@ -9104,7 +9233,7 @@ int new_recompile_block(u_int addr)
       #endif
     }
   }
-#endif // DISASM
+#endif // REG_ALLOC_PRINT
 
   /* Pass 8 - Assembly */
   linkcount=0;stubcount=0;
@@ -9137,6 +9266,10 @@ int new_recompile_block(u_int addr)
   }
   for(i=0;i<slen;i++)
   {
+    __builtin_prefetch(regs[i+1].regmap);
+    check_regmap(regmap_pre[i]);
+    check_regmap(regs[i].regmap_entry);
+    check_regmap(regs[i].regmap);
     //if(ds) printf("ds: ");
     disassemble_inst(i);
     if(ds) {
@@ -9166,6 +9299,11 @@ int new_recompile_block(u_int addr)
       instr_addr[i] = out;
       assem_debug("<->\n");
       drc_dbg_emit_do_cmp(i, ccadj[i]);
+      if (clear_hack_addr) {
+        emit_movimm(0, 0);
+        emit_writeword(0, &hack_addr);
+        clear_hack_addr = 0;
+      }
 
       // load regs
       if(regs[i].regmap_entry[HOST_CCREG]==CCREG&&regs[i].regmap[HOST_CCREG]!=CCREG)