about summary refs log tree commit diff stats
path: root/src/dynarec
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2024-12-02 16:19:06 +0100
committerptitSeb <sebastien.chev@gmail.com>2024-12-02 16:19:06 +0100
commit415fc458be52095395236d80a7c402cb77b0b718 (patch)
tree5f7ea72145622371b86ab7f13d50c67c138f6345 /src/dynarec
parentf2822f1a05afe63f233e172f67dcbe1f3b234551 (diff)
downloadbox64-415fc458be52095395236d80a7c402cb77b0b718.tar.gz
box64-415fc458be52095395236d80a7c402cb77b0b718.zip
[ARM64_DYNAREC] Improved some x87 opcode behaviour
Diffstat (limited to 'src/dynarec')
-rw-r--r--src/dynarec/arm64/dynarec_arm64_0f.c2
-rw-r--r--src/dynarec/arm64/dynarec_arm64_660f.c2
-rw-r--r--src/dynarec/arm64/dynarec_arm64_6664.c2
-rw-r--r--src/dynarec/arm64/dynarec_arm64_67.c2
-rw-r--r--src/dynarec/arm64/dynarec_arm64_avx_0f.c2
-rw-r--r--src/dynarec/arm64/dynarec_arm64_avx_66_0f.c2
-rw-r--r--src/dynarec/arm64/dynarec_arm64_d8.c8
-rw-r--r--src/dynarec/arm64/dynarec_arm64_d9.c24
-rw-r--r--src/dynarec/arm64/dynarec_arm64_da.c6
-rw-r--r--src/dynarec/arm64/dynarec_arm64_db.c4
-rw-r--r--src/dynarec/arm64/dynarec_arm64_dc.c8
-rw-r--r--src/dynarec/arm64/dynarec_arm64_dd.c4
-rw-r--r--src/dynarec/arm64/dynarec_arm64_de.c8
-rw-r--r--src/dynarec/arm64/dynarec_arm64_df.c4
-rw-r--r--src/dynarec/arm64/dynarec_arm64_helper.h48
-rw-r--r--src/dynarec/dynarec_native_functions.c18
16 files changed, 99 insertions, 45 deletions
diff --git a/src/dynarec/arm64/dynarec_arm64_0f.c b/src/dynarec/arm64/dynarec_arm64_0f.c
index beb6a34b..894c8320 100644
--- a/src/dynarec/arm64/dynarec_arm64_0f.c
+++ b/src/dynarec/arm64/dynarec_arm64_0f.c
@@ -499,7 +499,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
             GETGX(v0, 0);

             GETEXSS(s0, 0, 0);

             FCMPS(v0, s0);

-            FCOMI(x1, x2);

+            FCOMI(x1, x2, 0, v0, s0, 1);    // disabled precise cmp

             break;

         case 0x30:

             INST_NAME("WRMSR");

diff --git a/src/dynarec/arm64/dynarec_arm64_660f.c b/src/dynarec/arm64/dynarec_arm64_660f.c
index 34bd16cc..458b24ba 100644
--- a/src/dynarec/arm64/dynarec_arm64_660f.c
+++ b/src/dynarec/arm64/dynarec_arm64_660f.c
@@ -312,7 +312,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
             GETGX(v0, 0);

             GETEXSD(q0, 0, 0);

             FCMPD(v0, q0);

-            FCOMI(x1, x2);

+            FCOMI(x1, x2, 0, v0, q0, 0);    //disable precise cmp

             break;

 

         case 0x38:  // SSSE3 opcodes

diff --git a/src/dynarec/arm64/dynarec_arm64_6664.c b/src/dynarec/arm64/dynarec_arm64_6664.c
index dfc1bef1..7685d1b8 100644
--- a/src/dynarec/arm64/dynarec_arm64_6664.c
+++ b/src/dynarec/arm64/dynarec_arm64_6664.c
@@ -68,7 +68,7 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
                             VLDR64_REG(v1, ed, x4);
                     }
                     FCMPD(v0, v1);
-                    FCOMI(x1, x2);
+                    FCOMI(x1, x2, 0, v0, v1, 0);    //disable precise cmp
                     break;
 
                 case 0x6F:
diff --git a/src/dynarec/arm64/dynarec_arm64_67.c b/src/dynarec/arm64/dynarec_arm64_67.c
index 5dc4043a..5316866e 100644
--- a/src/dynarec/arm64/dynarec_arm64_67.c
+++ b/src/dynarec/arm64/dynarec_arm64_67.c
@@ -215,7 +215,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                                 VLD32(s0, ed, fixedaddress);

                             }

                             FCMPS(v0, s0);

