+ u_int c2op=source[i]&0x3f;
+ u_int hr,reglist_full=0,reglist;
+ int need_flags,need_ir;
+ for(hr=0;hr<HOST_REGS;hr++) {
+ if(i_regs->regmap[hr]>=0) reglist_full|=1<<hr;
+ }
+ reglist=reglist_full&CALLER_SAVE_REGS;
+
+ if (gte_handlers[c2op]!=NULL) {
+ need_flags=!(gte_unneeded[i+1]>>63); // +1 because of how liveness detection works
+ need_ir=(gte_unneeded[i+1]&0xe00)!=0xe00;
+ assem_debug("gte op %08x, unneeded %016lx, need_flags %d, need_ir %d\n",
+ source[i],gte_unneeded[i+1],need_flags,need_ir);
+ if(new_dynarec_hacks&NDHACK_GTE_NO_FLAGS)
+ need_flags=0;
+ //int shift = (source[i] >> 19) & 1;
+ //int lm = (source[i] >> 10) & 1;
+ switch(c2op) {
+ default:
+ (void)need_ir;
+ c2op_prologue(c2op,reglist);
+ emit_movimm(source[i],1); // opcode
+ emit_writeword(1,&psxRegs.code);
+ emit_call(need_flags?gte_handlers[c2op]:gte_handlers_nf[c2op]);
+ break;
+ }
+ c2op_epilogue(c2op,reglist);
+ }
+}
+
+static void c2op_ctc2_31_assemble(signed char sl, signed char temp)
+{
+ //value = value & 0x7ffff000;
+ //if (value & 0x7f87e000) value |= 0x80000000;
+ emit_andimm(sl, 0x7fffe000, temp);
+ emit_testimm(temp, 0xff87ffff);
+ emit_andimm(sl, 0x7ffff000, temp);
+ host_tempreg_acquire();
+ emit_orimm(temp, 0x80000000, HOST_TEMPREG);
+ emit_cmovne_reg(HOST_TEMPREG, temp);
+ host_tempreg_release();
+ assert(0); // testing needed
+}
+
+static void do_mfc2_31_one(u_int copr,signed char temp)
+{
+ emit_readshword(®_cop2d[copr],temp);
+ emit_bicsar_imm(temp,31,temp);
+ emit_cmpimm(temp,0xf80);
+ emit_csinvle_reg(temp,WZR,temp); // if (temp > 0xf80) temp = ~0;
+ emit_andimm(temp,0xf80,temp);
+}
+
+static void c2op_mfc2_29_assemble(signed char tl, signed char temp)
+{
+ if (temp < 0) {
+ host_tempreg_acquire();
+ temp = HOST_TEMPREG;
+ }
+ do_mfc2_31_one(9,temp);
+ emit_shrimm(temp,7,tl);
+ do_mfc2_31_one(10,temp);
+ emit_orrshr_imm(temp,2,tl);
+ do_mfc2_31_one(11,temp);
+ emit_orrshl_imm(temp,3,tl);
+ emit_writeword(tl,®_cop2d[29]);
+
+ if (temp == HOST_TEMPREG)
+ host_tempreg_release();