about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2023-02-19 14:50:01 +0100
committerptitSeb <sebastien.chev@gmail.com>2023-02-20 20:25:21 +0100
commit5d42d9212fde49278e0ad0167edd77755a2fbcd9 (patch)
tree8d77c0d42c421f6c729f4c1cad65a5484629c900 /src
parent4a1e05524affadab3ba5a75f79c115a0743e483f (diff)
downloadbox64-5d42d9212fde49278e0ad0167edd77755a2fbcd9.tar.gz
box64-5d42d9212fde49278e0ad0167edd77755a2fbcd9.zip
Improved convertion to/from 80bits double, and added BOX64_X87_NO80BITS to not handle them
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/arm64/dynarec_arm64_db.c30
-rwxr-xr-xsrc/emu/x87emu_private.c30
-rwxr-xr-xsrc/include/debug.h1
-rwxr-xr-xsrc/main.c7
-rw-r--r--src/tools/rcfile.c1
5 files changed, 59 insertions, 10 deletions
diff --git a/src/dynarec/arm64/dynarec_arm64_db.c b/src/dynarec/arm64/dynarec_arm64_db.c
index b9d71080..e40cc71d 100644
--- a/src/dynarec/arm64/dynarec_arm64_db.c
+++ b/src/dynarec/arm64/dynarec_arm64_db.c
@@ -295,21 +295,33 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                         STRx_U12(x5, ed, 0);
                         STRH_U12(x6, ed, 8);
                     } else {
-                        if(ed!=x1) {
-                            MOVx_REG(x1, ed);
+                        if(box64_x87_no80bits) {
+                            v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
+                            addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
+                            VLDR64_U12(v1, ed, fixedaddress);
+                        } else {
+                            if(ed!=x1) {
+                                MOVx_REG(x1, ed);
+                            }
+                            x87_do_push_empty(dyn, ninst, x3);
+                            CALL(arm_fld, -1);
                         }
-                        x87_do_push_empty(dyn, ninst, x3);
-                        CALL(arm_fld, -1);
                     }
                     break;
                 case 7:
                     INST_NAME("FSTP tbyte");
-                    x87_forget(dyn, ninst, x1, x3, 0);
-                    addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
-                    if(ed!=x1) {
-                        MOVx_REG(x1, ed);
+                    if(box64_x87_no80bits) {
+                        v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
+                        addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
+                        VSTR64_U12(v1, wback, fixedaddress);
+                    } else {
+                        x87_forget(dyn, ninst, x1, x3, 0);
+                        addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
+                        if(ed!=x1) {
+                            MOVx_REG(x1, ed);
+                        }
+                        CALL(arm_fstp, -1);
                     }
-                    CALL(arm_fstp, -1);
                     x87_do_pop(dyn, ninst, x3);
                     break;
                 default:
diff --git a/src/emu/x87emu_private.c b/src/emu/x87emu_private.c
index 2114c00d..9f4b8af6 100755
--- a/src/emu/x87emu_private.c
+++ b/src/emu/x87emu_private.c
@@ -83,6 +83,10 @@ void fpu_fbld(x64emu_t* emu, uint8_t* s) {
 // long double (80bits) -> double (64bits)
 void LD2D(void* ld, void* d)
 {
+    if(box64_x87_no80bits) {
+        *(uint64_t*)d = *(uint64_t*)ld;
+        return;
+    }
 	FPU_t result;
     #pragma pack(push, 1)
 	struct {
@@ -122,7 +126,7 @@ void LD2D(void* ld, void* d)
         *(uint64_t*)d = result.q;
         return;
     }
-    if(((uint32_t)(val.b&0x7fff)==0) || (exp64<=0)) {
+    if(((uint32_t)(val.b&0x7fff)==0) || (exp64<-1074)) {
         //if(val.f.q==0)
         // zero
         //if(val.f.q!=0)
@@ -134,6 +138,18 @@ void LD2D(void* ld, void* d)
         return;
     }
 
+    if(exp64<=0 && val.f.q) {
+        // try to see if it can be a denormal
+        int one = -exp64-1022;
+        uint64_t r = 0;
+        if(val.b&0x8000)
+            r |= 0x8000000000000000L;
+        r |= val.f.q>>one;
+        *(uint64_t*)d = r;
+        return;
+
+    }
+
     if(exp64>=0x7ff) {
         // to big value...
         result.d = HUGE_VAL;
@@ -154,6 +170,10 @@ void LD2D(void* ld, void* d)
 // double (64bits) -> long double (80bits)
 void D2LD(void* d, void* ld)
 {
+    if(box64_x87_no80bits) {
+        *(uint64_t*)ld = *(uint64_t*)d;
+        return;
+    }
     #pragma pack(push, 1)
 	struct {
 		FPU_t f;
@@ -190,6 +210,12 @@ void D2LD(void* d, void* ld)
         if(exp80!=0){ 
             mant80final |= 0x8000000000000000L;
             exp80final += (BIAS80 - BIAS64);
+        } else if(mant80final!=0) {
+            // denormals -> normal
+            exp80final = BIAS80-1023;
+            int one = __builtin_clz(mant80final) + 1;
+            exp80final -= one;
+            mant80final<<=one;
         }
     }
 	val.b = ((int16_t)(sign80)<<15)| (int16_t)(exp80final);
@@ -201,6 +227,8 @@ void D2LD(void* d, void* ld)
 
 double FromLD(void* ld)
 {
+    if(box64_x87_no80bits)
+        return *(double*)ld;
     double ret; // cannot add = 0; it break factorio (issue when calling fmodl)
     LD2D(ld, &ret);
     return ret;
diff --git a/src/include/debug.h b/src/include/debug.h
index 0a6f722e..024805a1 100755
--- a/src/include/debug.h
+++ b/src/include/debug.h
@@ -48,6 +48,7 @@ extern int box64_nosandbox;
 extern int box64_malloc_hack;
 extern int box64_dummy_crashhandler;
 extern int box64_sse_flushto0;
+extern int box64_x87_no80bits;
 extern int allow_missing_libs;
 extern int box64_mapclean;
 extern int box64_prefer_wrapped;
diff --git a/src/main.c b/src/main.c
index 4c0af6cd..ea809e54 100755
--- a/src/main.c
+++ b/src/main.c
@@ -93,6 +93,7 @@ int allow_missing_libs = 0;
 int box64_prefer_emulated = 0;
 int box64_prefer_wrapped = 0;
 int box64_sse_flushto0 = 0;
+int box64_x87_no80bits = 0;
 int fix_64bit_inodes = 0;
 int box64_dummy_crashhandler = 1;
 int box64_mapclean = 0;
@@ -965,6 +966,12 @@ void LoadEnvVars(box64context_t *context)
             printf_log(LOG_INFO, "BOX64: Direct apply of SSE Flush to 0 flag\n");
     	}
     }
+    if(getenv("BOX64_X87_NO80BITS")) {
+        if (strcmp(getenv("BOX64_X87_NO80BITS"), "1")==0) {
+            box64_x87_no80bits = 1;
+            printf_log(LOG_INFO, "BOX64: all 80bits x87 long double will be handle as double\n");
+    	}
+    }
     if(getenv("BOX64_PREFER_WRAPPED")) {
         if (strcmp(getenv("BOX64_PREFER_WRAPPED"), "1")==0) {
             box64_prefer_wrapped = 1;
diff --git a/src/tools/rcfile.c b/src/tools/rcfile.c
index 8a2ac920..75df7137 100644
--- a/src/tools/rcfile.c
+++ b/src/tools/rcfile.c
@@ -64,6 +64,7 @@ ENTRYBOOL(BOX64_X11THREADS, box64_x11threads)           \
 ENTRYBOOL(BOX64_X11GLX, box64_x11glx)                   \
 ENTRYDSTRING(BOX64_LIBGL, box64_libGL)                  \
 ENTRYBOOL(BOX64_SSE_FLUSHTO0, box64_sse_flushto0)       \
+ENTRYBOOL(BOX64_X87_NO80BITS, box64_x87_no80bits)       \
 ENTRYSTRING_(BOX64_EMULATED_LIBS, emulated_libs)        \
 ENTRYBOOL(BOX64_ALLOWMISSINGLIBS, allow_missing_libs)   \
 ENTRYBOOL(BOX64_PREFER_WRAPPED, box64_prefer_wrapped)   \