mirror of
https://github.com/kanjitalk755/macemu.git
synced 2024-12-29 14:31:44 +00:00
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:
parent
dc79320904
commit
04214f3820
@ -216,7 +216,11 @@ public:
|
||||
|
||||
// Initialization & finalization
|
||||
void initialize();
|
||||
#ifdef SHEEPSHAVER
|
||||
powerpc_cpu();
|
||||
#else
|
||||
powerpc_cpu(task_struct *parent_task);
|
||||
#endif
|
||||
~powerpc_cpu();
|
||||
|
||||
// Handle flight recorder
|
||||
|
@ -36,7 +36,6 @@ 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);
|
||||
register uint32 RC asm(REG_T2);
|
||||
|
||||
// Semantic action templates
|
||||
#define DYNGEN_OPS
|
||||
@ -134,25 +133,16 @@ void OPPROTO op_store_T0_CR(void)
|
||||
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) \
|
||||
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) \
|
||||
{ \
|
||||
uint32 cr = powerpc_dyngen_helper::get_cr(); \
|
||||
bit_field<N,N>::insert(cr, REG); \
|
||||
uint32 cr = powerpc_dyngen_helper::get_cr() & ~(1 << (31 - N)); \
|
||||
cr |= ((REG & 1) << (31 - N)); \
|
||||
powerpc_dyngen_helper::set_cr(cr); \
|
||||
}
|
||||
#define DEFINE_REG(N) \
|
||||
@ -195,48 +185,49 @@ DEFINE_REG(31);
|
||||
#undef DEFINE_REG
|
||||
#undef DEFINE_OP
|
||||
|
||||
#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<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 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); \
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
#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
|
||||
**/
|
||||
|
||||
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)
|
||||
{
|
||||
T0 = powerpc_dyngen_helper::get_pc();
|
||||
@ -346,36 +337,18 @@ static inline void do_execute_branch(uint32 tpc, uint32 npc)
|
||||
dyngen_barrier();
|
||||
}
|
||||
|
||||
template< int crb >
|
||||
struct RC_comparator {
|
||||
struct branch_if_T0_condition {
|
||||
static inline bool test() {
|
||||
return (RC & crb);
|
||||
return T0 != 0;
|
||||
}
|
||||
};
|
||||
|
||||
template< bool br_true, class comparator >
|
||||
struct bool_condition {
|
||||
struct branch_if_not_T0_condition {
|
||||
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 {
|
||||
static inline bool test() {
|
||||
return true;
|
||||
@ -399,7 +372,7 @@ struct ctr_11_condition {
|
||||
};
|
||||
|
||||
#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); \
|
||||
}
|
||||
@ -408,40 +381,93 @@ DEFINE_OP_CTR(COND,0x); \
|
||||
DEFINE_OP_CTR(COND,10); \
|
||||
DEFINE_OP_CTR(COND,11);
|
||||
|
||||
DEFINE_OP(blt);
|
||||
DEFINE_OP(bgt);
|
||||
DEFINE_OP(beq);
|
||||
DEFINE_OP(bso);
|
||||
DEFINE_OP(bnlt);
|
||||
DEFINE_OP(bngt);
|
||||
DEFINE_OP(bneq);
|
||||
DEFINE_OP(bnso);
|
||||
DEFINE_OP(branch_if_T0);
|
||||
DEFINE_OP(branch_if_not_T0);
|
||||
|
||||
#undef DEFINE_OP
|
||||
#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
|
||||
**/
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
#define im PARAM1
|
||||
|
||||
#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) \
|
||||
{ \
|
||||
RC = powerpc_dyngen_helper::xer().get_so(); \
|
||||
T0 = powerpc_dyngen_helper::xer().get_so(); \
|
||||
uint32 v; \
|
||||
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);
|
||||
@ -453,17 +479,17 @@ DEFINE_OP(compare_logical,"cmplwi",T0,"i",0);
|
||||
|
||||
#else
|
||||
|
||||
#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 DEFINE_OP(NAME, TYPE, LHS, RHS) \
|
||||
void OPPROTO op_##NAME##_##LHS##_##RHS(void) \
|
||||
{ \
|
||||
const uint32 SO = powerpc_dyngen_helper::xer().get_so(); \
|
||||
if ((TYPE)LHS < (TYPE)RHS) \
|
||||
T0 = SO | standalone_CR_LT_field::mask(); \
|
||||
else if ((TYPE)LHS > (TYPE)RHS) \
|
||||
T0 = SO | standalone_CR_GT_field::mask(); \
|
||||
else \
|
||||
T0 = SO | standalone_CR_EQ_field::mask(); \
|
||||
dyngen_barrier(); \
|
||||
}
|
||||
|
||||
DEFINE_OP(compare,int32,T0,T1);
|
||||
@ -842,10 +868,9 @@ void OPPROTO op_inc_32_mem(void)
|
||||
*m += 1;
|
||||
}
|
||||
|
||||
void OPPROTO op_mtcrf_T0_im(void)
|
||||
void OPPROTO op_nego_T0(void)
|
||||
{
|
||||
const uint32 mask = PARAM1;
|
||||
uint32 cr = powerpc_dyngen_helper::get_cr() & ~mask;
|
||||
cr |= T0 & mask;
|
||||
powerpc_dyngen_helper::set_cr(cr);
|
||||
powerpc_dyngen_helper::xer().set_ov(T0 == 0x80000000);
|
||||
T0 = -T0;
|
||||
}
|
||||
|
||||
|
@ -29,87 +29,42 @@
|
||||
#define DEFINE_GEN(NAME,ARGS) void powerpc_dyngen::NAME ARGS
|
||||
#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)
|
||||
{
|
||||
if (!rc_cache.has_field(crf))
|
||||
gen_commit_cr();
|
||||
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)
|
||||
{
|
||||
if (!rc_cache.has_field(crf))
|
||||
gen_commit_cr();
|
||||
if (value == 0)
|
||||
gen_op_compare_T0_0();
|
||||
else
|
||||
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)
|
||||
{
|
||||
if (!rc_cache.has_field(crf))
|
||||
gen_commit_cr();
|
||||
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)
|
||||
{
|
||||
if (!rc_cache.has_field(crf))
|
||||
gen_commit_cr();
|
||||
if (value == 0)
|
||||
gen_op_compare_logical_T0_0();
|
||||
else
|
||||
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
|
||||
**/
|
||||
@ -170,112 +125,75 @@ DEFINE_INSN(store, T1, crb);
|
||||
|
||||
#undef DEFINE_INSN
|
||||
|
||||
#define DEFINE_INSN(OP, REG) \
|
||||
void powerpc_dyngen::gen_##OP##_##REG##_cr(int crf) \
|
||||
{ \
|
||||
switch (crf) { \
|
||||
case 0: gen_op_##OP##_##REG##_cr0(); break; \
|
||||
case 1: gen_op_##OP##_##REG##_cr1(); break; \
|
||||
case 2: gen_op_##OP##_##REG##_cr2(); break; \
|
||||
case 3: gen_op_##OP##_##REG##_cr3(); break; \
|
||||
case 4: gen_op_##OP##_##REG##_cr4(); break; \
|
||||
case 5: gen_op_##OP##_##REG##_cr5(); break; \
|
||||
case 6: gen_op_##OP##_##REG##_cr6(); break; \
|
||||
case 7: gen_op_##OP##_##REG##_cr7(); break; \
|
||||
default: abort(); \
|
||||
} \
|
||||
#define DEFINE_INSN(OP, REG) \
|
||||
void powerpc_dyngen::gen_##OP##_##REG##_crf(int crf) \
|
||||
{ \
|
||||
switch (crf) { \
|
||||
case 0: gen_op_##OP##_##REG##_cr0(); break; \
|
||||
case 1: gen_op_##OP##_##REG##_cr1(); break; \
|
||||
case 2: gen_op_##OP##_##REG##_cr2(); break; \
|
||||
case 3: gen_op_##OP##_##REG##_cr3(); break; \
|
||||
case 4: gen_op_##OP##_##REG##_cr4(); break; \
|
||||
case 5: gen_op_##OP##_##REG##_cr5(); break; \
|
||||
case 6: gen_op_##OP##_##REG##_cr6(); break; \
|
||||
case 7: gen_op_##OP##_##REG##_cr7(); break; \
|
||||
default: abort(); \
|
||||
} \
|
||||
}
|
||||
|
||||
DEFINE_INSN(load, RC);
|
||||
DEFINE_INSN(store, RC);
|
||||
DEFINE_INSN(commit, so_cache);
|
||||
DEFINE_INSN(commit, rc_cache);
|
||||
DEFINE_INSN(load, T0);
|
||||
DEFINE_INSN(store, T0);
|
||||
|
||||
#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)
|
||||
{
|
||||
#if 1
|
||||
if (BO_CONDITIONAL_BRANCH(bo)) {
|
||||
enum { lt, gt, eq, so };
|
||||
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)) {
|
||||
switch (n) {
|
||||
#define C(CR) \
|
||||
case _(CR,0,0): gen_b##CR##_0x(npc); break; \
|
||||
case _(CR,0,1): gen_b##CR##_0x(npc); break; \
|
||||
case _(CR,1,0): gen_b##CR##_10(npc); break; \
|
||||
case _(CR,1,1): gen_b##CR##_11(npc); break;
|
||||
C(lt); C(gt); C(eq); C(so);
|
||||
#undef C
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (n) {
|
||||
#define C(CR) \
|
||||
case _(CR,0,0): gen_bn##CR##_0x(npc); break; \
|
||||
case _(CR,0,1): gen_bn##CR##_0x(npc); break; \
|
||||
case _(CR,1,0): gen_bn##CR##_10(npc); break; \
|
||||
case _(CR,1,1): gen_bn##CR##_11(npc); break;
|
||||
C(lt); C(gt); C(eq); C(so);
|
||||
#undef C
|
||||
}
|
||||
}
|
||||
gen_load_T0_CR();
|
||||
gen_and_32_T0_im(1 << (31 - bi));
|
||||
}
|
||||
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(npc); break;
|
||||
case _(0,0,0,1): gen_op_branch_A0_bo_0001(npc); break;
|
||||
case _(0,0,1,0):
|
||||
case _(0,0,1,1): gen_op_branch_A0_bo_001x(npc); break;
|
||||
case _(0,1,0,0): gen_op_branch_A0_bo_0100(npc); break;
|
||||
case _(0,1,0,1): gen_op_branch_A0_bo_0101(npc); break;
|
||||
case _(0,1,1,0):
|
||||
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;
|
||||
case _(1,0,0,1):
|
||||
case _(1,1,0,1): gen_op_branch_A0_bo_1x01(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(); 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();
|
||||
}
|
||||
}
|
||||
else {
|
||||
gen_commit_cr();
|
||||
if (BO_DECREMENT_CTR(bo)) {
|
||||
gen_decrement_ctr_T0();
|
||||
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();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -37,36 +37,6 @@ class powerpc_dyngen
|
||||
# include "ppc-dyngen-ops.hpp"
|
||||
#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:
|
||||
|
||||
// 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))
|
||||
#ifdef NO_DEFINE_ALIAS
|
||||
#define DEFINE_ALIAS(NAME,N)
|
||||
#define DEFINE_ALIAS_CLOBBER_SO(NAME,N)
|
||||
#define DEFINE_ALIAS_CLOBBER_CR(NAME,N)
|
||||
#else
|
||||
#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
|
||||
|
||||
// Misc instructions
|
||||
DEFINE_ALIAS(inc_32_mem,1);
|
||||
DEFINE_ALIAS(mtcrf_T0_im,1);
|
||||
DEFINE_ALIAS(nego_T0,0);
|
||||
|
||||
// Condition registers
|
||||
private:
|
||||
void gen_commit_so_cache_cr(int crf);
|
||||
void gen_commit_rc_cache_cr(int crf);
|
||||
public:
|
||||
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);
|
||||
DEFINE_ALIAS(load_T0_CR,0);
|
||||
DEFINE_ALIAS(store_T0_CR,0);
|
||||
void gen_load_T0_crf(int crf);
|
||||
void gen_store_T0_crf(int crf);
|
||||
void gen_load_T0_crb(int i);
|
||||
void gen_load_T1_crb(int i);
|
||||
void gen_store_T0_crb(int i);
|
||||
void gen_store_T1_crb(int i);
|
||||
void gen_load_RC_cr(int crf);
|
||||
void gen_store_RC_cr(int crf);
|
||||
void gen_prepare_RC(int bi);
|
||||
void gen_mtcrf_T0_im(uint32 mask);
|
||||
|
||||
// Special purpose registers
|
||||
DEFINE_ALIAS(load_T0_XER,0);
|
||||
DEFINE_ALIAS(store_T0_XER,0);
|
||||
DEFINE_ALIAS(load_T0_PC,0);
|
||||
DEFINE_ALIAS(store_T0_PC,0);
|
||||
DEFINE_ALIAS(set_PC_im,1);
|
||||
@ -150,11 +108,7 @@ public:
|
||||
DEFINE_ALIAS(branch_A0_if_not_T0,1);
|
||||
|
||||
// Compare & Record instructions
|
||||
DEFINE_ALIAS_CLOBBER_SO(record_nego_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);
|
||||
DEFINE_ALIAS(record_cr0_T0,0);
|
||||
void gen_compare_T0_T1(int crf);
|
||||
void gen_compare_T0_im(int crf, int32 value);
|
||||
void gen_compare_logical_T0_T1(int crf);
|
||||
@ -164,11 +118,11 @@ public:
|
||||
DEFINE_ALIAS(mulhw_T0_T1,0);
|
||||
DEFINE_ALIAS(mulhwu_T0_T1,0);
|
||||
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_CLOBBER_SO(divwo_T0_T1,0);
|
||||
DEFINE_ALIAS(divwo_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
|
||||
DEFINE_ALIAS(slw_T0_T1,0);
|
||||
@ -184,40 +138,27 @@ public:
|
||||
DEFINE_ALIAS(addo_T0_T1,0);
|
||||
DEFINE_ALIAS(addc_T0_im,1);
|
||||
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_CLOBBER_SO(addeo_T0_T1,0);
|
||||
DEFINE_ALIAS(addeo_T0_T1,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_CLOBBER_SO(addzeo_T0,0);
|
||||
DEFINE_ALIAS(addzeo_T0,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_T1,0);
|
||||
DEFINE_ALIAS_CLOBBER_SO(subfco_T0_T1,0);
|
||||
DEFINE_ALIAS(subfco_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_CLOBBER_SO(subfmeo_T0,0);
|
||||
DEFINE_ALIAS(subfmeo_T0,0);
|
||||
DEFINE_ALIAS(subfze_T0,0);
|
||||
DEFINE_ALIAS_CLOBBER_SO(subfzeo_T0,0);
|
||||
DEFINE_ALIAS(subfzeo_T0,0);
|
||||
|
||||
// Branch instructions
|
||||
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_0
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include "cpu/ppc/ppc-operands.hpp"
|
||||
|
||||
#ifdef SHEEPSHAVER
|
||||
#include "xlowmem.h"
|
||||
#include "cpu_emulation.h"
|
||||
#endif
|
||||
|
||||
@ -445,16 +444,6 @@ powerpc_cpu::compile_block(uint32 entry_point)
|
||||
const int bo = BO_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;
|
||||
if (LK_field::test(opcode))
|
||||
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(CRXOR): // Condition Register XOR
|
||||
{
|
||||
dg.gen_commit_cr();
|
||||
dg.gen_load_T0_crb(crbA_field::extract(opcode));
|
||||
dg.gen_load_T1_crb(crbB_field::extract(opcode));
|
||||
switch (ii->mnemo) {
|
||||
@ -660,8 +648,9 @@ powerpc_cpu::compile_block(uint32 entry_point)
|
||||
{
|
||||
dg.gen_load_T0_GPR(rA_field::extract(opcode));
|
||||
if (OE_field::test(opcode))
|
||||
dg.gen_record_nego_T0();
|
||||
dg.gen_neg_32_T0();
|
||||
dg.gen_nego_T0();
|
||||
else
|
||||
dg.gen_neg_32_T0();
|
||||
if (Rc_field::test(opcode))
|
||||
dg.gen_record_cr0_T0();
|
||||
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
|
||||
{
|
||||
dg.gen_commit_cr();
|
||||
dg.gen_load_T0_CR();
|
||||
dg.gen_store_T0_GPR(rD_field::extract(opcode));
|
||||
break;
|
||||
@ -1003,16 +991,14 @@ powerpc_cpu::compile_block(uint32 entry_point)
|
||||
}
|
||||
case PPC_I(MTCRF): // Move to Condition Register Fields
|
||||
{
|
||||
dg.gen_commit_cr();
|
||||
dg.gen_load_T0_GPR(rS_field::extract(opcode));
|
||||
dg.gen_mtcrf_T0_im(field2mask[CRM_field::extract(opcode)]);
|
||||
break;
|
||||
}
|
||||
case PPC_I(MCRF): // Move Condition Register Field
|
||||
{
|
||||
dg.gen_commit_cr();
|
||||
dg.gen_load_RC_cr(crfS_field::extract(opcode));
|
||||
dg.gen_store_RC_cr(crfD_field::extract(opcode));
|
||||
dg.gen_load_T0_crf(crfS_field::extract(opcode));
|
||||
dg.gen_store_T0_crf(crfD_field::extract(opcode));
|
||||
break;
|
||||
}
|
||||
default: // Direct call to instruction handler
|
||||
@ -1043,7 +1029,6 @@ powerpc_cpu::compile_block(uint32 entry_point)
|
||||
dg.gen_set_PC_im(dpc);
|
||||
}
|
||||
sync_pc_offset += 4;
|
||||
dg.gen_commit_cr();
|
||||
dg.gen_invoke_CPU_im(func, opcode);
|
||||
}
|
||||
}
|
||||
@ -1054,7 +1039,6 @@ powerpc_cpu::compile_block(uint32 entry_point)
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
dg.gen_commit_cr();
|
||||
dg.gen_exec_return();
|
||||
dg.gen_end();
|
||||
bi->end_pc = dpc;
|
||||
|
Loading…
Reference in New Issue
Block a user