// saved: r16-r23,r30, reserved: r0(zero), r26-r27(irq), r28(gp), r29(sp)
// r1,r15,r24,r25(at,t7-t9) are used internally by the code emitter
// MIPSN32/MIPS64 ABI: params: r4-r11, no caller-reserved save area on stack
+// for PIC code, on function calls r25(t9) must contain the called address
#define RET_REG 2 // v0
#define PARAM_REGS { 4, 5, 6, 7 } // a0-a3
#define PRESERVED_REGS { 16, 17, 18, 19, 20, 21, 22, 23 } // s0-s7
// registers usable for user code: r1-r25, others reserved or special
#define Z0 0 // zero register
+#define CR 25 // call register
#define GP 28 // global pointer
#define SP 29 // stack pointer
#define FP 30 // frame pointer
emith_jump_reg(r)
#define emith_jump_ctx(offs) do { \
- emith_ctx_read_ptr(AT, offs); \
- emith_jump_reg(AT); \
+ emith_ctx_read_ptr(CR, offs); \
+ emith_jump_reg(CR); \
} while (0)
#define emith_jump_ctx_c(cond, offs) \
emith_jump_ctx(offs)
#define emith_call_reg(r) \
emith_branch(MIPS_JALR(LR, r))
-
#define emith_call_ctx(offs) do { \
- emith_ctx_read_ptr(AT, offs); \
- emith_call_reg(AT); \
+ emith_ctx_read_ptr(CR, offs); \
+ emith_call_reg(CR); \
+} while (0)
+
+#define emith_abijump_reg(r) do { \
+ if ((r) != CR) emith_move_r_r(CR, r); \
+ emith_branch(MIPS_JR(CR)); \
+} while (0)
+#define emith_abijump_reg_c(cond, r) \
+ emith_abijump_reg(r)
+#define emith_abicall(target) do { \
+ emith_move_r_imm(CR, target); \
+ emith_branch(MIPS_JALR(LR, CR)); \
+} while (0)
+#define emith_abicall_cond(cond, target) \
+ emith_abicall(target)
+#define emith_abicall_reg(r) do { \
+ if ((r) != CR) emith_move_r_r(CR, r); \
+ emith_branch(MIPS_JALR(LR, CR)); \
} while (0)
#define emith_call_cleanup() /**/
emith_lsl(func, func, PTR_SCALE); \
emith_read_r_r_r_ptr(func, tab, func); \
emith_move_r_r_ptr(6, CONTEXT_REG); /* arg2 */ \
- emith_jump_reg(func); \
+ emith_abijump_reg(func); \
} while (0)
#define emith_sh2_delay_loop(cycles, reg) do { \
emith_move_r_imm(tmp4, pc);
emith_ctx_write(tmp4, SHR_PC * 4);
rcache_invalidate_tmp();
- emith_call(sh2_drc_log_entry);
+ emith_abicall(sh2_drc_log_entry);
emith_restore_caller_regs(tmp);
#endif
emith_save_caller_regs(tmp);
emit_do_static_regs(1, 0);
emith_pass_arg_r(0, CONTEXT_REG);
- emith_call(do_sh2_cmp);
+ emith_abicall(do_sh2_cmp);
emith_restore_caller_regs(tmp);
}
#endif
rcache_get_reg_arg(0, div(opd).rn, NULL);
rcache_get_reg_arg(1, div(opd).rm, NULL);
rcache_invalidate_tmp();
- emith_call(sh2_drc_divu32);
+ emith_abicall(sh2_drc_divu32);
tmp = rcache_get_tmp_ret();
#if REMAP_REGISTER
tmp2 = rcache_map_reg(div(opd).rn, tmp);
rcache_get_reg_arg(0, div(opd).rn, NULL);
rcache_get_reg_arg(2, div(opd).rm, NULL);
rcache_invalidate_tmp();
- emith_call(sh2_drc_divu64);
+ emith_abicall(sh2_drc_divu64);
tmp = rcache_get_tmp_ret();
#if REMAP_REGISTER
tmp2 = rcache_map_reg(div(opd).rn, tmp);
emith_lsr(tmp3, tmp2, 31);
emith_or_r_r_lsl(sr, tmp3, M_SHIFT); // M = Rm[31]
rcache_invalidate_tmp();
- emith_call(sh2_drc_divs32);
+ emith_abicall(sh2_drc_divs32);
tmp = rcache_get_tmp_ret();
#if REMAP_REGISTER
tmp2 = rcache_map_reg(div(opd).rn, tmp);
emith_or_r_r_lsl(sr, tmp3, M_SHIFT); // M = Rm[31]
emith_add_r_r_ptr_imm(tmp3, CONTEXT_REG, offsetof(SH2, drc_tmp));
rcache_invalidate_tmp();
- emith_call(sh2_drc_divs64);
+ emith_abicall(sh2_drc_divs64);
tmp = rcache_get_tmp_ret();
#if REMAP_REGISTER
tmp2 = rcache_map_reg(div(opd).rn, tmp);
emith_ret_c(DCOND_CC);
EMITH_SJMP_END(DCOND_CS);
emith_move_r_r_ptr(arg1, CONTEXT_REG);
- emith_jump_reg(arg2);
+ emith_abijump_reg(arg2);
emith_flush();
// d = sh2_drc_read16(u32 a)
emith_ret_c(DCOND_CC);
EMITH_SJMP_END(DCOND_CS);
emith_move_r_r_ptr(arg1, CONTEXT_REG);
- emith_jump_reg(arg2);
+ emith_abijump_reg(arg2);
emith_flush();
// d = sh2_drc_read32(u32 a)
emith_ret_c(DCOND_CC);
EMITH_SJMP_END(DCOND_CS);
emith_move_r_r_ptr(arg1, CONTEXT_REG);
- emith_jump_reg(arg2);
+ emith_abijump_reg(arg2);
emith_flush();
// d = sh2_drc_read8_poll(u32 a)
emith_sh2_rcall(arg0, arg1, arg2, arg3);
EMITH_SJMP_START(DCOND_CC);
emith_move_r_r_ptr_c(DCOND_CS, arg1, CONTEXT_REG);
- emith_jump_reg_c(DCOND_CS, arg2);
+ emith_abijump_reg_c(DCOND_CS, arg2);
EMITH_SJMP_END(DCOND_CC);
emith_and_r_r_r(arg1, arg0, arg3);
emith_eor_r_imm_ptr(arg1, 1);
emith_read8s_r_r_r(arg1, arg2, arg1);
emith_push_ret(arg1);
emith_move_r_r_ptr(arg2, CONTEXT_REG);
- emith_call(p32x_sh2_poll_memory8);
+ emith_abicall(p32x_sh2_poll_memory8);
emith_pop_and_ret(arg1);
emith_flush();
emith_sh2_rcall(arg0, arg1, arg2, arg3);
EMITH_SJMP_START(DCOND_CC);
emith_move_r_r_ptr_c(DCOND_CS, arg1, CONTEXT_REG);
- emith_jump_reg_c(DCOND_CS, arg2);
+ emith_abijump_reg_c(DCOND_CS, arg2);
EMITH_SJMP_END(DCOND_CC);
emith_and_r_r_r(arg1, arg0, arg3);
emith_read16s_r_r_r(arg1, arg2, arg1);
emith_push_ret(arg1);
emith_move_r_r_ptr(arg2, CONTEXT_REG);
- emith_call(p32x_sh2_poll_memory16);
+ emith_abicall(p32x_sh2_poll_memory16);
emith_pop_and_ret(arg1);
emith_flush();
emith_sh2_rcall(arg0, arg1, arg2, arg3);
EMITH_SJMP_START(DCOND_CC);
emith_move_r_r_ptr_c(DCOND_CS, arg1, CONTEXT_REG);
- emith_jump_reg_c(DCOND_CS, arg2);
+ emith_abijump_reg_c(DCOND_CS, arg2);
EMITH_SJMP_END(DCOND_CC);
emith_and_r_r_r(arg1, arg0, arg3);
emith_read_r_r_r(arg1, arg2, arg1);
emith_ror(arg1, arg1, 16);
emith_push_ret(arg1);
emith_move_r_r_ptr(arg2, CONTEXT_REG);
- emith_call(p32x_sh2_poll_memory32);
+ emith_abicall(p32x_sh2_poll_memory32);
emith_pop_and_ret(arg1);
emith_flush();
#endif
emith_move_r_r_ptr(arg1, CONTEXT_REG);
emith_add_r_r_ptr_imm(arg2, CONTEXT_REG, offsetof(SH2, drc_tmp));
- emith_call(dr_lookup_block);
+ emith_abicall(dr_lookup_block);
// store PC and block entry ptr (in arg0) in branch target cache
emith_tst_r_r_ptr(RET_REG, RET_REG);
EMITH_SJMP_START(DCOND_EQ);
// lookup failed, call sh2_translate()
emith_move_r_r_ptr(arg0, CONTEXT_REG);
emith_ctx_read(arg1, offsetof(SH2, drc_tmp)); // tcache_id
- emith_call(sh2_translate);
+ emith_abicall(sh2_translate);
emith_tst_r_r_ptr(RET_REG, RET_REG);
EMITH_SJMP_START(DCOND_EQ);
emith_jump_reg_c(DCOND_NE, RET_REG);
EMITH_SJMP_END(DCOND_EQ);
// XXX: can't translate, fail
- emith_call(dr_failure);
+ emith_abicall(dr_failure);
emith_flush();
#if CALL_STACK
emith_clear_msb(tmp, tmp, 22);
emith_move_r_r_ptr(arg2, CONTEXT_REG);
rcache_invalidate_tmp();
- emith_call(p32x_sh2_write32); // XXX: use sh2_drc_write32?
+ emith_abicall(p32x_sh2_write32); // XXX: use sh2_drc_write32?
// push PC
rcache_get_reg_arg(0, SHR_SP, NULL);
rcache_get_reg_arg(1, SHR_PC, NULL);
emith_move_r_r_ptr(arg2, CONTEXT_REG);
rcache_invalidate_tmp();
- emith_call(p32x_sh2_write32);
+ emith_abicall(p32x_sh2_write32);
// update I, cycles, do callback
emith_ctx_read(arg1, offsetof(SH2, pending_level));
sr = rcache_get_reg(SHR_SR, RC_GR_RMW, NULL);