summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--src/emu/cpu/powerpc/ppccom.c156
-rw-r--r--src/emu/cpu/powerpc/ppccom.h2
-rw-r--r--src/emu/cpu/powerpc/ppcdrc.c35
-rw-r--r--src/emu/cpu/powerpc/ppcfe.c20
4 files changed, 213 insertions, 0 deletions
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
@@ -21,6 +21,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
@@ -997,6 +1100,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 */