mirror of
https://github.com/kanjitalk755/macemu.git
synced 2025-01-27 23:32:52 +00:00
Cleanups. Rewrite gen_bc() so that no push/pop could be inserted thus
causing crahes with some compilers. However, that's slower.
This commit is contained in:
parent
301d3a3192
commit
f574a5df05
@ -600,90 +600,6 @@ void OPPROTO op_spcflags_clear(void)
|
||||
* Branch instructions
|
||||
**/
|
||||
|
||||
void OPPROTO op_decrement_ctr_T0(void)
|
||||
{
|
||||
T0 = powerpc_dyngen_helper::get_ctr() - 1;
|
||||
powerpc_dyngen_helper::set_ctr(T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_branch_A0_if_T0(void)
|
||||
{
|
||||
if (T0)
|
||||
powerpc_dyngen_helper::set_pc(A0);
|
||||
else
|
||||
powerpc_dyngen_helper::set_pc(PARAM1);
|
||||
dyngen_barrier();
|
||||
}
|
||||
|
||||
void OPPROTO op_branch_A0_if_not_T0(void)
|
||||
{
|
||||
if (!T0)
|
||||
powerpc_dyngen_helper::set_pc(A0);
|
||||
else
|
||||
powerpc_dyngen_helper::set_pc(PARAM1);
|
||||
dyngen_barrier();
|
||||
}
|
||||
|
||||
template< class branch_cond, class ctr_cond >
|
||||
static inline void do_execute_branch(uint32 tpc, uint32 npc)
|
||||
{
|
||||
if (branch_cond::test() && ctr_cond::test())
|
||||
powerpc_dyngen_helper::set_pc(tpc);
|
||||
else
|
||||
powerpc_dyngen_helper::set_pc(npc);
|
||||
dyngen_barrier();
|
||||
}
|
||||
|
||||
struct branch_if_T0_condition {
|
||||
static inline bool test() {
|
||||
return T0 != 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct branch_if_not_T0_condition {
|
||||
static inline bool test() {
|
||||
return T0 == 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct ctr_0x_condition {
|
||||
static inline bool test() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct ctr_10_condition {
|
||||
static inline bool test() {
|
||||
uint32 ctr = powerpc_dyngen_helper::get_ctr() - 1;
|
||||
powerpc_dyngen_helper::set_ctr(ctr);
|
||||
return ctr != 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct ctr_11_condition {
|
||||
static inline bool test() {
|
||||
uint32 ctr = powerpc_dyngen_helper::get_ctr() - 1;
|
||||
powerpc_dyngen_helper::set_ctr(ctr);
|
||||
return ctr == 0;
|
||||
}
|
||||
};
|
||||
|
||||
#define DEFINE_OP_CTR(COND,CTR) \
|
||||
void OPPROTO op_##COND##_ctr_##CTR(void) \
|
||||
{ \
|
||||
do_execute_branch<COND##_condition, ctr_##CTR##_condition>(A0, PARAM1); \
|
||||
}
|
||||
#define DEFINE_OP(COND) \
|
||||
DEFINE_OP_CTR(COND,0x); \
|
||||
DEFINE_OP_CTR(COND,10); \
|
||||
DEFINE_OP_CTR(COND,11);
|
||||
|
||||
DEFINE_OP(branch_if_T0);
|
||||
DEFINE_OP(branch_if_not_T0);
|
||||
|
||||
#undef DEFINE_OP
|
||||
#undef DEFINE_OP_CTR
|
||||
|
||||
#ifdef DYNGEN_FAST_DISPATCH
|
||||
#if defined(__x86_64__)
|
||||
#define FAST_COMPARE_SPECFLAGS_DISPATCH(SPCFLAGS, TARGET) \
|
||||
@ -695,8 +611,8 @@ DEFINE_OP(branch_if_not_T0);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
template< int bo, bool chain >
|
||||
static inline void do_execute_branch_bo(uint32 tpc, uint32 npc)
|
||||
template< int bo >
|
||||
static inline void do_prep_branch_bo(void)
|
||||
{
|
||||
bool ctr_ok = true;
|
||||
bool cond_ok = true;
|
||||
@ -712,40 +628,21 @@ static inline void do_execute_branch_bo(uint32 tpc, uint32 npc)
|
||||
T1 = powerpc_dyngen_helper::get_ctr() - 1;
|
||||
powerpc_dyngen_helper::set_ctr(T1);
|
||||
if (BO_BRANCH_IF_CTR_ZERO(bo))
|
||||
ctr_ok = T1 == 0;
|
||||
ctr_ok = !T1;
|
||||
else
|
||||
ctr_ok = T1 != 0;
|
||||
ctr_ok = T1;
|
||||
}
|
||||
|
||||
#ifdef DYNGEN_FAST_DISPATCH
|
||||
if (chain) {
|
||||
T1 = powerpc_dyngen_helper::spcflags().get();
|
||||
if (ctr_ok && cond_ok) {
|
||||
FAST_COMPARE_SPECFLAGS_DISPATCH(T1, __op_jmp0);
|
||||
T0 = tpc;
|
||||
}
|
||||
else {
|
||||
FAST_COMPARE_SPECFLAGS_DISPATCH(T1, __op_jmp1);
|
||||
T0 = npc;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
T0 = (ctr_ok && cond_ok) ? tpc : npc;
|
||||
powerpc_dyngen_helper::set_pc(T0);
|
||||
T0 = ctr_ok && cond_ok;
|
||||
dyngen_barrier();
|
||||
}
|
||||
|
||||
#define BO(A,B,C,D) (((A) << 4)| ((B) << 3) | ((C) << 2) | ((D) << 1))
|
||||
#define DEFINE_OP1(BO_SUFFIX, BO_VALUE, CHAIN) \
|
||||
void OPPROTO op_branch_A0_bo_##BO_SUFFIX##_##CHAIN(void) \
|
||||
{ \
|
||||
do_execute_branch_bo<BO BO_VALUE, CHAIN>(A0, PARAM1); \
|
||||
#define DEFINE_OP(BO_SUFFIX, BO_VALUE) \
|
||||
void OPPROTO op_prep_branch_bo_##BO_SUFFIX(void) \
|
||||
{ \
|
||||
do_prep_branch_bo<BO BO_VALUE>(); \
|
||||
}
|
||||
#define DEFINE_OP(BO_SUFFIX, BO_VALUE) \
|
||||
DEFINE_OP1(BO_SUFFIX, BO_VALUE, 0) \
|
||||
DEFINE_OP1(BO_SUFFIX, BO_VALUE, 1)
|
||||
|
||||
DEFINE_OP(0000,(0,0,0,0));
|
||||
DEFINE_OP(0001,(0,0,0,1));
|
||||
@ -761,6 +658,80 @@ DEFINE_OP(1x1x,(1,0,1,0));
|
||||
#undef DEFINE_OP
|
||||
#undef BO
|
||||
|
||||
template< bool chain >
|
||||
static inline void do_execute_branch_1(uint32 tpc)
|
||||
{
|
||||
#ifdef DYNGEN_FAST_DISPATCH
|
||||
if (chain)
|
||||
FAST_COMPARE_SPECFLAGS_DISPATCH(powerpc_dyngen_helper::spcflags().get(), __op_jmp0);
|
||||
#endif
|
||||
powerpc_dyngen_helper::set_pc(tpc);
|
||||
dyngen_barrier();
|
||||
}
|
||||
|
||||
void op_branch_1_A0(void)
|
||||
{
|
||||
do_execute_branch_1<0>(A0);
|
||||
}
|
||||
|
||||
void op_branch_chain_1_A0(void)
|
||||
{
|
||||
do_execute_branch_1<1>(A0);
|
||||
}
|
||||
|
||||
void op_branch_1_im(void)
|
||||
{
|
||||
do_execute_branch_1<0>(PARAM1);
|
||||
}
|
||||
|
||||
void op_branch_chain_1_im(void)
|
||||
{
|
||||
do_execute_branch_1<1>(PARAM1);
|
||||
}
|
||||
|
||||
template< bool chain >
|
||||
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;
|
||||
}
|
||||
else {
|
||||
FAST_COMPARE_SPECFLAGS_DISPATCH(T1, __op_jmp1);
|
||||
A0 = npc;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
A0 = T0 ? tpc : npc;
|
||||
powerpc_dyngen_helper::set_pc(A0);
|
||||
dyngen_barrier();
|
||||
}
|
||||
|
||||
void op_branch_2_A0_im(void)
|
||||
{
|
||||
do_execute_branch_2<0>(A0, PARAM1);
|
||||
}
|
||||
|
||||
void op_branch_chain_2_A0_im(void)
|
||||
{
|
||||
do_execute_branch_2<1>(A0, PARAM1);
|
||||
}
|
||||
|
||||
void op_branch_2_im_im(void)
|
||||
{
|
||||
do_execute_branch_2<0>(PARAM1, PARAM2);
|
||||
}
|
||||
|
||||
void op_branch_chain_2_im_im(void)
|
||||
{
|
||||
do_execute_branch_2<1>(PARAM1, PARAM2);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compare & Record instructions
|
||||
|
@ -260,91 +260,65 @@ DEFINE_INSN(store, T0);
|
||||
|
||||
#undef DEFINE_INSN
|
||||
|
||||
void powerpc_dyngen::gen_bc_A0(int bo, int bi, uint32 npc, bool direct_chaining)
|
||||
void powerpc_dyngen::gen_bc(int bo, int bi, uint32 tpc, uint32 npc, bool direct_chaining)
|
||||
{
|
||||
#if 1
|
||||
if (BO_CONDITIONAL_BRANCH(bo)) {
|
||||
gen_load_T0_CR();
|
||||
gen_and_32_T0_im(1 << (31 - bi));
|
||||
}
|
||||
if (direct_chaining) {
|
||||
|
||||
switch (bo >> 1) {
|
||||
#define _(A,B,C,D) (((A) << 3)| ((B) << 2) | ((C) << 1) | (D))
|
||||
case _(0,0,0,0): gen_op_branch_A0_bo_0000_1(npc); break;
|
||||
case _(0,0,0,1): gen_op_branch_A0_bo_0001_1(npc); break;
|
||||
case _(0,0,0,0): gen_op_prep_branch_bo_0000(); break;
|
||||
case _(0,0,0,1): gen_op_prep_branch_bo_0001(); break;
|
||||
case _(0,0,1,0):
|
||||
case _(0,0,1,1): gen_op_branch_A0_bo_001x_1(npc); break;
|
||||
case _(0,1,0,0): gen_op_branch_A0_bo_0100_1(npc); break;
|
||||
case _(0,1,0,1): gen_op_branch_A0_bo_0101_1(npc); break;
|
||||
case _(0,0,1,1): gen_op_prep_branch_bo_001x(); break;
|
||||
case _(0,1,0,0): gen_op_prep_branch_bo_0100(); break;
|
||||
case _(0,1,0,1): gen_op_prep_branch_bo_0101(); break;
|
||||
case _(0,1,1,0):
|
||||
case _(0,1,1,1): gen_op_branch_A0_bo_011x_1(npc); break;
|
||||
case _(0,1,1,1): gen_op_prep_branch_bo_011x(); break;
|
||||
case _(1,0,0,0):
|
||||
case _(1,1,0,0): gen_op_branch_A0_bo_1x00_1(npc); break;
|
||||
case _(1,1,0,0): gen_op_prep_branch_bo_1x00(); break;
|
||||
case _(1,0,0,1):
|
||||
case _(1,1,0,1): gen_op_branch_A0_bo_1x01_1(npc); break;
|
||||
case _(1,1,0,1): gen_op_prep_branch_bo_1x01(); break;
|
||||
case _(1,0,1,0):
|
||||
case _(1,0,1,1):
|
||||
case _(1,1,1,0):
|
||||
case _(1,1,1,1): gen_op_branch_A0_bo_1x1x_1(); break;
|
||||
case _(1,1,1,1): gen_op_prep_branch_bo_1x1x(); break;
|
||||
#undef _
|
||||
default: abort();
|
||||
}
|
||||
} else {
|
||||
switch (bo >> 1) {
|
||||
#define _(A,B,C,D) (((A) << 3)| ((B) << 2) | ((C) << 1) | (D))
|
||||
case _(0,0,0,0): gen_op_branch_A0_bo_0000_0(npc); break;
|
||||
case _(0,0,0,1): gen_op_branch_A0_bo_0001_0(npc); break;
|
||||
case _(0,0,1,0):
|
||||
case _(0,0,1,1): gen_op_branch_A0_bo_001x_0(npc); break;
|
||||
case _(0,1,0,0): gen_op_branch_A0_bo_0100_0(npc); break;
|
||||
case _(0,1,0,1): gen_op_branch_A0_bo_0101_0(npc); break;
|
||||
case _(0,1,1,0):
|
||||
case _(0,1,1,1): gen_op_branch_A0_bo_011x_0(npc); break;
|
||||
case _(1,0,0,0):
|
||||
case _(1,1,0,0): gen_op_branch_A0_bo_1x00_0(npc); break;
|
||||
case _(1,0,0,1):
|
||||
case _(1,1,0,1): gen_op_branch_A0_bo_1x01_0(npc); break;
|
||||
case _(1,0,1,0):
|
||||
case _(1,0,1,1):
|
||||
case _(1,1,1,0):
|
||||
case _(1,1,1,1): gen_op_branch_A0_bo_1x1x_0(); break;
|
||||
#undef _
|
||||
default: abort();
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (BO_CONDITIONAL_BRANCH(bo)) {
|
||||
gen_load_T0_CR();
|
||||
gen_and_32_T0_im(1 << (31 - bi));
|
||||
const int n = (bo >> 1) & 7;
|
||||
switch (n) {
|
||||
#define _(TRUE,DCTR,CTR0) (((TRUE) ? 4 : 0) | ((DCTR) ? 0 : 2) | ((CTR0) ? 1 : 0))
|
||||
case _(0,0,0): gen_op_branch_if_not_T0_ctr_0x(npc); break;
|
||||
case _(0,0,1): gen_op_branch_if_not_T0_ctr_0x(npc); break;
|
||||
case _(0,1,0): gen_op_branch_if_not_T0_ctr_10(npc); break;
|
||||
case _(0,1,1): gen_op_branch_if_not_T0_ctr_11(npc); break;
|
||||
case _(1,0,0): gen_op_branch_if_T0_ctr_0x(npc); break;
|
||||
case _(1,0,1): gen_op_branch_if_T0_ctr_0x(npc); break;
|
||||
case _(1,1,0): gen_op_branch_if_T0_ctr_10(npc); break;
|
||||
case _(1,1,1): gen_op_branch_if_T0_ctr_11(npc); break;
|
||||
#undef _
|
||||
default: abort();
|
||||
|
||||
if (BO_CONDITIONAL_BRANCH(bo) || BO_DECREMENT_CTR(bo)) {
|
||||
// two-way branches
|
||||
if (tpc != 0xffffffff) {
|
||||
if (direct_chaining)
|
||||
gen_op_branch_chain_2_im_im(tpc, npc);
|
||||
else
|
||||
gen_op_branch_2_im_im(tpc, npc);
|
||||
}
|
||||
else {
|
||||
if (direct_chaining)
|
||||
gen_op_branch_chain_2_A0_im(npc);
|
||||
else
|
||||
gen_op_branch_2_A0_im(npc);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (BO_DECREMENT_CTR(bo)) {
|
||||
gen_decrement_ctr_T0();
|
||||
if (BO_BRANCH_IF_CTR_ZERO(bo))
|
||||
gen_branch_A0_if_not_T0(npc);
|
||||
// one-way branches
|
||||
if (tpc != 0xffffffff) {
|
||||
if (direct_chaining)
|
||||
gen_op_branch_chain_1_im(tpc);
|
||||
else
|
||||
gen_branch_A0_if_T0(npc);
|
||||
gen_op_branch_1_im(tpc);
|
||||
}
|
||||
else {
|
||||
// Branch always
|
||||
gen_set_PC_A0();
|
||||
if (direct_chaining)
|
||||
gen_op_branch_chain_1_A0();
|
||||
else
|
||||
gen_op_branch_1_A0();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -125,9 +125,6 @@ public:
|
||||
DEFINE_ALIAS(spcflags_clear,1);
|
||||
|
||||
// Control Flow
|
||||
DEFINE_ALIAS(decrement_ctr_T0,0);
|
||||
DEFINE_ALIAS(branch_A0_if_T0,1);
|
||||
DEFINE_ALIAS(branch_A0_if_not_T0,1);
|
||||
DEFINE_ALIAS(jump_next_A0,0);
|
||||
|
||||
// Compare & Record instructions
|
||||
@ -224,7 +221,7 @@ public:
|
||||
void gen_store_single_F0_A0_im(int32 offset);
|
||||
|
||||
// Branch instructions
|
||||
void gen_bc_A0(int bo, int bi, uint32 npc, bool direct_chaining);
|
||||
void gen_bc(int bo, int bi, uint32 tpc, uint32 npc, bool direct_chaining);
|
||||
|
||||
// Vector instructions
|
||||
void gen_load_ad_VD_VR(int i);
|
||||
|
@ -479,9 +479,9 @@ powerpc_cpu::compile_block(uint32 entry_point)
|
||||
}
|
||||
#endif
|
||||
const uint32 tpc = ((AA_field::test(opcode) ? 0 : dpc) + operand_BD::get(this, opcode)) & -4;
|
||||
const uint32 npc = dpc + 4;
|
||||
#if DYNGEN_DIRECT_BLOCK_CHAINING
|
||||
// Use direct block chaining for in-page jumps or jumps to ROM area
|
||||
const uint32 npc = dpc + 4;
|
||||
if (direct_chaining_possible(bi->pc, tpc)) {
|
||||
use_direct_block_chaining = true;
|
||||
bi->jmp_pc[0] = tpc;
|
||||
@ -490,8 +490,12 @@ powerpc_cpu::compile_block(uint32 entry_point)
|
||||
bi->jmp_pc[1] = npc;
|
||||
}
|
||||
#endif
|
||||
dg.gen_mov_32_A0_im(tpc);
|
||||
goto do_branch;
|
||||
|
||||
if (LK_field::test(opcode))
|
||||
dg.gen_store_im_LR(npc);
|
||||
|
||||
dg.gen_bc(bo, BI_field::extract(opcode), tpc, npc, use_direct_block_chaining);
|
||||
break;
|
||||
}
|
||||
case PPC_I(BCCTR): // Branch Conditional to Count Register
|
||||
dg.gen_load_A0_CTR();
|
||||
@ -508,7 +512,7 @@ powerpc_cpu::compile_block(uint32 entry_point)
|
||||
if (LK_field::test(opcode))
|
||||
dg.gen_store_im_LR(npc);
|
||||
|
||||
dg.gen_bc_A0(bo, bi, npc, use_direct_block_chaining);
|
||||
dg.gen_bc(bo, bi, (uint32)-1, npc, use_direct_block_chaining);
|
||||
break;
|
||||
}
|
||||
case PPC_I(B): // Branch
|
||||
@ -546,10 +550,9 @@ powerpc_cpu::compile_block(uint32 entry_point)
|
||||
bi->jmp_pc[0] = tpc;
|
||||
}
|
||||
#endif
|
||||
dg.gen_mov_32_A0_im(tpc);
|
||||
|
||||
// BO field is built so that we always branch to A0
|
||||
dg.gen_bc_A0(BO_MAKE(0,0,0,0), 0, 0, use_direct_block_chaining);
|
||||
// BO field is built so that we always branch to pc
|
||||
dg.gen_bc(BO_MAKE(0,0,0,0), 0, tpc, 0, use_direct_block_chaining);
|
||||
break;
|
||||
}
|
||||
case PPC_I(CMP): // Compare
|
||||
|
Loading…
x
Reference in New Issue
Block a user