mirror of
https://github.com/kanjitalk755/macemu.git
synced 2025-03-01 07:30:27 +00:00
Remove use of global register A0 (now aliased to T0). This makes it possible
to cache the CPU context pointer to a register and thus rendering generated code CPU context independent. Not useful to SheepShaver, but it is for another project for threads emulation on plain x86-32. Note: AltiVec performance may drop a little on x86 but this will be restored (and even improved) in the future.
This commit is contained in:
parent
d0a64733ef
commit
abc911eaa7
@ -397,8 +397,8 @@ int sheepshaver_cpu::compile1(codegen_context_t & cg_context)
|
||||
if (!FN_field::test(opcode))
|
||||
cg_context.done_compile = false;
|
||||
else {
|
||||
dg.gen_load_A0_LR();
|
||||
dg.gen_set_PC_A0();
|
||||
dg.gen_load_T0_LR_aligned();
|
||||
dg.gen_set_PC_T0();
|
||||
cg_context.done_compile = true;
|
||||
}
|
||||
break;
|
||||
@ -408,8 +408,8 @@ int sheepshaver_cpu::compile1(codegen_context_t & cg_context)
|
||||
if (!FN_field::test(opcode))
|
||||
dg.gen_set_PC_im(cg_context.pc + 4);
|
||||
else {
|
||||
dg.gen_load_A0_LR();
|
||||
dg.gen_set_PC_A0();
|
||||
dg.gen_load_T0_LR_aligned();
|
||||
dg.gen_set_PC_T0();
|
||||
}
|
||||
dg.gen_mov_32_T0_im(selector);
|
||||
dg.gen_jmp(native_op_trampoline);
|
||||
|
@ -26,21 +26,13 @@
|
||||
|
||||
// We need at least 5 general purpose registers
|
||||
struct basic_cpu;
|
||||
#ifdef REG_CPU
|
||||
register basic_cpu *CPU asm(REG_CPU);
|
||||
#else
|
||||
#define CPU ((basic_cpu *)CPUPARAM)
|
||||
#endif
|
||||
#define DYNGEN_DEFINE_GLOBAL_REGISTER(REG) \
|
||||
register uintptr reg_##REG asm(REG_##REG); \
|
||||
register uint32 REG asm(REG_##REG)
|
||||
DYNGEN_DEFINE_GLOBAL_REGISTER(A0);
|
||||
DYNGEN_DEFINE_GLOBAL_REGISTER(T0);
|
||||
DYNGEN_DEFINE_GLOBAL_REGISTER(T1);
|
||||
DYNGEN_DEFINE_GLOBAL_REGISTER(T2);
|
||||
#ifdef REG_T3
|
||||
DYNGEN_DEFINE_GLOBAL_REGISTER(T3);
|
||||
#endif
|
||||
register uintptr A##REG asm(REG_T##REG); \
|
||||
register uint32 T##REG asm(REG_T##REG)
|
||||
DYNGEN_DEFINE_GLOBAL_REGISTER(0);
|
||||
DYNGEN_DEFINE_GLOBAL_REGISTER(1);
|
||||
DYNGEN_DEFINE_GLOBAL_REGISTER(2);
|
||||
|
||||
|
||||
/**
|
||||
@ -65,6 +57,26 @@ DYNGEN_DEFINE_GLOBAL_REGISTER(T3);
|
||||
* ALU operations
|
||||
**/
|
||||
|
||||
// XXX update for new 64-bit arches
|
||||
#if defined __x86_64__
|
||||
#define DEFINE_REG(REG) asm volatile ("movabsq $__op_param1,%" REG_T##REG)
|
||||
#else
|
||||
#define DEFINE_REG(REG) A##REG = PARAM1
|
||||
#endif
|
||||
|
||||
#define DEFINE_OP(REG) \
|
||||
void OPPROTO op_mov_ad_A##REG##_im(void) \
|
||||
{ \
|
||||
DEFINE_REG(REG); \
|
||||
}
|
||||
|
||||
DEFINE_OP(0);
|
||||
DEFINE_OP(1);
|
||||
DEFINE_OP(2);
|
||||
|
||||
#undef DEFINE_REG
|
||||
#undef DEFINE_OP
|
||||
|
||||
#define DEFINE_OP(NAME, CODE) \
|
||||
void OPPROTO op_##NAME(void) \
|
||||
{ \
|
||||
@ -75,76 +87,45 @@ void OPPROTO op_##NAME(void) \
|
||||
DEFINE_OP(mov_32_T0_im, T0 = PARAM1);
|
||||
DEFINE_OP(mov_32_T0_T1, T0 = T1);
|
||||
DEFINE_OP(mov_32_T0_T2, T0 = T2);
|
||||
DEFINE_OP(mov_32_T0_A0, T0 = A0);
|
||||
DEFINE_OP(mov_32_T1_im, T1 = PARAM1);
|
||||
DEFINE_OP(mov_32_T1_T0, T1 = T0);
|
||||
DEFINE_OP(mov_32_T1_T2, T1 = T2);
|
||||
DEFINE_OP(mov_32_T1_A0, T1 = A0);
|
||||
DEFINE_OP(mov_32_T2_im, T2 = PARAM1);
|
||||
DEFINE_OP(mov_32_T2_T1, T2 = T1);
|
||||
DEFINE_OP(mov_32_T2_T0, T2 = T0);
|
||||
DEFINE_OP(mov_32_T2_A0, T2 = A0);
|
||||
DEFINE_OP(mov_32_A0_im, A0 = PARAM1);
|
||||
DEFINE_OP(mov_32_A0_T0, A0 = T0);
|
||||
DEFINE_OP(mov_32_A0_T1, A0 = T1);
|
||||
DEFINE_OP(mov_32_A0_T2, A0 = T2);
|
||||
DEFINE_OP(mov_32_T0_0, T0 = 0);
|
||||
DEFINE_OP(mov_32_T1_0, T1 = 0);
|
||||
DEFINE_OP(mov_32_T2_0, T2 = 0);
|
||||
DEFINE_OP(mov_32_A0_0, A0 = 0);
|
||||
|
||||
#if SIZEOF_VOID_P == 8
|
||||
#if defined(__x86_64__)
|
||||
#define DEFINE_MOV_AD(REG) asm volatile ("movabsq $__op_param1,%" REG_##REG)
|
||||
#else
|
||||
#error "unsupported 64-bit value move in"
|
||||
#endif
|
||||
#else
|
||||
#define DEFINE_MOV_AD(REG) REG = PARAM1
|
||||
#endif
|
||||
|
||||
void OPPROTO op_mov_ad_T0_im(void) { DEFINE_MOV_AD(T0); }
|
||||
void OPPROTO op_mov_ad_T1_im(void) { DEFINE_MOV_AD(T1); }
|
||||
void OPPROTO op_mov_ad_T2_im(void) { DEFINE_MOV_AD(T2); }
|
||||
void OPPROTO op_mov_ad_A0_im(void) { DEFINE_MOV_AD(A0); }
|
||||
|
||||
// Arithmetic operations
|
||||
DEFINE_OP(add_32_T0_T2, T0 += T2);
|
||||
DEFINE_OP(add_32_T0_T1, T0 += T1);
|
||||
DEFINE_OP(add_32_T0_im, T0 += PARAM1);
|
||||
DEFINE_OP(add_32_T0_1, T0 += 1);
|
||||
DEFINE_OP(add_32_T0_2, T0 += 2);
|
||||
DEFINE_OP(add_32_T0_4, T0 += 4);
|
||||
DEFINE_OP(add_32_T0_8, T0 += 8);
|
||||
DEFINE_OP(sub_32_T0_T2, T0 -= T2);
|
||||
DEFINE_OP(sub_32_T0_T1, T0 -= T1);
|
||||
DEFINE_OP(sub_32_T0_im, T0 -= PARAM1);
|
||||
DEFINE_OP(sub_32_T0_1, T0 -= 1);
|
||||
DEFINE_OP(sub_32_T0_2, T0 -= 2);
|
||||
DEFINE_OP(sub_32_T0_4, T0 -= 4);
|
||||
DEFINE_OP(sub_32_T0_8, T0 -= 8);
|
||||
DEFINE_OP(add_32_T1_T2, T1 += T2);
|
||||
DEFINE_OP(add_32_T1_T0, T1 += T0);
|
||||
DEFINE_OP(add_32_T1_im, T1 += PARAM1);
|
||||
DEFINE_OP(add_32_T1_1, T1 += 1);
|
||||
DEFINE_OP(add_32_T1_2, T1 += 2);
|
||||
DEFINE_OP(add_32_T1_4, T1 += 4);
|
||||
DEFINE_OP(add_32_T1_8, T1 += 8);
|
||||
DEFINE_OP(sub_32_T1_T2, T1 -= T2);
|
||||
DEFINE_OP(sub_32_T1_T0, T1 -= T0);
|
||||
DEFINE_OP(sub_32_T1_im, T1 -= PARAM1);
|
||||
DEFINE_OP(sub_32_T1_1, T1 -= 1);
|
||||
DEFINE_OP(sub_32_T1_2, T1 -= 2);
|
||||
DEFINE_OP(sub_32_T1_4, T1 -= 4);
|
||||
DEFINE_OP(sub_32_T1_8, T1 -= 8);
|
||||
DEFINE_OP(add_32_A0_T1, A0 += T1);
|
||||
DEFINE_OP(add_32_A0_im, A0 += PARAM1);
|
||||
DEFINE_OP(add_32_A0_1, A0 += 1);
|
||||
DEFINE_OP(add_32_A0_2, A0 += 2);
|
||||
DEFINE_OP(add_32_A0_4, A0 += 4);
|
||||
DEFINE_OP(add_32_A0_8, A0 += 8);
|
||||
DEFINE_OP(sub_32_A0_T1, A0 -= T1);
|
||||
DEFINE_OP(sub_32_A0_im, A0 -= PARAM1);
|
||||
DEFINE_OP(sub_32_A0_1, A0 -= 1);
|
||||
DEFINE_OP(sub_32_A0_2, A0 -= 2);
|
||||
DEFINE_OP(sub_32_A0_4, A0 -= 4);
|
||||
DEFINE_OP(sub_32_A0_8, A0 -= 8);
|
||||
DEFINE_OP(umul_32_T0_T1, T0 = (uint32)T0 * (uint32)T1);
|
||||
DEFINE_OP(smul_32_T0_T1, T0 = (int32)T0 * (int32)T1);
|
||||
DEFINE_OP(udiv_32_T0_T1, T0 = do_udiv_32(T0, T1));
|
||||
@ -197,28 +178,28 @@ DEFINE_OP(ze_8_32_T0, T0 = (uint32)(uint8)T0);
|
||||
|
||||
#define im PARAM1
|
||||
#define DEFINE_OP(BITS,REG,SIZE,OFFSET) \
|
||||
void OPPROTO op_load_u##BITS##_##REG##_A0_##OFFSET(void) \
|
||||
void OPPROTO op_load_u##BITS##_##REG##_T1_##OFFSET(void) \
|
||||
{ \
|
||||
REG = (uint32)(uint##BITS)vm_read_memory_##SIZE(A0 + OFFSET); \
|
||||
REG = (uint32)(uint##BITS)vm_read_memory_##SIZE(T1 + OFFSET); \
|
||||
} \
|
||||
void OPPROTO op_load_s##BITS##_##REG##_A0_##OFFSET(void) \
|
||||
void OPPROTO op_load_s##BITS##_##REG##_T1_##OFFSET(void) \
|
||||
{ \
|
||||
REG = (int32)(int##BITS)vm_read_memory_##SIZE(A0 + OFFSET); \
|
||||
REG = (int32)(int##BITS)vm_read_memory_##SIZE(T1 + OFFSET); \
|
||||
} \
|
||||
void OPPROTO op_store_##BITS##_##REG##_A0_##OFFSET(void) \
|
||||
void OPPROTO op_store_##BITS##_##REG##_T1_##OFFSET(void) \
|
||||
{ \
|
||||
vm_write_memory_##SIZE(A0 + OFFSET, REG); \
|
||||
vm_write_memory_##SIZE(T1 + OFFSET, REG); \
|
||||
}
|
||||
|
||||
DEFINE_OP(32,T0,4,0);
|
||||
DEFINE_OP(32,T0,4,im);
|
||||
DEFINE_OP(32,T0,4,T1);
|
||||
DEFINE_OP(32,T0,4,T2);
|
||||
DEFINE_OP(16,T0,2,0);
|
||||
DEFINE_OP(16,T0,2,im);
|
||||
DEFINE_OP(16,T0,2,T1);
|
||||
DEFINE_OP(16,T0,2,T2);
|
||||
DEFINE_OP(8,T0,1,0);
|
||||
DEFINE_OP(8,T0,1,im);
|
||||
DEFINE_OP(8,T0,1,T1);
|
||||
DEFINE_OP(8,T0,1,T2);
|
||||
|
||||
#undef im
|
||||
#undef DEFINE_OP
|
||||
@ -274,27 +255,13 @@ void OPPROTO op_execute(uint8 *entry_point, basic_cpu *this_cpu)
|
||||
{
|
||||
typedef void (*func_t)(void);
|
||||
func_t func = (func_t)entry_point;
|
||||
const int n_slots = 16 + 6; /* 16 stack slots + 6 VCPU registers */
|
||||
const int n_slots = 16 + 4; /* 16 stack slots + 4 VCPU registers */
|
||||
volatile uintptr stk[n_slots];
|
||||
#ifdef REG_CPU
|
||||
stk[n_slots - 1] = (uintptr)CPU;
|
||||
stk[n_slots - 2] = A0;
|
||||
stk[n_slots - 3] = A1;
|
||||
stk[n_slots - 4] = A2;
|
||||
CPU = this_cpu;
|
||||
#endif
|
||||
#ifdef REG_A0
|
||||
stk[n_slots - 2] = reg_A0;
|
||||
#endif
|
||||
#ifdef REG_T0
|
||||
stk[n_slots - 3] = reg_T0;
|
||||
#endif
|
||||
#ifdef REG_T1
|
||||
stk[n_slots - 4] = reg_T1;
|
||||
#endif
|
||||
#ifdef REG_T2
|
||||
stk[n_slots - 5] = reg_T2;
|
||||
#endif
|
||||
#ifdef REG_T3
|
||||
stk[n_slots - 6] = reg_T3;
|
||||
#endif
|
||||
SLOW_DISPATCH(entry_point);
|
||||
func(); // NOTE: never called, fake to make compiler save return point
|
||||
#ifdef ASM_OP_EXEC_RETURN_INSN
|
||||
@ -308,24 +275,10 @@ void OPPROTO op_execute(uint8 *entry_point, basic_cpu *this_cpu)
|
||||
asm volatile (ASM_PREVIOUS_SECTION);
|
||||
asm volatile ("1:");
|
||||
#endif
|
||||
#ifdef REG_T3
|
||||
reg_T3 = stk[n_slots - 6];
|
||||
#endif
|
||||
#ifdef REG_T2
|
||||
reg_T2 = stk[n_slots - 5];
|
||||
#endif
|
||||
#ifdef REG_T1
|
||||
reg_T1 = stk[n_slots - 4];
|
||||
#endif
|
||||
#ifdef REG_T0
|
||||
reg_T0 = stk[n_slots - 3];
|
||||
#endif
|
||||
#ifdef REG_A0
|
||||
reg_A0 = stk[n_slots - 2];
|
||||
#endif
|
||||
#ifdef REG_CPU
|
||||
A2 = stk[n_slots - 4];
|
||||
A1 = stk[n_slots - 3];
|
||||
A0 = stk[n_slots - 2];
|
||||
CPU = (basic_cpu *)stk[n_slots - 1];
|
||||
#endif
|
||||
}
|
||||
|
||||
void OPPROTO op_jmp_slow(void)
|
||||
@ -344,7 +297,7 @@ void OPPROTO op_jmp_fast(void)
|
||||
|
||||
void OPPROTO op_jmp_A0(void)
|
||||
{
|
||||
SLOW_DISPATCH(reg_A0);
|
||||
SLOW_DISPATCH(A0);
|
||||
}
|
||||
|
||||
// Register calling conventions based arches don't need a stack frame
|
||||
@ -399,112 +352,123 @@ void OPPROTO NAME(void) \
|
||||
|
||||
DEFINE_OP(op_invoke, {
|
||||
typedef void (*func_t)(void);
|
||||
CALL(reg_A0,());
|
||||
func_t func = (func_t)PARAM1;
|
||||
CALL(func, ());
|
||||
});
|
||||
|
||||
DEFINE_OP(op_invoke_T0, {
|
||||
typedef void (*func_t)(uint32);
|
||||
CALL(reg_A0,(T0));
|
||||
func_t func = (func_t)PARAM1;
|
||||
CALL(func, (T0));
|
||||
});
|
||||
|
||||
DEFINE_OP(op_invoke_T0_T1, {
|
||||
typedef void (*func_t)(uint32, uint32);
|
||||
CALL(reg_A0,(T0, T1));
|
||||
func_t func = (func_t)PARAM1;
|
||||
CALL(func, (T0, T1));
|
||||
});
|
||||
|
||||
DEFINE_OP(op_invoke_T0_T1_T2, {
|
||||
typedef void (*func_t)(uint32, uint32, uint32);
|
||||
CALL(reg_A0,(T0, T1, T2));
|
||||
func_t func = (func_t)PARAM1;
|
||||
CALL(func, (T0, T1, T2));
|
||||
});
|
||||
|
||||
DEFINE_OP(op_invoke_T0_ret_T0, {
|
||||
typedef uint32 (*func_t)(uint32);
|
||||
T0 = CALL(reg_A0,(T0));
|
||||
func_t func = (func_t)PARAM1;
|
||||
T0 = CALL(func, (T0));
|
||||
});
|
||||
|
||||
DEFINE_OP(op_invoke_im, {
|
||||
typedef void (*func_t)(uint32);
|
||||
CALL(reg_A0,(PARAM1));
|
||||
func_t func = (func_t)PARAM1;
|
||||
CALL(func, (PARAM2));
|
||||
});
|
||||
|
||||
DEFINE_OP(op_invoke_CPU, {
|
||||
typedef void (*func_t)(void *);
|
||||
CALL(reg_A0,(CPU));
|
||||
func_t func = (func_t)PARAM1;
|
||||
CALL(func, (CPU));
|
||||
});
|
||||
|
||||
DEFINE_OP(op_invoke_CPU_T0, {
|
||||
typedef void (*func_t)(void *, uint32);
|
||||
CALL(reg_A0,(CPU, T0));
|
||||
func_t func = (func_t)PARAM1;
|
||||
CALL(func, (CPU, T0));
|
||||
});
|
||||
|
||||
DEFINE_OP(op_invoke_CPU_im, {
|
||||
typedef void (*func_t)(void *, uint32);
|
||||
CALL(reg_A0,(CPU, PARAM1));
|
||||
func_t func = (func_t)PARAM1;
|
||||
CALL(func, (CPU, PARAM2));
|
||||
});
|
||||
|
||||
DEFINE_OP(op_invoke_CPU_im_im, {
|
||||
typedef void (*func_t)(void *, uint32, uint32);
|
||||
CALL(reg_A0,(CPU, PARAM1, PARAM2));
|
||||
func_t func = (func_t)PARAM1;
|
||||
CALL(func, (CPU, PARAM2, PARAM3));
|
||||
});
|
||||
|
||||
DEFINE_OP(op_invoke_CPU_A0_ret_A0, {
|
||||
typedef void *(*func_t)(void *, uintptr);
|
||||
func_t func = (func_t)PARAM1;
|
||||
A0 = (uintptr)CALL(func, (CPU, A0));
|
||||
});
|
||||
|
||||
DEFINE_OP(op_invoke_direct, {
|
||||
typedef void (*func_t)(void);
|
||||
CALL(PARAM1,());
|
||||
CALL(PARAM1, ());
|
||||
});
|
||||
|
||||
DEFINE_OP(op_invoke_direct_T0, {
|
||||
typedef void (*func_t)(uint32);
|
||||
CALL(PARAM1,(T0));
|
||||
CALL(PARAM1, (T0));
|
||||
});
|
||||
|
||||
DEFINE_OP(op_invoke_direct_T0_T1, {
|
||||
typedef void (*func_t)(uint32, uint32);
|
||||
CALL(PARAM1,(T0, T1));
|
||||
CALL(PARAM1, (T0, T1));
|
||||
});
|
||||
|
||||
DEFINE_OP(op_invoke_direct_T0_T1_T2, {
|
||||
typedef void (*func_t)(uint32, uint32, uint32);
|
||||
CALL(PARAM1,(T0, T1, T2));
|
||||
CALL(PARAM1, (T0, T1, T2));
|
||||
});
|
||||
|
||||
DEFINE_OP(op_invoke_direct_T0_ret_T0, {
|
||||
typedef uint32 (*func_t)(uint32);
|
||||
T0 = CALL(PARAM1,(T0));
|
||||
T0 = CALL(PARAM1, (T0));
|
||||
});
|
||||
|
||||
DEFINE_OP(op_invoke_direct_im, {
|
||||
typedef void (*func_t)(uint32);
|
||||
CALL(PARAM1,(PARAM2));
|
||||
CALL(PARAM1, (PARAM2));
|
||||
});
|
||||
|
||||
DEFINE_OP(op_invoke_direct_CPU, {
|
||||
typedef void (*func_t)(void *);
|
||||
CALL(PARAM1,(CPU));
|
||||
CALL(PARAM1, (CPU));
|
||||
});
|
||||
|
||||
DEFINE_OP(op_invoke_direct_CPU_T0, {
|
||||
typedef void (*func_t)(void *, uint32);
|
||||
CALL(PARAM1,(CPU, T0));
|
||||
CALL(PARAM1, (CPU, T0));
|
||||
});
|
||||
|
||||
DEFINE_OP(op_invoke_direct_CPU_im, {
|
||||
typedef void (*func_t)(void *, uint32);
|
||||
CALL(PARAM1,(CPU, PARAM2));
|
||||
CALL(PARAM1, (CPU, PARAM2));
|
||||
});
|
||||
|
||||
DEFINE_OP(op_invoke_direct_CPU_im_im, {
|
||||
typedef void (*func_t)(void *, uint32, uint32);
|
||||
CALL(PARAM1,(CPU, PARAM2, PARAM3));
|
||||
CALL(PARAM1, (CPU, PARAM2, PARAM3));
|
||||
});
|
||||
|
||||
DEFINE_OP(op_invoke_CPU_T0_ret_A0, {
|
||||
DEFINE_OP(op_invoke_direct_CPU_A0_ret_A0, {
|
||||
typedef void *(*func_t)(void *, uintptr);
|
||||
reg_A0 = (uintptr)CALL(reg_A0,(CPU, reg_T0));
|
||||
});
|
||||
|
||||
DEFINE_OP(op_invoke_direct_CPU_T0_ret_A0, {
|
||||
typedef void *(*func_t)(void *, uintptr);
|
||||
reg_A0 = (uintptr)CALL(PARAM1,(CPU, reg_T0));
|
||||
A0 = (uintptr)CALL(PARAM1, (CPU, A0));
|
||||
});
|
||||
|
||||
#undef DEFINE_OP
|
||||
|
@ -48,121 +48,33 @@ basic_dyngen::basic_dyngen(dyngen_cpu_base cpu, int cache_size)
|
||||
void
|
||||
basic_dyngen::gen_invoke(void (*func)())
|
||||
{
|
||||
if (direct_call_possible((uintptr)func))
|
||||
gen_op_invoke_direct((uintptr)func);
|
||||
else {
|
||||
gen_op_mov_ad_A0_im((uintptr)func);
|
||||
gen_op_invoke();
|
||||
}
|
||||
uintptr funcptr = (uintptr)func;
|
||||
if (direct_call_possible(funcptr))
|
||||
gen_op_invoke_direct(funcptr);
|
||||
else
|
||||
gen_op_invoke(funcptr);
|
||||
}
|
||||
|
||||
void
|
||||
basic_dyngen::gen_invoke_T0(void (*func)(uint32))
|
||||
{
|
||||
if (direct_call_possible((uintptr)func))
|
||||
gen_op_invoke_direct_T0((uintptr)func);
|
||||
else {
|
||||
gen_op_mov_ad_A0_im((uintptr)func);
|
||||
gen_op_invoke_T0();
|
||||
}
|
||||
#define DEFINE_INVOKE(NAME, ARGS, IARGS) \
|
||||
void \
|
||||
basic_dyngen::gen_invoke_##NAME ARGS \
|
||||
{ \
|
||||
uintptr funcptr = (uintptr)func; \
|
||||
if (direct_call_possible(funcptr)) \
|
||||
gen_op_invoke_direct_##NAME IARGS; \
|
||||
else \
|
||||
gen_op_invoke_##NAME IARGS; \
|
||||
}
|
||||
|
||||
void
|
||||
basic_dyngen::gen_invoke_T0_T1(void (*func)(uint32, uint32))
|
||||
{
|
||||
if (direct_call_possible((uintptr)func))
|
||||
gen_op_invoke_direct_T0_T1((uintptr)func);
|
||||
else {
|
||||
gen_op_mov_ad_A0_im((uintptr)func);
|
||||
gen_op_invoke_T0_T1();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
basic_dyngen::gen_invoke_T0_T1_T2(void (*func)(uint32, uint32, uint32))
|
||||
{
|
||||
if (direct_call_possible((uintptr)func))
|
||||
gen_op_invoke_direct_T0_T1_T2((uintptr)func);
|
||||
else {
|
||||
gen_op_mov_ad_A0_im((uintptr)func);
|
||||
gen_op_invoke_T0_T1_T2();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
basic_dyngen::gen_invoke_T0_ret_T0(uint32 (*func)(uint32))
|
||||
{
|
||||
if (direct_call_possible((uintptr)func))
|
||||
gen_op_invoke_direct_T0_ret_T0((uintptr)func);
|
||||
else {
|
||||
gen_op_mov_ad_A0_im((uintptr)func);
|
||||
gen_op_invoke_T0_ret_T0();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
basic_dyngen::gen_invoke_im(void (*func)(uint32), uint32 value)
|
||||
{
|
||||
if (direct_call_possible((uintptr)func))
|
||||
gen_op_invoke_direct_im((uintptr)func, value);
|
||||
else {
|
||||
gen_op_mov_ad_A0_im((uintptr)func);
|
||||
gen_op_invoke_im(value);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
basic_dyngen::gen_invoke_CPU(void (*func)(dyngen_cpu_base))
|
||||
{
|
||||
if (direct_call_possible((uintptr)func))
|
||||
gen_op_invoke_direct_CPU((uintptr)func);
|
||||
else {
|
||||
gen_op_mov_ad_A0_im((uintptr)func);
|
||||
gen_op_invoke_CPU();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
basic_dyngen::gen_invoke_CPU_T0(void (*func)(dyngen_cpu_base, uint32))
|
||||
{
|
||||
if (direct_call_possible((uintptr)func))
|
||||
gen_op_invoke_direct_CPU_T0((uintptr)func);
|
||||
else {
|
||||
gen_op_mov_ad_A0_im((uintptr)func);
|
||||
gen_op_invoke_CPU_T0();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
basic_dyngen::gen_invoke_CPU_im(void (*func)(dyngen_cpu_base, uint32), uint32 value)
|
||||
{
|
||||
if (direct_call_possible((uintptr)func))
|
||||
gen_op_invoke_direct_CPU_im((uintptr)func, value);
|
||||
else {
|
||||
gen_op_mov_ad_A0_im((uintptr)func);
|
||||
gen_op_invoke_CPU_im(value);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
basic_dyngen::gen_invoke_CPU_im_im(void (*func)(dyngen_cpu_base, uint32, uint32), uint32 param1, uint32 param2)
|
||||
{
|
||||
if (direct_call_possible((uintptr)func))
|
||||
gen_op_invoke_direct_CPU_im_im((uintptr)func, param1, param2);
|
||||
else {
|
||||
gen_op_mov_ad_A0_im((uintptr)func);
|
||||
gen_op_invoke_CPU_im_im(param1, param2);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
basic_dyngen::gen_invoke_CPU_T0_ret_A0(void *(*func)(dyngen_cpu_base))
|
||||
{
|
||||
if (direct_call_possible((uintptr)func))
|
||||
gen_op_invoke_direct_CPU_T0_ret_A0((uintptr)func);
|
||||
else {
|
||||
gen_op_mov_ad_A0_im((uintptr)func);
|
||||
gen_op_invoke_CPU_T0_ret_A0();
|
||||
}
|
||||
}
|
||||
DEFINE_INVOKE(T0, (void (*func)(uint32)), (funcptr));
|
||||
DEFINE_INVOKE(T0_T1, (void (*func)(uint32, uint32)), (funcptr));
|
||||
DEFINE_INVOKE(T0_T1_T2, (void (*func)(uint32, uint32, uint32)), (funcptr));
|
||||
DEFINE_INVOKE(T0_ret_T0, (uint32 (*func)(uint32)), (funcptr));
|
||||
DEFINE_INVOKE(im, (void (*func)(uint32), uint32 value), (funcptr, value));
|
||||
DEFINE_INVOKE(CPU, (void (*func)(dyngen_cpu_base)), (funcptr));
|
||||
DEFINE_INVOKE(CPU_T0, (void (*func)(dyngen_cpu_base, uint32)), (funcptr));
|
||||
DEFINE_INVOKE(CPU_im, (void (*func)(dyngen_cpu_base, uint32), uint32 value), (funcptr, value));
|
||||
DEFINE_INVOKE(CPU_im_im, (void (*func)(dyngen_cpu_base, uint32, uint32), uint32 param1, uint32 param2), (funcptr, param1, param2));
|
||||
DEFINE_INVOKE(CPU_A0_ret_A0, (void *(*func)(dyngen_cpu_base)), (funcptr));
|
||||
|
||||
#undef DEFINE_INVOKE
|
||||
|
@ -111,7 +111,7 @@ public:
|
||||
void gen_invoke_CPU_T0(void (*func)(dyngen_cpu_base, uint32));
|
||||
void gen_invoke_CPU_im(void (*func)(dyngen_cpu_base, uint32), uint32 value);
|
||||
void gen_invoke_CPU_im_im(void (*func)(dyngen_cpu_base, uint32, uint32), uint32 param1, uint32 param2);
|
||||
void gen_invoke_CPU_T0_ret_A0(void *(*func)(dyngen_cpu_base));
|
||||
void gen_invoke_CPU_A0_ret_A0(void *(*func)(dyngen_cpu_base));
|
||||
|
||||
// Raw aliases
|
||||
#define DEFINE_ALIAS_RAW(NAME, ARGLIST, ARGS) \
|
||||
@ -127,37 +127,29 @@ public:
|
||||
void gen_mov_32_T0_im(int32 value);
|
||||
DEFINE_ALIAS(mov_32_T0_T1,0);
|
||||
DEFINE_ALIAS(mov_32_T0_T2,0);
|
||||
DEFINE_ALIAS(mov_32_T0_A0,0);
|
||||
void gen_mov_32_T1_im(int32 value);
|
||||
DEFINE_ALIAS(mov_32_T1_T0,0);
|
||||
DEFINE_ALIAS(mov_32_T1_T2,0);
|
||||
DEFINE_ALIAS(mov_32_T1_A0,0);
|
||||
void gen_mov_32_T2_im(int32 value);
|
||||
DEFINE_ALIAS(mov_32_T2_T0,0);
|
||||
DEFINE_ALIAS(mov_32_T2_T1,0);
|
||||
DEFINE_ALIAS(mov_32_T2_A0,0);
|
||||
void gen_mov_32_A0_im(int32 value);
|
||||
DEFINE_ALIAS(mov_32_A0_T0,0);
|
||||
DEFINE_ALIAS(mov_32_A0_T1,0);
|
||||
DEFINE_ALIAS(mov_32_A0_T2,0);
|
||||
DEFINE_ALIAS(mov_ad_T0_im,1);
|
||||
DEFINE_ALIAS(mov_ad_T1_im,1);
|
||||
DEFINE_ALIAS(mov_ad_T2_im,1);
|
||||
DEFINE_ALIAS(mov_ad_A0_im,1);
|
||||
DEFINE_ALIAS(mov_ad_A1_im,1);
|
||||
DEFINE_ALIAS(mov_ad_A2_im,1);
|
||||
|
||||
// Arithmetic operations
|
||||
DEFINE_ALIAS(add_32_T0_T1,0);
|
||||
DEFINE_ALIAS(add_32_T0_T2,0);
|
||||
void gen_add_32_T0_im(int32 value);
|
||||
DEFINE_ALIAS(sub_32_T0_T1,0);
|
||||
DEFINE_ALIAS(sub_32_T0_T2,0);
|
||||
void gen_sub_32_T0_im(int32 value);
|
||||
DEFINE_ALIAS(add_32_T1_T0,0);
|
||||
DEFINE_ALIAS(add_32_T1_T2,0);
|
||||
void gen_add_32_T1_im(int32 value);
|
||||
DEFINE_ALIAS(sub_32_T1_T0,0);
|
||||
DEFINE_ALIAS(sub_32_T1_T2,0);
|
||||
void gen_sub_32_T1_im(int32 value);
|
||||
DEFINE_ALIAS(add_32_A0_T1,0);
|
||||
void gen_add_32_A0_im(int32 value);
|
||||
DEFINE_ALIAS(sub_32_A0_T1,0);
|
||||
void gen_sub_32_A0_im(int32 value);
|
||||
DEFINE_ALIAS(umul_32_T0_T1,0);
|
||||
DEFINE_ALIAS(smul_32_T0_T1,0);
|
||||
DEFINE_ALIAS(udiv_32_T0_T1,0);
|
||||
@ -207,24 +199,24 @@ public:
|
||||
DEFINE_ALIAS(jmp_A0,0);
|
||||
|
||||
// Load/Store instructions
|
||||
DEFINE_ALIAS(load_u32_T0_A0_T1,0);
|
||||
void gen_load_u32_T0_A0_im(int32 offset);
|
||||
DEFINE_ALIAS(load_s32_T0_A0_T1,0);
|
||||
void gen_load_s32_T0_A0_im(int32 offset);
|
||||
DEFINE_ALIAS(load_u16_T0_A0_T1,0);
|
||||
void gen_load_u16_T0_A0_im(int32 offset);
|
||||
DEFINE_ALIAS(load_s16_T0_A0_T1,0);
|
||||
void gen_load_s16_T0_A0_im(int32 offset);
|
||||
DEFINE_ALIAS(load_u8_T0_A0_T1,0);
|
||||
void gen_load_u8_T0_A0_im(int32 offset);
|
||||
DEFINE_ALIAS(load_s8_T0_A0_T1,0);
|
||||
void gen_load_s8_T0_A0_im(int32 offset);
|
||||
DEFINE_ALIAS(store_32_T0_A0_T1,0);
|
||||
void gen_store_32_T0_A0_im(int32 offset);
|
||||
DEFINE_ALIAS(store_16_T0_A0_T1,0);
|
||||
void gen_store_16_T0_A0_im(int32 offset);
|
||||
DEFINE_ALIAS(store_8_T0_A0_T1,0);
|
||||
void gen_store_8_T0_A0_im(int32 offset);
|
||||
DEFINE_ALIAS(load_u32_T0_T1_T2,0);
|
||||
void gen_load_u32_T0_T1_im(int32 offset);
|
||||
DEFINE_ALIAS(load_s32_T0_T1_T2,0);
|
||||
void gen_load_s32_T0_T1_im(int32 offset);
|
||||
DEFINE_ALIAS(load_u16_T0_T1_T2,0);
|
||||
void gen_load_u16_T0_T1_im(int32 offset);
|
||||
DEFINE_ALIAS(load_s16_T0_T1_T2,0);
|
||||
void gen_load_s16_T0_T1_im(int32 offset);
|
||||
DEFINE_ALIAS(load_u8_T0_T1_T2,0);
|
||||
void gen_load_u8_T0_T1_im(int32 offset);
|
||||
DEFINE_ALIAS(load_s8_T0_T1_T2,0);
|
||||
void gen_load_s8_T0_T1_im(int32 offset);
|
||||
DEFINE_ALIAS(store_32_T0_T1_T2,0);
|
||||
void gen_store_32_T0_T1_im(int32 offset);
|
||||
DEFINE_ALIAS(store_16_T0_T1_T2,0);
|
||||
void gen_store_16_T0_T1_im(int32 offset);
|
||||
DEFINE_ALIAS(store_8_T0_T1_T2,0);
|
||||
void gen_store_8_T0_T1_im(int32 offset);
|
||||
|
||||
#undef DEFINE_ALIAS
|
||||
#undef DEFINE_ALIAS_0
|
||||
@ -335,13 +327,12 @@ basic_dyngen::gen_mov_32_##REG##_im(int32 value) \
|
||||
DEFINE_OP(T0);
|
||||
DEFINE_OP(T1);
|
||||
DEFINE_OP(T2);
|
||||
DEFINE_OP(A0);
|
||||
|
||||
#undef DEFINE_OP
|
||||
|
||||
#define DEFINE_OP(OP,REG) \
|
||||
inline void \
|
||||
basic_dyngen::gen_##OP##_32_##REG##_im(int32 value) \
|
||||
basic_dyngen::gen_##OP##_32_##REG##_im(int32 value) \
|
||||
{ \
|
||||
if (value == 0) return; \
|
||||
else if (value == 1) gen_op_##OP##_32_##REG##_1(); \
|
||||
@ -351,23 +342,21 @@ basic_dyngen::gen_##OP##_32_##REG##_im(int32 value) \
|
||||
else gen_op_##OP##_32_##REG##_im(value); \
|
||||
}
|
||||
|
||||
DEFINE_OP(add,A0);
|
||||
DEFINE_OP(add,T0);
|
||||
DEFINE_OP(add,T1);
|
||||
DEFINE_OP(sub,A0);
|
||||
DEFINE_OP(sub,T0);
|
||||
DEFINE_OP(sub,T1);
|
||||
|
||||
#undef DEFINE_OP
|
||||
|
||||
#define DEFINE_OP(NAME,REG,SIZE) \
|
||||
inline void \
|
||||
basic_dyngen::gen_##NAME##_##SIZE##_##REG##_A0_im(int32 offset) \
|
||||
{ \
|
||||
if (offset == 0) \
|
||||
gen_op_##NAME##_##SIZE##_##REG##_A0_0(); \
|
||||
else \
|
||||
gen_op_##NAME##_##SIZE##_##REG##_A0_im(offset); \
|
||||
#define DEFINE_OP(NAME,REG,SIZE) \
|
||||
inline void \
|
||||
basic_dyngen::gen_##NAME##_##SIZE##_##REG##_T1_im(int32 offset) \
|
||||
{ \
|
||||
if (offset == 0) \
|
||||
gen_op_##NAME##_##SIZE##_##REG##_T1_0(); \
|
||||
else \
|
||||
gen_op_##NAME##_##SIZE##_##REG##_T1_im(offset); \
|
||||
}
|
||||
|
||||
DEFINE_OP(load,T0,u32);
|
||||
|
@ -27,8 +27,8 @@
|
||||
#include "cpu/jit/jit-target-dispatch.h"
|
||||
|
||||
/* define virtual register set */
|
||||
#define REG_A0 AREG0
|
||||
#define REG_A0_ID AREG0_ID
|
||||
#define REG_CPU AREG0
|
||||
#define REG_CPU_ID AREG0_ID
|
||||
#define REG_T0 AREG1
|
||||
#define REG_T0_ID AREG1_ID
|
||||
#define REG_T1 AREG2
|
||||
@ -39,10 +39,6 @@
|
||||
#define REG_T3 AREG4
|
||||
#define REG_T3_ID AREG4_ID
|
||||
#endif
|
||||
#ifdef AREG5
|
||||
#define REG_CPU AREG5
|
||||
#define REG_CPU_ID AREG5_ID
|
||||
#endif
|
||||
#ifdef FREG0
|
||||
#define REG_F0 FREG0
|
||||
#define REG_F0_ID FREG0_ID
|
||||
|
@ -28,43 +28,41 @@
|
||||
#include "cpu/ppc/ppc-operations.hpp"
|
||||
|
||||
// We need at least 4 general purpose registers
|
||||
#ifdef REG_CPU
|
||||
register struct powerpc_cpu *CPU asm(REG_CPU);
|
||||
#else
|
||||
#define CPU ((powerpc_cpu *)CPUPARAM)
|
||||
#endif
|
||||
#define DYNGEN_DEFINE_GLOBAL_REGISTER(REG) \
|
||||
register uintptr reg_##REG asm(REG_##REG); \
|
||||
register uint32 REG asm(REG_##REG)
|
||||
DYNGEN_DEFINE_GLOBAL_REGISTER(A0);
|
||||
DYNGEN_DEFINE_GLOBAL_REGISTER(T0);
|
||||
DYNGEN_DEFINE_GLOBAL_REGISTER(T1);
|
||||
DYNGEN_DEFINE_GLOBAL_REGISTER(T2);
|
||||
register uintptr A##REG asm(REG_T##REG); \
|
||||
register uint32 T##REG asm(REG_T##REG)
|
||||
DYNGEN_DEFINE_GLOBAL_REGISTER(0);
|
||||
DYNGEN_DEFINE_GLOBAL_REGISTER(1);
|
||||
DYNGEN_DEFINE_GLOBAL_REGISTER(2);
|
||||
#ifdef REG_T3
|
||||
DYNGEN_DEFINE_GLOBAL_REGISTER(T3);
|
||||
DYNGEN_DEFINE_GLOBAL_REGISTER(3);
|
||||
#else
|
||||
#define A3 powerpc_dyngen_helper::reg_T3()
|
||||
#define T3 powerpc_dyngen_helper::reg_T3()
|
||||
#endif
|
||||
|
||||
// Floating-point registers
|
||||
#define FPREG(X) ((powerpc_fpr *)(X))
|
||||
#define F0 FPREG(reg_T0)->d
|
||||
#define F0_dw FPREG(reg_T0)->j
|
||||
#define F1 FPREG(reg_T1)->d
|
||||
#define F1_dw FPREG(reg_T1)->j
|
||||
#define F2 FPREG(reg_T2)->d
|
||||
#define F2_dw FPREG(reg_T2)->j
|
||||
#define F0 FPREG(A0)->d
|
||||
#define F0_dw FPREG(A0)->j
|
||||
#define F1 FPREG(A1)->d
|
||||
#define F1_dw FPREG(A1)->j
|
||||
#define F2 FPREG(A2)->d
|
||||
#define F2_dw FPREG(A2)->j
|
||||
#define FD powerpc_dyngen_helper::fp_result()
|
||||
#define FD_dw powerpc_dyngen_helper::fp_result_dw()
|
||||
|
||||
// Vector registers
|
||||
#define VREG(X) ((powerpc_vr *)(X))[0]
|
||||
#define VD VREG(reg_VD)
|
||||
#define reg_VD reg_A0
|
||||
#define V0 VREG(reg_V0)
|
||||
#define reg_V0 reg_T0
|
||||
#define reg_V0 A0
|
||||
#define V1 VREG(reg_V1)
|
||||
#define reg_V1 reg_T1
|
||||
#define reg_V1 A1
|
||||
#define V2 VREG(reg_V2)
|
||||
#define reg_V2 reg_T2
|
||||
#define reg_V2 A2
|
||||
#define VD VREG(reg_VD)
|
||||
#define reg_VD A3
|
||||
|
||||
/**
|
||||
* Helper class to access protected CPU context
|
||||
@ -96,6 +94,10 @@ struct powerpc_dyngen_helper {
|
||||
static uint64 & fp_result_dw() { return CPU->fp_result_dw(); }
|
||||
static inline void set_cr(int crfd, int v) { CPU->cr().set(crfd, v); }
|
||||
|
||||
#ifndef REG_T3
|
||||
static inline uintptr & reg_T3() { return CPU->codegen.reg_T3; }
|
||||
#endif
|
||||
|
||||
static inline powerpc_block_info *find_block(uint32 pc) { return CPU->block_cache.fast_find(pc); }
|
||||
};
|
||||
|
||||
@ -118,7 +120,6 @@ void OPPROTO op_store_##REG##_GPR##N(void) \
|
||||
CPU->gpr(N) = REG; \
|
||||
}
|
||||
#define DEFINE_REG(N) \
|
||||
DEFINE_OP(A0,N); \
|
||||
DEFINE_OP(T0,N); \
|
||||
DEFINE_OP(T1,N); \
|
||||
DEFINE_OP(T2,N);
|
||||
@ -167,7 +168,7 @@ DEFINE_REG(31);
|
||||
#define DEFINE_OP(REG, N) \
|
||||
void OPPROTO op_load_F##REG##_FPR##N(void) \
|
||||
{ \
|
||||
reg_T##REG = (uintptr)&CPU->fpr(N); \
|
||||
A##REG = (uintptr)&CPU->fpr(N); \
|
||||
} \
|
||||
void OPPROTO op_store_F##REG##_FPR##N(void) \
|
||||
{ \
|
||||
@ -254,26 +255,26 @@ DEFINE_REG(31);
|
||||
|
||||
#define im PARAM1
|
||||
#define DEFINE_OP(OFFSET) \
|
||||
void OPPROTO op_load_double_FD_A0_##OFFSET(void) \
|
||||
void OPPROTO op_load_double_FD_T1_##OFFSET(void) \
|
||||
{ \
|
||||
do_load_double(FD, A0 + OFFSET); \
|
||||
do_load_double(FD, T1 + OFFSET); \
|
||||
} \
|
||||
void OPPROTO op_load_single_FD_A0_##OFFSET(void) \
|
||||
void OPPROTO op_load_single_FD_T1_##OFFSET(void) \
|
||||
{ \
|
||||
do_load_single(FD, A0 + OFFSET); \
|
||||
do_load_single(FD, T1 + OFFSET); \
|
||||
} \
|
||||
void OPPROTO op_store_double_F0_A0_##OFFSET(void) \
|
||||
void OPPROTO op_store_double_F0_T1_##OFFSET(void) \
|
||||
{ \
|
||||
do_store_double(F0, A0 + OFFSET); \
|
||||
do_store_double(F0, T1 + OFFSET); \
|
||||
} \
|
||||
void OPPROTO op_store_single_F0_A0_##OFFSET(void) \
|
||||
void OPPROTO op_store_single_F0_T1_##OFFSET(void) \
|
||||
{ \
|
||||
do_store_single(F0, A0 + OFFSET); \
|
||||
do_store_single(F0, T1 + OFFSET); \
|
||||
}
|
||||
|
||||
DEFINE_OP(0);
|
||||
DEFINE_OP(im);
|
||||
DEFINE_OP(T1);
|
||||
DEFINE_OP(T2);
|
||||
|
||||
#undef im
|
||||
#undef DEFINE_OP
|
||||
@ -516,9 +517,9 @@ void OPPROTO op_set_PC_im(void)
|
||||
powerpc_dyngen_helper::set_pc(PARAM1);
|
||||
}
|
||||
|
||||
void OPPROTO op_set_PC_A0(void)
|
||||
void OPPROTO op_set_PC_T0(void)
|
||||
{
|
||||
powerpc_dyngen_helper::set_pc(A0);
|
||||
powerpc_dyngen_helper::set_pc(T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_inc_PC(void)
|
||||
@ -546,29 +547,19 @@ void OPPROTO op_store_T0_CTR(void)
|
||||
powerpc_dyngen_helper::set_ctr(T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_store_T1_CTR(void)
|
||||
{
|
||||
powerpc_dyngen_helper::set_ctr(T1);
|
||||
}
|
||||
|
||||
void OPPROTO op_load_T1_PC(void)
|
||||
{
|
||||
T1 = powerpc_dyngen_helper::get_pc();
|
||||
}
|
||||
|
||||
void OPPROTO op_store_im_LR(void)
|
||||
{
|
||||
powerpc_dyngen_helper::set_lr(PARAM1);
|
||||
}
|
||||
|
||||
void OPPROTO op_load_A0_CTR(void)
|
||||
void OPPROTO op_load_T0_CTR_aligned(void)
|
||||
{
|
||||
A0 = powerpc_dyngen_helper::get_ctr() & -4;
|
||||
T0 = powerpc_dyngen_helper::get_ctr() & -4;
|
||||
}
|
||||
|
||||
void OPPROTO op_load_A0_LR(void)
|
||||
void OPPROTO op_load_T0_LR_aligned(void)
|
||||
{
|
||||
A0 = powerpc_dyngen_helper::get_lr() & -4;
|
||||
T0 = powerpc_dyngen_helper::get_lr() & -4;
|
||||
}
|
||||
|
||||
void OPPROTO op_spcflags_init(void)
|
||||
@ -610,21 +601,21 @@ static inline void do_prep_branch_bo(void)
|
||||
|
||||
if (BO_CONDITIONAL_BRANCH(bo)) {
|
||||
if (BO_BRANCH_IF_TRUE(bo))
|
||||
cond_ok = T0;
|
||||
cond_ok = T1;
|
||||
else
|
||||
cond_ok = !T0;
|
||||
cond_ok = !T1;
|
||||
}
|
||||
|
||||
if (BO_DECREMENT_CTR(bo)) {
|
||||
T1 = powerpc_dyngen_helper::get_ctr() - 1;
|
||||
powerpc_dyngen_helper::set_ctr(T1);
|
||||
T2 = powerpc_dyngen_helper::get_ctr() - 1;
|
||||
powerpc_dyngen_helper::set_ctr(T2);
|
||||
if (BO_BRANCH_IF_CTR_ZERO(bo))
|
||||
ctr_ok = !T1;
|
||||
ctr_ok = !T2;
|
||||
else
|
||||
ctr_ok = T1;
|
||||
ctr_ok = T2;
|
||||
}
|
||||
|
||||
T0 = ctr_ok && cond_ok;
|
||||
T1 = ctr_ok && cond_ok;
|
||||
dyngen_barrier();
|
||||
}
|
||||
|
||||
@ -660,14 +651,14 @@ static inline void do_execute_branch_1(uint32 tpc)
|
||||
dyngen_barrier();
|
||||
}
|
||||
|
||||
void op_branch_1_A0(void)
|
||||
void op_branch_1_T0(void)
|
||||
{
|
||||
do_execute_branch_1<0>(A0);
|
||||
do_execute_branch_1<0>(T0);
|
||||
}
|
||||
|
||||
void op_branch_chain_1_A0(void)
|
||||
void op_branch_chain_1_T0(void)
|
||||
{
|
||||
do_execute_branch_1<1>(A0);
|
||||
do_execute_branch_1<1>(T0);
|
||||
}
|
||||
|
||||
void op_branch_1_im(void)
|
||||
@ -685,32 +676,32 @@ static inline void do_execute_branch_2(uint32 tpc, uint32 npc)
|
||||
{
|
||||
#ifdef DYNGEN_FAST_DISPATCH
|
||||
if (chain) {
|
||||
T1 = powerpc_dyngen_helper::spcflags().get();
|
||||
if (T0) {
|
||||
FAST_COMPARE_SPECFLAGS_DISPATCH(T1, __op_jmp0);
|
||||
A0 = tpc;
|
||||
T2 = powerpc_dyngen_helper::spcflags().get();
|
||||
if (T1) {
|
||||
FAST_COMPARE_SPECFLAGS_DISPATCH(T2, __op_jmp0);
|
||||
T0 = tpc;
|
||||
}
|
||||
else {
|
||||
FAST_COMPARE_SPECFLAGS_DISPATCH(T1, __op_jmp1);
|
||||
A0 = npc;
|
||||
FAST_COMPARE_SPECFLAGS_DISPATCH(T2, __op_jmp1);
|
||||
T0 = npc;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
A0 = T0 ? tpc : npc;
|
||||
powerpc_dyngen_helper::set_pc(A0);
|
||||
T0 = T1 ? tpc : npc;
|
||||
powerpc_dyngen_helper::set_pc(T0);
|
||||
dyngen_barrier();
|
||||
}
|
||||
|
||||
void op_branch_2_A0_im(void)
|
||||
void op_branch_2_T0_im(void)
|
||||
{
|
||||
do_execute_branch_2<0>(A0, PARAM1);
|
||||
do_execute_branch_2<0>(T0, PARAM1);
|
||||
}
|
||||
|
||||
void op_branch_chain_2_A0_im(void)
|
||||
void op_branch_chain_2_T0_im(void)
|
||||
{
|
||||
do_execute_branch_2<1>(A0, PARAM1);
|
||||
do_execute_branch_2<1>(T0, PARAM1);
|
||||
}
|
||||
|
||||
void op_branch_2_im_im(void)
|
||||
@ -1371,7 +1362,7 @@ void OPPROTO op_jump_next_A0(void)
|
||||
{
|
||||
// Make sure there is no pending interrupt request
|
||||
if (likely(powerpc_dyngen_helper::spcflags().empty())) {
|
||||
powerpc_block_info *bi = (powerpc_block_info *)reg_A0;
|
||||
powerpc_block_info *bi = (powerpc_block_info *)A0;
|
||||
uint32 pc = powerpc_dyngen_helper::get_pc();
|
||||
if (likely(bi->pc == pc) || likely((bi = powerpc_dyngen_helper::find_block(pc)) != NULL))
|
||||
goto *(bi->entry_point);
|
||||
@ -1447,17 +1438,16 @@ DEFINE_OP(31);
|
||||
* Load/store addresses to vector registers
|
||||
**/
|
||||
|
||||
#define reg_TD reg_A0
|
||||
#define DEFINE_OP(REG, N) \
|
||||
void OPPROTO op_load_ad_V##REG##_VR##N(void) \
|
||||
{ \
|
||||
reg_T##REG = (uintptr)&CPU->vr(N); \
|
||||
reg_V##REG = (uintptr)&CPU->vr(N); \
|
||||
}
|
||||
#define DEFINE_REG(N) \
|
||||
DEFINE_OP(D,N); \
|
||||
DEFINE_OP(0,N); \
|
||||
DEFINE_OP(1,N); \
|
||||
DEFINE_OP(2,N); \
|
||||
DEFINE_OP(2,N)
|
||||
|
||||
DEFINE_REG(0);
|
||||
DEFINE_REG(1);
|
||||
@ -1494,7 +1484,7 @@ DEFINE_REG(31);
|
||||
|
||||
#undef DEFINE_REG
|
||||
#undef DEFINE_OP
|
||||
#undef reg_TD
|
||||
#undef AD
|
||||
|
||||
void op_load_word_VD_T0(void)
|
||||
{
|
||||
|
@ -219,11 +219,9 @@ void powerpc_dyngen::gen_##OP##_##REG##_##REGT(int i) \
|
||||
}
|
||||
|
||||
// General purpose registers
|
||||
DEFINE_INSN(load, A0, GPR);
|
||||
DEFINE_INSN(load, T0, GPR);
|
||||
DEFINE_INSN(load, T1, GPR);
|
||||
DEFINE_INSN(load, T2, GPR);
|
||||
DEFINE_INSN(store, A0, GPR);
|
||||
DEFINE_INSN(store, T0, GPR);
|
||||
DEFINE_INSN(store, T1, GPR);
|
||||
DEFINE_INSN(store, T2, GPR);
|
||||
@ -249,12 +247,12 @@ DEFINE_INSN(store, T1, crb);
|
||||
|
||||
// Floating point load store
|
||||
#define DEFINE_OP(NAME, REG, TYPE) \
|
||||
void powerpc_dyngen::gen_##NAME##_##TYPE##_##REG##_A0_im(int32 offset) \
|
||||
void powerpc_dyngen::gen_##NAME##_##TYPE##_##REG##_T1_im(int32 offset) \
|
||||
{ \
|
||||
if (offset == 0) \
|
||||
gen_op_##NAME##_##TYPE##_##REG##_A0_0(); \
|
||||
gen_op_##NAME##_##TYPE##_##REG##_T1_0(); \
|
||||
else \
|
||||
gen_op_##NAME##_##TYPE##_##REG##_A0_im(offset); \
|
||||
gen_op_##NAME##_##TYPE##_##REG##_T1_im(offset); \
|
||||
}
|
||||
|
||||
DEFINE_OP(load, FD, double);
|
||||
@ -287,10 +285,8 @@ DEFINE_INSN(store, T0);
|
||||
|
||||
void powerpc_dyngen::gen_bc(int bo, int bi, uint32 tpc, uint32 npc, bool direct_chaining)
|
||||
{
|
||||
if (BO_CONDITIONAL_BRANCH(bo)) {
|
||||
gen_load_T0_CR();
|
||||
gen_and_32_T0_im(1 << (31 - bi));
|
||||
}
|
||||
if (BO_CONDITIONAL_BRANCH(bo))
|
||||
gen_load_T1_crb(bi);
|
||||
|
||||
switch (bo >> 1) {
|
||||
#define _(A,B,C,D) (((A) << 3)| ((B) << 2) | ((C) << 1) | (D))
|
||||
@ -324,9 +320,9 @@ void powerpc_dyngen::gen_bc(int bo, int bi, uint32 tpc, uint32 npc, bool direct_
|
||||
}
|
||||
else {
|
||||
if (direct_chaining)
|
||||
gen_op_branch_chain_2_A0_im(npc);
|
||||
gen_op_branch_chain_2_T0_im(npc);
|
||||
else
|
||||
gen_op_branch_2_A0_im(npc);
|
||||
gen_op_branch_2_T0_im(npc);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -339,9 +335,9 @@ void powerpc_dyngen::gen_bc(int bo, int bi, uint32 tpc, uint32 npc, bool direct_
|
||||
}
|
||||
else {
|
||||
if (direct_chaining)
|
||||
gen_op_branch_chain_1_A0();
|
||||
gen_op_branch_chain_1_T0();
|
||||
else
|
||||
gen_op_branch_1_A0();
|
||||
gen_op_branch_1_T0();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,10 @@ class powerpc_dyngen
|
||||
# include "ppc-dyngen-ops.hpp"
|
||||
#endif
|
||||
|
||||
#ifndef REG_T3
|
||||
uintptr reg_T3;
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
// Make rc_cache accessible to codegen helper
|
||||
@ -50,11 +54,9 @@ public:
|
||||
powerpc_dyngen(dyngen_cpu_base cpu, int cache_size = -1);
|
||||
|
||||
// Load/store registers
|
||||
void gen_load_A0_GPR(int i);
|
||||
void gen_load_T0_GPR(int i);
|
||||
void gen_load_T1_GPR(int i);
|
||||
void gen_load_T2_GPR(int i);
|
||||
void gen_store_A0_GPR(int i);
|
||||
void gen_store_T0_GPR(int i);
|
||||
void gen_store_T1_GPR(int i);
|
||||
void gen_store_T2_GPR(int i);
|
||||
@ -108,16 +110,14 @@ public:
|
||||
DEFINE_ALIAS(load_T0_PC,0);
|
||||
DEFINE_ALIAS(store_T0_PC,0);
|
||||
DEFINE_ALIAS(set_PC_im,1);
|
||||
DEFINE_ALIAS(set_PC_A0,0);
|
||||
DEFINE_ALIAS(set_PC_T0,0);
|
||||
DEFINE_ALIAS(inc_PC,1);
|
||||
DEFINE_ALIAS(load_T0_LR,0);
|
||||
DEFINE_ALIAS(store_T0_LR,0);
|
||||
DEFINE_ALIAS(load_T0_CTR,0);
|
||||
DEFINE_ALIAS(load_A0_CTR,0);
|
||||
DEFINE_ALIAS(load_T0_CTR_aligned,0);
|
||||
DEFINE_ALIAS(store_T0_CTR,0);
|
||||
DEFINE_ALIAS(store_T1_CTR,0);
|
||||
DEFINE_ALIAS(load_T1_PC,0);
|
||||
DEFINE_ALIAS(load_A0_LR,0);
|
||||
DEFINE_ALIAS(load_T0_LR_aligned,0);
|
||||
DEFINE_ALIAS(store_im_LR,1);
|
||||
|
||||
DEFINE_ALIAS(spcflags_init,1);
|
||||
@ -211,14 +211,14 @@ public:
|
||||
DEFINE_ALIAS(fnmsubs_FD_F0_F1_F2,0);
|
||||
|
||||
// Load/store floating point data
|
||||
DEFINE_ALIAS(load_double_FD_A0_T1,0);
|
||||
void gen_load_double_FD_A0_im(int32 offset);
|
||||
DEFINE_ALIAS(load_single_FD_A0_T1,0);
|
||||
void gen_load_single_FD_A0_im(int32 offset);
|
||||
DEFINE_ALIAS(store_double_F0_A0_T1,0);
|
||||
void gen_store_double_F0_A0_im(int32 offset);
|
||||
DEFINE_ALIAS(store_single_F0_A0_T1,0);
|
||||
void gen_store_single_F0_A0_im(int32 offset);
|
||||
DEFINE_ALIAS(load_double_FD_T1_T2,0);
|
||||
void gen_load_double_FD_T1_im(int32 offset);
|
||||
DEFINE_ALIAS(load_single_FD_T1_T2,0);
|
||||
void gen_load_single_FD_T1_im(int32 offset);
|
||||
DEFINE_ALIAS(store_double_F0_T1_T2,0);
|
||||
void gen_store_double_F0_T1_im(int32 offset);
|
||||
DEFINE_ALIAS(store_single_F0_T1_T2,0);
|
||||
void gen_store_single_F0_T1_im(int32 offset);
|
||||
|
||||
// Branch instructions
|
||||
void gen_bc(int bo, int bi, uint32 tpc, uint32 npc, bool direct_chaining);
|
||||
|
@ -288,43 +288,43 @@ powerpc_cpu::compile_block(uint32 entry_point)
|
||||
// Extract RZ operand
|
||||
const int rA = rA_field::extract(opcode);
|
||||
if (rA == 0 && !op.mem.do_update)
|
||||
dg.gen_mov_32_A0_im(0);
|
||||
dg.gen_mov_32_T1_im(0);
|
||||
else
|
||||
dg.gen_load_A0_GPR(rA);
|
||||
dg.gen_load_T1_GPR(rA);
|
||||
|
||||
// Extract index operand
|
||||
if (op.mem.do_indexed)
|
||||
dg.gen_load_T1_GPR(rB_field::extract(opcode));
|
||||
dg.gen_load_T2_GPR(rB_field::extract(opcode));
|
||||
|
||||
switch (op.mem.size) {
|
||||
case 1:
|
||||
if (op.mem.do_indexed)
|
||||
dg.gen_load_u8_T0_A0_T1();
|
||||
dg.gen_load_u8_T0_T1_T2();
|
||||
else
|
||||
dg.gen_load_u8_T0_A0_im(operand_D::get(this, opcode));
|
||||
dg.gen_load_u8_T0_T1_im(operand_D::get(this, opcode));
|
||||
break;
|
||||
case 2:
|
||||
if (op.mem.do_indexed) {
|
||||
if (op.mem.sign)
|
||||
dg.gen_load_s16_T0_A0_T1();
|
||||
dg.gen_load_s16_T0_T1_T2();
|
||||
else
|
||||
dg.gen_load_u16_T0_A0_T1();
|
||||
dg.gen_load_u16_T0_T1_T2();
|
||||
}
|
||||
else {
|
||||
const int32 offset = operand_D::get(this, opcode);
|
||||
if (op.mem.sign)
|
||||
dg.gen_load_s16_T0_A0_im(offset);
|
||||
dg.gen_load_s16_T0_T1_im(offset);
|
||||
else
|
||||
dg.gen_load_u16_T0_A0_im(offset);
|
||||
dg.gen_load_u16_T0_T1_im(offset);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if (op.mem.do_indexed) {
|
||||
dg.gen_load_u32_T0_A0_T1();
|
||||
dg.gen_load_u32_T0_T1_T2();
|
||||
}
|
||||
else {
|
||||
const int32 offset = operand_D::get(this, opcode);
|
||||
dg.gen_load_u32_T0_A0_im(offset);
|
||||
dg.gen_load_u32_T0_T1_im(offset);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -335,10 +335,10 @@ powerpc_cpu::compile_block(uint32 entry_point)
|
||||
// Update RA
|
||||
if (op.mem.do_update) {
|
||||
if (op.mem.do_indexed)
|
||||
dg.gen_add_32_A0_T1();
|
||||
dg.gen_add_32_T1_T2();
|
||||
else
|
||||
dg.gen_add_32_A0_im(operand_D::get(this, opcode));
|
||||
dg.gen_store_A0_GPR(rA);
|
||||
dg.gen_add_32_T1_im(operand_D::get(this, opcode));
|
||||
dg.gen_store_T1_GPR(rA);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -407,13 +407,13 @@ powerpc_cpu::compile_block(uint32 entry_point)
|
||||
// Extract RZ operand
|
||||
const int rA = rA_field::extract(opcode);
|
||||
if (rA == 0 && !op.mem.do_update)
|
||||
dg.gen_mov_32_A0_im(0);
|
||||
dg.gen_mov_32_T1_im(0);
|
||||
else
|
||||
dg.gen_load_A0_GPR(rA);
|
||||
dg.gen_load_T1_GPR(rA);
|
||||
|
||||
// Extract index operand
|
||||
if (op.mem.do_indexed)
|
||||
dg.gen_load_T1_GPR(rB_field::extract(opcode));
|
||||
dg.gen_load_T2_GPR(rB_field::extract(opcode));
|
||||
|
||||
// Load register to commit to memory
|
||||
dg.gen_load_T0_GPR(rS_field::extract(opcode));
|
||||
@ -421,31 +421,31 @@ powerpc_cpu::compile_block(uint32 entry_point)
|
||||
switch (op.mem.size) {
|
||||
case 1:
|
||||
if (op.mem.do_indexed)
|
||||
dg.gen_store_8_T0_A0_T1();
|
||||
dg.gen_store_8_T0_T1_T2();
|
||||
else
|
||||
dg.gen_store_8_T0_A0_im(operand_D::get(this, opcode));
|
||||
dg.gen_store_8_T0_T1_im(operand_D::get(this, opcode));
|
||||
break;
|
||||
case 2:
|
||||
if (op.mem.do_indexed)
|
||||
dg.gen_store_16_T0_A0_T1();
|
||||
dg.gen_store_16_T0_T1_T2();
|
||||
else
|
||||
dg.gen_store_16_T0_A0_im(operand_D::get(this, opcode));
|
||||
dg.gen_store_16_T0_T1_im(operand_D::get(this, opcode));
|
||||
break;
|
||||
case 4:
|
||||
if (op.mem.do_indexed)
|
||||
dg.gen_store_32_T0_A0_T1();
|
||||
dg.gen_store_32_T0_T1_T2();
|
||||
else
|
||||
dg.gen_store_32_T0_A0_im(operand_D::get(this, opcode));
|
||||
dg.gen_store_32_T0_T1_im(operand_D::get(this, opcode));
|
||||
break;
|
||||
}
|
||||
|
||||
// Update RA
|
||||
if (op.mem.do_update) {
|
||||
if (op.mem.do_indexed)
|
||||
dg.gen_add_32_A0_T1();
|
||||
dg.gen_add_32_T1_T2();
|
||||
else
|
||||
dg.gen_add_32_A0_im(operand_D::get(this, opcode));
|
||||
dg.gen_store_A0_GPR(rA);
|
||||
dg.gen_add_32_T1_im(operand_D::get(this, opcode));
|
||||
dg.gen_store_T1_GPR(rA);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -500,10 +500,10 @@ powerpc_cpu::compile_block(uint32 entry_point)
|
||||
break;
|
||||
}
|
||||
case PPC_I(BCCTR): // Branch Conditional to Count Register
|
||||
dg.gen_load_A0_CTR();
|
||||
dg.gen_load_T0_CTR_aligned();
|
||||
goto do_branch;
|
||||
case PPC_I(BCLR): // Branch Conditional to Link Register
|
||||
dg.gen_load_A0_LR();
|
||||
dg.gen_load_T0_LR_aligned();
|
||||
goto do_branch;
|
||||
{
|
||||
do_branch:
|
||||
@ -1156,26 +1156,26 @@ powerpc_cpu::compile_block(uint32 entry_point)
|
||||
// Extract RZ operand
|
||||
const int rA = rA_field::extract(opcode);
|
||||
if (rA == 0 && !op.mem.do_update)
|
||||
dg.gen_mov_32_A0_im(0);
|
||||
dg.gen_mov_32_T1_im(0);
|
||||
else
|
||||
dg.gen_load_A0_GPR(rA);
|
||||
dg.gen_load_T1_GPR(rA);
|
||||
|
||||
// Extract index operand
|
||||
if (op.mem.do_indexed)
|
||||
dg.gen_load_T1_GPR(rB_field::extract(opcode));
|
||||
dg.gen_load_T2_GPR(rB_field::extract(opcode));
|
||||
|
||||
// Load floating point data
|
||||
if (op.mem.size == 8) {
|
||||
if (op.mem.do_indexed)
|
||||
dg.gen_load_double_FD_A0_T1();
|
||||
dg.gen_load_double_FD_T1_T2();
|
||||
else
|
||||
dg.gen_load_double_FD_A0_im(operand_D::get(this, opcode));
|
||||
dg.gen_load_double_FD_T1_im(operand_D::get(this, opcode));
|
||||
}
|
||||
else {
|
||||
if (op.mem.do_indexed)
|
||||
dg.gen_load_single_FD_A0_T1();
|
||||
dg.gen_load_single_FD_T1_T2();
|
||||
else
|
||||
dg.gen_load_single_FD_A0_im(operand_D::get(this, opcode));
|
||||
dg.gen_load_single_FD_T1_im(operand_D::get(this, opcode));
|
||||
}
|
||||
|
||||
// Commit result
|
||||
@ -1184,10 +1184,10 @@ powerpc_cpu::compile_block(uint32 entry_point)
|
||||
// Update RA
|
||||
if (op.mem.do_update) {
|
||||
if (op.mem.do_indexed)
|
||||
dg.gen_add_32_A0_T1();
|
||||
dg.gen_add_32_T1_T2();
|
||||
else
|
||||
dg.gen_add_32_A0_im(operand_D::get(this, opcode));
|
||||
dg.gen_store_A0_GPR(rA);
|
||||
dg.gen_add_32_T1_im(operand_D::get(this, opcode));
|
||||
dg.gen_store_T1_GPR(rA);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1236,13 +1236,13 @@ powerpc_cpu::compile_block(uint32 entry_point)
|
||||
// Extract RZ operand
|
||||
const int rA = rA_field::extract(opcode);
|
||||
if (rA == 0 && !op.mem.do_update)
|
||||
dg.gen_mov_32_A0_im(0);
|
||||
dg.gen_mov_32_T1_im(0);
|
||||
else
|
||||
dg.gen_load_A0_GPR(rA);
|
||||
dg.gen_load_T1_GPR(rA);
|
||||
|
||||
// Extract index operand
|
||||
if (op.mem.do_indexed)
|
||||
dg.gen_load_T1_GPR(rB_field::extract(opcode));
|
||||
dg.gen_load_T2_GPR(rB_field::extract(opcode));
|
||||
|
||||
// Load register to commit to memory
|
||||
dg.gen_load_F0_FPR(frS_field::extract(opcode));
|
||||
@ -1250,24 +1250,24 @@ powerpc_cpu::compile_block(uint32 entry_point)
|
||||
// Store floating point data
|
||||
if (op.mem.size == 8) {
|
||||
if (op.mem.do_indexed)
|
||||
dg.gen_store_double_F0_A0_T1();
|
||||
dg.gen_store_double_F0_T1_T2();
|
||||
else
|
||||
dg.gen_store_double_F0_A0_im(operand_D::get(this, opcode));
|
||||
dg.gen_store_double_F0_T1_im(operand_D::get(this, opcode));
|
||||
}
|
||||
else {
|
||||
if (op.mem.do_indexed)
|
||||
dg.gen_store_single_F0_A0_T1();
|
||||
dg.gen_store_single_F0_T1_T2();
|
||||
else
|
||||
dg.gen_store_single_F0_A0_im(operand_D::get(this, opcode));
|
||||
dg.gen_store_single_F0_T1_im(operand_D::get(this, opcode));
|
||||
}
|
||||
|
||||
// Update RA
|
||||
if (op.mem.do_update) {
|
||||
if (op.mem.do_indexed)
|
||||
dg.gen_add_32_A0_T1();
|
||||
dg.gen_add_32_T1_T2();
|
||||
else
|
||||
dg.gen_add_32_A0_im(operand_D::get(this, opcode));
|
||||
dg.gen_store_A0_GPR(rA);
|
||||
dg.gen_add_32_T1_im(operand_D::get(this, opcode));
|
||||
dg.gen_store_T1_GPR(rA);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1555,8 +1555,8 @@ powerpc_cpu::compile_block(uint32 entry_point)
|
||||
for (int i = 0; i < block_info::MAX_TARGETS; i++) {
|
||||
if (bi->li[i].jmp_pc != block_info::INVALID_PC) {
|
||||
uint8 *p = dg.gen_align(16);
|
||||
dg.gen_mov_ad_T0_im(((uintptr)bi) | i);
|
||||
dg.gen_invoke_CPU_T0_ret_A0(func);
|
||||
dg.gen_mov_ad_A0_im(((uintptr)bi) | i);
|
||||
dg.gen_invoke_CPU_A0_ret_A0(func);
|
||||
dg.gen_jmp_A0();
|
||||
assert(dg.jmp_addr[i] != NULL);
|
||||
bi->li[i].jmp_addr = dg.jmp_addr[i];
|
||||
|
Loading…
x
Reference in New Issue
Block a user