-                            FCOMI(x1, x2);

+                            FCOMI(x1, x2, 0, v0, s0, 1);    //disabled precise cmp

                             break;

                         default:

                             DEFAULT;

diff --git a/src/dynarec/arm64/dynarec_arm64_avx_0f.c b/src/dynarec/arm64/dynarec_arm64_avx_0f.c
index 2cdc6e51..439a0997 100644
--- a/src/dynarec/arm64/dynarec_arm64_avx_0f.c
+++ b/src/dynarec/arm64/dynarec_arm64_avx_0f.c
@@ -290,7 +290,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
             GETGX(v0, 0);
             GETEXSS(s0, 0, 0);
             FCMPS(v0, s0);
-            FCOMI(x1, x2);
+            FCOMI(x1, x2, 0, v0, s0, 1);    //disable precise cmp
             break;
 
         case 0x50:
diff --git a/src/dynarec/arm64/dynarec_arm64_avx_66_0f.c b/src/dynarec/arm64/dynarec_arm64_avx_66_0f.c
index 4acb4d31..bcd9ed8a 100644
--- a/src/dynarec/arm64/dynarec_arm64_avx_66_0f.c
+++ b/src/dynarec/arm64/dynarec_arm64_avx_66_0f.c
@@ -273,7 +273,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
             GETGX(v0, 0);
             GETEXSD(q0, 0, 0);
             FCMPD(v0, q0);
-            FCOMI(x1, x2);
+            FCOMI(x1, x2, 0, v0, q0, 0);    //disable precise cmp
             break;
 
         case 0x50:
diff --git a/src/dynarec/arm64/dynarec_arm64_d8.c b/src/dynarec/arm64/dynarec_arm64_d8.c
index e8f002a4..668694c0 100644
--- a/src/dynarec/arm64/dynarec_arm64_d8.c
+++ b/src/dynarec/arm64/dynarec_arm64_d8.c
@@ -90,7 +90,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
             } else {
                 FCMPD(v1, v2);
             }
-            FCOM(x1, x2, x3);
+            FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
             break;
         case 0xD8:
         case 0xD9:
@@ -108,7 +108,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
             } else {
                 FCMPD(v1, v2);
             }
-            FCOM(x1, x2, x3);
+            FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
             X87_POP_OR_FAIL(dyn, ninst, x3);
             break;
         case 0xE0:
@@ -222,7 +222,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                     FCVT_D_S(s0, s0);
                     FCMPD(v1, s0);
                 }
-                FCOM(x1, x2, x3);
+                FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
                 break;
             case 3:
                 INST_NAME("FCOMP ST0, float[ED]");
@@ -236,7 +236,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                     FCVT_D_S(s0, s0);
                     FCMPD(v1, s0);
                 }
-                FCOM(x1, x2, x3);
+                FCOM(x1, x2, x3, x4, v1, s0, ST_IS_F(0));
                 X87_POP_OR_FAIL(dyn, ninst, x3);
                 break;
             case 4:
diff --git a/src/dynarec/arm64/dynarec_arm64_d9.c b/src/dynarec/arm64/dynarec_arm64_d9.c
index 9a002202..557b3673 100644
--- a/src/dynarec/arm64/dynarec_arm64_d9.c
+++ b/src/dynarec/arm64/dynarec_arm64_d9.c
@@ -128,7 +128,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
             } else {
                 FCMPD_0(v1);
             }
-            FCOM(x1, x2, x3);   // same flags...
+            FCOM(x1, x2, x3, x4, 0, 0, ST_IS_F(0));   // same flags...
             break;
         case 0xE5:
             INST_NAME("FXAM");
@@ -161,21 +161,21 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                         } else {
                             ADDw_U12(x5, x5, i2);
                         }
-                        ANDw_mask(x5, x5, 0, 3);    // (emu->top + i)&7
+                        ANDw_mask(x5, x5, 0, 2);    // (emu->top + i)&7
                     }
-                    // load tag
-                    LDRH_U12(x3, xEmu, offsetof(x64emu_t, fpu_tags));
-                    if(i2<0) {
-                        LSLw_IMM(x3, x3, -i2*2);
-                    } else if(i2>0) {
-                        ORRw_mask(x3, x3, 0b010000, 0b001111);  // 0xffff0000
-                        LSRw_IMM(x3, x3, i2*2);
-                    }
-                    TSTw_mask(x3, 0, 1);    // 0b11
-                    B_MARK3(cNE);   // empty: C3,C2,C0 = 101
                     // load x2 with ST0 anyway, for sign extraction
                     ADDx_REG_LSL(x1, xEmu, x5, 3);
                     LDRx_U12(x2, x1, offsetof(x64emu_t, x87));
