diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen-ops.cpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen-ops.cpp index 26385e95..17030515 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen-ops.cpp +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen-ops.cpp @@ -36,16 +36,7 @@ register struct powerpc_cpu *CPU asm(REG_CPU); register uint32 A0 asm(REG_A0); register uint32 T0 asm(REG_T0); register uint32 T1 asm(REG_T1); -#ifdef REG_T2 -register uint32 CC_LHS asm(REG_T2); -#else -#define CC_LHS powerpc_dyngen_helper::cc_lhs() -#endif -#ifdef REG_T3 -register uint32 CC_RHS asm(REG_T3); -#else -#define CC_RHS powerpc_dyngen_helper::cc_rhs() -#endif +register uint32 RC asm(REG_T2); // Semantic action templates #define DYNGEN_OPS @@ -71,8 +62,6 @@ struct powerpc_dyngen_helper { static inline void record(int crf, int32 v) { CPU->record_cr(crf, v); } static inline powerpc_cr_register & cr() { return CPU->cr(); } static inline powerpc_xer_register & xer() { return CPU->xer(); } - static inline uint32 & cc_lhs() { return CPU->codegen_ptr()->rc_cache.cc_lhs; } - static inline uint32 & cc_rhs() { return CPU->codegen_ptr()->rc_cache.cc_rhs; } }; @@ -206,79 +195,43 @@ DEFINE_REG(31); #undef DEFINE_REG #undef DEFINE_OP -#define DEFINE_OP(CRF, REG) \ -void OPPROTO op_load_##REG##_cr##CRF(void) \ -{ \ - T0 = powerpc_dyngen_helper::cr().get(CRF); \ -} \ -void OPPROTO op_store_##REG##_cr##CRF(void) \ -{ \ - powerpc_dyngen_helper::cr().set(CRF, REG); \ +#define DEFINE_OP(CRF, REG) \ +void OPPROTO op_load_##REG##_cr##CRF(void) \ +{ \ + REG = powerpc_dyngen_helper::cr().get(CRF); \ +} \ +void OPPROTO op_store_##REG##_cr##CRF(void) \ +{ \ + 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::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::mask() | \ + CR_GT_field::mask() | \ + CR_EQ_field::mask()); \ + cr = (cr & ~cr_mask) | ((RC << (28 - 4 * CRF)) & cr_mask); \ + powerpc_dyngen_helper::set_cr(cr); \ } -DEFINE_OP(0, T0); -DEFINE_OP(1, T0); -DEFINE_OP(2, T0); -DEFINE_OP(3, T0); -DEFINE_OP(4, T0); -DEFINE_OP(5, T0); -DEFINE_OP(6, T0); -DEFINE_OP(7, T0); +DEFINE_OP(0, RC); +DEFINE_OP(1, RC); +DEFINE_OP(2, RC); +DEFINE_OP(3, RC); +DEFINE_OP(4, RC); +DEFINE_OP(5, RC); +DEFINE_OP(6, RC); +DEFINE_OP(7, RC); #undef DEFINE_OP -#define DEFINE_OP(CRF) \ -void OPPROTO op_commit_so_cache_cr##CRF(void) \ -{ \ - int so = powerpc_dyngen_helper::xer().get_so(); \ - powerpc_dyngen_helper::cr().set_so(CRF, so); \ -} - -DEFINE_OP(0); -DEFINE_OP(1); -DEFINE_OP(2); -DEFINE_OP(3); -DEFINE_OP(4); -DEFINE_OP(5); -DEFINE_OP(6); -DEFINE_OP(7); - -#undef DEFINE_OP - -#define DEFINE_OP_1(NAME,TYPE,CRF) \ -void OPPROTO op_##NAME##_rc_cache_cr##CRF(void) \ -{ \ - uint32 cr = powerpc_dyngen_helper::get_cr(); \ - cr &= ~(CR_LT_field::mask() | \ - CR_GT_field::mask() | \ - CR_EQ_field::mask()); \ - \ - if ((TYPE)CC_LHS < (TYPE)CC_RHS) \ - cr |= CR_LT_field::mask(); \ - else if ((TYPE)CC_LHS > (TYPE)CC_RHS) \ - cr |= CR_GT_field::mask(); \ - else \ - cr |= CR_EQ_field::mask(); \ - \ - powerpc_dyngen_helper::set_cr(cr); \ - dyngen_barrier(); \ -} -#define DEFINE_OP(CRF) \ -DEFINE_OP_1(commit,int32,CRF); \ -DEFINE_OP_1(commit_logical,uint32,CRF) - -DEFINE_OP(0); -DEFINE_OP(1); -DEFINE_OP(2); -DEFINE_OP(3); -DEFINE_OP(4); -DEFINE_OP(5); -DEFINE_OP(6); -DEFINE_OP(7); - -#undef DEFINE_OP -#undef DEFINE_OP_1 - /** * Special purpose registers @@ -394,9 +347,9 @@ static inline void do_execute_branch(uint32 tpc, uint32 npc) } template< int crb > -struct CR_comparator { +struct RC_comparator { static inline bool test() { - return (T0 & crb); + return (RC & crb); } }; @@ -414,14 +367,14 @@ struct bool_condition< false, comparator > { } }; -typedef bool_condition< true, CR_comparator<8> > blt_condition; -typedef bool_condition > bnlt_condition; -typedef bool_condition< true, CR_comparator<4> > bgt_condition; -typedef bool_condition > bngt_condition; -typedef bool_condition< true, CR_comparator<2> > beq_condition; -typedef bool_condition > bneq_condition; -typedef bool_condition< true, CR_comparator<1> > bso_condition; -typedef bool_condition > bnso_condition; +typedef bool_condition< true, RC_comparator<8> > blt_condition; +typedef bool_condition > bnlt_condition; +typedef bool_condition< true, RC_comparator<4> > bgt_condition; +typedef bool_condition > bngt_condition; +typedef bool_condition< true, RC_comparator<2> > beq_condition; +typedef bool_condition > bneq_condition; +typedef bool_condition< true, RC_comparator<1> > bso_condition; +typedef bool_condition > bnso_condition; struct ctr_0x_condition { static inline bool test() { @@ -453,7 +406,7 @@ void OPPROTO op_##COND##_##CTR(void) \ #define DEFINE_OP(COND) \ DEFINE_OP_CTR(COND,0x); \ DEFINE_OP_CTR(COND,10); \ -DEFINE_OP_CTR(COND,11) +DEFINE_OP_CTR(COND,11); DEFINE_OP(blt); DEFINE_OP(bgt); @@ -478,52 +431,9 @@ void OPPROTO op_record_nego_T0(void) dyngen_barrier(); } -void OPPROTO op_record_cr0_T0(void) -{ - uint32 cr = powerpc_dyngen_helper::get_cr(); - cr &= ~(CR_LT_field<0>::mask() | - CR_GT_field<0>::mask() | - CR_EQ_field<0>::mask() | - CR_SO_field<0>::mask()); - -#if DYNGEN_ASM_OPTS -#if defined(__powerpc__) - uint32 v; - asm volatile ("cmpwi 0,%1,0 ; mfcr %0" : "=r" (v) : "r" (T0) : "cr0"); - cr |= (v & (0xe0000000)); - cr |= (powerpc_dyngen_helper::xer().get_so() << (31 - 3)); - goto end; -#endif -#endif - - if (powerpc_dyngen_helper::xer().get_so()) - cr |= CR_SO_field<0>::mask(); - 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(); - - end: - powerpc_dyngen_helper::set_cr(cr); - dyngen_barrier(); -} - #define im PARAM1 -#define DEFINE_OP(LHS, RHS) \ -void OPPROTO op_compare_##LHS##_##RHS(void) \ -{ \ - CC_LHS = LHS; \ - CC_RHS = RHS; \ -} -DEFINE_OP(T0,T1); -DEFINE_OP(T0,im); -DEFINE_OP(T0,0); -#undef DEFINE_OP - -#if DYNGEN_ASM_OPTS && defined(__powerpc__) +#if DYNGEN_ASM_OPTS && defined(__powerpc__) && 0 #define DEFINE_OP(NAME, COMP, LHS, RHST, RHS) \ void OPPROTO op_##NAME##_##LHS##_##RHS(void) \ @@ -543,26 +453,25 @@ DEFINE_OP(do_compare_logical,"cmplwi",T0,"i",0); #else -#define DEFINE_OP(NAME, TYPE, LHS, RHS) \ -void OPPROTO op_##NAME##_##LHS##_##RHS(void) \ -{ \ - uint32 cr = powerpc_dyngen_helper::xer().get_so(); \ - if ((TYPE)LHS < (TYPE)RHS) \ - cr |= standalone_CR_LT_field::mask(); \ - else if ((TYPE)LHS > (TYPE)RHS) \ - cr |= standalone_CR_GT_field::mask(); \ - else \ - cr |= standalone_CR_EQ_field::mask(); \ - T0 = cr; \ - dyngen_barrier(); \ +#define DEFINE_OP(NAME, TYPE, LHS, RHS) \ +void OPPROTO op_##NAME##_##LHS##_##RHS(void) \ +{ \ + RC = powerpc_dyngen_helper::xer().get_so(); \ + if ((TYPE)LHS < (TYPE)RHS) \ + RC |= standalone_CR_LT_field::mask(); \ + else if ((TYPE)LHS > (TYPE)RHS) \ + RC |= standalone_CR_GT_field::mask(); \ + else \ + RC |= standalone_CR_EQ_field::mask(); \ + dyngen_barrier(); \ } -DEFINE_OP(do_compare,int32,T0,T1); -DEFINE_OP(do_compare,int32,T0,im); -DEFINE_OP(do_compare,int32,T0,0); -DEFINE_OP(do_compare_logical,uint32,T0,T1); -DEFINE_OP(do_compare_logical,uint32,T0,im); -DEFINE_OP(do_compare_logical,uint32,T0,0); +DEFINE_OP(compare,int32,T0,T1); +DEFINE_OP(compare,int32,T0,im); +DEFINE_OP(compare,int32,T0,0); +DEFINE_OP(compare_logical,uint32,T0,T1); +DEFINE_OP(compare_logical,uint32,T0,im); +DEFINE_OP(compare_logical,uint32,T0,0); #endif diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen.cpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen.cpp index d67f3c62..936f130f 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen.cpp +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen.cpp @@ -31,51 +31,44 @@ void powerpc_dyngen::invalidate_so_cache() { - rc_cache.so_status = RC_cache::STATUS_TRASH; + rc_cache.set_so_status(RC_cache::STATUS_TRASH); } void powerpc_dyngen::invalidate_cr_cache() { invalidate_so_cache(); - rc_cache.val_status = RC_cache::STATUS_TRASH; - rc_cache.crf = -1; -} - -void powerpc_dyngen::do_gen_commit_cr() -{ - gen_commit_so(); - switch (rc_cache.val_status) { - case RC_cache::STATUS_VALID: - gen_commit_rc_cache_cr(rc_cache.crf); - break; - case RC_cache::STATUS_VALID_LOGICAL: - gen_commit_logical_rc_cache_cr(rc_cache.crf); - break; - default: - abort(); - } - invalidate_cr_cache(); -} - -void powerpc_dyngen::do_gen_commit_so() -{ - gen_commit_so_cache_cr(rc_cache.crf); - 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_TRASH) { - assert(rc_cache.crf != -1); - do_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_TRASH) { - assert(rc_cache.crf != -1); - do_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(); } } @@ -102,8 +95,8 @@ void powerpc_dyngen::gen_compare_logical_T0_T1(int crf) { if (!rc_cache.has_field(crf)) gen_commit_cr(); - gen_op_compare_T0_T1(); - rc_cache.cache_field(crf, RC_cache::STATUS_VALID_LOGICAL); + gen_op_compare_logical_T0_T1(); + rc_cache.cache_field(crf); } void powerpc_dyngen::gen_compare_logical_T0_im(int crf, int32 value) @@ -111,10 +104,10 @@ void powerpc_dyngen::gen_compare_logical_T0_im(int crf, int32 value) if (!rc_cache.has_field(crf)) gen_commit_cr(); if (value == 0) - gen_op_compare_T0_0(); + gen_op_compare_logical_T0_0(); else - gen_op_compare_T0_im(value); - rc_cache.cache_field(crf, RC_cache::STATUS_VALID_LOGICAL); + gen_op_compare_logical_T0_im(value); + rc_cache.cache_field(crf); } /** @@ -193,11 +186,10 @@ void powerpc_dyngen::gen_##OP##_##REG##_cr(int crf) \ } \ } -DEFINE_INSN(load, T0); -DEFINE_INSN(store, T0); +DEFINE_INSN(load, RC); +DEFINE_INSN(store, RC); DEFINE_INSN(commit, so_cache); DEFINE_INSN(commit, rc_cache); -DEFINE_INSN(commit_logical, rc_cache); #undef DEFINE_INSN @@ -206,12 +198,20 @@ void powerpc_dyngen::gen_record_cr0_T0(void) gen_compare_T0_im(0, 0); } +void powerpc_dyngen::gen_prepare_RC(int bi) +{ + const int crf = bi / 4; + const int crb = bi % 4; + + gen_commit_cr(); + gen_load_RC_cr(crf); +} + void powerpc_dyngen::gen_bc_A0(int bo, int bi, uint32 npc) { - gen_commit_cr(); if (BO_CONDITIONAL_BRANCH(bo)) { enum { lt, gt, eq, so }; - gen_load_T0_cr(bi / 4); + gen_prepare_RC(bi); const int n = ((bi % 4) << 2) | ((bo >> 1) & 3); #define _(CR,DCTR,CTR0) (((CR) << 2) | ((DCTR) ? 0 : 2) | ((CTR0) ? 1 : 0)) if (BO_BRANCH_IF_TRUE(bo)) { @@ -239,6 +239,7 @@ void powerpc_dyngen::gen_bc_A0(int bo, int bi, uint32 npc) #undef _ } else { + gen_commit_cr(); if (BO_DECREMENT_CTR(bo)) { gen_decrement_ctr_T0(); if (BO_BRANCH_IF_CTR_ZERO(bo)) diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen.hpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen.hpp index a939d1ec..2f192e14 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen.hpp +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen.hpp @@ -37,30 +37,33 @@ class powerpc_dyngen # include "ppc-dyngen-ops.hpp" #endif - struct RC_cache { + 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, - STATUS_VALID_LOGICAL }; - int val_status; - int so_status; - int crf; - - // Used only by generated code if not enough native registers - // are available to cache them all - uint32 cc_lhs; - uint32 cc_rhs; RC_cache() - : val_status(STATUS_TRASH), so_status(STATUS_TRASH), crf(-1) + : m_val_status(STATUS_TRASH), m_so_status(STATUS_TRASH), m_crf(-1) { } - bool has_field(int test_crf) - { return val_status != STATUS_TRASH && crf == test_crf; } + bool has_field(int crf) const + { return m_crf == crf; } - void cache_field(int new_crf, int new_status = STATUS_VALID) - { val_status = so_status = new_status; crf = new_crf; } + void cache_field(int crf) + { m_val_status = m_so_status = STATUS_VALID; m_crf = crf; } }; RC_cache rc_cache; @@ -102,11 +105,8 @@ public: // Condition registers private: - void do_gen_commit_so(); - void do_gen_commit_cr(); void gen_commit_so_cache_cr(int crf); void gen_commit_rc_cache_cr(int crf); - void gen_commit_logical_rc_cache_cr(int crf); public: void invalidate_so_cache(); void invalidate_cr_cache(); @@ -120,8 +120,9 @@ public: void gen_load_T1_crb(int i); void gen_store_T0_crb(int i); void gen_store_T1_crb(int i); - void gen_load_T0_cr(int crf); - void gen_store_T0_cr(int crf); + void gen_load_RC_cr(int crf); + void gen_store_RC_cr(int crf); + void gen_prepare_RC(int bi); // Special purpose registers DEFINE_ALIAS(load_T0_PC,0);