about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/emu/x64rund9.c15
-rw-r--r--src/emu/x64rundb.c6
-rw-r--r--src/emu/x87emu_private.c35
-rw-r--r--src/emu/x87emu_private.h8
4 files changed, 36 insertions, 28 deletions
diff --git a/src/emu/x64rund9.c b/src/emu/x64rund9.c
index 3c7ac142..648eb0a7 100644
--- a/src/emu/x64rund9.c
+++ b/src/emu/x64rund9.c
@@ -140,9 +140,20 @@ uintptr_t RunD9(x64emu_t *emu, rex_t rex, uintptr_t addr, uintptr_t offs)
             fpu_do_pop(emu);

             break;

         case 0xF4:  /* FXTRACT */

-            ST0.d = frexp(ST0.d, &tmp32s);

             fpu_do_push(emu);

-            ST0.d = 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;

+            }

             break;

 

         case 0xF8:  /* FPREM */

diff --git a/src/emu/x64rundb.c b/src/emu/x64rundb.c
index 9fdae847..82ea43ff 100644
--- a/src/emu/x64rundb.c
+++ b/src/emu/x64rundb.c
@@ -172,10 +172,10 @@ uintptr_t RunDB(x64emu_t *emu, rex_t rex, uintptr_t addr)
                 break;

             case 7: /* FSTP tbyte */

                 GETET(0);

-                if(ST0.q!=STld(0).uref)

-                    D2LD(&ST0.d, ED);

-                else

+                if(STld(0).uref && (ST0.q==STld(0).uref))

                     memcpy(ED, &STld(0).ld, 10);

+                else

+                    D2LD(&ST0.d, ED);

                 fpu_do_pop(emu);

                 break;

             default:

diff --git a/src/emu/x87emu_private.c b/src/emu/x87emu_private.c
index 5f6bdba0..21090ce8 100644
--- a/src/emu/x87emu_private.c
+++ b/src/emu/x87emu_private.c
@@ -99,39 +99,31 @@ void LD2D(void* ld, void* d)
     val.f.ud[1] = *(uint32_t*)(char*)(ld+4);
     val.b  = *(int16_t*)((char*)ld+8);
     #endif
-    int32_t exp64 = (((uint32_t)(val.b&0x7fff) - BIAS80) + BIAS64);
-    int32_t exp64final = exp64&0x7ff;
     // do specific value first (0, infinite...)
     // bit 63 is "integer part"
-    // bit 62 is sign
     if((uint32_t)(val.b&0x7fff)==0x7fff) {
         // infinity and nans
-        int t = 0; //nan
-        switch((val.f.ud[1]>>30)) {
-            case 0: if((val.f.ud[1]&(1<<29))==0) t = 1;
-                    break;
-            case 2: if((val.f.ud[1]&(1<<29))==0) t = 1;
-                    break;
-        }
+        int t = (val.f.q&0x7fffffffffffffffLL)?0:1;
         if(t) {    // infinite
-            result.d = HUGE_VAL;
-        } else {      // NaN
-            result.ud[1] = 0x7ff << 20;
+            result.ud[1] = (val.b>>4) << 20;
             result.ud[0] = 0;
+        } else {      // NaN
+            result.ud[1] = (val.b>>4) << 20 | ((val.f.q>>(63-20))&0x000fffff);
+            result.ud[0] = (val.f.q>>(63-56))&0xffffffff;
+            if(!(result.q&0x000fffffffffffffLL))
+                result.q |= 1;
         }
-        if(val.b&0x8000)
-            result.ud[1] |= 0x80000000;
         *(uint64_t*)d = result.q;
         return;
     }
+    int32_t exp64 = (((uint32_t)(val.b&0x7fff) - BIAS80) + BIAS64);
+    int32_t exp64final = exp64&0x7ff;
     if(((uint32_t)(val.b&0x7fff)==0) || (exp64<-1074)) {
         //if(val.f.q==0)
         // zero
         //if(val.f.q!=0)
         // denormal, but that's to small value for double 
-        uint64_t r = 0;
-        if(val.b&0x8000)
-            r |= 0x8000000000000000L;
+        uint64_t r = (val.b&0x8000)?0x8000000000000000LL:0LL;
         *(uint64_t*)d = r;
         return;
     }
@@ -184,10 +176,7 @@ void D2LD(void* d, void* ld)
     if((s.q&0x7fffffffffffffffL)==0) {
         // zero...
         val.f.q = 0;
-        if(s.ud[1]&0x8000)
-            val.b = 0x8000;
-        else
-            val.b = 0;
+        val.b = (s.ud[1]&0x80000000)?0x8000:0;
         memcpy(ld, &val, 10);
         return;
     }
@@ -203,7 +192,7 @@ void D2LD(void* d, void* ld)
         if(mant80==0x0)
             mant80final = 0x8000000000000000L; //infinity
         else
-            mant80final = 0xc000000000000000L; //(quiet)NaN
+            mant80final |= 0x8000000000000000L; //(quiet)NaN
     } else {
         if(exp80!=0){ 
             mant80final |= 0x8000000000000000L;
diff --git a/src/emu/x87emu_private.h b/src/emu/x87emu_private.h
index 74758acf..e3f0d233 100644
--- a/src/emu/x87emu_private.h
+++ b/src/emu/x87emu_private.h
@@ -73,6 +73,10 @@ static inline void fpu_fcom(x64emu_t* emu, double b)
         emu->sw.f.F87_C0 = 1;
         emu->sw.f.F87_C2 = 1;
         emu->sw.f.F87_C3 = 1;
+    } else if ((b==-INFINITY) || (ST0.d==INFINITY)) {
+        emu->sw.f.F87_C0 = 0;
+        emu->sw.f.F87_C2 = 0;
+        emu->sw.f.F87_C3 = 0;
     } else if (isgreater(ST0.d, b)) {
         emu->sw.f.F87_C0 = 0;
         emu->sw.f.F87_C2 = 0;
@@ -100,6 +104,10 @@ static inline void fpu_fcomi(x64emu_t* emu, double b)
         SET_FLAG(F_CF);
         SET_FLAG(F_PF);
         SET_FLAG(F_ZF);
+    } else if ((b==-INFINITY) || (ST0.d==INFINITY)) {
+        CLEAR_FLAG(F_CF);
+        CLEAR_FLAG(F_PF);
+        CLEAR_FLAG(F_ZF);
     } else if (isgreater(ST0.d, b)) {
         CLEAR_FLAG(F_CF);
         CLEAR_FLAG(F_PF);