+                    // load tag
+                    if(i2>=0) {
+                        LDRH_U12(x3, xEmu, offsetof(x64emu_t, fpu_tags));
+                        if(i2>0) {
+                            ORRw_mask(x3, x3, 0b010000, 0b001111);  // 0xffff0000
+                            LSRw_IMM(x3, x3, i2*2);
+                        }
+                        TSTw_mask(x3, 0, 1);    // 0b11
+                        B_MARK3(cNE);   // empty: C3,C2,C0 = 101
+                    }
                 }
             } else {
                 // simply move from cache reg to x2
diff --git a/src/dynarec/arm64/dynarec_arm64_da.c b/src/dynarec/arm64/dynarec_arm64_da.c
index 52965b3f..1c87f3c7 100644
--- a/src/dynarec/arm64/dynarec_arm64_da.c
+++ b/src/dynarec/arm64/dynarec_arm64_da.c
@@ -130,7 +130,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
             } else {
                 FCMPD(v1, v2);
             }
-            FCOM(x1, x2, x3);
+            FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
             X87_POP_OR_FAIL(dyn, ninst, x3);
             X87_POP_OR_FAIL(dyn, ninst, x3);
             break;
@@ -169,7 +169,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                 SXTL_32(v2, v2);    // i32 -> i64
                 SCVTFDD(v2, v2);    // i64 -> double
                 FCMPD(v1, v2);
-                FCOM(x1, x2, x3);
+                FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
                 break;
             case 3:
                 INST_NAME("FICOMP ST0, Ed");
@@ -180,7 +180,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                 SXTL_32(v2, v2);    // i32 -> i64
                 SCVTFDD(v2, v2);    // i64 -> double
                 FCMPD(v1, v2);
-                FCOM(x1, x2, x3);
+                FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
                 X87_POP_OR_FAIL(dyn, ninst, x3);
                 break;
             case 4:
diff --git a/src/dynarec/arm64/dynarec_arm64_db.c b/src/dynarec/arm64/dynarec_arm64_db.c
index 68e36ef4..feba2072 100644
--- a/src/dynarec/arm64/dynarec_arm64_db.c
+++ b/src/dynarec/arm64/dynarec_arm64_db.c
@@ -155,7 +155,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
             } else {
                 FCMPD(v1, v2);
             }
-            FCOMI(x1, x2);
+            FCOMI(x1, x2, x4, v1, v2, ST_IS_F(0));
             break;
         case 0xF0:
         case 0xF1:
@@ -174,7 +174,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
             } else {
                 FCMPD(v1, v2);
             }
-            FCOMI(x1, x2);
+            FCOMI(x1, x2, x4, v1, v2, ST_IS_F(0));
             break;
 
         default:
diff --git a/src/dynarec/arm64/dynarec_arm64_dc.c b/src/dynarec/arm64/dynarec_arm64_dc.c
index ee5b2c62..8834de6c 100644
--- a/src/dynarec/arm64/dynarec_arm64_dc.c
+++ b/src/dynarec/arm64/dynarec_arm64_dc.c
@@ -88,7 +88,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
             } else {
                 FCMPD(v1, v2);
             }
-            FCOM(x1, x2, x3);
+            FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
             break;
         case 0xD8:
         case 0xD9:
@@ -106,7 +106,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
             } else {
                 FCMPD(v1, v2);
             }
-            FCOM(x1, x2, x3);
+            FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
             X87_POP_OR_FAIL(dyn, ninst, x3);
             break;
         case 0xE0:
@@ -205,7 +205,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                 addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
                 VLD64(v2, wback, fixedaddress);
                 FCMPD(v1, v2);
-                FCOM(x1, x2, x3);
+                FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
                 break;
             case 3:
                 INST_NAME("FCOMP ST0, double[ED]");
@@ -214,7 +214,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                 addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
                 VLD64(v2, wback, fixedaddress);
                 FCMPD(v1, v2);
-                FCOM(x1, x2, x3);
+                FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
                 X87_POP_OR_FAIL(dyn, ninst, x3);
                 break;
             case 4:
