+ break;
+ default:
+ goto default_;
+ }
+ goto end_op;
+ case 0x0c: // MOV.B @(R0,Rm),Rn 0000nnnnmmmm1100
+ case 0x0d: // MOV.W @(R0,Rm),Rn 0000nnnnmmmm1101
+ case 0x0e: // MOV.L @(R0,Rm),Rn 0000nnnnmmmm1110
+ tmp = emit_indirect_indexed_read(SHR_R0, GET_Rm(), op & 3);
+ tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
+ if ((op & 3) != 2) {
+ emith_sext(tmp2, tmp, (op & 1) ? 16 : 8);
+ } else
+ emith_move_r_r(tmp2, tmp);
+ rcache_free_tmp(tmp);
+ goto end_op;
+ case 0x0f: // MAC.L @Rm+,@Rn+ 0000nnnnmmmm1111
+ emit_indirect_read_double(&tmp, &tmp2, GET_Rn(), GET_Rm(), 2);
+ sr = rcache_get_reg(SHR_SR, RC_GR_READ);
+ tmp4 = rcache_get_reg(SHR_MACH, RC_GR_RMW);
+ /* MS 16 MAC bits unused if saturated */
+ emith_tst_r_imm(sr, S);
+ EMITH_SJMP_START(DCOND_EQ);
+ emith_clear_msb_c(DCOND_NE, tmp4, tmp4, 16);
+ EMITH_SJMP_END(DCOND_EQ);
+ tmp3 = rcache_get_reg(SHR_MACL, RC_GR_RMW); // might evict SR
+ emith_mula_s64(tmp3, tmp4, tmp, tmp2);
+ rcache_free_tmp(tmp2);
+ sr = rcache_get_reg(SHR_SR, RC_GR_READ); // reget just in case
+ emith_tst_r_imm(sr, S);
+
+ EMITH_JMP_START(DCOND_EQ);
+ emith_asr(tmp, tmp4, 15);
+ emith_cmp_r_imm(tmp, -1); // negative overflow (0x80000000..0xffff7fff)
+ EMITH_SJMP_START(DCOND_GE);
+ emith_move_r_imm_c(DCOND_LT, tmp4, 0x8000);
+ emith_move_r_imm_c(DCOND_LT, tmp3, 0x0000);
+ EMITH_SJMP_END(DCOND_GE);
+ emith_cmp_r_imm(tmp, 0); // positive overflow (0x00008000..0x7fffffff)
+ EMITH_SJMP_START(DCOND_LE);
+ emith_move_r_imm_c(DCOND_GT, tmp4, 0x00007fff);
+ emith_move_r_imm_c(DCOND_GT, tmp3, 0xffffffff);
+ EMITH_SJMP_END(DCOND_LE);
+ EMITH_JMP_END(DCOND_EQ);
+
+ rcache_free_tmp(tmp);
+ cycles += 3;
+ goto end_op;
+ }
+ goto default_;
+
+ /////////////////////////////////////////////
+ case 0x01:
+ // MOV.L Rm,@(disp,Rn) 0001nnnnmmmmdddd
+ rcache_clean();
+ tmp = rcache_get_reg_arg(0, GET_Rn());
+ tmp2 = rcache_get_reg_arg(1, GET_Rm());
+ emith_add_r_imm(tmp, (op & 0x0f) * 4);
+ emit_memhandler_write(2, pc, drcf.delayed_op);
+ goto end_op;
+
+ case 0x02:
+ switch (op & 0x0f)
+ {
+ case 0x00: // MOV.B Rm,@Rn 0010nnnnmmmm0000
+ case 0x01: // MOV.W Rm,@Rn 0010nnnnmmmm0001
+ case 0x02: // MOV.L Rm,@Rn 0010nnnnmmmm0010
+ rcache_clean();
+ rcache_get_reg_arg(0, GET_Rn());
+ rcache_get_reg_arg(1, GET_Rm());
+ emit_memhandler_write(op & 3, pc, drcf.delayed_op);
+ goto end_op;
+ case 0x04: // MOV.B Rm,@–Rn 0010nnnnmmmm0100
+ case 0x05: // MOV.W Rm,@–Rn 0010nnnnmmmm0101
+ case 0x06: // MOV.L Rm,@–Rn 0010nnnnmmmm0110
+ tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
+ emith_sub_r_imm(tmp, (1 << (op & 3)));
+ rcache_clean();
+ rcache_get_reg_arg(0, GET_Rn());
+ rcache_get_reg_arg(1, GET_Rm());
+ emit_memhandler_write(op & 3, pc, drcf.delayed_op);
+ goto end_op;
+ case 0x07: // DIV0S Rm,Rn 0010nnnnmmmm0111
+ sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
+ tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
+ tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
+ if (drcf.delayed_op)
+ DELAY_SAVE_T(sr);
+ emith_bic_r_imm(sr, M|Q|T);
+ emith_tst_r_imm(tmp2, (1<<31));
+ EMITH_SJMP_START(DCOND_EQ);
+ emith_or_r_imm_c(DCOND_NE, sr, Q);
+ EMITH_SJMP_END(DCOND_EQ);
+ emith_tst_r_imm(tmp3, (1<<31));
+ EMITH_SJMP_START(DCOND_EQ);
+ emith_or_r_imm_c(DCOND_NE, sr, M);
+ EMITH_SJMP_END(DCOND_EQ);
+ emith_teq_r_r(tmp2, tmp3);
+ EMITH_SJMP_START(DCOND_PL);
+ emith_or_r_imm_c(DCOND_MI, sr, T);
+ EMITH_SJMP_END(DCOND_PL);
+ goto end_op;
+ case 0x08: // TST Rm,Rn 0010nnnnmmmm1000
+ sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
+ tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
+ tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
+ if (drcf.delayed_op)
+ DELAY_SAVE_T(sr);
+ emith_bic_r_imm(sr, T);
+ emith_tst_r_r(tmp2, tmp3);
+ emit_or_t_if_eq(sr);
+ goto end_op;
+ case 0x09: // AND Rm,Rn 0010nnnnmmmm1001
+ tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
+ tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
+ emith_and_r_r(tmp, tmp2);
+ goto end_op;
+ case 0x0a: // XOR Rm,Rn 0010nnnnmmmm1010
+ tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
+ tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
+ emith_eor_r_r(tmp, tmp2);
+ goto end_op;
+ case 0x0b: // OR Rm,Rn 0010nnnnmmmm1011
+ tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
+ tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
+ emith_or_r_r(tmp, tmp2);
+ goto end_op;
+ case 0x0c: // CMP/STR Rm,Rn 0010nnnnmmmm1100
+ tmp = rcache_get_tmp();
+ tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
+ tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
+ emith_eor_r_r_r(tmp, tmp2, tmp3);
+ sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
+ if (drcf.delayed_op)
+ DELAY_SAVE_T(sr);
+ emith_bic_r_imm(sr, T);
+ emith_tst_r_imm(tmp, 0x000000ff);
+ emit_or_t_if_eq(tmp);
+ emith_tst_r_imm(tmp, 0x0000ff00);
+ emit_or_t_if_eq(tmp);
+ emith_tst_r_imm(tmp, 0x00ff0000);
+ emit_or_t_if_eq(tmp);
+ emith_tst_r_imm(tmp, 0xff000000);
+ emit_or_t_if_eq(tmp);
+ rcache_free_tmp(tmp);
+ goto end_op;
+ case 0x0d: // XTRCT Rm,Rn 0010nnnnmmmm1101
+ tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
+ tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
+ emith_lsr(tmp, tmp, 16);
+ emith_or_r_r_lsl(tmp, tmp2, 16);
+ goto end_op;
+ case 0x0e: // MULU.W Rm,Rn 0010nnnnmmmm1110
+ case 0x0f: // MULS.W Rm,Rn 0010nnnnmmmm1111
+ tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
+ tmp = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
+ if (op & 1) {
+ emith_sext(tmp, tmp2, 16);
+ } else
+ emith_clear_msb(tmp, tmp2, 16);
+ tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
+ tmp2 = rcache_get_tmp();
+ if (op & 1) {
+ emith_sext(tmp2, tmp3, 16);
+ } else
+ emith_clear_msb(tmp2, tmp3, 16);
+ emith_mul(tmp, tmp, tmp2);
+ rcache_free_tmp(tmp2);
+// FIXME: causes timing issues in Doom?
+// cycles++;
+ goto end_op;
+ }
+ goto default_;
+
+ /////////////////////////////////////////////
+ case 0x03:
+ switch (op & 0x0f)
+ {
+ case 0x00: // CMP/EQ Rm,Rn 0011nnnnmmmm0000
+ case 0x02: // CMP/HS Rm,Rn 0011nnnnmmmm0010
+ case 0x03: // CMP/GE Rm,Rn 0011nnnnmmmm0011
+ case 0x06: // CMP/HI Rm,Rn 0011nnnnmmmm0110
+ case 0x07: // CMP/GT Rm,Rn 0011nnnnmmmm0111
+ sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
+ tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
+ tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
+ if (drcf.delayed_op)
+ DELAY_SAVE_T(sr);
+ emith_bic_r_imm(sr, T);
+ emith_cmp_r_r(tmp2, tmp3);
+ switch (op & 0x07)
+ {
+ case 0x00: // CMP/EQ
+ emit_or_t_if_eq(sr);
+ break;
+ case 0x02: // CMP/HS
+ EMITH_SJMP_START(DCOND_LO);
+ emith_or_r_imm_c(DCOND_HS, sr, T);
+ EMITH_SJMP_END(DCOND_LO);
+ break;
+ case 0x03: // CMP/GE
+ EMITH_SJMP_START(DCOND_LT);
+ emith_or_r_imm_c(DCOND_GE, sr, T);
+ EMITH_SJMP_END(DCOND_LT);
+ break;
+ case 0x06: // CMP/HI
+ EMITH_SJMP_START(DCOND_LS);
+ emith_or_r_imm_c(DCOND_HI, sr, T);
+ EMITH_SJMP_END(DCOND_LS);
+ break;
+ case 0x07: // CMP/GT
+ EMITH_SJMP_START(DCOND_LE);
+ emith_or_r_imm_c(DCOND_GT, sr, T);
+ EMITH_SJMP_END(DCOND_LE);
+ break;