+ int op, delayed_op = 0, test_irq = 0;
+ int tcache_id = 0, blkid = 0;
+ int cycles = 0;
+ u32 tmp, tmp2, tmp3, tmp4;
+
+ // validate PC
+ tmp = sh2->pc >> 29;
+ if ((tmp != 0 && tmp != 1 && tmp != 6) || sh2->pc == 0) {
+ printf("invalid PC, aborting: %08x\n", sh2->pc);
+ // FIXME: be less destructive
+ exit(1);
+ }
+
+ if ((sh2->pc & 0xe0000000) == 0xc0000000 || (sh2->pc & ~0xfff) == 0) {
+ // data_array, BIOS have separate tcache (shared)
+ tcache_id = 1 + sh2->is_slave;
+ }
+
+ tcache_ptr = tcache_ptrs[tcache_id];
+ this_block = dr_add_block(pc, tcache_id, &blkid);
+
+ tmp = tcache_ptr - tcache_bases[tcache_id];
+ if (tmp > tcache_sizes[tcache_id] - MAX_BLOCK_SIZE || this_block == NULL) {
+ flush_tcache(tcache_id);
+ tcache_ptr = tcache_ptrs[tcache_id];
+ other_block = NULL; // also gone too due to flush
+ this_block = dr_add_block(pc, tcache_id, &blkid);
+ }
+
+ this_block->next = other_block;
+ if ((sh2->pc & 0xc6000000) == 0x02000000) // ROM
+ HASH_FUNC(hash_table, pc) = this_block;
+
+ block_entry = tcache_ptr;
+#if (DRC_DEBUG & 1)
+ printf("== %csh2 block #%d,%d %08x -> %p\n", sh2->is_slave ? 's' : 'm',
+ tcache_id, block_counts[tcache_id], pc, block_entry);
+ if (other_block != NULL) {
+ printf(" hash collision with %08x\n", other_block->addr);
+ hash_collisions++;
+ }
+#endif
+
+ while (cycles < BLOCK_CYCLE_LIMIT || delayed_op)
+ {
+ if (delayed_op > 0)
+ delayed_op--;
+
+ op = p32x_sh2_read16(pc, sh2);
+
+#if (DRC_DEBUG & 3)
+ insns_compiled++;
+#if (DRC_DEBUG & 2)
+ DasmSH2(sh2dasm_buff, pc, op);
+ printf("%08x %04x %s\n", pc, op, sh2dasm_buff);
+#endif
+#endif
+
+ pc += 2;
+ cycles++;
+
+ switch ((op >> 12) & 0x0f)
+ {
+ /////////////////////////////////////////////
+ case 0x00:
+ switch (op & 0x0f)
+ {
+ case 0x02:
+ tmp = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
+ switch (GET_Fx())
+ {
+ case 0: // STC SR,Rn 0000nnnn00000010
+ tmp2 = SHR_SR;
+ break;
+ case 1: // STC GBR,Rn 0000nnnn00010010
+ tmp2 = SHR_GBR;
+ break;
+ case 2: // STC VBR,Rn 0000nnnn00100010
+ tmp2 = SHR_VBR;
+ break;
+ default:
+ goto default_;
+ }
+ tmp3 = rcache_get_reg(tmp2, RC_GR_READ);
+ emith_move_r_r(tmp, tmp3);
+ if (tmp2 == SHR_SR)
+ emith_clear_msb(tmp, tmp, 20); // reserved bits defined by ISA as 0
+ goto end_op;
+ case 0x03:
+ CHECK_UNHANDLED_BITS(0xd0);
+ // BRAF Rm 0000mmmm00100011
+ // BSRF Rm 0000mmmm00000011
+ DELAYED_OP;
+ if (!(op & 0x20))
+ emit_move_r_imm32(SHR_PR, pc + 2);
+ tmp = rcache_get_reg(SHR_PPC, RC_GR_WRITE);
+ tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
+ emith_move_r_r(tmp, tmp2);
+ emith_add_r_imm(tmp, pc + 2);
+ cycles++;
+ goto end_op;
+ case 0x04: // MOV.B Rm,@(R0,Rn) 0000nnnnmmmm0100
+ case 0x05: // MOV.W Rm,@(R0,Rn) 0000nnnnmmmm0101
+ case 0x06: // MOV.L Rm,@(R0,Rn) 0000nnnnmmmm0110
+ rcache_clean();
+ tmp = rcache_get_reg_arg(0, SHR_R0);
+ tmp2 = rcache_get_reg_arg(1, GET_Rm());
+ tmp3 = rcache_get_reg(GET_Rn(), RC_GR_READ);
+ emith_add_r_r(tmp, tmp3);
+ emit_memhandler_write(op & 3);
+ goto end_op;
+ case 0x07:
+ // MUL.L Rm,Rn 0000nnnnmmmm0111
+ tmp = rcache_get_reg(GET_Rn(), RC_GR_READ);
+ tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
+ tmp3 = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
+ emith_mul(tmp3, tmp2, tmp);
+ cycles++;
+ goto end_op;
+ case 0x08:
+ CHECK_UNHANDLED_BITS(0xf00);
+ switch (GET_Fx())
+ {
+ case 0: // CLRT 0000000000001000
+ tmp = rcache_get_reg(SHR_SR, RC_GR_RMW);
+ emith_bic_r_imm(tmp, T);
+ break;
+ case 1: // SETT 0000000000011000
+ tmp = rcache_get_reg(SHR_SR, RC_GR_RMW);
+ emith_or_r_imm(tmp, T);
+ break;
+ case 2: // CLRMAC 0000000000101000
+ tmp = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
+ emith_move_r_imm(tmp, 0);
+ tmp = rcache_get_reg(SHR_MACH, RC_GR_WRITE);
+ emith_move_r_imm(tmp, 0);
+ break;
+ default:
+ goto default_;
+ }
+ goto end_op;
+ case 0x09:
+ switch (GET_Fx())
+ {
+ case 0: // NOP 0000000000001001
+ CHECK_UNHANDLED_BITS(0xf00);
+ break;
+ case 1: // DIV0U 0000000000011001
+ CHECK_UNHANDLED_BITS(0xf00);
+ tmp = rcache_get_reg(SHR_SR, RC_GR_RMW);
+ emith_bic_r_imm(tmp, M|Q|T);
+ break;
+ case 2: // MOVT Rn 0000nnnn00101001
+ tmp = rcache_get_reg(SHR_SR, RC_GR_READ);
+ tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
+ emith_clear_msb(tmp2, tmp, 31);
+ break;
+ default:
+ goto default_;
+ }
+ goto end_op;
+ case 0x0a:
+ tmp = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
+ switch (GET_Fx())
+ {
+ case 0: // STS MACH,Rn 0000nnnn00001010
+ tmp2 = SHR_MACH;
+ break;
+ case 1: // STS MACL,Rn 0000nnnn00011010
+ tmp2 = SHR_MACL;
+ break;
+ case 2: // STS PR,Rn 0000nnnn00101010
+ tmp2 = SHR_PR;
+ break;
+ default:
+ goto default_;
+ }
+ tmp2 = rcache_get_reg(tmp2, RC_GR_READ);
+ emith_move_r_r(tmp, tmp2);
+ goto end_op;
+ case 0x0b:
+ CHECK_UNHANDLED_BITS(0xf00);
+ switch (GET_Fx())
+ {
+ case 0: // RTS 0000000000001011
+ DELAYED_OP;
+ emit_move_r_r(SHR_PPC, SHR_PR);
+ cycles++;
+ break;
+ case 1: // SLEEP 0000000000011011
+ emit_move_r_imm32(SHR_PC, pc - 2);
+ tmp = rcache_get_reg(SHR_SR, RC_GR_RMW);
+ emith_clear_msb(tmp, tmp, 20); // clear cycles
+ test_irq = 1;
+ cycles = 1;
+ break;
+ case 2: // RTE 0000000000101011
+ //emit_move_r_r(SHR_PC, SHR_PR);
+ emit_move_r_imm32(SHR_PC, pc - 2);
+ rcache_flush();
+ emith_pass_arg_r(0, CONTEXT_REG);
+ emith_pass_arg_imm(1, op);
+ emith_call(sh2_do_op);
+ emit_move_r_r(SHR_PPC, SHR_PC);
+ test_irq = 1;
+ cycles += 3;
+ 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
+ rcache_clean();
+ tmp = rcache_get_reg_arg(0, SHR_R0);
+ tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
+ emith_add_r_r(tmp, tmp2);
+ tmp = emit_memhandler_read(op & 3);
+ tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
+ rcache_free_tmp(tmp);
+ if ((op & 3) != 2) {
+ emith_sext(tmp2, tmp, (op & 1) ? 16 : 8);
+ } else
+ emith_move_r_r(tmp2, tmp);
+ goto end_op;
+ case 0x0f: // MAC.L @Rm+,@Rn+ 0000nnnnmmmm1111
+ // TODO
+ break;
+ }
+ 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);
+ 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);
+ 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);
+ goto end_op;
+ case 0x07: // DIV0S Rm,Rn 0010nnnnmmmm0111
+ tmp = 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);
+ emith_bic_r_imm(tmp, M|Q|T);
+ emith_tst_r_imm(tmp2, (1<<31));
+ EMITH_SJMP_START(DCOND_EQ);
+ emith_or_r_imm_c(DCOND_NE, tmp, 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, tmp, M);
+ EMITH_SJMP_END(DCOND_EQ);
+ emith_teq_r_r(tmp2, tmp3);
+ EMITH_SJMP_START(DCOND_PL);
+ emith_or_r_imm_c(DCOND_MI, tmp, T);
+ EMITH_SJMP_END(DCOND_PL);
+ goto end_op;
+ case 0x08: // TST Rm,Rn 0010nnnnmmmm1000
+ tmp = 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);
+ emith_bic_r_imm(tmp, T);
+ emith_tst_r_r(tmp2, tmp3);
+ EMITH_SJMP_START(DCOND_NE);
+ emith_or_r_imm_c(DCOND_EQ, tmp, T);
+ EMITH_SJMP_END(DCOND_NE);
+ 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);
+ tmp2 = rcache_get_reg(SHR_SR, RC_GR_RMW);
+ emith_bic_r_imm(tmp2, T);
+ emith_tst_r_imm(tmp, 0x000000ff);
+ EMITH_SJMP_START(DCOND_NE);
+ emith_or_r_imm_c(DCOND_EQ, tmp2, T);
+ EMITH_SJMP_END(DCOND_NE);
+ emith_tst_r_imm(tmp, 0x0000ff00);
+ EMITH_SJMP_START(DCOND_NE);
+ emith_or_r_imm_c(DCOND_EQ, tmp2, T);
+ EMITH_SJMP_END(DCOND_NE);
+ emith_tst_r_imm(tmp, 0x00ff0000);
+ EMITH_SJMP_START(DCOND_NE);
+ emith_or_r_imm_c(DCOND_EQ, tmp2, T);
+ EMITH_SJMP_END(DCOND_NE);
+ emith_tst_r_imm(tmp, 0xff000000);
+ EMITH_SJMP_START(DCOND_NE);
+ emith_or_r_imm_c(DCOND_EQ, tmp2, T);
+ EMITH_SJMP_END(DCOND_NE);
+ 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_r_lsl(tmp, 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
+ tmp = 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);
+ emith_bic_r_imm(tmp, T);
+ emith_cmp_r_r(tmp2, tmp3);
+ switch (op & 0x07)
+ {
+ case 0x00: // CMP/EQ
+ EMITH_SJMP_START(DCOND_NE);
+ emith_or_r_imm_c(DCOND_EQ, tmp, T);
+ EMITH_SJMP_END(DCOND_NE);
+ break;
+ case 0x02: // CMP/HS
+ EMITH_SJMP_START(DCOND_LO);
+ emith_or_r_imm_c(DCOND_HS, tmp, T);
+ EMITH_SJMP_END(DCOND_LO);
+ break;
+ case 0x03: // CMP/GE
+ EMITH_SJMP_START(DCOND_LT);
+ emith_or_r_imm_c(DCOND_GE, tmp, T);
+ EMITH_SJMP_END(DCOND_LT);
+ break;
+ case 0x06: // CMP/HI
+ EMITH_SJMP_START(DCOND_LS);
+ emith_or_r_imm_c(DCOND_HI, tmp, T);
+ EMITH_SJMP_END(DCOND_LS);
+ break;
+ case 0x07: // CMP/GT
+ EMITH_SJMP_START(DCOND_LE);
+ emith_or_r_imm_c(DCOND_GT, tmp, T);
+ EMITH_SJMP_END(DCOND_LE);
+ break;
+ }
+ goto end_op;
+ case 0x04: // DIV1 Rm,Rn 0011nnnnmmmm0100
+ // TODO
+ break;
+ case 0x05: // DMULU.L Rm,Rn 0011nnnnmmmm0101
+ tmp = rcache_get_reg(GET_Rn(), RC_GR_READ);
+ tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
+ tmp3 = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
+ tmp4 = rcache_get_reg(SHR_MACH, RC_GR_WRITE);
+ emith_mul_u64(tmp3, tmp4, tmp, tmp2);
+ goto end_op;
+ case 0x08: // SUB Rm,Rn 0011nnnnmmmm1000
+ case 0x0c: // ADD Rm,Rn 0011nnnnmmmm1100
+ tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
+ tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
+ if (op & 4) {
+ emith_add_r_r(tmp, tmp2);
+ } else
+ emith_sub_r_r(tmp, tmp2);
+ goto end_op;
+ case 0x0a: // SUBC Rm,Rn 0011nnnnmmmm1010
+ case 0x0e: // ADDC Rm,Rn 0011nnnnmmmm1110
+ tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
+ tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
+ tmp3 = rcache_get_reg(SHR_SR, RC_GR_RMW);
+ if (op & 4) { // adc
+ emith_set_carry(tmp3);
+ emith_adcf_r_r(tmp, tmp2);
+ emith_carry_to_t(tmp3, 0);
+ } else {
+ emith_set_carry_sub(tmp3);
+ emith_sbcf_r_r(tmp, tmp2);
+ emith_carry_to_t(tmp3, 1);
+ }
+ goto end_op;
+ case 0x0b: // SUBV Rm,Rn 0011nnnnmmmm1011
+ case 0x0f: // ADDV Rm,Rn 0011nnnnmmmm1111
+ tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
+ tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
+ tmp3 = rcache_get_reg(SHR_SR, RC_GR_RMW);
+ emith_bic_r_imm(tmp3, T);
+ if (op & 4) {
+ emith_addf_r_r(tmp, tmp2);
+ } else
+ emith_subf_r_r(tmp, tmp2);
+ EMITH_SJMP_START(DCOND_VC);
+ emith_or_r_imm_c(DCOND_VS, tmp3, T);
+ EMITH_SJMP_END(DCOND_VC);
+ goto end_op;
+ case 0x0d: // DMULS.L Rm,Rn 0011nnnnmmmm1101
+ tmp = rcache_get_reg(GET_Rn(), RC_GR_READ);
+ tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
+ tmp3 = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
+ tmp4 = rcache_get_reg(SHR_MACH, RC_GR_WRITE);
+ emith_mul_s64(tmp3, tmp4, tmp, tmp2);
+ goto end_op;
+ }
+ goto default_;
+
+ /////////////////////////////////////////////
+ case 0x04:
+ switch (op & 0x0f)
+ {
+ case 0x00:
+ switch (GET_Fx())
+ {
+ case 0: // SHLL Rn 0100nnnn00000000
+ case 2: // SHAL Rn 0100nnnn00100000
+ tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
+ tmp2 = rcache_get_reg(SHR_SR, RC_GR_RMW);
+ emith_lslf(tmp, tmp, 1);
+ emith_carry_to_t(tmp2, 0);
+ goto end_op;
+ case 1: // DT Rn 0100nnnn00010000
+ if (p32x_sh2_read16(pc, sh2) == 0x8bfd) { // BF #-2
+ emith_sh2_dtbf_loop();
+ goto end_op;
+ }
+ tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
+ tmp2 = rcache_get_reg(SHR_SR, RC_GR_RMW);
+ emith_bic_r_imm(tmp2, T);
+ emith_subf_r_imm(tmp, 1);
+ EMITH_SJMP_START(DCOND_NE);
+ emith_or_r_imm_c(DCOND_EQ, tmp2, T);
+ EMITH_SJMP_END(DCOND_NE);
+ goto end_op;
+ }
+ goto default_;
+ case 0x01:
+ switch (GET_Fx())
+ {
+ case 0: // SHLR Rn 0100nnnn00000001
+ case 2: // SHAR Rn 0100nnnn00100001
+ tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
+ tmp2 = rcache_get_reg(SHR_SR, RC_GR_RMW);
+ if (op & 0x20) {
+ emith_asrf(tmp, tmp, 1);
+ } else
+ emith_lsrf(tmp, tmp, 1);
+ emith_carry_to_t(tmp2, 0);
+ goto end_op;
+ case 1: // CMP/PZ Rn 0100nnnn00010001
+ tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
+ tmp2 = rcache_get_reg(SHR_SR, RC_GR_RMW);
+ emith_bic_r_imm(tmp2, T);
+ emith_cmp_r_imm(tmp, 0);
+ EMITH_SJMP_START(DCOND_LT);
+ emith_or_r_imm_c(DCOND_GE, tmp2, T);
+ EMITH_SJMP_END(DCOND_LT);
+ goto end_op;
+ }
+ goto default_;
+ case 0x02:
+ case 0x03:
+ switch (op & 0x3f)
+ {
+ case 0x02: // STS.L MACH,@–Rn 0100nnnn00000010
+ tmp = SHR_MACH;
+ break;
+ case 0x12: // STS.L MACL,@–Rn 0100nnnn00010010
+ tmp = SHR_MACL;
+ break;
+ case 0x22: // STS.L PR,@–Rn 0100nnnn00100010
+ tmp = SHR_PR;
+ break;
+ case 0x03: // STC.L SR,@–Rn 0100nnnn00000011
+ tmp = SHR_SR;
+ break;
+ case 0x13: // STC.L GBR,@–Rn 0100nnnn00010011
+ tmp = SHR_GBR;
+ break;
+ case 0x23: // STC.L VBR,@–Rn 0100nnnn00100011
+ tmp = SHR_VBR;
+ break;
+ default:
+ goto default_;
+ }
+ tmp2 = rcache_get_reg(GET_Rn(), RC_GR_RMW);
+ emith_sub_r_imm(tmp2, 4);
+ rcache_clean();
+ rcache_get_reg_arg(0, GET_Rn());
+ tmp3 = rcache_get_reg_arg(1, tmp);
+ if (tmp == SHR_SR)
+ emith_clear_msb(tmp3, tmp3, 20); // reserved bits defined by ISA as 0
+ emit_memhandler_write(2);
+ goto end_op;
+ case 0x04:
+ case 0x05:
+ switch (op & 0x3f)
+ {
+ case 0x04: // ROTL Rn 0100nnnn00000100
+ case 0x05: // ROTR Rn 0100nnnn00000101
+ tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
+ tmp2 = rcache_get_reg(SHR_SR, RC_GR_RMW);
+ if (op & 1) {
+ emith_rorf(tmp, tmp, 1);
+ } else
+ emith_rolf(tmp, tmp, 1);
+ emith_carry_to_t(tmp2, 0);
+ goto end_op;
+ case 0x24: // ROTCL Rn 0100nnnn00100100
+ case 0x25: // ROTCR Rn 0100nnnn00100101
+ tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
+ tmp2 = rcache_get_reg(SHR_SR, RC_GR_RMW);
+ emith_set_carry(tmp2);
+ if (op & 1) {
+ emith_rorcf(tmp);
+ } else
+ emith_rolcf(tmp);
+ emith_carry_to_t(tmp2, 0);
+ goto end_op;
+ case 0x15: // CMP/PL Rn 0100nnnn00010101
+ tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
+ tmp2 = rcache_get_reg(SHR_SR, RC_GR_RMW);
+ emith_bic_r_imm(tmp2, T);
+ emith_cmp_r_imm(tmp, 0);
+ EMITH_SJMP_START(DCOND_LE);
+ emith_or_r_imm_c(DCOND_GT, tmp2, T);
+ EMITH_SJMP_END(DCOND_LE);
+ goto end_op;
+ }
+ goto default_;
+ case 0x06:
+ case 0x07:
+ switch (op & 0x3f)
+ {
+ case 0x06: // LDS.L @Rm+,MACH 0100mmmm00000110
+ tmp = SHR_MACH;
+ break;
+ case 0x16: // LDS.L @Rm+,MACL 0100mmmm00010110
+ tmp = SHR_MACL;
+ break;
+ case 0x26: // LDS.L @Rm+,PR 0100mmmm00100110
+ tmp = SHR_PR;
+ break;
+ case 0x07: // LDC.L @Rm+,SR 0100mmmm00000111
+ tmp = SHR_SR;
+ break;
+ case 0x17: // LDC.L @Rm+,GBR 0100mmmm00010111
+ tmp = SHR_GBR;
+ break;
+ case 0x27: // LDC.L @Rm+,VBR 0100mmmm00100111
+ tmp = SHR_VBR;
+ break;
+ default:
+ goto default_;
+ }
+ rcache_clean();
+ rcache_get_reg_arg(0, GET_Rn());
+ tmp2 = emit_memhandler_read(2);
+ if (tmp == SHR_SR) {
+ emith_write_sr(tmp2);
+ test_irq = 1;
+ } else {
+ tmp = rcache_get_reg(tmp, RC_GR_WRITE);
+ emith_move_r_r(tmp, tmp2);
+ }
+ rcache_free_tmp(tmp2);
+ tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
+ emith_add_r_imm(tmp, 4);
+ goto end_op;
+ case 0x0b:
+ if ((op & 0xd0) != 0)
+ goto default_;
+ // JMP @Rm 0100mmmm00101011
+ // JSR @Rm 0100mmmm00001011
+ DELAYED_OP;
+ if (!(op & 0x20))
+ emit_move_r_imm32(SHR_PR, pc + 2);
+ emit_move_r_r(SHR_PPC, (op >> 8) & 0x0f);
+ cycles++;
+ goto end_op;
+ case 0x0e:
+ if ((op & 0xf0) != 0)
+ goto default_;
+ // LDC Rm,SR 0100mmmm00001110
+ test_irq = 1;
+ goto default_;
+ }
+ goto default_;
+
+ /////////////////////////////////////////////
+ case 0x08:
+ switch (op & 0x0f00) {
+ // BT/S label 10001101dddddddd
+ case 0x0d00:
+ // BF/S label 10001111dddddddd
+ case 0x0f00:
+ DELAYED_OP;
+ cycles--;
+ // fallthrough
+ // BT label 10001001dddddddd
+ case 0x0900:
+ // BF label 10001011dddddddd
+ case 0x0b00: {
+ // jmp_cond ~ cond when guest doesn't jump
+ int jmp_cond = (op & 0x0200) ? DCOND_NE : DCOND_EQ;
+ int insn_cond = (op & 0x0200) ? DCOND_EQ : DCOND_NE;
+ signed int offs = ((signed int)(op << 24) >> 23);
+ tmp = rcache_get_reg(delayed_op ? SHR_PPC : SHR_PC, RC_GR_WRITE);
+ emith_move_r_imm(tmp, pc + (delayed_op ? 2 : 0));
+ emith_sh2_test_t();
+ EMITH_SJMP_START(jmp_cond);
+ if (!delayed_op)
+ offs += 2;
+ if (offs < 0) {
+ emith_sub_r_imm_c(insn_cond, tmp, -offs);
+ } else
+ emith_add_r_imm_c(insn_cond, tmp, offs);
+ EMITH_SJMP_END(jmp_cond);
+ cycles += 2;
+ if (!delayed_op)
+ goto end_block;
+ goto end_op;
+ }}
+ goto default_;
+
+ /////////////////////////////////////////////
+ case 0x0a:
+ // BRA label 1010dddddddddddd
+ DELAYED_OP;
+ do_bra:
+ tmp = ((signed int)(op << 20) >> 19);
+ emit_move_r_imm32(SHR_PPC, pc + tmp + 2);
+ cycles++;
+ break;
+
+ /////////////////////////////////////////////
+ case 0x0b:
+ // BSR label 1011dddddddddddd
+ DELAYED_OP;
+ emit_move_r_imm32(SHR_PR, pc + 2);
+ goto do_bra;
+
+ default:
+ default_:
+ emit_move_r_imm32(SHR_PC, pc - 2);
+ rcache_flush();
+ emith_pass_arg_r(0, CONTEXT_REG);
+ emith_pass_arg_imm(1, op);
+ emith_call(sh2_do_op);
+ break;
+ }
+
+end_op:
+ if (delayed_op == 1)
+ emit_move_r_r(SHR_PC, SHR_PPC);
+
+ if (test_irq && delayed_op != 2) {
+ rcache_flush();
+ emith_pass_arg_r(0, CONTEXT_REG);
+ emith_call(sh2_test_irq);
+ break;
+ }
+ if (delayed_op == 1)
+ break;
+
+ do_host_disasm(tcache_id);
+ }
+
+end_block:
+ this_block->end_addr = pc;
+
+ // mark memory blocks as containing compiled code
+ if ((sh2->pc & 0xe0000000) == 0xc0000000 || (sh2->pc & ~0xfff) == 0) {
+ // data array, BIOS
+ u16 *drcblk = Pico32xMem->drcblk_da[sh2->is_slave];
+ tmp = (this_block->addr & 0xfff) >> SH2_DRCBLK_DA_SHIFT;
+ tmp2 = (this_block->end_addr & 0xfff) >> SH2_DRCBLK_DA_SHIFT;
+ Pico32xMem->drcblk_da[sh2->is_slave][tmp] = (blkid << 1) | 1;
+ for (++tmp; tmp < tmp2; tmp++) {
+ if (drcblk[tmp])
+ break; // dont overwrite overlay block
+ drcblk[tmp] = blkid << 1;
+ }
+ }
+ else if ((this_block->addr & 0xc7fc0000) == 0x06000000) { // DRAM
+ tmp = (this_block->addr & 0x3ffff) >> SH2_DRCBLK_RAM_SHIFT;
+ tmp2 = (this_block->end_addr & 0x3ffff) >> SH2_DRCBLK_RAM_SHIFT;
+ Pico32xMem->drcblk_ram[tmp] = (blkid << 1) | 1;
+ for (++tmp; tmp < tmp2; tmp++) {
+ if (Pico32xMem->drcblk_ram[tmp])
+ break;
+ Pico32xMem->drcblk_ram[tmp] = blkid << 1;
+ }
+ }
+
+ tmp = rcache_get_reg(SHR_SR, RC_GR_RMW);
+ emith_sub_r_imm(tmp, cycles << 12);
+ rcache_flush();
+ emith_jump(sh2_drc_exit);
+ tcache_ptrs[tcache_id] = tcache_ptr;
+
+#ifdef ARM
+ cache_flush_d_inval_i(block_entry, tcache_ptr);
+#endif
+
+ do_host_disasm(tcache_id);
+ dbg(1, " block #%d,%d tcache %d/%d, insns %d -> %d %.3f",
+ tcache_id, block_counts[tcache_id],
+ tcache_ptr - tcache_bases[tcache_id], tcache_sizes[tcache_id],
+ insns_compiled, host_insn_count, (double)host_insn_count / insns_compiled);
+ if ((sh2->pc & 0xc6000000) == 0x02000000) // ROM
+ dbg(1, " hash collisions %d/%d", hash_collisions, block_counts[tcache_id]);
+#if (DRC_DEBUG & 2)
+ fflush(stdout);
+#endif
+
+ return block_entry;
+/*
+unimplemented:
+ // last op
+ do_host_disasm(tcache_id);
+ exit(1);
+*/
+}
+
+void __attribute__((noinline)) sh2_drc_dispatcher(SH2 *sh2)
+{
+ while (((signed int)sh2->sr >> 12) > 0)
+ {
+ void *block = NULL;
+ block_desc *bd = NULL;