diff --git a/src/dynarec/arm64/dynarec_arm64_dd.c b/src/dynarec/arm64/dynarec_arm64_dd.c
index 6ce37042..33282abd 100644
--- a/src/dynarec/arm64/dynarec_arm64_dd.c
+++ b/src/dynarec/arm64/dynarec_arm64_dd.c
@@ -118,7 +118,7 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
             } else {
                 FCMPD(v1, v2);
             }
-            FCOM(x1, x2, x3);
+            FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
             break;
         case 0xE8:
         case 0xE9:
@@ -136,7 +136,7 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
             } else {
                 FCMPD(v1, v2);
             }
-            FCOM(x1, x2, x3);
+            FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
             X87_POP_OR_FAIL(dyn, ninst, x3);
             break;
 
diff --git a/src/dynarec/arm64/dynarec_arm64_de.c b/src/dynarec/arm64/dynarec_arm64_de.c
index 7dbbb210..6da8f029 100644
--- a/src/dynarec/arm64/dynarec_arm64_de.c
+++ b/src/dynarec/arm64/dynarec_arm64_de.c
@@ -90,7 +90,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
             } else {
                 FCMPD(v1, v2);
             }
-            FCOM(x1, x2, x3);
+            FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
             X87_POP_OR_FAIL(dyn, ninst, x3);
             break;
         case 0xD9:
@@ -102,7 +102,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
             } else {
                 FCMPD(v1, v2);
             }
-            FCOM(x1, x2, x3);
+            FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
             X87_POP_OR_FAIL(dyn, ninst, x3);
             X87_POP_OR_FAIL(dyn, ninst, x3);
             break;
@@ -215,7 +215,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                 SXTL_32(v2, v2);
                 SCVTFDD(v2, v2);
                 FCMPD(v1, v2);
-                FCOM(x1, x2, x3);
+                FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
                 break;
             case 3:
                 INST_NAME("FICOMP ST0, word[ED]");
@@ -227,7 +227,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                 SXTL_32(v2, v2);
                 SCVTFDD(v2, v2);
                 FCMPD(v1, v2);
-                FCOM(x1, x2, x3);
+                FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
                 X87_POP_OR_FAIL(dyn, ninst, x3);
                 break;
             case 4:
diff --git a/src/dynarec/arm64/dynarec_arm64_df.c b/src/dynarec/arm64/dynarec_arm64_df.c
index cef734bf..bbcf3758 100644
--- a/src/dynarec/arm64/dynarec_arm64_df.c
+++ b/src/dynarec/arm64/dynarec_arm64_df.c
@@ -109,7 +109,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
             } else {
                 FCMPD(v1, v2);
             }
-            FCOMI(x1, x2);
+            FCOMI(x1, x2, x4, v1, v2, ST_IS_F(0));
             X87_POP_OR_FAIL(dyn, ninst, x3);
             break;
         case 0xF0:
@@ -130,7 +130,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
             } else {
                 FCMPD(v1, v2);
             }
-            FCOMI(x1, x2);
+            FCOMI(x1, x2, x4, v1, v2, ST_IS_F(0));
             X87_POP_OR_FAIL(dyn, ninst, x3);
             break;
 
diff --git a/src/dynarec/arm64/dynarec_arm64_helper.h b/src/dynarec/arm64/dynarec_arm64_helper.h
index 267d873b..77cedbf1 100644
--- a/src/dynarec/arm64/dynarec_arm64_helper.h
+++ b/src/dynarec/arm64/dynarec_arm64_helper.h
@@ -880,7 +880,7 @@
 #endif
 
 // Generate FCOM with s1 and s2 scratch regs (the VCMP is already done)
-#define FCOM(s1, s2, s3)                                                    \
+#define FCOM(s1, s2, s3, s4, v1, v2, is_f)                                  \
     LDRH_U12(s3, xEmu, offsetof(x64emu_t, sw));   /*offset is 8bits right?*/\
     MOV32w(s1, 0b0100011100000000);                                         \
     BICw_REG(s3, s3, s1);                                                   \
@@ -890,11 +890,33 @@
     CSELw(s1, s2, s1, cEQ);                                                 \
     MOV32w(s2, 0b01000101); /* unordered */                                 \
     CSELw(s1, s2, s1, cVS);                                                 \
