+}
+
+// Write back dirty registers as soon as we will no longer modify them,
+// so that we don't end up with lots of writes at the branches.
+static noinline void pass6_clean_registers(int istart, int iend, int wr)
+{
+ int i;
+ int r;
+ u_int will_dirty_i,will_dirty_next,temp_will_dirty;
+ u_int wont_dirty_i,wont_dirty_next,temp_wont_dirty;
+ if(iend==slen-1) {
+ will_dirty_i=will_dirty_next=0;
+ wont_dirty_i=wont_dirty_next=0;
+ }else{
+ will_dirty_i=will_dirty_next=will_dirty[iend+1];
+ wont_dirty_i=wont_dirty_next=wont_dirty[iend+1];
+ }
+ for (i=iend;i>=istart;i--)
+ {
+ signed char rregmap_i[RRMAP_SIZE];
+ u_int hr_candirty = 0;
+ assert(HOST_REGS < 32);
+ make_rregs(regs[i].regmap, rregmap_i, &hr_candirty);
+ __builtin_prefetch(regs[i-1].regmap);
+ if(dops[i].is_jump)
+ {
+ signed char branch_rregmap_i[RRMAP_SIZE];
+ u_int branch_hr_candirty = 0;
+ make_rregs(branch_regs[i].regmap, branch_rregmap_i, &branch_hr_candirty);
+ if(ba[i]<start || ba[i]>=(start+slen*4))
+ {
+ // Branch out of this block, flush all regs
+ will_dirty_i = 0;
+ will_dirty_i |= 1u << (get_rreg(branch_rregmap_i, dops[i].rt1) & 31);
+ will_dirty_i |= 1u << (get_rreg(branch_rregmap_i, dops[i].rt2) & 31);
+ will_dirty_i |= 1u << (get_rreg(branch_rregmap_i, dops[i+1].rt1) & 31);
+ will_dirty_i |= 1u << (get_rreg(branch_rregmap_i, dops[i+1].rt2) & 31);
+ will_dirty_i |= 1u << (get_rreg(branch_rregmap_i, CCREG) & 31);
+ will_dirty_i &= branch_hr_candirty;
+ if (dops[i].is_ujump)
+ {
+ // Unconditional branch
+ wont_dirty_i = 0;
+ // Merge in delay slot (will dirty)
+ will_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i].rt1) & 31);
+ will_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i].rt2) & 31);
+ will_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i+1].rt1) & 31);
+ will_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i+1].rt2) & 31);
+ will_dirty_i |= 1u << (get_rreg(rregmap_i, CCREG) & 31);
+ will_dirty_i &= hr_candirty;
+ }
+ else
+ {
+ // Conditional branch
+ wont_dirty_i = wont_dirty_next;
+ // Merge in delay slot (will dirty)
+ // (the original code had no explanation why these 2 are commented out)
+ //will_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i].rt1) & 31);
+ //will_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i].rt2) & 31);
+ will_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i+1].rt1) & 31);
+ will_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i+1].rt2) & 31);
+ will_dirty_i |= 1u << (get_rreg(rregmap_i, CCREG) & 31);
+ will_dirty_i &= hr_candirty;
+ }
+ // Merge in delay slot (wont dirty)
+ wont_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i].rt1) & 31);
+ wont_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i].rt2) & 31);
+ wont_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i+1].rt1) & 31);
+ wont_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i+1].rt2) & 31);
+ wont_dirty_i |= 1u << (get_rreg(rregmap_i, CCREG) & 31);
+ wont_dirty_i |= 1u << (get_rreg(branch_rregmap_i, dops[i].rt1) & 31);
+ wont_dirty_i |= 1u << (get_rreg(branch_rregmap_i, dops[i].rt2) & 31);
+ wont_dirty_i |= 1u << (get_rreg(branch_rregmap_i, dops[i+1].rt1) & 31);
+ wont_dirty_i |= 1u << (get_rreg(branch_rregmap_i, dops[i+1].rt2) & 31);
+ wont_dirty_i |= 1u << (get_rreg(branch_rregmap_i, CCREG) & 31);
+ wont_dirty_i &= ~(1u << 31);
+ if(wr) {
+ #ifndef DESTRUCTIVE_WRITEBACK
+ branch_regs[i].dirty&=wont_dirty_i;
+ #endif
+ branch_regs[i].dirty|=will_dirty_i;
+ }
+ }
+ else
+ {
+ // Internal branch
+ if(ba[i]<=start+i*4) {
+ // Backward branch
+ if (dops[i].is_ujump)
+ {
+ // Unconditional branch
+ temp_will_dirty=0;
+ temp_wont_dirty=0;
+ // Merge in delay slot (will dirty)
+ temp_will_dirty |= 1u << (get_rreg(branch_rregmap_i, dops[i].rt1) & 31);
+ temp_will_dirty |= 1u << (get_rreg(branch_rregmap_i, dops[i].rt2) & 31);
+ temp_will_dirty |= 1u << (get_rreg(branch_rregmap_i, dops[i+1].rt1) & 31);
+ temp_will_dirty |= 1u << (get_rreg(branch_rregmap_i, dops[i+1].rt2) & 31);
+ temp_will_dirty |= 1u << (get_rreg(branch_rregmap_i, CCREG) & 31);
+ temp_will_dirty &= branch_hr_candirty;
+ temp_will_dirty |= 1u << (get_rreg(rregmap_i, dops[i].rt1) & 31);
+ temp_will_dirty |= 1u << (get_rreg(rregmap_i, dops[i].rt2) & 31);
+ temp_will_dirty |= 1u << (get_rreg(rregmap_i, dops[i+1].rt1) & 31);
+ temp_will_dirty |= 1u << (get_rreg(rregmap_i, dops[i+1].rt2) & 31);
+ temp_will_dirty |= 1u << (get_rreg(rregmap_i, CCREG) & 31);
+ temp_will_dirty &= hr_candirty;
+ } else {
+ // Conditional branch (not taken case)
+ temp_will_dirty=will_dirty_next;
+ temp_wont_dirty=wont_dirty_next;
+ // Merge in delay slot (will dirty)
+ temp_will_dirty |= 1u << (get_rreg(branch_rregmap_i, dops[i].rt1) & 31);
+ temp_will_dirty |= 1u << (get_rreg(branch_rregmap_i, dops[i].rt2) & 31);
+ temp_will_dirty |= 1u << (get_rreg(branch_rregmap_i, dops[i+1].rt1) & 31);
+ temp_will_dirty |= 1u << (get_rreg(branch_rregmap_i, dops[i+1].rt2) & 31);
+ temp_will_dirty |= 1u << (get_rreg(branch_rregmap_i, CCREG) & 31);
+ temp_will_dirty &= branch_hr_candirty;
+ //temp_will_dirty |= 1u << (get_rreg(rregmap_i, dops[i].rt1) & 31);
+ //temp_will_dirty |= 1u << (get_rreg(rregmap_i, dops[i].rt2) & 31);
+ temp_will_dirty |= 1u << (get_rreg(rregmap_i, dops[i+1].rt1) & 31);
+ temp_will_dirty |= 1u << (get_rreg(rregmap_i, dops[i+1].rt2) & 31);
+ temp_will_dirty |= 1u << (get_rreg(rregmap_i, CCREG) & 31);
+ temp_will_dirty &= hr_candirty;
+ }
+ // Merge in delay slot (wont dirty)
+ temp_wont_dirty |= 1u << (get_rreg(rregmap_i, dops[i].rt1) & 31);
+ temp_wont_dirty |= 1u << (get_rreg(rregmap_i, dops[i].rt2) & 31);
+ temp_wont_dirty |= 1u << (get_rreg(rregmap_i, dops[i+1].rt1) & 31);
+ temp_wont_dirty |= 1u << (get_rreg(rregmap_i, dops[i+1].rt2) & 31);
+ temp_wont_dirty |= 1u << (get_rreg(rregmap_i, CCREG) & 31);
+ temp_wont_dirty |= 1u << (get_rreg(branch_rregmap_i, dops[i].rt1) & 31);
+ temp_wont_dirty |= 1u << (get_rreg(branch_rregmap_i, dops[i].rt2) & 31);
+ temp_wont_dirty |= 1u << (get_rreg(branch_rregmap_i, dops[i+1].rt1) & 31);
+ temp_wont_dirty |= 1u << (get_rreg(branch_rregmap_i, dops[i+1].rt2) & 31);
+ temp_wont_dirty |= 1u << (get_rreg(branch_rregmap_i, CCREG) & 31);
+ temp_wont_dirty &= ~(1u << 31);
+ // Deal with changed mappings
+ if(i<iend) {
+ for(r=0;r<HOST_REGS;r++) {
+ if(r!=EXCLUDE_REG) {
+ if(regs[i].regmap[r]!=regmap_pre[i][r]) {
+ temp_will_dirty&=~(1<<r);
+ temp_wont_dirty&=~(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;
+ }
+ }
+ }
+ }
+ }
+ if(wr) {
+ will_dirty[i]=temp_will_dirty;
+ wont_dirty[i]=temp_wont_dirty;
+ pass6_clean_registers((ba[i]-start)>>2,i-1,0);
+ }else{
+ // Limit recursion. It can take an excessive amount
+ // of time if there are a lot of nested loops.
+ will_dirty[(ba[i]-start)>>2]=0;
+ wont_dirty[(ba[i]-start)>>2]=-1;
+ }
+ }
+ /*else*/ if(1)
+ {
+ if (dops[i].is_ujump)
+ {
+ // Unconditional branch
+ will_dirty_i=0;
+ wont_dirty_i=0;
+ //if(ba[i]>start+i*4) { // Disable recursion (for debugging)
+ for(r=0;r<HOST_REGS;r++) {
+ if(r!=EXCLUDE_REG) {
+ if(branch_regs[i].regmap[r]==regs[(ba[i]-start)>>2].regmap_entry[r]) {
+ will_dirty_i|=will_dirty[(ba[i]-start)>>2]&(1<<r);
+ 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])&1)<<r;
+ wont_dirty_i|=((unneeded_reg[(ba[i]-start)>>2]>>branch_regs[i].regmap[r])&1)<<r;
+ }
+ }
+ }
+ //}
+ // Merge in delay slot
+ will_dirty_i |= 1u << (get_rreg(branch_rregmap_i, dops[i].rt1) & 31);
+ will_dirty_i |= 1u << (get_rreg(branch_rregmap_i, dops[i].rt2) & 31);
+ will_dirty_i |= 1u << (get_rreg(branch_rregmap_i, dops[i+1].rt1) & 31);
+ will_dirty_i |= 1u << (get_rreg(branch_rregmap_i, dops[i+1].rt2) & 31);
+ will_dirty_i |= 1u << (get_rreg(branch_rregmap_i, CCREG) & 31);
+ will_dirty_i &= branch_hr_candirty;
+ will_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i].rt1) & 31);
+ will_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i].rt2) & 31);
+ will_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i+1].rt1) & 31);
+ will_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i+1].rt2) & 31);
+ will_dirty_i |= 1u << (get_rreg(rregmap_i, CCREG) & 31);
+ will_dirty_i &= hr_candirty;
+ } else {
+ // Conditional branch
+ will_dirty_i=will_dirty_next;
+ wont_dirty_i=wont_dirty_next;
+ //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];
+ if(target_reg==regs[(ba[i]-start)>>2].regmap_entry[r]) {
+ will_dirty_i&=will_dirty[(ba[i]-start)>>2]&(1<<r);
+ 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)&1)<<r;
+ wont_dirty_i|=((unneeded_reg[(ba[i]-start)>>2]>>target_reg)&1)<<r;
+ }
+ }
+ }
+ // Merge in delay slot
+ will_dirty_i |= 1u << (get_rreg(branch_rregmap_i, dops[i].rt1) & 31);
+ will_dirty_i |= 1u << (get_rreg(branch_rregmap_i, dops[i].rt2) & 31);
+ will_dirty_i |= 1u << (get_rreg(branch_rregmap_i, dops[i+1].rt1) & 31);
+ will_dirty_i |= 1u << (get_rreg(branch_rregmap_i, dops[i+1].rt2) & 31);
+ will_dirty_i |= 1u << (get_rreg(branch_rregmap_i, CCREG) & 31);
+ will_dirty_i &= branch_hr_candirty;
+ //will_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i].rt1) & 31);
+ //will_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i].rt2) & 31);
+ will_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i+1].rt1) & 31);
+ will_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i+1].rt2) & 31);
+ will_dirty_i |= 1u << (get_rreg(rregmap_i, CCREG) & 31);
+ will_dirty_i &= hr_candirty;
+ }
+ // Merge in delay slot (won't dirty)
+ wont_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i].rt1) & 31);
+ wont_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i].rt2) & 31);
+ wont_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i+1].rt1) & 31);
+ wont_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i+1].rt2) & 31);
+ wont_dirty_i |= 1u << (get_rreg(rregmap_i, CCREG) & 31);
+ wont_dirty_i |= 1u << (get_rreg(branch_rregmap_i, dops[i].rt1) & 31);
+ wont_dirty_i |= 1u << (get_rreg(branch_rregmap_i, dops[i].rt2) & 31);
+ wont_dirty_i |= 1u << (get_rreg(branch_rregmap_i, dops[i+1].rt1) & 31);
+ wont_dirty_i |= 1u << (get_rreg(branch_rregmap_i, dops[i+1].rt2) & 31);
+ wont_dirty_i |= 1u << (get_rreg(branch_rregmap_i, CCREG) & 31);
+ wont_dirty_i &= ~(1u << 31);
+ if(wr) {
+ #ifndef DESTRUCTIVE_WRITEBACK
+ branch_regs[i].dirty&=wont_dirty_i;
+ #endif
+ branch_regs[i].dirty|=will_dirty_i;
+ }
+ }
+ }
+ }
+ else if(dops[i].itype==SYSCALL||dops[i].itype==HLECALL||dops[i].itype==INTCALL)
+ {
+ // SYSCALL instruction (software interrupt)
+ will_dirty_i=0;
+ wont_dirty_i=0;
+ }
+ else if(dops[i].itype==COP0 && (source[i]&0x3f)==0x18)
+ {
+ // ERET instruction (return from interrupt)
+ will_dirty_i=0;
+ wont_dirty_i=0;
+ }
+ will_dirty_next=will_dirty_i;
+ wont_dirty_next=wont_dirty_i;
+ will_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i].rt1) & 31);
+ will_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i].rt2) & 31);
+ will_dirty_i |= 1u << (get_rreg(rregmap_i, CCREG) & 31);
+ will_dirty_i &= hr_candirty;
+ wont_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i].rt1) & 31);
+ wont_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i].rt2) & 31);
+ wont_dirty_i |= 1u << (get_rreg(rregmap_i, CCREG) & 31);
+ wont_dirty_i &= ~(1u << 31);
+ if (i > istart && !dops[i].is_jump) {
+ // Don't store a register immediately after writing it,
+ // may prevent dual-issue.
+ wont_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i-1].rt1) & 31);
+ wont_dirty_i |= 1u << (get_rreg(rregmap_i, dops[i-1].rt2) & 31);
+ }
+ // Save it
+ will_dirty[i]=will_dirty_i;
+ wont_dirty[i]=wont_dirty_i;
+ // Mark registers that won't be dirtied as not dirty
+ if(wr) {
+ regs[i].dirty|=will_dirty_i;
+ #ifndef DESTRUCTIVE_WRITEBACK
+ regs[i].dirty&=wont_dirty_i;
+ if(dops[i].is_jump)
+ {
+ if (i < iend-1 && !dops[i].is_ujump) {
+ for(r=0;r<HOST_REGS;r++) {
+ if(r!=EXCLUDE_REG) {
+ if(regs[i].regmap[r]==regmap_pre[i+2][r]) {
+ regs[i+2].wasdirty&=wont_dirty_i|~(1<<r);
+ }else {/*printf("i: %x (%d) mismatch(+2): %d\n",start+i*4,i,r);assert(!((wont_dirty_i>>r)&1));*/}
+ }
+ }
+ }
+ }
+ else
+ {
+ if(i<iend) {
+ for(r=0;r<HOST_REGS;r++) {
+ if(r!=EXCLUDE_REG) {
+ if(regs[i].regmap[r]==regmap_pre[i+1][r]) {
+ regs[i+1].wasdirty&=wont_dirty_i|~(1<<r);
+ }else {/*printf("i: %x (%d) mismatch(+1): %d\n",start+i*4,i,r);assert(!((wont_dirty_i>>r)&1));*/}
+ }
+ }
+ }
+ }
+ #endif
+ }
+ // Deal with changed mappings
+ temp_will_dirty=will_dirty_i;
+ temp_wont_dirty=wont_dirty_i;
+ for(r=0;r<HOST_REGS;r++) {
+ if(r!=EXCLUDE_REG) {
+ int nr;
+ if(regs[i].regmap[r]==regmap_pre[i][r]) {
+ if(wr) {
+ #ifndef DESTRUCTIVE_WRITEBACK
+ regs[i].wasdirty&=wont_dirty_i|~(1<<r);
+ #endif
+ regs[i].wasdirty|=will_dirty_i&(1<<r);
+ }
+ }
+ else if(regmap_pre[i][r]>=0&&(nr=get_rreg(rregmap_i,regmap_pre[i][r]))>=0) {
+ // Register moved to a different register
+ will_dirty_i&=~(1<<r);
+ wont_dirty_i&=~(1<<r);
+ will_dirty_i|=((temp_will_dirty>>nr)&1)<<r;
+ wont_dirty_i|=((temp_wont_dirty>>nr)&1)<<r;
+ if(wr) {
+ #ifndef DESTRUCTIVE_WRITEBACK
+ regs[i].wasdirty&=wont_dirty_i|~(1<<r);
+ #endif
+ regs[i].wasdirty|=will_dirty_i&(1<<r);
+ }
+ }
+ else {
+ will_dirty_i&=~(1<<r);
+ wont_dirty_i&=~(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));*/
+ }
+ }
+ }
+ }
+ }
+}
+
+static noinline void pass10_expire_blocks(void)
+{
+ int i, end;
+ end = (((out-ndrc->translation_cache)>>(TARGET_SIZE_2-16)) + 16384) & 65535;
+ while (expirep != end)
+ {
+ int shift=TARGET_SIZE_2-3; // Divide into 8 blocks
+ uintptr_t base_offs = ((uintptr_t)(expirep >> 13) << shift); // Base offset of this block
+ uintptr_t base_offs_s = base_offs >> shift;
+ inv_debug("EXP: Phase %d\n",expirep);
+ switch((expirep>>11)&3)
+ {
+ case 0:
+ // Clear jump_in and jump_dirty
+ ll_remove_matching_addrs(jump_in+(expirep&2047),base_offs_s,shift);
+ ll_remove_matching_addrs(jump_dirty+(expirep&2047),base_offs_s,shift);
+ ll_remove_matching_addrs(jump_in+2048+(expirep&2047),base_offs_s,shift);
+ ll_remove_matching_addrs(jump_dirty+2048+(expirep&2047),base_offs_s,shift);
+ break;
+ case 1:
+ // Clear pointers
+ ll_kill_pointers(jump_out[expirep&2047],base_offs_s,shift);
+ ll_kill_pointers(jump_out[(expirep&2047)+2048],base_offs_s,shift);
+ break;
+ case 2:
+ // Clear hash table
+ for(i=0;i<32;i++) {
+ struct ht_entry *ht_bin = &hash_table[((expirep&2047)<<5)+i];
+ uintptr_t o1 = (u_char *)ht_bin->tcaddr[1] - ndrc->translation_cache;
+ uintptr_t o2 = o1 - MAX_OUTPUT_BLOCK_SIZE;
+ if ((o1 >> shift) == base_offs_s || (o2 >> shift) == base_offs_s) {
+ inv_debug("EXP: Remove hash %x -> %p\n",ht_bin->vaddr[1],ht_bin->tcaddr[1]);
+ ht_bin->vaddr[1] = -1;
+ ht_bin->tcaddr[1] = NULL;
+ }
+ o1 = (u_char *)ht_bin->tcaddr[0] - ndrc->translation_cache;
+ o2 = o1 - MAX_OUTPUT_BLOCK_SIZE;
+ if ((o1 >> shift) == base_offs_s || (o2 >> shift) == base_offs_s) {
+ inv_debug("EXP: Remove hash %x -> %p\n",ht_bin->vaddr[0],ht_bin->tcaddr[0]);
+ ht_bin->vaddr[0] = ht_bin->vaddr[1];
+ ht_bin->tcaddr[0] = ht_bin->tcaddr[1];
+ ht_bin->vaddr[1] = -1;
+ ht_bin->tcaddr[1] = NULL;
+ }
+ }
+ break;
+ case 3:
+ // Clear jump_out
+ if((expirep&2047)==0)
+ do_clear_cache();
+ ll_remove_matching_addrs(jump_out+(expirep&2047),base_offs_s,shift);
+ ll_remove_matching_addrs(jump_out+2048+(expirep&2047),base_offs_s,shift);
+ break;
+ }
+ expirep=(expirep+1)&65535;
+ }
+}
+
+int new_recompile_block(u_int addr)
+{
+ u_int pagelimit = 0;
+ u_int state_rflags = 0;
+ int i;
+
+ assem_debug("NOTCOMPILED: addr = %x -> %p\n", addr, out);
+
+ // this is just for speculation
+ for (i = 1; i < 32; i++) {
+ if ((psxRegs.GPR.r[i] & 0xffff0000) == 0x1f800000)
+ state_rflags |= 1 << i;
+ }
+
+ start = (u_int)addr&~3;
+ //assert(((u_int)addr&1)==0); // start-in-delay-slot flag
+ new_dynarec_did_compile=1;
+ if (Config.HLE && start == 0x80001000) // hlecall
+ {
+ // XXX: is this enough? Maybe check hleSoftCall?
+ void *beginning=start_block();
+ u_int page=get_page(start);
+
+ invalid_code[start>>12]=0;
+ emit_movimm(start,0);
+ emit_writeword(0,&pcaddr);
+ emit_far_jump(new_dyna_leave);
+ literal_pool(0);
+ end_block(beginning);
+ ll_add_flags(jump_in+page,start,state_rflags,(void *)beginning);
+ return 0;
+ }
+ 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);
+ emit_readptr_dualindexedx_ptrlen(1, 2, 1);
+ emit_addimm(0, 0x18, 0);
+ emit_adds_ptr(1, 1, 1);
+ emit_ldr_dualindexed(1, 0, 0);
+ emit_writeword(0, &psxRegs.GPR.r[26]); // lw k0, 0x18(sp)
+ emit_far_call(get_addr_ht);
+ emit_jmpreg(0); // jr k0
+ literal_pool(0);
+ end_block(beginning);
+
+ ll_add_flags(jump_in + page, start, state_rflags, beginning);
+ SysPrintf("F1 hack to %08x\n", 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) {
+ if (addr != hack_addr) {
+ SysPrintf("Compile at bogus memory address: %08x\n", addr);
+ hack_addr = addr;
+ }
+ //abort();
+ return -1;
+ }
+
+ /* Pass 1: disassemble */
+ /* Pass 2: register dependencies, branch targets */
+ /* Pass 3: register allocation */
+ /* Pass 4: branch dependencies */
+ /* Pass 5: pre-alloc */
+ /* Pass 6: optimize clean/dirty state */
+ /* Pass 7: flag 32-bit registers */
+ /* Pass 8: assembly */
+ /* Pass 9: linker */
+ /* Pass 10: garbage collection / free memory */
+
+ /* Pass 1 disassembly */
+
+ pass1_disassemble(pagelimit);
+
+ int clear_hack_addr = apply_hacks();
+
+ /* Pass 2 - Register dependencies and branch targets */
+
+ pass2_unneeded_regs(0,slen-1,0);
+
+ /* Pass 3 - Register allocation */
+
+ pass3_register_alloc(addr);
+
+ /* Pass 4 - Cull unused host registers */
+
+ pass4_cull_unused_regs();
+
+ /* Pass 5 - Pre-allocate registers */
+
+ pass5a_preallocate1();
+ pass5b_preallocate2();