From 1643786c04738d1dab9604e98cc1d815a2ca027b Mon Sep 17 00:00:00 2001
From: Jannik Vogel <email@jannikvogel.de>
Date: Sun, 15 May 2016 16:32:42 +0200
Subject: [PATCH 1/3] Disable VFP3 instructions

---
 src/core/arm/dyncom/arm_dyncom_dec.cpp | 4 ++++
 1 file changed, 4 insertions(+)

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

From 6fe0cb671df9daf29314be9cbe754606f8cb1ed1 Mon Sep 17 00:00:00 2001
From: Jannik Vogel <email@jannikvogel.de>
Date: Mon, 16 May 2016 10:47:01 +0200
Subject: [PATCH 2/3] Respect fpscr in ftoiz

---
 src/core/arm/skyeye_common/vfp/vfpdouble.cpp | 4 ++--
 src/core/arm/skyeye_common/vfp/vfpsingle.cpp | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp
index 45914d479..5215d48eb 100644
--- a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp
@@ -615,7 +615,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)
@@ -692,7 +692,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 e47ad2760..e15a95716 100644
--- a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
@@ -638,7 +638,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)
@@ -717,7 +717,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[] = {

From 501d0bc5edd9091c7c831a710e6ebff9839fad36 Mon Sep 17 00:00:00 2001
From: Jannik Vogel <email@jannikvogel.de>
Date: Sun, 15 May 2016 16:33:36 +0200
Subject: [PATCH 3/3] Fix ftoi behaviour

---
 src/core/arm/skyeye_common/vfp/vfpdouble.cpp | 37 +++++++++++++------
 src/core/arm/skyeye_common/vfp/vfpsingle.cpp | 38 ++++++++++++++------
 2 files changed, 53 insertions(+), 22 deletions(-)

diff --git a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp
index 5215d48eb..a2a625abc 100644
--- a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp
@@ -560,7 +560,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;
 
@@ -595,12 +595,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;
             }
         }
     }
@@ -639,12 +647,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;
 
@@ -675,10 +683,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;
+            }
         }
     }
 
diff --git a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
index e15a95716..6f6e0ca31 100644
--- a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
@@ -592,7 +592,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;
@@ -619,12 +623,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;
             }
         }
     }
@@ -661,7 +673,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
          */
@@ -675,7 +687,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;
@@ -701,10 +713,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;
+            }
         }
     }