+    if(v1||v2) {                                                            \
+        Bcond(cVS, 10*4);                                                   \
+        if(is_f) {                                                          \
+            ORRw_mask(s4, xZR, 12, 10); /*+inf*/                            \
+            FMOVwS(s2, v1);                                                 \
+            CMPSw_REG(s2, s4);                                              \
+            Bcond(cEQ, 5*4); /* same */                                     \
+            FMOVwS(s2, v2);                                                 \
+            ORRw_mask(s4, s4, 1, 0); /*-inf*/                               \
+            CMPSw_REG(s2, s4);                                              \
+        } else {                                                            \
+            ORRx_mask(s4, xZR, 1, 12, 10); /*+inf*/                         \
+            FMOVxD(s2, v1);                                                 \
+            CMPSx_REG(s2, s4);                                              \
+            Bcond(cEQ, 5*4); /* same */                                     \
+            FMOVxD(s2, v2);                                                 \
+            ORRx_mask(s4, s4, 1, 1, 0); /*-inf*/                            \
+            CMPSx_REG(s2, s4);                                              \
+        }                                                                   \
+        Bcond(cNE, 4+4); /* same */                                         \
+        MOVZw(s2, 0);                                                       \
+    }                                                                       \
     ORRw_REG_LSL(s3, s3, s1, 8);                                            \
     STRH_U12(s3, xEmu, offsetof(x64emu_t, sw))
 
 // Generate FCOMI with s1 and s2 scratch regs (the VCMP is already done)
-#define FCOMI(s1, s2)    \
+#define FCOMI(s1, s2, s4, v1, v2, is_f)                                     \
     IFX(X_OF|X_AF|X_SF|X_PEND) {                                            \
         MOV32w(s2, 0b100011010101);                                         \
         BICw_REG(xFlags, xFlags, s2);                                       \
@@ -914,6 +936,28 @@
         MOV32w(s2, 0b01000000); /* zero */                                  \
         CSELw(s1, s2, s1, cEQ);                                             \
         /* greater than leave 0 */                                          \
+        if(s4) {                                                            \
+            Bcond(cVS, 10*4);                                               \
+            if(is_f) {                                                      \
+                ORRw_mask(s4, xZR, 12, 10); /*+inf*/                        \
+                FMOVwS(s2, v1);                                             \
+                CMPSw_REG(s2, s4);                                          \
+                Bcond(cEQ, 5*4); /* same */                                 \
+                FMOVwS(s2, v2);                                             \
+                ORRw_mask(s4, s4, 1, 0); /*-inf*/                           \
+                CMPSw_REG(s2, s4);                                          \
+            } else {                                                        \
+                ORRx_mask(s4, xZR, 1, 12, 10); /*+inf*/                     \
+                FMOVxD(s2, v1);                                             \
+                CMPSx_REG(s2, s4);                                          \
+                Bcond(cEQ, 5*4); /* same */                                 \
+                FMOVxD(s2, v2);                                             \
+                ORRx_mask(s4, s4, 1, 1, 0); /*-inf*/                        \
+                CMPSx_REG(s2, s4);                                          \
+            }                                                               \
+            Bcond(cNE, 4+4); /* same */                                     \
+            MOVZw(s1, 0);                                                   \
+        }                                                                   \
         ORRw_REG(xFlags, xFlags, s1);                                       \
     }                                                                       \
     SET_DFNONE(s1);                                                         \
diff --git a/src/dynarec/dynarec_native_functions.c b/src/dynarec/dynarec_native_functions.c
index e2e149f2..4b72ea01 100644
--- a/src/dynarec/dynarec_native_functions.c
+++ b/src/dynarec/dynarec_native_functions.c
@@ -59,10 +59,20 @@ void native_fpatan(x64emu_t* emu)
 }
 void native_fxtract(x64emu_t* emu)
 {
-    int32_t tmp32s = (ST1.q&0x7ff0000000000000LL)>>52;
-    tmp32s -= 1023;
-    ST1.d /= exp2(tmp32s);
-    ST0.d = tmp32s;
+    int tmp32s;
+    if(isnan(ST1.d)) {
+        ST0.d = ST1.d;
+    } else if(isinf(ST1.d)) {
+        ST0.d = ST1.d;
+        ST1.d = INFINITY;
+    } else if(ST1.d==0.0) {
+        ST0.d = ST1.d;
+        ST1.d = -INFINITY;
+    } else {
+        // LD80bits doesn't have implicit "1" bit, so need to adjust for that
+        ST0.d = frexp(ST1.d, &tmp32s)*2;
+        ST1.d = tmp32s-1;
+    }
 }
 void native_fprem(x64emu_t* emu)
 {