summaryrefslogtreecommitdiffstats
path: root/src/core/arm
diff options
context:
space:
mode:
authorMat M <mathew1800@gmail.com>2016-05-27 01:03:00 +0200
committerMat M <mathew1800@gmail.com>2016-05-27 01:03:00 +0200
commit031a9c57bba04c5e01a2ddcad0f48091a1ca88fc (patch)
tree9bcf9e6aa1eade024b4a2077c6156d4165e3c4ad /src/core/arm
parentMerge pull request #1810 from JayFoxRox/fix-float-exceptions (diff)
parentFix ftoi behaviour (diff)
downloadyuzu-031a9c57bba04c5e01a2ddcad0f48091a1ca88fc.tar
yuzu-031a9c57bba04c5e01a2ddcad0f48091a1ca88fc.tar.gz
yuzu-031a9c57bba04c5e01a2ddcad0f48091a1ca88fc.tar.bz2
yuzu-031a9c57bba04c5e01a2ddcad0f48091a1ca88fc.tar.lz
yuzu-031a9c57bba04c5e01a2ddcad0f48091a1ca88fc.tar.xz
yuzu-031a9c57bba04c5e01a2ddcad0f48091a1ca88fc.tar.zst
yuzu-031a9c57bba04c5e01a2ddcad0f48091a1ca88fc.zip
Diffstat (limited to 'src/core/arm')
-rw-r--r--src/core/arm/dyncom/arm_dyncom_dec.cpp4
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpdouble.cpp41
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpsingle.cpp42
3 files changed, 61 insertions, 26 deletions
diff --git a/src/core/arm/dyncom/arm_dyncom_dec.cpp b/src/core/arm/dyncom/arm_dyncom_dec.cpp
index 8cd6755cb..247d379e3 100644
--- a/src/core/arm/dyncom/arm_dyncom_dec.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_dec.cpp
@@ -422,6 +422,10 @@ ARMDecodeStatus DecodeARMInstruction(u32 instr, s32* idx) {
n = arm_instruction[i].attribute_value;
base = 0;
+ // 3DS has no VFP3 support
+ if (arm_instruction[i].version == ARMVFP3)
+ continue;
+
while (n) {
if (arm_instruction[i].content[base + 1] == 31 && arm_instruction[i].content[base] == 0) {
// clrex
diff --git a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp
index 580e60c85..1d5641810 100644
--- a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp
@@ -568,7 +568,7 @@ static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32
if (vdm.exponent >= 1023 + 32) {
d = vdm.sign ? 0 : 0xffffffff;
exceptions = FPSCR_IOC;
- } else if (vdm.exponent >= 1023 - 1) {
+ } else if (vdm.exponent >= 1023) {
int shift = 1023 + 63 - vdm.exponent;
u64 rem, incr = 0;
@@ -603,12 +603,20 @@ static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32
} else {
d = 0;
if (vdm.exponent | vdm.significand) {
- exceptions |= FPSCR_IXC;
- if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0)
+ if (rmode == FPSCR_ROUND_NEAREST) {
+ if (vdm.exponent >= 1022) {
+ d = vdm.sign ? 0 : 1;
+ exceptions |= vdm.sign ? FPSCR_IOC : FPSCR_IXC;
+ } else {
+ exceptions |= FPSCR_IXC;
+ }
+ } else if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0) {
d = 1;
- else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign) {
- d = 0;
- exceptions |= FPSCR_IOC;
+ exceptions |= FPSCR_IXC;
+ } else if (rmode == FPSCR_ROUND_MINUSINF) {
+ exceptions |= vdm.sign ? FPSCR_IOC : FPSCR_IXC;
+ } else {
+ exceptions |= FPSCR_IXC;
}
}
}
@@ -623,7 +631,7 @@ static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32
static u32 vfp_double_ftouiz(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
{
LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__);
- return vfp_double_ftoui(state, sd, unused, dm, FPSCR_ROUND_TOZERO);
+ return vfp_double_ftoui(state, sd, unused, dm, (fpscr & ~FPSCR_RMODE_MASK) | FPSCR_ROUND_TOZERO);
}
static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
@@ -647,12 +655,12 @@ static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32
if (tm & VFP_NAN) {
d = 0;
exceptions |= FPSCR_IOC;
- } else if (vdm.exponent >= 1023 + 32) {
+ } else if (vdm.exponent >= 1023 + 31) {
d = 0x7fffffff;
if (vdm.sign)
d = ~d;
exceptions |= FPSCR_IOC;
- } else if (vdm.exponent >= 1023 - 1) {
+ } else if (vdm.exponent >= 1023) {
int shift = 1023 + 63 - vdm.exponent; /* 58 */
u64 rem, incr = 0;
@@ -683,10 +691,17 @@ static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32
d = 0;
if (vdm.exponent | vdm.significand) {
exceptions |= FPSCR_IXC;
- if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0)
+ if (rmode == FPSCR_ROUND_NEAREST) {
+ if (vdm.exponent >= 1022) {
+ d = vdm.sign ? 0xffffffff : 1;
+ } else {
+ d = 0;
+ }
+ } else if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0) {
d = 1;
- else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign)
- d = -1;
+ } else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign) {
+ d = 0xffffffff;
+ }
}
}
@@ -700,7 +715,7 @@ static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32
static u32 vfp_double_ftosiz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
{
LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__);
- return vfp_double_ftosi(state, dd, unused, dm, FPSCR_ROUND_TOZERO);
+ return vfp_double_ftosi(state, dd, unused, dm, (fpscr & ~FPSCR_RMODE_MASK) | FPSCR_ROUND_TOZERO);
}
static struct op fops_ext[] = {
diff --git a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
index 23e0cdf26..60264f9b3 100644
--- a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
@@ -600,7 +600,11 @@ static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 f
* 2^0 <= m < 2^32-2^8
*/
d = (vsm.significand << 1) >> shift;
- rem = vsm.significand << (33 - shift);
+ if (shift > 0) {
+ rem = (vsm.significand << 1) << (32 - shift);
+ } else {
+ rem = 0;
+ }
if (rmode == FPSCR_ROUND_NEAREST) {
incr = 0x80000000;
@@ -627,12 +631,20 @@ static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 f
} else {
d = 0;
if (vsm.exponent | vsm.significand) {
- exceptions |= FPSCR_IXC;
- if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0)
+ if (rmode == FPSCR_ROUND_NEAREST) {
+ if (vsm.exponent >= 126) {
+ d = vsm.sign ? 0 : 1;
+ exceptions |= vsm.sign ? FPSCR_IOC : FPSCR_IXC;
+ } else {
+ exceptions |= FPSCR_IXC;
+ }
+ } else if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0) {
d = 1;
- else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign) {
- d = 0;
- exceptions |= FPSCR_IOC;
+ exceptions |= FPSCR_IXC;
+ } else if (rmode == FPSCR_ROUND_MINUSINF) {
+ exceptions |= vsm.sign ? FPSCR_IOC : FPSCR_IXC;
+ } else {
+ exceptions |= FPSCR_IXC;
}
}
}
@@ -646,7 +658,7 @@ static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 f
static u32 vfp_single_ftouiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
{
- return vfp_single_ftoui(state, sd, unused, m, FPSCR_ROUND_TOZERO);
+ return vfp_single_ftoui(state, sd, unused, m, (fpscr & ~FPSCR_RMODE_MASK) | FPSCR_ROUND_TOZERO);
}
static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
@@ -669,7 +681,7 @@ static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 f
if (tm & VFP_NAN) {
d = 0;
exceptions |= FPSCR_IOC;
- } else if (vsm.exponent >= 127 + 32) {
+ } else if (vsm.exponent >= 127 + 31) {
/*
* m >= 2^31-2^7: invalid
*/
@@ -683,7 +695,7 @@ static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 f
/* 2^0 <= m <= 2^31-2^7 */
d = (vsm.significand << 1) >> shift;
- rem = vsm.significand << (33 - shift);
+ rem = (vsm.significand << 1) << (32 - shift);
if (rmode == FPSCR_ROUND_NEAREST) {
incr = 0x80000000;
@@ -709,10 +721,14 @@ static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 f
d = 0;
if (vsm.exponent | vsm.significand) {
exceptions |= FPSCR_IXC;
- if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0)
+ if (rmode == FPSCR_ROUND_NEAREST) {
+ if (vsm.exponent >= 126)
+ d = vsm.sign ? 0xffffffff : 1;
+ } else if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0) {
d = 1;
- else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign)
- d = -1;
+ } else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign) {
+ d = 0xffffffff;
+ }
}
}
@@ -725,7 +741,7 @@ static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 f
static u32 vfp_single_ftosiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
{
- return vfp_single_ftosi(state, sd, unused, m, FPSCR_ROUND_TOZERO);
+ return vfp_single_ftosi(state, sd, unused, m, (fpscr & ~FPSCR_RMODE_MASK) | FPSCR_ROUND_TOZERO);
}
static struct op fops_ext[] = {