+static void sh2_generate_utils(void)
+{
+ int arg0, arg1, arg2, sr, tmp;
+ void *sh2_drc_write_end, *sh2_drc_write_slot_end;
+
+ sh2_drc_write32 = p32x_sh2_write32;
+ sh2_drc_read8 = p32x_sh2_read8;
+ sh2_drc_read16 = p32x_sh2_read16;
+ sh2_drc_read32 = p32x_sh2_read32;
+
+ host_arg2reg(arg0, 0);
+ host_arg2reg(arg1, 1);
+ host_arg2reg(arg2, 2);
+ emith_move_r_r(arg0, arg0); // nop
+
+ // sh2_drc_exit(void)
+ sh2_drc_exit = (void *)tcache_ptr;
+ emit_do_static_regs(1, arg2);
+ emith_sh2_drc_exit();
+
+ // sh2_drc_dispatcher(void)
+ sh2_drc_dispatcher = (void *)tcache_ptr;
+ sr = rcache_get_reg(SHR_SR, RC_GR_READ);
+ emith_cmp_r_imm(sr, 0);
+ emith_jump_cond(DCOND_LT, sh2_drc_exit);
+ rcache_invalidate();
+ emith_ctx_read(arg0, SHR_PC * 4);
+ emith_ctx_read(arg1, offsetof(SH2, is_slave));
+ emith_add_r_r_imm(arg2, CONTEXT_REG, offsetof(SH2, drc_tmp));
+ emith_call(dr_lookup_block);
+ emit_block_entry();
+ // lookup failed, call sh2_translate()
+ emith_move_r_r(arg0, CONTEXT_REG);
+ emith_ctx_read(arg1, offsetof(SH2, drc_tmp)); // tcache_id
+ emith_call(sh2_translate);
+ emit_block_entry();
+ // sh2_translate() failed, flush cache and retry
+ emith_ctx_read(arg0, offsetof(SH2, drc_tmp));
+ emith_call(flush_tcache);
+ emith_move_r_r(arg0, CONTEXT_REG);
+ emith_ctx_read(arg1, offsetof(SH2, drc_tmp));
+ emith_call(sh2_translate);
+ emit_block_entry();
+ // XXX: can't translate, fail
+ emith_call(dr_failure);
+
+ // sh2_drc_test_irq(void)
+ // assumes it's called from main function (may jump to dispatcher)
+ sh2_drc_test_irq = (void *)tcache_ptr;
+ emith_ctx_read(arg1, offsetof(SH2, pending_level));
+ sr = rcache_get_reg(SHR_SR, RC_GR_READ);
+ emith_lsr(arg0, sr, I_SHIFT);
+ emith_and_r_imm(arg0, 0x0f);
+ emith_cmp_r_r(arg1, arg0); // pending_level > ((sr >> 4) & 0x0f)?
+ EMITH_SJMP_START(DCOND_GT);
+ emith_ret_c(DCOND_LE); // nope, return
+ EMITH_SJMP_END(DCOND_GT);
+ // adjust SP
+ tmp = rcache_get_reg(SHR_SP, RC_GR_RMW);
+ emith_sub_r_imm(tmp, 4*2);
+ rcache_clean();
+ // push SR
+ tmp = rcache_get_reg_arg(0, SHR_SP);
+ emith_add_r_imm(tmp, 4);
+ tmp = rcache_get_reg_arg(1, SHR_SR);
+ emith_clear_msb(tmp, tmp, 22);
+ emith_move_r_r(arg2, CONTEXT_REG);
+ emith_call(p32x_sh2_write32); // XXX: use sh2_drc_write32?
+ rcache_invalidate();
+ // push PC
+ rcache_get_reg_arg(0, SHR_SP);
+ emith_ctx_read(arg1, SHR_PC * 4);
+ emith_move_r_r(arg2, CONTEXT_REG);
+ emith_call(p32x_sh2_write32);
+ rcache_invalidate();
+ // update I, cycles, do callback
+ emith_ctx_read(arg1, offsetof(SH2, pending_level));
+ sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
+ emith_bic_r_imm(sr, I);
+ emith_or_r_r_lsl(sr, arg1, I_SHIFT);
+ emith_sub_r_imm(sr, 13 << 12); // at least 13 cycles
+ rcache_flush();
+ emith_move_r_r(arg0, CONTEXT_REG);
+ emith_call_ctx(offsetof(SH2, irq_callback)); // vector = sh2->irq_callback(sh2, level);
+ // obtain new PC
+ emith_lsl(arg0, arg0, 2);
+ emith_ctx_read(arg1, SHR_VBR * 4);
+ emith_add_r_r(arg0, arg1);
+ emit_memhandler_read(2);
+ emith_ctx_write(arg0, SHR_PC * 4);
+#ifdef __i386__
+ emith_add_r_imm(xSP, 4); // fix stack
+#endif
+ emith_jump(sh2_drc_dispatcher);
+ rcache_invalidate();
+
+ // sh2_drc_entry(SH2 *sh2)
+ sh2_drc_entry = (void *)tcache_ptr;
+ emith_sh2_drc_entry();
+ emith_move_r_r(CONTEXT_REG, arg0); // move ctx, arg0
+ emit_do_static_regs(0, arg2);
+ emith_call(sh2_drc_test_irq);
+ emith_jump(sh2_drc_dispatcher);
+
+ // write-caused irq detection
+ sh2_drc_write_end = tcache_ptr;
+ emith_tst_r_r(arg0, arg0);
+ EMITH_SJMP_START(DCOND_NE);
+ emith_jump_ctx_c(DCOND_EQ, offsetof(SH2, drc_tmp)); // return
+ EMITH_SJMP_END(DCOND_NE);
+ emith_call(sh2_drc_test_irq);
+ emith_jump_ctx(offsetof(SH2, drc_tmp));
+
+ // write-caused irq detection for writes in delay slot
+ sh2_drc_write_slot_end = tcache_ptr;
+ emith_tst_r_r(arg0, arg0);
+ EMITH_SJMP_START(DCOND_NE);
+ emith_jump_ctx_c(DCOND_EQ, offsetof(SH2, drc_tmp));
+ EMITH_SJMP_END(DCOND_NE);
+ // just burn cycles to get back to dispatcher after branch is handled
+ sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
+ emith_ctx_write(sr, offsetof(SH2, irq_cycles));
+ emith_clear_msb(sr, sr, 20); // clear cycles
+ rcache_flush();
+ emith_jump_ctx(offsetof(SH2, drc_tmp));
+
+ // sh2_drc_write8(u32 a, u32 d)
+ sh2_drc_write8 = (void *)tcache_ptr;
+ emith_ret_to_ctx(offsetof(SH2, drc_tmp));
+ emith_ctx_read(arg2, offsetof(SH2, write8_tab));
+ emith_sh2_wcall(arg0, arg2, sh2_drc_write_end);
+
+ // sh2_drc_write16(u32 a, u32 d)
+ sh2_drc_write16 = (void *)tcache_ptr;
+ emith_ret_to_ctx(offsetof(SH2, drc_tmp));
+ emith_ctx_read(arg2, offsetof(SH2, write16_tab));
+ emith_sh2_wcall(arg0, arg2, sh2_drc_write_end);
+
+ // sh2_drc_write8_slot(u32 a, u32 d)
+ sh2_drc_write8_slot = (void *)tcache_ptr;
+ emith_ret_to_ctx(offsetof(SH2, drc_tmp));
+ emith_ctx_read(arg2, offsetof(SH2, write8_tab));
+ emith_sh2_wcall(arg0, arg2, sh2_drc_write_slot_end);
+
+ // sh2_drc_write16_slot(u32 a, u32 d)
+ sh2_drc_write16_slot = (void *)tcache_ptr;
+ emith_ret_to_ctx(offsetof(SH2, drc_tmp));
+ emith_ctx_read(arg2, offsetof(SH2, write16_tab));
+ emith_sh2_wcall(arg0, arg2, sh2_drc_write_slot_end);
+
+#ifdef PDB_NET
+ // debug
+ #define MAKE_READ_WRAPPER(func) { \
+ void *tmp = (void *)tcache_ptr; \
+ emith_push_ret(); \
+ emith_call(func); \
+ emith_ctx_read(arg2, offsetof(SH2, pdb_io_csum[0])); \
+ emith_addf_r_r(arg2, arg0); \
+ emith_ctx_write(arg2, offsetof(SH2, pdb_io_csum[0])); \
+ emith_ctx_read(arg2, offsetof(SH2, pdb_io_csum[1])); \
+ emith_adc_r_imm(arg2, 0x01000000); \
+ emith_ctx_write(arg2, offsetof(SH2, pdb_io_csum[1])); \
+ emith_pop_and_ret(); \
+ func = tmp; \
+ }
+ #define MAKE_WRITE_WRAPPER(func) { \
+ void *tmp = (void *)tcache_ptr; \
+ emith_ctx_read(arg2, offsetof(SH2, pdb_io_csum[0])); \
+ emith_addf_r_r(arg2, arg1); \
+ emith_ctx_write(arg2, offsetof(SH2, pdb_io_csum[0])); \
+ emith_ctx_read(arg2, offsetof(SH2, pdb_io_csum[1])); \
+ emith_adc_r_imm(arg2, 0x01000000); \
+ emith_ctx_write(arg2, offsetof(SH2, pdb_io_csum[1])); \
+ emith_move_r_r(arg2, CONTEXT_REG); \
+ emith_jump(func); \
+ func = tmp; \
+ }
+
+ MAKE_READ_WRAPPER(sh2_drc_read8);
+ MAKE_READ_WRAPPER(sh2_drc_read16);
+ MAKE_READ_WRAPPER(sh2_drc_read32);
+ MAKE_WRITE_WRAPPER(sh2_drc_write8);
+ MAKE_WRITE_WRAPPER(sh2_drc_write8_slot);
+ MAKE_WRITE_WRAPPER(sh2_drc_write16);
+ MAKE_WRITE_WRAPPER(sh2_drc_write16_slot);
+ MAKE_WRITE_WRAPPER(sh2_drc_write32);
+#if (DRC_DEBUG & 4)
+ host_dasm_new_symbol(sh2_drc_read8);
+ host_dasm_new_symbol(sh2_drc_read16);
+ host_dasm_new_symbol(sh2_drc_read32);
+ host_dasm_new_symbol(sh2_drc_write32);
+#endif
+#endif
+
+ rcache_invalidate();
+#if (DRC_DEBUG & 4)
+ host_dasm_new_symbol(sh2_drc_entry);
+ host_dasm_new_symbol(sh2_drc_dispatcher);
+ host_dasm_new_symbol(sh2_drc_exit);
+ host_dasm_new_symbol(sh2_drc_test_irq);
+ host_dasm_new_symbol(sh2_drc_write_end);
+ host_dasm_new_symbol(sh2_drc_write_slot_end);
+ host_dasm_new_symbol(sh2_drc_write8);
+ host_dasm_new_symbol(sh2_drc_write8_slot);
+ host_dasm_new_symbol(sh2_drc_write16);
+ host_dasm_new_symbol(sh2_drc_write16_slot);