Fix decrement the CTR, then branch conditional if decremented CTR != 0.

Remove CR cache for now. Remove BC & MODE_68K hacks for SheepShaver,
that was a colateral damage of wrong branch emulation of the former.
This commit is contained in:
gbeauche 2003-12-02 22:49:18 +00:00
parent dc79320904
commit 04214f3820
5 changed files with 222 additions and 349 deletions

View File

@ -216,7 +216,11 @@ public:
// Initialization & finalization // Initialization & finalization
void initialize(); void initialize();
#ifdef SHEEPSHAVER
powerpc_cpu(); powerpc_cpu();
#else
powerpc_cpu(task_struct *parent_task);
#endif
~powerpc_cpu(); ~powerpc_cpu();
// Handle flight recorder // Handle flight recorder

View File

@ -36,7 +36,6 @@ register struct powerpc_cpu *CPU asm(REG_CPU);
register uint32 A0 asm(REG_A0); register uint32 A0 asm(REG_A0);
register uint32 T0 asm(REG_T0); register uint32 T0 asm(REG_T0);
register uint32 T1 asm(REG_T1); register uint32 T1 asm(REG_T1);
register uint32 RC asm(REG_T2);
// Semantic action templates // Semantic action templates
#define DYNGEN_OPS #define DYNGEN_OPS
@ -134,25 +133,16 @@ void OPPROTO op_store_T0_CR(void)
powerpc_dyngen_helper::set_cr(T0); powerpc_dyngen_helper::set_cr(T0);
} }
void OPPROTO op_load_T0_XER(void)
{
T0 = powerpc_dyngen_helper::get_xer();
}
void OPPROTO op_store_T0_XER(void)
{
powerpc_dyngen_helper::set_xer(T0);
}
#define DEFINE_OP(REG, N) \ #define DEFINE_OP(REG, N) \
void OPPROTO op_load_##REG##_crb##N(void) \ void OPPROTO op_load_##REG##_crb##N(void) \
{ \ { \
REG = bit_field<N,N>::extract(powerpc_dyngen_helper::get_cr()); \ const uint32 cr = powerpc_dyngen_helper::get_cr(); \
REG = (cr >> (31 - N)) & 1; \
} \ } \
void OPPROTO op_store_##REG##_crb##N(void) \ void OPPROTO op_store_##REG##_crb##N(void) \
{ \ { \
uint32 cr = powerpc_dyngen_helper::get_cr(); \ uint32 cr = powerpc_dyngen_helper::get_cr() & ~(1 << (31 - N)); \
bit_field<N,N>::insert(cr, REG); \ cr |= ((REG & 1) << (31 - N)); \
powerpc_dyngen_helper::set_cr(cr); \ powerpc_dyngen_helper::set_cr(cr); \
} }
#define DEFINE_REG(N) \ #define DEFINE_REG(N) \
@ -195,48 +185,49 @@ DEFINE_REG(31);
#undef DEFINE_REG #undef DEFINE_REG
#undef DEFINE_OP #undef DEFINE_OP
#define DEFINE_OP(CRF, REG) \ #define DEFINE_OP(CRF, REG) \
void OPPROTO op_load_##REG##_cr##CRF(void) \ void OPPROTO op_load_##REG##_cr##CRF(void) \
{ \ { \
REG = powerpc_dyngen_helper::cr().get(CRF); \ REG = powerpc_dyngen_helper::cr().get(CRF); \
} \ } \
void OPPROTO op_store_##REG##_cr##CRF(void) \ void OPPROTO op_store_##REG##_cr##CRF(void) \
{ \ { \
powerpc_dyngen_helper::cr().set(CRF, REG); \ powerpc_dyngen_helper::cr().set(CRF, REG); \
} \
void OPPROTO op_commit_so_cache_cr##CRF(void) \
{ \
uint32 cr = powerpc_dyngen_helper::get_cr(); \
const uint32 cr_mask = CR_SO_field<CRF>::mask(); \
cr = (cr & ~cr_mask) | ((RC << (28 - 4 * CRF)) & cr_mask); \
powerpc_dyngen_helper::set_cr(cr); \
} \
void OPPROTO op_commit_rc_cache_cr##CRF(void) \
{ \
uint32 cr = powerpc_dyngen_helper::get_cr(); \
const uint32 cr_mask = (CR_LT_field<CRF>::mask() | \
CR_GT_field<CRF>::mask() | \
CR_EQ_field<CRF>::mask()); \
cr = (cr & ~cr_mask) | ((RC << (28 - 4 * CRF)) & cr_mask); \
powerpc_dyngen_helper::set_cr(cr); \
} }
DEFINE_OP(0, RC); DEFINE_OP(0, T0);
DEFINE_OP(1, RC); DEFINE_OP(1, T0);
DEFINE_OP(2, RC); DEFINE_OP(2, T0);
DEFINE_OP(3, RC); DEFINE_OP(3, T0);
DEFINE_OP(4, RC); DEFINE_OP(4, T0);
DEFINE_OP(5, RC); DEFINE_OP(5, T0);
DEFINE_OP(6, RC); DEFINE_OP(6, T0);
DEFINE_OP(7, RC); DEFINE_OP(7, T0);
#undef DEFINE_OP #undef DEFINE_OP
void OPPROTO op_mtcrf_T0_im(void)
{
const uint32 mask = PARAM1;
const uint32 cr = powerpc_dyngen_helper::get_cr();
powerpc_dyngen_helper::set_cr((cr & ~mask) | (T0 & mask));
}
/** /**
* Special purpose registers * Special purpose registers
**/ **/
void OPPROTO op_load_T0_XER(void)
{
T0 = powerpc_dyngen_helper::get_xer();
}
void OPPROTO op_store_T0_XER(void)
{
powerpc_dyngen_helper::set_xer(T0);
}
void OPPROTO op_load_T0_PC(void) void OPPROTO op_load_T0_PC(void)
{ {
T0 = powerpc_dyngen_helper::get_pc(); T0 = powerpc_dyngen_helper::get_pc();
@ -346,36 +337,18 @@ static inline void do_execute_branch(uint32 tpc, uint32 npc)
dyngen_barrier(); dyngen_barrier();
} }
template< int crb > struct branch_if_T0_condition {
struct RC_comparator {
static inline bool test() { static inline bool test() {
return (RC & crb); return T0 != 0;
} }
}; };
template< bool br_true, class comparator > struct branch_if_not_T0_condition {
struct bool_condition {
static inline bool test() { static inline bool test() {
return comparator::test(); return T0 == 0;
} }
}; };
template< class comparator >
struct bool_condition< false, comparator > {
static inline bool test() {
return !comparator::test();
}
};
typedef bool_condition< true, RC_comparator<8> > blt_condition;
typedef bool_condition<false, RC_comparator<8> > bnlt_condition;
typedef bool_condition< true, RC_comparator<4> > bgt_condition;
typedef bool_condition<false, RC_comparator<4> > bngt_condition;
typedef bool_condition< true, RC_comparator<2> > beq_condition;
typedef bool_condition<false, RC_comparator<2> > bneq_condition;
typedef bool_condition< true, RC_comparator<1> > bso_condition;
typedef bool_condition<false, RC_comparator<1> > bnso_condition;
struct ctr_0x_condition { struct ctr_0x_condition {
static inline bool test() { static inline bool test() {
return true; return true;
@ -399,7 +372,7 @@ struct ctr_11_condition {
}; };
#define DEFINE_OP_CTR(COND,CTR) \ #define DEFINE_OP_CTR(COND,CTR) \
void OPPROTO op_##COND##_##CTR(void) \ void OPPROTO op_##COND##_ctr_##CTR(void) \
{ \ { \
do_execute_branch<COND##_condition, ctr_##CTR##_condition>(A0, PARAM1); \ do_execute_branch<COND##_condition, ctr_##CTR##_condition>(A0, PARAM1); \
} }
@ -408,40 +381,93 @@ DEFINE_OP_CTR(COND,0x); \
DEFINE_OP_CTR(COND,10); \ DEFINE_OP_CTR(COND,10); \
DEFINE_OP_CTR(COND,11); DEFINE_OP_CTR(COND,11);
DEFINE_OP(blt); DEFINE_OP(branch_if_T0);
DEFINE_OP(bgt); DEFINE_OP(branch_if_not_T0);
DEFINE_OP(beq);
DEFINE_OP(bso);
DEFINE_OP(bnlt);
DEFINE_OP(bngt);
DEFINE_OP(bneq);
DEFINE_OP(bnso);
#undef DEFINE_OP #undef DEFINE_OP
#undef DEFINE_OP_CTR #undef DEFINE_OP_CTR
template< int bo >
static inline void do_execute_branch_bo(uint32 tpc, uint32 npc)
{
bool ctr_ok = true;
bool cond_ok = true;
if (BO_CONDITIONAL_BRANCH(bo)) {
if (BO_BRANCH_IF_TRUE(bo))
cond_ok = T0;
else
cond_ok = !T0;
}
if (BO_DECREMENT_CTR(bo)) {
uint32 ctr = powerpc_dyngen_helper::get_ctr() - 1;
if (BO_BRANCH_IF_CTR_ZERO(bo))
ctr_ok = ctr == 0;
else
ctr_ok = ctr != 0;
powerpc_dyngen_helper::set_ctr(ctr);
}
if (ctr_ok && cond_ok)
powerpc_dyngen_helper::set_pc(tpc);
else
powerpc_dyngen_helper::set_pc(npc);
dyngen_barrier();
}
#define BO(A,B,C,D) (((A) << 4)| ((B) << 3) | ((C) << 2) | ((D) << 1))
#define DEFINE_OP(BO_SUFFIX, BO_VALUE) \
void OPPROTO op_branch_A0_bo_##BO_SUFFIX(void) \
{ \
do_execute_branch_bo<BO BO_VALUE>(A0, PARAM1); \
}
DEFINE_OP(0000,(0,0,0,0));
DEFINE_OP(0001,(0,0,0,1));
DEFINE_OP(001x,(0,0,1,0));
DEFINE_OP(0100,(0,1,0,0));
DEFINE_OP(0101,(0,1,0,1));
DEFINE_OP(011x,(0,1,1,0));
DEFINE_OP(1x00,(1,0,0,0));
DEFINE_OP(1x01,(1,0,0,1));
// NOTE: the compiler is expected to optimize out the use of PARAM1
DEFINE_OP(1x1x,(1,0,1,0));
#undef DEFINE_OP
#undef BO
/** /**
* Compare & Record instructions * Compare & Record instructions
**/ **/
void OPPROTO op_record_nego_T0(void) void OPPROTO op_record_cr0_T0(void)
{ {
powerpc_dyngen_helper::xer().set_ov(T0 == 0x80000000); uint32 cr = powerpc_dyngen_helper::get_cr() & ~CR_field<0>::mask();
cr |= powerpc_dyngen_helper::xer().get_so() << 28;
if ((int32)T0 < 0)
cr |= CR_LT_field<0>::mask();
else if ((int32)T0 > 0)
cr |= CR_GT_field<0>::mask();
else
cr |= CR_EQ_field<0>::mask();
powerpc_dyngen_helper::set_cr(cr);
dyngen_barrier(); dyngen_barrier();
} }
#define im PARAM1 #define im PARAM1
#if DYNGEN_ASM_OPTS && defined(__powerpc__) #if DYNGEN_ASM_OPTS && defined(__powerpc__) && 0
#define DEFINE_OP(NAME, COMP, LHS, RHST, RHS) \ #define DEFINE_OP(NAME, COMP, LHS, RHST, RHS) \
void OPPROTO op_##NAME##_##LHS##_##RHS(void) \ void OPPROTO op_##NAME##_##LHS##_##RHS(void) \
{ \ { \
RC = powerpc_dyngen_helper::xer().get_so(); \ T0 = powerpc_dyngen_helper::xer().get_so(); \
uint32 v; \ uint32 v; \
asm volatile (COMP " 7,%1,%2 ; mfcr %0" : "=r" (v) : "r" (LHS), RHST (RHS) : "cr7"); \ asm volatile (COMP " 7,%1,%2 ; mfcr %0" : "=r" (v) : "r" (LHS), RHST (RHS) : "cr7"); \
RC |= (v & 0xe); \ T0 |= (v & 0xe); \
} }
DEFINE_OP(compare,"cmpw",T0,"r",T1); DEFINE_OP(compare,"cmpw",T0,"r",T1);
@ -453,17 +479,17 @@ DEFINE_OP(compare_logical,"cmplwi",T0,"i",0);
#else #else
#define DEFINE_OP(NAME, TYPE, LHS, RHS) \ #define DEFINE_OP(NAME, TYPE, LHS, RHS) \
void OPPROTO op_##NAME##_##LHS##_##RHS(void) \ void OPPROTO op_##NAME##_##LHS##_##RHS(void) \
{ \ { \
RC = powerpc_dyngen_helper::xer().get_so(); \ const uint32 SO = powerpc_dyngen_helper::xer().get_so(); \
if ((TYPE)LHS < (TYPE)RHS) \ if ((TYPE)LHS < (TYPE)RHS) \
RC |= standalone_CR_LT_field::mask(); \ T0 = SO | standalone_CR_LT_field::mask(); \
else if ((TYPE)LHS > (TYPE)RHS) \ else if ((TYPE)LHS > (TYPE)RHS) \
RC |= standalone_CR_GT_field::mask(); \ T0 = SO | standalone_CR_GT_field::mask(); \
else \ else \
RC |= standalone_CR_EQ_field::mask(); \ T0 = SO | standalone_CR_EQ_field::mask(); \
dyngen_barrier(); \ dyngen_barrier(); \
} }
DEFINE_OP(compare,int32,T0,T1); DEFINE_OP(compare,int32,T0,T1);
@ -842,10 +868,9 @@ void OPPROTO op_inc_32_mem(void)
*m += 1; *m += 1;
} }
void OPPROTO op_mtcrf_T0_im(void) void OPPROTO op_nego_T0(void)
{ {
const uint32 mask = PARAM1; powerpc_dyngen_helper::xer().set_ov(T0 == 0x80000000);
uint32 cr = powerpc_dyngen_helper::get_cr() & ~mask; T0 = -T0;
cr |= T0 & mask;
powerpc_dyngen_helper::set_cr(cr);
} }

View File

@ -29,87 +29,42 @@
#define DEFINE_GEN(NAME,ARGS) void powerpc_dyngen::NAME ARGS #define DEFINE_GEN(NAME,ARGS) void powerpc_dyngen::NAME ARGS
#include "ppc-dyngen-ops.hpp" #include "ppc-dyngen-ops.hpp"
void powerpc_dyngen::invalidate_so_cache()
{
rc_cache.set_so_status(RC_cache::STATUS_TRASH);
}
void powerpc_dyngen::invalidate_cr_cache()
{
invalidate_so_cache();
rc_cache.set_val_status(RC_cache::STATUS_TRASH);
rc_cache.set_crf(-1);
}
void powerpc_dyngen::gen_commit_cr()
{
if (rc_cache.val_status() == RC_cache::STATUS_VALID &&
rc_cache.so_status() == RC_cache::STATUS_VALID) {
const int crf = rc_cache.crf();
assert(crf != -1);
gen_store_RC_cr(crf);
invalidate_cr_cache();
}
else if (rc_cache.val_status() == RC_cache::STATUS_VALID) {
const int crf = rc_cache.crf();
assert(crf != -1);
gen_commit_rc_cache_cr(crf);
invalidate_cr_cache();
}
else {
// Maybe only SO field left to spill
gen_commit_so();
}
}
void powerpc_dyngen::gen_commit_so()
{
if (rc_cache.so_status() == RC_cache::STATUS_VALID) {
const int crf = rc_cache.crf();
assert(crf != -1);
gen_commit_so_cache_cr(crf);
invalidate_so_cache();
}
}
void powerpc_dyngen::gen_compare_T0_T1(int crf) void powerpc_dyngen::gen_compare_T0_T1(int crf)
{ {
if (!rc_cache.has_field(crf))
gen_commit_cr();
gen_op_compare_T0_T1(); gen_op_compare_T0_T1();
rc_cache.cache_field(crf); gen_store_T0_crf(crf);
} }
void powerpc_dyngen::gen_compare_T0_im(int crf, int32 value) void powerpc_dyngen::gen_compare_T0_im(int crf, int32 value)
{ {
if (!rc_cache.has_field(crf))
gen_commit_cr();
if (value == 0) if (value == 0)
gen_op_compare_T0_0(); gen_op_compare_T0_0();
else else
gen_op_compare_T0_im(value); gen_op_compare_T0_im(value);
rc_cache.cache_field(crf); gen_store_T0_crf(crf);
} }
void powerpc_dyngen::gen_compare_logical_T0_T1(int crf) void powerpc_dyngen::gen_compare_logical_T0_T1(int crf)
{ {
if (!rc_cache.has_field(crf))
gen_commit_cr();
gen_op_compare_logical_T0_T1(); gen_op_compare_logical_T0_T1();
rc_cache.cache_field(crf); gen_store_T0_crf(crf);
} }
void powerpc_dyngen::gen_compare_logical_T0_im(int crf, int32 value) void powerpc_dyngen::gen_compare_logical_T0_im(int crf, int32 value)
{ {
if (!rc_cache.has_field(crf))
gen_commit_cr();
if (value == 0) if (value == 0)
gen_op_compare_logical_T0_0(); gen_op_compare_logical_T0_0();
else else
gen_op_compare_logical_T0_im(value); gen_op_compare_logical_T0_im(value);
rc_cache.cache_field(crf); gen_store_T0_crf(crf);
} }
void powerpc_dyngen::gen_mtcrf_T0_im(uint32 mask)
{
gen_op_mtcrf_T0_im(mask);
}
/** /**
* Load/store registers * Load/store registers
**/ **/
@ -170,112 +125,75 @@ DEFINE_INSN(store, T1, crb);
#undef DEFINE_INSN #undef DEFINE_INSN
#define DEFINE_INSN(OP, REG) \ #define DEFINE_INSN(OP, REG) \
void powerpc_dyngen::gen_##OP##_##REG##_cr(int crf) \ void powerpc_dyngen::gen_##OP##_##REG##_crf(int crf) \
{ \ { \
switch (crf) { \ switch (crf) { \
case 0: gen_op_##OP##_##REG##_cr0(); break; \ case 0: gen_op_##OP##_##REG##_cr0(); break; \
case 1: gen_op_##OP##_##REG##_cr1(); break; \ case 1: gen_op_##OP##_##REG##_cr1(); break; \
case 2: gen_op_##OP##_##REG##_cr2(); break; \ case 2: gen_op_##OP##_##REG##_cr2(); break; \
case 3: gen_op_##OP##_##REG##_cr3(); break; \ case 3: gen_op_##OP##_##REG##_cr3(); break; \
case 4: gen_op_##OP##_##REG##_cr4(); break; \ case 4: gen_op_##OP##_##REG##_cr4(); break; \
case 5: gen_op_##OP##_##REG##_cr5(); break; \ case 5: gen_op_##OP##_##REG##_cr5(); break; \
case 6: gen_op_##OP##_##REG##_cr6(); break; \ case 6: gen_op_##OP##_##REG##_cr6(); break; \
case 7: gen_op_##OP##_##REG##_cr7(); break; \ case 7: gen_op_##OP##_##REG##_cr7(); break; \
default: abort(); \ default: abort(); \
} \ } \
} }
DEFINE_INSN(load, RC); DEFINE_INSN(load, T0);
DEFINE_INSN(store, RC); DEFINE_INSN(store, T0);
DEFINE_INSN(commit, so_cache);
DEFINE_INSN(commit, rc_cache);
#undef DEFINE_INSN #undef DEFINE_INSN
void powerpc_dyngen::gen_record_cr0_T0(void)
{
gen_compare_T0_im(0, 0);
}
/**
* Prepare condition register cache for branch
*
* This was meant to be a CR caching system but gain is almost
* zero. However, this shows the ability to handle a CR cache
* forwards and actually, a superblock-level (traces) optimizer
* with proper code generation will benefit from it.
**/
#define USE_CR_CACHE 1
void powerpc_dyngen::gen_prepare_RC(int bi)
{
const int crf = bi / 4;
const int crb = bi % 4;
#if USE_CR_CACHE
if (rc_cache.crf() == crf) {
if (crb != 3) {
// Rematerialize (LT, GT, EQ) if they are not live
if (rc_cache.val_status() == RC_cache::STATUS_VALID)
gen_commit_rc_cache_cr(crf);
else
gen_load_RC_cr(crf);
}
else {
// Rematerialize SO if it is not in cache
if (rc_cache.so_status() == RC_cache::STATUS_VALID)
gen_commit_so_cache_cr(crf);
else
gen_load_RC_cr(crf);
}
invalidate_cr_cache();
}
else {
// Reload flags from memory
gen_commit_cr();
gen_load_RC_cr(crf);
}
#else
gen_commit_cr();
gen_load_RC_cr(crf);
#endif
}
void powerpc_dyngen::gen_bc_A0(int bo, int bi, uint32 npc) void powerpc_dyngen::gen_bc_A0(int bo, int bi, uint32 npc)
{ {
#if 1
if (BO_CONDITIONAL_BRANCH(bo)) { if (BO_CONDITIONAL_BRANCH(bo)) {
enum { lt, gt, eq, so }; gen_load_T0_CR();
gen_prepare_RC(bi); gen_and_32_T0_im(1 << (31 - bi));
const int n = ((bi % 4) << 2) | ((bo >> 1) & 3); }
#define _(CR,DCTR,CTR0) (((CR) << 2) | ((DCTR) ? 0 : 2) | ((CTR0) ? 1 : 0)) switch (bo >> 1) {
if (BO_BRANCH_IF_TRUE(bo)) { #define _(A,B,C,D) (((A) << 3)| ((B) << 2) | ((C) << 1) | (D))
switch (n) { case _(0,0,0,0): gen_op_branch_A0_bo_0000(npc); break;
#define C(CR) \ case _(0,0,0,1): gen_op_branch_A0_bo_0001(npc); break;
case _(CR,0,0): gen_b##CR##_0x(npc); break; \ case _(0,0,1,0):
case _(CR,0,1): gen_b##CR##_0x(npc); break; \ case _(0,0,1,1): gen_op_branch_A0_bo_001x(npc); break;
case _(CR,1,0): gen_b##CR##_10(npc); break; \ case _(0,1,0,0): gen_op_branch_A0_bo_0100(npc); break;
case _(CR,1,1): gen_b##CR##_11(npc); break; case _(0,1,0,1): gen_op_branch_A0_bo_0101(npc); break;
C(lt); C(gt); C(eq); C(so); case _(0,1,1,0):
#undef C case _(0,1,1,1): gen_op_branch_A0_bo_011x(npc); break;
} case _(1,0,0,0):
} case _(1,1,0,0): gen_op_branch_A0_bo_1x00(npc); break;
else { case _(1,0,0,1):
switch (n) { case _(1,1,0,1): gen_op_branch_A0_bo_1x01(npc); break;
#define C(CR) \ case _(1,0,1,0):
case _(CR,0,0): gen_bn##CR##_0x(npc); break; \ case _(1,0,1,1):
case _(CR,0,1): gen_bn##CR##_0x(npc); break; \ case _(1,1,1,0):
case _(CR,1,0): gen_bn##CR##_10(npc); break; \ case _(1,1,1,1): gen_op_branch_A0_bo_1x1x(); break;
case _(CR,1,1): gen_bn##CR##_11(npc); break;
C(lt); C(gt); C(eq); C(so);
#undef C
}
}
#undef _ #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();
}
} }
else { else {
gen_commit_cr();
if (BO_DECREMENT_CTR(bo)) { if (BO_DECREMENT_CTR(bo)) {
gen_decrement_ctr_T0(); gen_decrement_ctr_T0();
if (BO_BRANCH_IF_CTR_ZERO(bo)) if (BO_BRANCH_IF_CTR_ZERO(bo))
@ -288,4 +206,5 @@ void powerpc_dyngen::gen_bc_A0(int bo, int bi, uint32 npc)
gen_set_PC_A0(); gen_set_PC_A0();
} }
} }
#endif
} }

