aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/arm/skyeye_common/vfp/vfp.cpp
diff options
context:
space:
mode:
authorGravatar bunnei <bunneidev@gmail.com>2014-10-29 22:25:54 -0400
committerGravatar bunnei <bunneidev@gmail.com>2014-11-02 01:04:41 -0500
commitbc6989b0752b601762499fc1f3a0771980fd88f5 (patch)
treed07786caf1858fb41812d6b38b9865260e2178f4 /src/core/arm/skyeye_common/vfp/vfp.cpp
parent2ca12e7f3899a58e112ee8bb4e46d11ca61f7152 (diff)
ARM: Merge latest VFP fixes from 3dmoo team.
Diffstat (limited to 'src/core/arm/skyeye_common/vfp/vfp.cpp')
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp.cpp476
1 files changed, 258 insertions, 218 deletions
diff --git a/src/core/arm/skyeye_common/vfp/vfp.cpp b/src/core/arm/skyeye_common/vfp/vfp.cpp
index e4fa3c20..454f6009 100644
--- a/src/core/arm/skyeye_common/vfp/vfp.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfp.cpp
@@ -28,230 +28,270 @@
#include "core/arm/skyeye_common/armdefs.h"
#include "core/arm/skyeye_common/vfp/vfp.h"
+#define DEBUG DBG
+
//ARMul_State* persistent_state; /* function calls from SoftFloat lib don't have an access to ARMul_state. */
unsigned
VFPInit (ARMul_State *state)
{
- state->VFP[VFP_OFFSET(VFP_FPSID)] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 |
- VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION;
- state->VFP[VFP_OFFSET(VFP_FPEXC)] = 0;
- state->VFP[VFP_OFFSET(VFP_FPSCR)] = 0;
-
- //persistent_state = state;
- /* Reset only specify VFP_FPEXC_EN = '0' */
-
- return No_exp;
+ state->VFP[VFP_OFFSET(VFP_FPSID)] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 |
+ VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION;
+ state->VFP[VFP_OFFSET(VFP_FPEXC)] = 0;
+ state->VFP[VFP_OFFSET(VFP_FPSCR)] = 0;
+
+ //persistent_state = state;
+ /* Reset only specify VFP_FPEXC_EN = '0' */
+
+ return 0;
}
unsigned
-VFPMRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value)
+VFPMRC (ARMul_State * state, unsigned type, u32 instr, u32 * value)
{
- /* MRC<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
- int CoProc = BITS (8, 11); /* 10 or 11 */
- int OPC_1 = BITS (21, 23);
- int Rt = BITS (12, 15);
- int CRn = BITS (16, 19);
- int CRm = BITS (0, 3);
- int OPC_2 = BITS (5, 7);
-
- /* TODO check access permission */
-
- /* CRn/opc1 CRm/opc2 */
-
- if (CoProc == 10 || CoProc == 11)
- {
- #define VFP_MRC_TRANS
- #include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
- #undef VFP_MRC_TRANS
- }
- DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
- instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
-
- return ARMul_CANT;
+ /* MRC<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
+ int CoProc = BITS (8, 11); /* 10 or 11 */
+ int OPC_1 = BITS (21, 23);
+ int Rt = BITS (12, 15);
+ int CRn = BITS (16, 19);
+ int CRm = BITS (0, 3);
+ int OPC_2 = BITS (5, 7);
+
+ /* TODO check access permission */
+
+ /* CRn/opc1 CRm/opc2 */
+
+ if (CoProc == 10 || CoProc == 11) {
+#define VFP_MRC_TRANS
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_MRC_TRANS
+ }
+ DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
+ instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
+
+ return ARMul_CANT;
}
unsigned
-VFPMCR (ARMul_State * state, unsigned type, ARMword instr, ARMword value)
+VFPMCR (ARMul_State * state, unsigned type, u32 instr, u32 value)
{
- /* MCR<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
- int CoProc = BITS (8, 11); /* 10 or 11 */
- int OPC_1 = BITS (21, 23);
- int Rt = BITS (12, 15);
- int CRn = BITS (16, 19);
- int CRm = BITS (0, 3);
- int OPC_2 = BITS (5, 7);
-
- /* TODO check access permission */
-
- /* CRn/opc1 CRm/opc2 */
- if (CoProc == 10 || CoProc == 11)
- {
- #define VFP_MCR_TRANS
- #include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
- #undef VFP_MCR_TRANS
- }
- DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
- instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
-
- return ARMul_CANT;
+ /* MCR<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
+ int CoProc = BITS (8, 11); /* 10 or 11 */
+ int OPC_1 = BITS (21, 23);
+ int Rt = BITS (12, 15);
+ int CRn = BITS (16, 19);
+ int CRm = BITS (0, 3);
+ int OPC_2 = BITS (5, 7);
+
+ /* TODO check access permission */
+
+ /* CRn/opc1 CRm/opc2 */
+ if (CoProc == 10 || CoProc == 11) {
+#define VFP_MCR_TRANS
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_MCR_TRANS
+ }
+ DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
+ instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
+
+ return ARMul_CANT;
}
unsigned
-VFPMRRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value1, ARMword * value2)
+VFPMRRC (ARMul_State * state, unsigned type, u32 instr, u32 * value1, u32 * value2)
{
- /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
- int CoProc = BITS (8, 11); /* 10 or 11 */
- int OPC_1 = BITS (4, 7);
- int Rt = BITS (12, 15);
- int Rt2 = BITS (16, 19);
- int CRm = BITS (0, 3);
-
- if (CoProc == 10 || CoProc == 11)
- {
- #define VFP_MRRC_TRANS
- #include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
- #undef VFP_MRRC_TRANS
- }
- DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
- instr, CoProc, OPC_1, Rt, Rt2, CRm);
-
- return ARMul_CANT;
+ /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
+ int CoProc = BITS (8, 11); /* 10 or 11 */
+ int OPC_1 = BITS (4, 7);
+ int Rt = BITS (12, 15);
+ int Rt2 = BITS (16, 19);
+ int CRm = BITS (0, 3);
+
+ if (CoProc == 10 || CoProc == 11) {
+#define VFP_MRRC_TRANS
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_MRRC_TRANS
+ }
+ DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
+ instr, CoProc, OPC_1, Rt, Rt2, CRm);
+
+ return ARMul_CANT;
}
unsigned
-VFPMCRR (ARMul_State * state, unsigned type, ARMword instr, ARMword value1, ARMword value2)
+VFPMCRR (ARMul_State * state, unsigned type, u32 instr, u32 value1, u32 value2)
{
- /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
- int CoProc = BITS (8, 11); /* 10 or 11 */
- int OPC_1 = BITS (4, 7);
- int Rt = BITS (12, 15);
- int Rt2 = BITS (16, 19);
- int CRm = BITS (0, 3);
-
- /* TODO check access permission */
-
- /* CRn/opc1 CRm/opc2 */
-
- if (CoProc == 11 || CoProc == 10)
- {
- #define VFP_MCRR_TRANS
- #include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
- #undef VFP_MCRR_TRANS
- }
- DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
- instr, CoProc, OPC_1, Rt, Rt2, CRm);
-
- return ARMul_CANT;
+ /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
+ int CoProc = BITS (8, 11); /* 10 or 11 */
+ int OPC_1 = BITS (4, 7);
+ int Rt = BITS (12, 15);
+ int Rt2 = BITS (16, 19);
+ int CRm = BITS (0, 3);
+
+ /* TODO check access permission */
+
+ /* CRn/opc1 CRm/opc2 */
+
+ if (CoProc == 11 || CoProc == 10) {
+#define VFP_MCRR_TRANS
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_MCRR_TRANS
+ }
+ DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
+ instr, CoProc, OPC_1, Rt, Rt2, CRm);
+
+ return ARMul_CANT;
}
unsigned
-VFPSTC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value)
+VFPSTC (ARMul_State * state, unsigned type, u32 instr, u32 * value)
{
- /* STC{L}<c> <coproc>,<CRd>,[<Rn>],<option> */
- int CoProc = BITS (8, 11); /* 10 or 11 */
- int CRd = BITS (12, 15);
- int Rn = BITS (16, 19);
- int imm8 = BITS (0, 7);
- int P = BIT(24);
- int U = BIT(23);
- int D = BIT(22);
- int W = BIT(21);
-
- /* TODO check access permission */
-
- /* VSTM */
- if ( (P|U|D|W) == 0 )
- {
- DEBUG_LOG(ARM11, "In %s, UNDEFINED\n", __FUNCTION__); exit(-1);
- }
- if (CoProc == 10 || CoProc == 11)
- {
- #if 1
- if (P == 0 && U == 0 && W == 0)
- {
- DEBUG_LOG(ARM11, "VSTM Related encodings\n"); exit(-1);
- }
- if (P == U && W == 1)
- {
- DEBUG_LOG(ARM11, "UNDEFINED\n"); exit(-1);
- }
- #endif
-
- #define VFP_STC_TRANS
- #include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
- #undef VFP_STC_TRANS
- }
- DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
- instr, CoProc, CRd, Rn, imm8, P, U, D, W);
-
- return ARMul_CANT;
+ /* STC{L}<c> <coproc>,<CRd>,[<Rn>],<option> */
+ int CoProc = BITS (8, 11); /* 10 or 11 */
+ int CRd = BITS (12, 15);
+ int Rn = BITS (16, 19);
+ int imm8 = BITS (0, 7);
+ int P = BIT(24);
+ int U = BIT(23);
+ int D = BIT(22);
+ int W = BIT(21);
+
+ /* TODO check access permission */
+
+ /* VSTM */
+ if ( (P|U|D|W) == 0 ) {
+ DEBUG("In %s, UNDEFINED\n", __FUNCTION__);
+ exit(-1);
+ }
+ if (CoProc == 10 || CoProc == 11) {
+#if 1
+ if (P == 0 && U == 0 && W == 0) {
+ DEBUG("VSTM Related encodings\n");
+ exit(-1);
+ }
+ if (P == U && W == 1) {
+ DEBUG("UNDEFINED\n");
+ exit(-1);
+ }
+#endif
+
+#define VFP_STC_TRANS
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_STC_TRANS
+ }
+ DEBUG("Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
+ instr, CoProc, CRd, Rn, imm8, P, U, D, W);
+
+ return ARMul_CANT;
}
unsigned
-VFPLDC (ARMul_State * state, unsigned type, ARMword instr, ARMword value)
+VFPLDC (ARMul_State * state, unsigned type, u32 instr, u32 value)
{
- /* LDC{L}<c> <coproc>,<CRd>,[<Rn>] */
- int CoProc = BITS (8, 11); /* 10 or 11 */
- int CRd = BITS (12, 15);
- int Rn = BITS (16, 19);
- int imm8 = BITS (0, 7);
- int P = BIT(24);
- int U = BIT(23);
- int D = BIT(22);
- int W = BIT(21);
-
- /* TODO check access permission */
-
- if ( (P|U|D|W) == 0 )
- {
- DEBUG_LOG(ARM11, "In %s, UNDEFINED\n", __FUNCTION__); exit(-1);
- }
- if (CoProc == 10 || CoProc == 11)
- {
- #define VFP_LDC_TRANS
- #include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
- #undef VFP_LDC_TRANS
- }
- DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
- instr, CoProc, CRd, Rn, imm8, P, U, D, W);
-
- return ARMul_CANT;
+ /* LDC{L}<c> <coproc>,<CRd>,[<Rn>] */
+ int CoProc = BITS (8, 11); /* 10 or 11 */
+ int CRd = BITS (12, 15);
+ int Rn = BITS (16, 19);
+ int imm8 = BITS (0, 7);
+ int P = BIT(24);
+ int U = BIT(23);
+ int D = BIT(22);
+ int W = BIT(21);
+
+ /* TODO check access permission */
+
+ if ( (P|U|D|W) == 0 ) {
+ DEBUG("In %s, UNDEFINED\n", __FUNCTION__);
+ exit(-1);
+ }
+ if (CoProc == 10 || CoProc == 11) {
+#define VFP_LDC_TRANS
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_LDC_TRANS
+ }
+ DEBUG("Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
+ instr, CoProc, CRd, Rn, imm8, P, U, D, W);
+
+ return ARMul_CANT;
}
unsigned
-VFPCDP (ARMul_State * state, unsigned type, ARMword instr)
+VFPCDP (ARMul_State * state, unsigned type, u32 instr)
{
- /* CDP<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> */
- int CoProc = BITS (8, 11); /* 10 or 11 */
- int OPC_1 = BITS (20, 23);
- int CRd = BITS (12, 15);
- int CRn = BITS (16, 19);
- int CRm = BITS (0, 3);
- int OPC_2 = BITS (5, 7);
-
- /* TODO check access permission */
-
- /* CRn/opc1 CRm/opc2 */
-
- if (CoProc == 10 || CoProc == 11)
- {
- #define VFP_CDP_TRANS
- #include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
- #undef VFP_CDP_TRANS
-
- int exceptions = 0;
- if (CoProc == 10)
- exceptions = vfp_single_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
- else
- exceptions = vfp_double_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
-
- vfp_raise_exceptions(state, exceptions, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
-
- return ARMul_DONE;
- }
- DEBUG_LOG(ARM11, "Can't identify %x\n", instr);
- return ARMul_CANT;
+ /* CDP<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> */
+ int CoProc = BITS (8, 11); /* 10 or 11 */
+ int OPC_1 = BITS (20, 23);
+ int CRd = BITS (12, 15);
+ int CRn = BITS (16, 19);
+ int CRm = BITS (0, 3);
+ int OPC_2 = BITS (5, 7);
+
+ //ichfly
+ /*if ((instr & 0x0FBF0FD0) == 0x0EB70AC0) //vcvt.f64.f32 d8, s16 (s is bit 0-3 and LSB bit 22) (d is bit 12 - 15 MSB is Bit 6)
+ {
+ struct vfp_double vdd;
+ struct vfp_single vsd;
+ int dn = BITS(12, 15) + (BIT(22) << 4);
+ int sd = (BITS(0, 3) << 1) + BIT(5);
+ s32 n = vfp_get_float(state, sd);
+ vfp_single_unpack(&vsd, n);
+ if (vsd.exponent & 0x80)
+ {
+ vdd.exponent = (vsd.exponent&~0x80) | 0x400;
+ }
+ else
+ {
+ vdd.exponent = vsd.exponent | 0x380;
+ }
+ vdd.sign = vsd.sign;
+ vdd.significand = (u64)(vsd.significand & ~0xC0000000) << 32; // I have no idea why but the 2 uppern bits are not from the significand
+ vfp_put_double(state, vfp_double_pack(&vdd), dn);
+ return ARMul_DONE;
+ }
+ if ((instr & 0x0FBF0FD0) == 0x0EB70BC0) //vcvt.f32.f64 s15, d6
+ {
+ struct vfp_double vdd;
+ struct vfp_single vsd;
+ int sd = BITS(0, 3) + (BIT(5) << 4);
+ int dn = (BITS(12, 15) << 1) + BIT(22);
+ vfp_double_unpack(&vdd, vfp_get_double(state, sd));
+ if (vdd.exponent & 0x400) //todo if the exponent is to low or to high for this convert
+ {
+ vsd.exponent = (vdd.exponent) | 0x80;
+ }
+ else
+ {
+ vsd.exponent = vdd.exponent & ~0x80;
+ }
+ vsd.exponent &= 0xFF;
+ // vsd.exponent = vdd.exponent >> 3;
+ vsd.sign = vdd.sign;
+ vsd.significand = ((u64)(vdd.significand ) >> 32)& ~0xC0000000;
+ vfp_put_float(state, vfp_single_pack(&vsd), dn);
+ return ARMul_DONE;
+ }*/
+
+ /* TODO check access permission */
+
+ /* CRn/opc1 CRm/opc2 */
+
+ if (CoProc == 10 || CoProc == 11) {
+#define VFP_CDP_TRANS
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_CDP_TRANS
+
+ int exceptions = 0;
+ if (CoProc == 10)
+ exceptions = vfp_single_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ else
+ exceptions = vfp_double_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
+
+ vfp_raise_exceptions(state, exceptions, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
+
+ return ARMul_DONE;
+ }
+ DEBUG("Can't identify %x\n", instr);
+ return ARMul_CANT;
}
@@ -301,29 +341,29 @@ VFPCDP (ARMul_State * state, unsigned type, ARMword instr)
/* Miscellaneous functions */
int32_t vfp_get_float(arm_core_t* state, unsigned int reg)
{
- DBG("VFP get float: s%d=[%08x]\n", reg, state->ExtReg[reg]);
- return state->ExtReg[reg];
+ DEBUG("VFP get float: s%d=[%08x]\n", reg, state->ExtReg[reg]);
+ return state->ExtReg[reg];
}
void vfp_put_float(arm_core_t* state, int32_t val, unsigned int reg)
{
- DBG("VFP put float: s%d <= [%08x]\n", reg, val);
- state->ExtReg[reg] = val;
+ DEBUG("VFP put float: s%d <= [%08x]\n", reg, val);
+ state->ExtReg[reg] = val;
}
uint64_t vfp_get_double(arm_core_t* state, unsigned int reg)
{
- uint64_t result;
- result = ((uint64_t) state->ExtReg[reg*2+1])<<32 | state->ExtReg[reg*2];
- DBG("VFP get double: s[%d-%d]=[%016llx]\n", reg*2+1, reg*2, result);
- return result;
+ uint64_t result;
+ result = ((uint64_t) state->ExtReg[reg*2+1])<<32 | state->ExtReg[reg*2];
+ DEBUG("VFP get double: s[%d-%d]=[%016llx]\n", reg*2+1, reg*2, result);
+ return result;
}
void vfp_put_double(arm_core_t* state, uint64_t val, unsigned int reg)
{
- DBG("VFP put double: s[%d-%d] <= [%08x-%08x]\n", reg*2+1, reg*2, (uint32_t) (val>>32), (uint32_t) (val & 0xffffffff));
- state->ExtReg[reg*2] = (uint32_t) (val & 0xffffffff);
- state->ExtReg[reg*2+1] = (uint32_t) (val>>32);
+ DEBUG("VFP put double: s[%d-%d] <= [%08x-%08x]\n", reg*2+1, reg*2, (uint32_t) (val>>32), (uint32_t) (val & 0xffffffff));
+ state->ExtReg[reg*2] = (uint32_t) (val & 0xffffffff);
+ state->ExtReg[reg*2+1] = (uint32_t) (val>>32);
}
@@ -333,25 +373,25 @@ void vfp_put_double(arm_core_t* state, uint64_t val, unsigned int reg)
*/
void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr)
{
- int si_code = 0;
+ int si_code = 0;
- vfpdebug("VFP: raising exceptions %08x\n", exceptions);
+ vfpdebug("VFP: raising exceptions %08x\n", exceptions);
- if (exceptions == VFP_EXCEPTION_ERROR) {
- DEBUG_LOG(ARM11, "unhandled bounce %x\n", inst);
- exit(-1);
- return;
- }
+ if (exceptions == VFP_EXCEPTION_ERROR) {
+ DEBUG("unhandled bounce %x\n", inst);
+ exit(-1);
+ return;
+ }
- /*
- * If any of the status flags are set, update the FPSCR.
- * Comparison instructions always return at least one of
- * these flags set.
- */
- if (exceptions & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V))
- fpscr &= ~(FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V);
+ /*
+ * If any of the status flags are set, update the FPSCR.
+ * Comparison instructions always return at least one of
+ * these flags set.
+ */
+ if (exceptions & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V))
+ fpscr &= ~(FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V);
- fpscr |= exceptions;
+ fpscr |= exceptions;
- state->VFP[VFP_OFFSET(VFP_FPSCR)] = fpscr;
+ state->VFP[VFP_OFFSET(VFP_FPSCR)] = fpscr;
}