diff --git a/src/emu/cpu/powerpc/ppccom.c b/src/emu/cpu/powerpc/ppccom.c index b01adce2c10..1edcaef32e0 100644 --- a/src/emu/cpu/powerpc/ppccom.c +++ b/src/emu/cpu/powerpc/ppccom.c @@ -20,6 +20,17 @@ +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define DOUBLE_SIGN (U64(0x8000000000000000)) +#define DOUBLE_EXP (U64(0x7ff0000000000000)) +#define DOUBLE_FRAC (U64(0x000fffffffffffff)) +#define DOUBLE_ZERO (0) + + + /*************************************************************************** FUNCTION PROTOTYPES ***************************************************************************/ @@ -174,6 +185,98 @@ INLINE void set_decrementer(powerpc_state *ppc, UINT32 newdec) } +/*------------------------------------------------- + is_nan_double - is a double value a NaN +-------------------------------------------------*/ + +INLINE int is_nan_double(double x) +{ + UINT64 xi = *(UINT64*)&x; + return( ((xi & DOUBLE_EXP) == DOUBLE_EXP) && + ((xi & DOUBLE_FRAC) != DOUBLE_ZERO) ); +} + + +/*------------------------------------------------- + is_qnan_double - is a double value a + quiet NaN +-------------------------------------------------*/ + +INLINE int is_qnan_double(double x) +{ + UINT64 xi = *(UINT64*)&x; + return( ((xi & DOUBLE_EXP) == DOUBLE_EXP) && + ((xi & U64(0x0007fffffffffff)) == U64(0x000000000000000)) && + ((xi & U64(0x000800000000000)) == U64(0x000800000000000)) ); +} + + +/*------------------------------------------------- + is_snan_double - is a double value a + signaling NaN +-------------------------------------------------*/ + +INLINE int is_snan_double(double x) +{ + UINT64 xi = *(UINT64*)&x; + return( ((xi & DOUBLE_EXP) == DOUBLE_EXP) && + ((xi & DOUBLE_FRAC) != DOUBLE_ZERO) && + ((xi & U64(0x0008000000000000)) == DOUBLE_ZERO) ); +} + + +/*------------------------------------------------- + is_infinity_double - is a double value + infinity +-------------------------------------------------*/ + +INLINE int is_infinity_double(double x) +{ + UINT64 xi = *(UINT64*)&x; + return( ((xi & DOUBLE_EXP) == DOUBLE_EXP) && + ((xi & DOUBLE_FRAC) == DOUBLE_ZERO) ); +} + + +/*------------------------------------------------- + is_normalized_double - is a double value + normalized +-------------------------------------------------*/ + +INLINE int is_normalized_double(double x) +{ + UINT64 exp; + UINT64 xi = *(UINT64*)&x; + exp = (xi & DOUBLE_EXP) >> 52; + + return (exp >= 1) && (exp <= 2046); +} + + +/*------------------------------------------------- + is_denormalized_double - is a double value + denormalized +-------------------------------------------------*/ + +INLINE int is_denormalized_double(double x) +{ + UINT64 xi = *(UINT64*)&x; + return( ((xi & DOUBLE_EXP) == 0) && + ((xi & DOUBLE_FRAC) != DOUBLE_ZERO) ); +} + + +/*------------------------------------------------- + sign_double - return sign of a double value +-------------------------------------------------*/ + +INLINE int sign_double(double x) +{ + UINT64 xi = *(UINT64*)&x; + return ((xi & DOUBLE_SIGN) != 0); +} + + /*************************************************************************** INITIALIZATION AND SHUTDOWN @@ -996,6 +1099,59 @@ void ppccom_execute_mtdcr(powerpc_state *ppc) +/*************************************************************************** + FLOATING POINT STATUS FLAGS HANDLING +***************************************************************************/ + +/*------------------------------------------------- + ppccom_update_fprf - update the FPRF field + of the FPSCR register +-------------------------------------------------*/ + +void ppccom_update_fprf(powerpc_state *ppc) +{ + UINT32 fprf; + double f = ppc->f[ppc->param0]; + + if (is_qnan_double(f)) + { + fprf = 0x11; + } + else if (is_infinity_double(f)) + { + if (sign_double(f)) /* -Infinity */ + fprf = 0x09; + else /* +Infinity */ + fprf = 0x05; + } + else if (is_normalized_double(f)) + { + if (sign_double(f)) /* -Normalized */ + fprf = 0x08; + else /* +Normalized */ + fprf = 0x04; + } + else if (is_denormalized_double(f)) + { + if (sign_double(f)) /* -Denormalized */ + fprf = 0x18; + else /* +Denormalized */ + fprf = 0x14; + } + else + { + if (sign_double(f)) /* -Zero */ + fprf = 0x12; + else /* +Zero */ + fprf = 0x02; + } + + ppc->fpscr &= ~0x0001f000; + ppc->fpscr |= fprf << 12; +} + + + /*************************************************************************** COMMON GET/SET INFO ***************************************************************************/ diff --git a/src/emu/cpu/powerpc/ppccom.h b/src/emu/cpu/powerpc/ppccom.h index e3ae41949ff..85e556cb9b4 100644 --- a/src/emu/cpu/powerpc/ppccom.h +++ b/src/emu/cpu/powerpc/ppccom.h @@ -596,6 +596,8 @@ void ppccom_execute_mtspr(powerpc_state *ppc); void ppccom_execute_mfdcr(powerpc_state *ppc); void ppccom_execute_mtdcr(powerpc_state *ppc); +void ppccom_update_fprf(powerpc_state *ppc); + void ppc4xx_set_info(powerpc_state *ppc, UINT32 state, cpuinfo *info); void ppc4xx_get_info(powerpc_state *ppc, UINT32 state, cpuinfo *info); diff --git a/src/emu/cpu/powerpc/ppcdrc.c b/src/emu/cpu/powerpc/ppcdrc.c index 78cfac2f3e5..cf93f3077d8 100644 --- a/src/emu/cpu/powerpc/ppcdrc.c +++ b/src/emu/cpu/powerpc/ppcdrc.c @@ -2334,6 +2334,20 @@ static void generate_compute_flags(powerpc_state *ppc, drcuml_block *block, cons UML_OR(block, CR32(0), IREG(1), XERSO32); // or [cr0],i1,[xerso] } +/*------------------------------------------------- + generate_fp_flags - compute FPSCR floating + point status flags +-------------------------------------------------*/ + +static void generate_fp_flags(powerpc_state *ppc, drcuml_block *block, const opcode_desc *desc, int updatefprf) +{ + /* for now, only handle the FPRF field */ + if (updatefprf) + { + UML_MOV(block, MEM(&ppc->param0), IMM(G_RD(desc->opptr.l[0]))); + UML_CALLC(block, ppccom_update_fprf, ppc); + } +} /*------------------------------------------------- generate_branch - generate an unconditional @@ -3795,6 +3809,7 @@ static int generate_instruction_3b(powerpc_state *ppc, drcuml_block *block, comp return generate_instruction_3f(ppc, block, compiler, desc); UML_FDADD(block, FREG(0), F64(G_RA(op)), F64(G_RB(op))); // fdadd f0,ra,rb UML_FDRNDS(block, F64(G_RD(op)), FREG(0)); // fdrnds rd,f0 + generate_fp_flags(ppc, block, desc, TRUE); return TRUE; case 0x14: /* FSUBSx */ @@ -3802,6 +3817,7 @@ static int generate_instruction_3b(powerpc_state *ppc, drcuml_block *block, comp return generate_instruction_3f(ppc, block, compiler, desc); UML_FDSUB(block, FREG(0), F64(G_RA(op)), F64(G_RB(op))); // fdsub f0,ra,rb UML_FDRNDS(block, F64(G_RD(op)), FREG(0)); // fdrnds rd,f0 + generate_fp_flags(ppc, block, desc, TRUE); return TRUE; case 0x19: /* FMULSx */ @@ -3809,6 +3825,7 @@ static int generate_instruction_3b(powerpc_state *ppc, drcuml_block *block, comp return generate_instruction_3f(ppc, block, compiler, desc); UML_FDMUL(block, FREG(0), F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc UML_FDRNDS(block, F64(G_RD(op)), FREG(0)); // fdrnds rd,f0 + generate_fp_flags(ppc, block, desc, TRUE); return TRUE; case 0x12: /* FDIVSx */ @@ -3816,6 +3833,7 @@ static int generate_instruction_3b(powerpc_state *ppc, drcuml_block *block, comp return generate_instruction_3f(ppc, block, compiler, desc); UML_FDDIV(block, FREG(0), F64(G_RA(op)), F64(G_RB(op))); // fddiv f0,ra,rb UML_FDRNDS(block, F64(G_RD(op)), FREG(0)); // fdrnds rd,f0 + generate_fp_flags(ppc, block, desc, TRUE); return TRUE; case 0x16: /* FSQRTSx */ @@ -3823,12 +3841,14 @@ static int generate_instruction_3b(powerpc_state *ppc, drcuml_block *block, comp return generate_instruction_3f(ppc, block, compiler, desc); UML_FDSQRT(block, FREG(0), F64(G_RB(op))); // fdsqrt f0,rb UML_FDRNDS(block, F64(G_RD(op)), FREG(0)); // fdrnds rd,f0 + generate_fp_flags(ppc, block, desc, TRUE); return TRUE; case 0x18: /* FRESx */ UML_FSFRFLT(block, FREG(0), F64(G_RB(op)), QWORD); // fsfrlt f0,rb,qword UML_FSRECIP(block, FREG(0), FREG(0)); // fsrecip f0,f0 UML_FDFRFLT(block, F64(G_RD(op)), FREG(0), DWORD); // fdfrflt rd,f0,dword + generate_fp_flags(ppc, block, desc, TRUE); return TRUE; case 0x1d: /* FMADDSx */ @@ -3837,6 +3857,7 @@ static int generate_instruction_3b(powerpc_state *ppc, drcuml_block *block, comp UML_FDMUL(block, FREG(0), F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc UML_FDADD(block, FREG(0), FREG(0), F64(G_RB(op))); // fdadd f0,f0,rb UML_FDRNDS(block, F64(G_RD(op)), FREG(0)); // fdrnds rd,f0 + generate_fp_flags(ppc, block, desc, TRUE); return TRUE; case 0x1c: /* FMSUBSx */ @@ -3845,6 +3866,7 @@ static int generate_instruction_3b(powerpc_state *ppc, drcuml_block *block, comp UML_FDMUL(block, FREG(0), F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc UML_FDSUB(block, FREG(0), FREG(0), F64(G_RB(op))); // fdsub f0,f0,rb UML_FDRNDS(block, F64(G_RD(op)), FREG(0)); // fdrnds rd,f0 + generate_fp_flags(ppc, block, desc, TRUE); return TRUE; case 0x1f: /* FNMADDSx */ @@ -3854,6 +3876,7 @@ static int generate_instruction_3b(powerpc_state *ppc, drcuml_block *block, comp UML_FDADD(block, FREG(0), FREG(0), F64(G_RB(op))); // fdadd f0,f0,rb UML_FDNEG(block, FREG(0), FREG(0)); // fdneg f0,f0 UML_FDRNDS(block, F64(G_RD(op)), FREG(0)); // fdrnds rd,f0 + generate_fp_flags(ppc, block, desc, TRUE); return TRUE; case 0x1e: /* FNMSUBSx */ @@ -3862,6 +3885,7 @@ static int generate_instruction_3b(powerpc_state *ppc, drcuml_block *block, comp UML_FDMUL(block, FREG(0), F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc UML_FDSUB(block, FREG(0), F64(G_RB(op)), FREG(0)); // fdsub f0,rb,f0 UML_FDRNDS(block, F64(G_RD(op)), FREG(0)); // fdrnds rd,f0 + generate_fp_flags(ppc, block, desc, TRUE); return TRUE; } @@ -3887,26 +3911,32 @@ static int generate_instruction_3f(powerpc_state *ppc, drcuml_block *block, comp { case 0x15: /* FADDx */ UML_FDADD(block, F64(G_RD(op)), F64(G_RA(op)), F64(G_RB(op))); // fdadd rd,ra,rb + generate_fp_flags(ppc, block, desc, TRUE); return TRUE; case 0x14: /* FSUBx */ UML_FDSUB(block, F64(G_RD(op)), F64(G_RA(op)), F64(G_RB(op))); // fdsub rd,ra,rb + generate_fp_flags(ppc, block, desc, TRUE); return TRUE; case 0x19: /* FMULx */ UML_FDMUL(block, F64(G_RD(op)), F64(G_RA(op)), F64(G_REGC(op))); // fdmul rd,ra,rc + generate_fp_flags(ppc, block, desc, TRUE); return TRUE; case 0x12: /* FDIVx */ UML_FDDIV(block, F64(G_RD(op)), F64(G_RA(op)), F64(G_RB(op))); // fddiv rd,ra,rb + generate_fp_flags(ppc, block, desc, TRUE); return TRUE; case 0x16: /* FSQRTx */ UML_FDSQRT(block, F64(G_RD(op)), F64(G_RB(op))); // fdsqrt rd,rb + generate_fp_flags(ppc, block, desc, TRUE); return TRUE; case 0x1a: /* FRSQRTEx */ UML_FDRSQRT(block, F64(G_RD(op)), F64(G_RB(op))); // fdrsqrt rd,rb + generate_fp_flags(ppc, block, desc, TRUE); return TRUE; case 0x17: /* FSELx */ @@ -3918,22 +3948,26 @@ static int generate_instruction_3f(powerpc_state *ppc, drcuml_block *block, comp case 0x1d: /* FMADDx */ UML_FDMUL(block, FREG(0), F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc UML_FDADD(block, F64(G_RD(op)), FREG(0), F64(G_RB(op))); // fdadd rd,f0,rb + generate_fp_flags(ppc, block, desc, TRUE); return TRUE; case 0x1f: /* FNMADDx */ UML_FDMUL(block, FREG(0), F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc UML_FDADD(block, FREG(0), FREG(0), F64(G_RB(op))); // fdadd f0,f0,rb UML_FDNEG(block, F64(G_RD(op)), FREG(0)); // fdneg rd,f0 + generate_fp_flags(ppc, block, desc, TRUE); return TRUE; case 0x1c: /* FMSUBx */ UML_FDMUL(block, FREG(0), F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc UML_FDSUB(block, F64(G_RD(op)), FREG(0), F64(G_RB(op))); // fdsub rd,f0,rb + generate_fp_flags(ppc, block, desc, TRUE); return TRUE; case 0x1e: /* FNMSUBx */ UML_FDMUL(block, FREG(0), F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc UML_FDSUB(block, F64(G_RD(op)), F64(G_RB(op)), FREG(0)); // fdsub rd,rb,f0 + generate_fp_flags(ppc, block, desc, TRUE); return TRUE; } } @@ -3956,6 +3990,7 @@ static int generate_instruction_3f(powerpc_state *ppc, drcuml_block *block, comp case 0x00c: /* FRSPx */ UML_FDRNDS(block, F64(G_RD(op)), F64(G_RB(op))); // fdrnds rd,rb + generate_fp_flags(ppc, block, desc, TRUE); return TRUE; case 0x00e: /* FCTIWx */ diff --git a/src/emu/cpu/powerpc/ppcfe.c b/src/emu/cpu/powerpc/ppcfe.c index 064f7ae9aa2..47ecc200fa6 100644 --- a/src/emu/cpu/powerpc/ppcfe.c +++ b/src/emu/cpu/powerpc/ppcfe.c @@ -1243,6 +1243,7 @@ static int describe_instruction_3b(powerpc_state *ppc, UINT32 op, opcode_desc *d desc->cycles = 18; /* 603 */ else desc->cycles = 17; /* ??? */ + FPSCR_MODIFIED(desc, 4); return TRUE; case 0x14: /* FSUBSx */ @@ -1252,6 +1253,7 @@ static int describe_instruction_3b(powerpc_state *ppc, UINT32 op, opcode_desc *d FPR_MODIFIED(desc, G_RD(op)); if (op & M_RC) CR_MODIFIED(desc, 1); + FPSCR_MODIFIED(desc, 4); return TRUE; case 0x19: /* FMULSx - not the same form as FSUB/FADD! */ @@ -1260,6 +1262,7 @@ static int describe_instruction_3b(powerpc_state *ppc, UINT32 op, opcode_desc *d FPR_MODIFIED(desc, G_RD(op)); if (op & M_RC) CR_MODIFIED(desc, 1); + FPSCR_MODIFIED(desc, 4); return TRUE; case 0x16: /* FSQRTSx */ @@ -1268,6 +1271,7 @@ static int describe_instruction_3b(powerpc_state *ppc, UINT32 op, opcode_desc *d FPR_MODIFIED(desc, G_RD(op)); if (op & M_RC) CR_MODIFIED(desc, 1); + FPSCR_MODIFIED(desc, 4); return TRUE; case 0x1c: /* FMSUBSx */ @@ -1280,6 +1284,7 @@ static int describe_instruction_3b(powerpc_state *ppc, UINT32 op, opcode_desc *d FPR_MODIFIED(desc, G_RD(op)); if (op & M_RC) CR_MODIFIED(desc, 1); + FPSCR_MODIFIED(desc, 4); return TRUE; } @@ -1317,6 +1322,7 @@ static int describe_instruction_3f(powerpc_state *ppc, UINT32 op, opcode_desc *d desc->cycles = 33; /* 603 */ else desc->cycles = 31; /* ??? */ + FPSCR_MODIFIED(desc, 4); return TRUE; case 0x19: /* FMULx */ @@ -1326,6 +1332,7 @@ static int describe_instruction_3f(powerpc_state *ppc, UINT32 op, opcode_desc *d if (op & M_RC) CR_MODIFIED(desc, 1); desc->cycles = 2; /* 601/603 */ + FPSCR_MODIFIED(desc, 4); return TRUE; case 0x14: /* FSUBx */ @@ -1335,6 +1342,7 @@ static int describe_instruction_3f(powerpc_state *ppc, UINT32 op, opcode_desc *d FPR_MODIFIED(desc, G_RD(op)); if (op & M_RC) CR_MODIFIED(desc, 1); + FPSCR_MODIFIED(desc, 4); return TRUE; case 0x16: /* FSQRTx */ @@ -1343,9 +1351,19 @@ static int describe_instruction_3f(powerpc_state *ppc, UINT32 op, opcode_desc *d FPR_MODIFIED(desc, G_RD(op)); if (op & M_RC) CR_MODIFIED(desc, 1); + FPSCR_MODIFIED(desc, 4); return TRUE; case 0x17: /* FSELx */ + FPR_USED(desc, G_RA(op)); + FPR_USED(desc, G_RB(op)); + FPR_USED(desc, G_REGC(op)); + FPR_MODIFIED(desc, G_RD(op)); + if (op & M_RC) + CR_MODIFIED(desc, 1); + desc->cycles = 2; /* 601/603 */ + return TRUE; + case 0x1c: /* FMSUBx */ case 0x1d: /* FMADDx */ case 0x1e: /* FNMSUBx */ @@ -1357,6 +1375,7 @@ static int describe_instruction_3f(powerpc_state *ppc, UINT32 op, opcode_desc *d if (op & M_RC) CR_MODIFIED(desc, 1); desc->cycles = 2; /* 601/603 */ + FPSCR_MODIFIED(desc, 4); return TRUE; } } @@ -1379,6 +1398,7 @@ static int describe_instruction_3f(powerpc_state *ppc, UINT32 op, opcode_desc *d case 0x00c: /* FRSPx */ case 0x00e: /* FCTIWx */ case 0x00f: /* FCTIWZx */ + FPSCR_MODIFIED(desc, 4); case 0x028: /* FNEGx */ case 0x048: /* FMRx */ case 0x088: /* FNABSx */