View File

@ -37,36 +37,6 @@ class powerpc_dyngen
# include "ppc-dyngen-ops.hpp" # include "ppc-dyngen-ops.hpp"
#endif #endif
class RC_cache {
int m_val_status;
int m_so_status;
int m_crf;
public:
int crf() const { return m_crf; }
int val_status() const { return m_val_status; }
int so_status() const { return m_so_status; }
void set_crf(int v) { m_crf = v; }
void set_val_status(int v) { m_val_status = v; }
void set_so_status(int v) { m_so_status = v; }
enum {
STATUS_TRASH,
STATUS_VALID,
};
RC_cache()
: m_val_status(STATUS_TRASH), m_so_status(STATUS_TRASH), m_crf(-1)
{ }
bool has_field(int crf) const
{ return m_crf == crf; }
void cache_field(int crf)
{ m_val_status = m_so_status = STATUS_VALID; m_crf = crf; }
};
RC_cache rc_cache;
public: public:
// Make rc_cache accessible to codegen helper // Make rc_cache accessible to codegen helper
@ -95,40 +65,28 @@ public:
#define DEFINE_ALIAS_3(NAME,PRE,POST) DEFINE_ALIAS_RAW(NAME,PRE,POST,(long p1,long p2,long p3),(p1,p2,p3)) #define DEFINE_ALIAS_3(NAME,PRE,POST) DEFINE_ALIAS_RAW(NAME,PRE,POST,(long p1,long p2,long p3),(p1,p2,p3))
#ifdef NO_DEFINE_ALIAS #ifdef NO_DEFINE_ALIAS
#define DEFINE_ALIAS(NAME,N) #define DEFINE_ALIAS(NAME,N)
#define DEFINE_ALIAS_CLOBBER_SO(NAME,N)
#define DEFINE_ALIAS_CLOBBER_CR(NAME,N)
#else #else
#define DEFINE_ALIAS(NAME,N) DEFINE_ALIAS_##N(NAME,,) #define DEFINE_ALIAS(NAME,N) DEFINE_ALIAS_##N(NAME,,)
#define DEFINE_ALIAS_CLOBBER_CR(NAME,N) DEFINE_ALIAS_##N(NAME,gen_commit_cr(),)
#define DEFINE_ALIAS_CLOBBER_SO(NAME,N) DEFINE_ALIAS_##N(NAME,gen_commit_so(),)
#endif #endif
// Misc instructions // Misc instructions
DEFINE_ALIAS(inc_32_mem,1); DEFINE_ALIAS(inc_32_mem,1);
DEFINE_ALIAS(mtcrf_T0_im,1); DEFINE_ALIAS(nego_T0,0);
// Condition registers // Condition registers
private: DEFINE_ALIAS(load_T0_CR,0);
void gen_commit_so_cache_cr(int crf); DEFINE_ALIAS(store_T0_CR,0);
void gen_commit_rc_cache_cr(int crf); void gen_load_T0_crf(int crf);
public: void gen_store_T0_crf(int crf);
void invalidate_so_cache();
void invalidate_cr_cache();
void gen_commit_so();
void gen_commit_cr();
DEFINE_ALIAS_CLOBBER_CR(load_T0_CR,0);
DEFINE_ALIAS_CLOBBER_CR(store_T0_CR,0);
DEFINE_ALIAS(load_T0_XER,0);
DEFINE_ALIAS(store_T0_XER,0);
void gen_load_T0_crb(int i); void gen_load_T0_crb(int i);
void gen_load_T1_crb(int i); void gen_load_T1_crb(int i);
void gen_store_T0_crb(int i); void gen_store_T0_crb(int i);
void gen_store_T1_crb(int i); void gen_store_T1_crb(int i);
void gen_load_RC_cr(int crf); void gen_mtcrf_T0_im(uint32 mask);
void gen_store_RC_cr(int crf);
void gen_prepare_RC(int bi);
// Special purpose registers // Special purpose registers
DEFINE_ALIAS(load_T0_XER,0);
DEFINE_ALIAS(store_T0_XER,0);
DEFINE_ALIAS(load_T0_PC,0); DEFINE_ALIAS(load_T0_PC,0);
DEFINE_ALIAS(store_T0_PC,0); DEFINE_ALIAS(store_T0_PC,0);
DEFINE_ALIAS(set_PC_im,1); DEFINE_ALIAS(set_PC_im,1);
@ -150,11 +108,7 @@ public:
DEFINE_ALIAS(branch_A0_if_not_T0,1); DEFINE_ALIAS(branch_A0_if_not_T0,1);
// Compare & Record instructions // Compare & Record instructions
DEFINE_ALIAS_CLOBBER_SO(record_nego_T0,0); DEFINE_ALIAS(record_cr0_T0,0);
void gen_record_cr0_T0();
DEFINE_ALIAS(compare_T0_T1,0);
DEFINE_ALIAS(compare_T0_0,0);
DEFINE_ALIAS(compare_T0_im,1);
void gen_compare_T0_T1(int crf); void gen_compare_T0_T1(int crf);
void gen_compare_T0_im(int crf, int32 value); void gen_compare_T0_im(int crf, int32 value);
void gen_compare_logical_T0_T1(int crf); void gen_compare_logical_T0_T1(int crf);
@ -164,11 +118,11 @@ public:
DEFINE_ALIAS(mulhw_T0_T1,0); DEFINE_ALIAS(mulhw_T0_T1,0);
DEFINE_ALIAS(mulhwu_T0_T1,0); DEFINE_ALIAS(mulhwu_T0_T1,0);
DEFINE_ALIAS(mulli_T0_im,1); DEFINE_ALIAS(mulli_T0_im,1);
DEFINE_ALIAS_CLOBBER_SO(mullwo_T0_T1,0); DEFINE_ALIAS(mullwo_T0_T1,0);
DEFINE_ALIAS(divw_T0_T1,0); DEFINE_ALIAS(divw_T0_T1,0);
DEFINE_ALIAS_CLOBBER_SO(divwo_T0_T1,0); DEFINE_ALIAS(divwo_T0_T1,0);
DEFINE_ALIAS(divwu_T0_T1,0); DEFINE_ALIAS(divwu_T0_T1,0);
DEFINE_ALIAS_CLOBBER_SO(divwuo_T0_T1,0); DEFINE_ALIAS(divwuo_T0_T1,0);
// Shift/Rotate instructions // Shift/Rotate instructions
DEFINE_ALIAS(slw_T0_T1,0); DEFINE_ALIAS(slw_T0_T1,0);
@ -184,40 +138,27 @@ public:
DEFINE_ALIAS(addo_T0_T1,0); DEFINE_ALIAS(addo_T0_T1,0);
DEFINE_ALIAS(addc_T0_im,1); DEFINE_ALIAS(addc_T0_im,1);
DEFINE_ALIAS(addc_T0_T1,0); DEFINE_ALIAS(addc_T0_T1,0);
DEFINE_ALIAS_CLOBBER_SO(addco_T0_T1,0); DEFINE_ALIAS(addco_T0_T1,0);
DEFINE_ALIAS(adde_T0_T1,0); DEFINE_ALIAS(adde_T0_T1,0);
DEFINE_ALIAS_CLOBBER_SO(addeo_T0_T1,0); DEFINE_ALIAS(addeo_T0_T1,0);
DEFINE_ALIAS(addme_T0,0); DEFINE_ALIAS(addme_T0,0);
DEFINE_ALIAS_CLOBBER_SO(addmeo_T0,0); DEFINE_ALIAS(addmeo_T0,0);
DEFINE_ALIAS(addze_T0,0); DEFINE_ALIAS(addze_T0,0);
DEFINE_ALIAS_CLOBBER_SO(addzeo_T0,0); DEFINE_ALIAS(addzeo_T0,0);
DEFINE_ALIAS(subf_T0_T1,0); DEFINE_ALIAS(subf_T0_T1,0);
DEFINE_ALIAS_CLOBBER_SO(subfo_T0_T1,0); DEFINE_ALIAS(subfo_T0_T1,0);
DEFINE_ALIAS(subfc_T0_im,1); DEFINE_ALIAS(subfc_T0_im,1);
DEFINE_ALIAS(subfc_T0_T1,0); DEFINE_ALIAS(subfc_T0_T1,0);
DEFINE_ALIAS_CLOBBER_SO(subfco_T0_T1,0); DEFINE_ALIAS(subfco_T0_T1,0);
DEFINE_ALIAS(subfe_T0_T1,0); DEFINE_ALIAS(subfe_T0_T1,0);
DEFINE_ALIAS_CLOBBER_SO(subfeo_T0_T1,0); DEFINE_ALIAS(subfeo_T0_T1,0);
DEFINE_ALIAS(subfme_T0,0); DEFINE_ALIAS(subfme_T0,0);
DEFINE_ALIAS_CLOBBER_SO(subfmeo_T0,0); DEFINE_ALIAS(subfmeo_T0,0);
DEFINE_ALIAS(subfze_T0,0); DEFINE_ALIAS(subfze_T0,0);
DEFINE_ALIAS_CLOBBER_SO(subfzeo_T0,0); DEFINE_ALIAS(subfzeo_T0,0);
// Branch instructions // Branch instructions
void gen_bc_A0(int bo, int bi, uint32 npc); void gen_bc_A0(int bo, int bi, uint32 npc);
#define DEFINE_ALIAS_GRP_1(CR,CTR) \
DEFINE_ALIAS(b##CR##_##CTR,1); \
DEFINE_ALIAS(bn##CR##_##CTR,1);
#define DEFINE_ALIAS_GRP_2(CR) \
DEFINE_ALIAS_GRP_1(CR,0x); \
DEFINE_ALIAS_GRP_1(CR,10); \
DEFINE_ALIAS_GRP_1(CR,11);
DEFINE_ALIAS_GRP_2(lt);
DEFINE_ALIAS_GRP_2(gt);
DEFINE_ALIAS_GRP_2(eq);
DEFINE_ALIAS_GRP_2(so);
#undef DEFINE_ALAIS_GRP_2
#undef DEFINE_ALIAS_GRP_1
#undef DEFINE_ALIAS #undef DEFINE_ALIAS
#undef DEFINE_ALIAS_0 #undef DEFINE_ALIAS_0

View File

@ -24,7 +24,6 @@
#include "cpu/ppc/ppc-operands.hpp" #include "cpu/ppc/ppc-operands.hpp"
#ifdef SHEEPSHAVER #ifdef SHEEPSHAVER
#include "xlowmem.h"
#include "cpu_emulation.h" #include "cpu_emulation.h"
#endif #endif
@ -445,16 +444,6 @@ powerpc_cpu::compile_block(uint32 entry_point)
const int bo = BO_field::extract(opcode); const int bo = BO_field::extract(opcode);
const int bi = BI_field::extract(opcode); const int bi = BI_field::extract(opcode);
#ifdef SHEEPSHAVER
if (BO_CONDITIONAL_BRANCH(bo)) {
// FIXME: use the slow way if we expect to clobber CR
// in m68k emulator. In that case, we should merge CR
// flags, not commit cached one to memory.
if (vm_read_memory_4(XLM_RUN_MODE) == MODE_68K)
goto do_generic;
}
#endif
const uint32 npc = dpc + 4; const uint32 npc = dpc + 4;
if (LK_field::test(opcode)) if (LK_field::test(opcode))
dg.gen_store_im_LR(npc); dg.gen_store_im_LR(npc);
@ -531,7 +520,6 @@ powerpc_cpu::compile_block(uint32 entry_point)
case PPC_I(CRORC): // Condition Register OR with Complement case PPC_I(CRORC): // Condition Register OR with Complement
case PPC_I(CRXOR): // Condition Register XOR case PPC_I(CRXOR): // Condition Register XOR
{ {
dg.gen_commit_cr();
dg.gen_load_T0_crb(crbA_field::extract(opcode)); dg.gen_load_T0_crb(crbA_field::extract(opcode));
dg.gen_load_T1_crb(crbB_field::extract(opcode)); dg.gen_load_T1_crb(crbB_field::extract(opcode));
switch (ii->mnemo) { switch (ii->mnemo) {
@ -660,8 +648,9 @@ powerpc_cpu::compile_block(uint32 entry_point)
{ {
dg.gen_load_T0_GPR(rA_field::extract(opcode)); dg.gen_load_T0_GPR(rA_field::extract(opcode));
if (OE_field::test(opcode)) if (OE_field::test(opcode))
dg.gen_record_nego_T0(); dg.gen_nego_T0();
dg.gen_neg_32_T0(); else
dg.gen_neg_32_T0();
if (Rc_field::test(opcode)) if (Rc_field::test(opcode))
dg.gen_record_cr0_T0(); dg.gen_record_cr0_T0();
dg.gen_store_T0_GPR(rD_field::extract(opcode)); dg.gen_store_T0_GPR(rD_field::extract(opcode));
@ -669,7 +658,6 @@ powerpc_cpu::compile_block(uint32 entry_point)
} }
case PPC_I(MFCR): // Move from Condition Register case PPC_I(MFCR): // Move from Condition Register
{ {
dg.gen_commit_cr();
dg.gen_load_T0_CR(); dg.gen_load_T0_CR();
dg.gen_store_T0_GPR(rD_field::extract(opcode)); dg.gen_store_T0_GPR(rD_field::extract(opcode));
break; break;
@ -1003,16 +991,14 @@ powerpc_cpu::compile_block(uint32 entry_point)
} }
case PPC_I(MTCRF): // Move to Condition Register Fields case PPC_I(MTCRF): // Move to Condition Register Fields
{ {
dg.gen_commit_cr();
dg.gen_load_T0_GPR(rS_field::extract(opcode)); dg.gen_load_T0_GPR(rS_field::extract(opcode));
dg.gen_mtcrf_T0_im(field2mask[CRM_field::extract(opcode)]); dg.gen_mtcrf_T0_im(field2mask[CRM_field::extract(opcode)]);
break; break;
} }
case PPC_I(MCRF): // Move Condition Register Field case PPC_I(MCRF): // Move Condition Register Field
{ {
dg.gen_commit_cr(); dg.gen_load_T0_crf(crfS_field::extract(opcode));
dg.gen_load_RC_cr(crfS_field::extract(opcode)); dg.gen_store_T0_crf(crfD_field::extract(opcode));
dg.gen_store_RC_cr(crfD_field::extract(opcode));
break; break;
} }
default: // Direct call to instruction handler default: // Direct call to instruction handler
@ -1043,7 +1029,6 @@ powerpc_cpu::compile_block(uint32 entry_point)
dg.gen_set_PC_im(dpc); dg.gen_set_PC_im(dpc);
} }
sync_pc_offset += 4; sync_pc_offset += 4;
dg.gen_commit_cr();
dg.gen_invoke_CPU_im(func, opcode); dg.gen_invoke_CPU_im(func, opcode);
} }
} }
@ -1054,7 +1039,6 @@ powerpc_cpu::compile_block(uint32 entry_point)
goto again; goto again;
} }
} }
dg.gen_commit_cr();
dg.gen_exec_return(); dg.gen_exec_return();
dg.gen_end(); dg.gen_end();
bi->end_pc = dpc; bi->end_pc = dpc;