about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2025-04-16 12:03:05 +0200
committerptitSeb <sebastien.chev@gmail.com>2025-04-16 12:03:13 +0200
commit1ba0ea157fdde73df5c9f242c6ad4db7abddeaca (patch)
tree2e5c62cd25b0aa6f906f66d371f134198e1fcc3a /src
parent1e64476f313bf286caac8de08104891b5956f9ac (diff)
downloadbox64-1ba0ea157fdde73df5c9f242c6ad4db7abddeaca.tar.gz
box64-1ba0ea157fdde73df5c9f242c6ad4db7abddeaca.zip
[INTERP] Added x87 Precision Control set to 24bits handling
Diffstat (limited to 'src')
-rw-r--r--src/emu/x64rund8.c12
-rw-r--r--src/emu/x64rund9.c1
-rw-r--r--src/emu/x64runda.c6
-rw-r--r--src/emu/x64rundc.c12
-rw-r--r--src/emu/x64runde.c12
-rw-r--r--src/include/regs.h6
6 files changed, 49 insertions, 0 deletions
diff --git a/src/emu/x64rund8.c b/src/emu/x64rund8.c
index 44413c10..fc1101f4 100644
--- a/src/emu/x64rund8.c
+++ b/src/emu/x64rund8.c
@@ -50,6 +50,7 @@ uintptr_t RunD8(x64emu_t *emu, rex_t rex, uintptr_t addr, uintptr_t offs)
         case 0xC6:

         case 0xC7:  /* FADD */

             ST0.d += ST(nextop&7).d;

+            if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;

             break;

         case 0xC8:

         case 0xC9:

@@ -60,6 +61,7 @@ uintptr_t RunD8(x64emu_t *emu, rex_t rex, uintptr_t addr, uintptr_t offs)
         case 0xCE:

         case 0xCF:  /* FMUL */

             ST0.d *= ST(nextop&7).d;

+            if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;

             break;

         case 0xD0:

         case 0xD1:

@@ -91,6 +93,7 @@ uintptr_t RunD8(x64emu_t *emu, rex_t rex, uintptr_t addr, uintptr_t offs)
         case 0xE6:

         case 0xE7:  /* FSUB */

             ST0.d -= ST(nextop&7).d;

+            if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;

             break;

         case 0xE8:

         case 0xE9:

@@ -101,6 +104,7 @@ uintptr_t RunD8(x64emu_t *emu, rex_t rex, uintptr_t addr, uintptr_t offs)
         case 0xEE:

         case 0xEF:  /* FSUBR */

             ST0.d = ST(nextop&7).d - ST0.d;

+            if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;

             break;

         case 0xF0:

         case 0xF1:

@@ -111,6 +115,7 @@ uintptr_t RunD8(x64emu_t *emu, rex_t rex, uintptr_t addr, uintptr_t offs)
         case 0xF6:

         case 0xF7:  /* FDIV */

             ST0.d /= ST(nextop&7).d;

+            if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;

             break;

         case 0xF8:

         case 0xF9:

@@ -121,6 +126,7 @@ uintptr_t RunD8(x64emu_t *emu, rex_t rex, uintptr_t addr, uintptr_t offs)
         case 0xFE:

         case 0xFF:  /* FDIVR */

             ST0.d = ST(nextop&7).d / ST0.d;

+            if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;

             break;

         default:

             fesetround(oldround);

@@ -134,6 +140,7 @@ uintptr_t RunD8(x64emu_t *emu, rex_t rex, uintptr_t addr, uintptr_t offs)
                     GETE4(0);

                 }

                 ST0.d += *(float*)ED;

+                if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;

                 break;

             case 1:         /* FMUL ST0, float */

                 if(offs) {

@@ -142,6 +149,7 @@ uintptr_t RunD8(x64emu_t *emu, rex_t rex, uintptr_t addr, uintptr_t offs)
                     GETE4(0);

                 }

                 ST0.d *= *(float*)ED;

+                if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;

                 break;

             case 2:      /* FCOM ST0, float */

                 if(offs) {

@@ -167,6 +175,7 @@ uintptr_t RunD8(x64emu_t *emu, rex_t rex, uintptr_t addr, uintptr_t offs)
                     GETE4(0);

                 }

                 ST0.d -= *(float*)ED;

+                if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;

                 break;

             case 5:         /* FSUBR ST0, float */

                 if(offs) {

@@ -175,6 +184,7 @@ uintptr_t RunD8(x64emu_t *emu, rex_t rex, uintptr_t addr, uintptr_t offs)
                     GETE4(0);

                 }

                 ST0.d = *(float*)ED - ST0.d;

+                if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;

                 break;

             case 6:         /* FDIV ST0, float */

                 if(offs) {

@@ -183,6 +193,7 @@ uintptr_t RunD8(x64emu_t *emu, rex_t rex, uintptr_t addr, uintptr_t offs)
                     GETE4(0);

                 }

                 ST0.d /= *(float*)ED;

+                if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;

                 break;

             case 7:         /* FDIVR ST0, float */

                 if(offs) {

@@ -191,6 +202,7 @@ uintptr_t RunD8(x64emu_t *emu, rex_t rex, uintptr_t addr, uintptr_t offs)
                     GETE4(0);

                 }

                 ST0.d = *(float*)ED / ST0.d;

+                if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;

                 break;

             default:

                 fesetround(oldround);

diff --git a/src/emu/x64rund9.c b/src/emu/x64rund9.c
index a4f6cc2b..1f4366f5 100644
--- a/src/emu/x64rund9.c
+++ b/src/emu/x64rund9.c
@@ -230,6 +230,7 @@ uintptr_t RunD9(x64emu_t *emu, rex_t rex, uintptr_t addr, uintptr_t offs)
         case 0xFA:  /* FSQRT */

             oldround = fpu_setround(emu);

             ST0.d = sqrt(ST0.d);

+            if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;

             fesetround(oldround);

             break;

         case 0xFB:  /* FSINCOS */

diff --git a/src/emu/x64runda.c b/src/emu/x64runda.c
index f8a1b70e..59278b15 100644
--- a/src/emu/x64runda.c
+++ b/src/emu/x64runda.c
@@ -101,10 +101,12 @@ uintptr_t RunDA(x64emu_t *emu, rex_t rex, uintptr_t addr)
             case 0:     /* FIADD ST0, Ed int */

                 GETE4(0);

                 ST0.d += ED->sdword[0];

+                if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;

                 break;

             case 1:     /* FIMUL ST0, Ed int */

                 GETE4(0);

                 ST0.d *= ED->sdword[0];

+                if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;

                 break;

             case 2:     /* FICOM ST0, Ed int */

                 GETE4(0);

@@ -118,18 +120,22 @@ uintptr_t RunDA(x64emu_t *emu, rex_t rex, uintptr_t addr)
             case 4:     /* FISUB ST0, Ed int */

                 GETE4(0);

                 ST0.d -= ED->sdword[0];

+                if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;

                 break;

             case 5:     /* FISUBR ST0, Ed int */

                 GETE4(0);

                 ST0.d = (double)ED->sdword[0] - ST0.d;

+                if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;

                 break;

             case 6:     /* FIDIV ST0, Ed int */

                 GETE4(0);

                 ST0.d /= ED->sdword[0];

+                if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;

                 break;

             case 7:     /* FIDIVR ST0, Ed int */

                 GETE4(0);

                 ST0.d = (double)ED->sdword[0] / ST0.d;

+                if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;

                 break;

         }

         fesetround(oldround);

diff --git a/src/emu/x64rundc.c b/src/emu/x64rundc.c
index 00775698..99b12c76 100644
--- a/src/emu/x64rundc.c
+++ b/src/emu/x64rundc.c
@@ -47,6 +47,7 @@ uintptr_t RunDC(x64emu_t *emu, rex_t rex, uintptr_t addr)
         case 0xC6:
         case 0xC7:  /* FADD */
             ST(nextop&7).d += ST0.d;
+            if(!emu->cw.f.C87_PC) ST(nextop&7).d = (float)ST(nextop&7).d;
             break;
         case 0xC8:
         case 0xC9:
@@ -57,6 +58,7 @@ uintptr_t RunDC(x64emu_t *emu, rex_t rex, uintptr_t addr)
         case 0xCE:
         case 0xCF:  /* FMUL */
             ST(nextop&7).d *= ST0.d;
+            if(!emu->cw.f.C87_PC) ST(nextop&7).d = (float)ST(nextop&7).d;
             break;
         case 0xD0:
         case 0xD1:
@@ -88,6 +90,7 @@ uintptr_t RunDC(x64emu_t *emu, rex_t rex, uintptr_t addr)
         case 0xE6:
         case 0xE7:  /* FSUBR */
             ST(nextop&7).d = ST0.d -ST(nextop&7).d;
+            if(!emu->cw.f.C87_PC) ST(nextop&7).d = (float)ST(nextop&7).d;
             break;
         case 0xE8:
         case 0xE9:
@@ -98,6 +101,7 @@ uintptr_t RunDC(x64emu_t *emu, rex_t rex, uintptr_t addr)
         case 0xEE:
         case 0xEF:  /* FSUB */
             ST(nextop&7).d -= ST0.d;
+            if(!emu->cw.f.C87_PC) ST(nextop&7).d = (float)ST(nextop&7).d;
             break;
         case 0xF0:
         case 0xF1:
@@ -108,6 +112,7 @@ uintptr_t RunDC(x64emu_t *emu, rex_t rex, uintptr_t addr)
         case 0xF6:
         case 0xF7:  /* FDIVR */
             ST(nextop&7).d = ST0.d / ST(nextop&7).d;
+            if(!emu->cw.f.C87_PC) ST(nextop&7).d = (float)ST(nextop&7).d;
             break;
         case 0xF8:
         case 0xF9:
@@ -118,6 +123,7 @@ uintptr_t RunDC(x64emu_t *emu, rex_t rex, uintptr_t addr)
         case 0xFE:
         case 0xFF:  /* FDIV */
             ST(nextop&7).d /=  ST0.d;
+            if(!emu->cw.f.C87_PC) ST(nextop&7).d = (float)ST(nextop&7).d;
             break;
         default:
             fesetround(oldround);
@@ -127,9 +133,11 @@ uintptr_t RunDC(x64emu_t *emu, rex_t rex, uintptr_t addr)
             switch((nextop>>3)&7) {
             case 0:         /* FADD ST0, double */
                 ST0.d += *(double*)ED;
+                if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;
                 break;
             case 1:         /* FMUL ST0, double */
                 ST0.d *= *(double*)ED;
+                if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;
                 break;
             case 2:      /* FCOM ST0, double */
                 fpu_fcom(emu, *(double*)ED);
@@ -140,15 +148,19 @@ uintptr_t RunDC(x64emu_t *emu, rex_t rex, uintptr_t addr)
                 break;
             case 4:         /* FSUB ST0, double */
                 ST0.d -= *(double*)ED;
+                if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;
                 break;
             case 5:         /* FSUBR ST0, double */
                 ST0.d = *(double*)ED - ST0.d;
+                if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;
                 break;
             case 6:         /* FDIV ST0, double */
                 ST0.d /= *(double*)ED;
+                if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;
                 break;
             case 7:         /* FDIVR ST0, double */
                 ST0.d = *(double*)ED / ST0.d;
+                if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;
                 break;
            default:
                 fesetround(oldround);
diff --git a/src/emu/x64runde.c b/src/emu/x64runde.c
index 782edcc7..8c5a444b 100644
--- a/src/emu/x64runde.c
+++ b/src/emu/x64runde.c
@@ -48,6 +48,7 @@ uintptr_t RunDE(x64emu_t *emu, rex_t rex, uintptr_t addr)
         case 0xC6:
         case 0xC7:
             ST(nextop&7).d += ST0.d;
+            if(!emu->cw.f.C87_PC) ST(nextop&7).d = (float)ST(nextop&7).d;
             fpu_do_pop(emu);
             break;
         case 0xC8:  /* FMULP STx, ST0 */
@@ -59,6 +60,7 @@ uintptr_t RunDE(x64emu_t *emu, rex_t rex, uintptr_t addr)
         case 0xCE:
         case 0xCF:
             ST(nextop&7).d *= ST0.d;
+            if(!emu->cw.f.C87_PC) ST(nextop&7).d = (float)ST(nextop&7).d;
             fpu_do_pop(emu);
             break;
         case 0xD0:
@@ -91,6 +93,7 @@ uintptr_t RunDE(x64emu_t *emu, rex_t rex, uintptr_t addr)
         case 0xE6:
         case 0xE7:
             ST(nextop&7).d = ST0.d - ST(nextop&7).d;
+            if(!emu->cw.f.C87_PC) ST(nextop&7).d = (float)ST(nextop&7).d;
             fpu_do_pop(emu);
             break;
         case 0xE8:  /* FSUBP STx, ST0 */
@@ -102,6 +105,7 @@ uintptr_t RunDE(x64emu_t *emu, rex_t rex, uintptr_t addr)
         case 0xEE:
         case 0xEF:
             ST(nextop&7).d -= ST0.d;
+            if(!emu->cw.f.C87_PC) ST(nextop&7).d = (float)ST(nextop&7).d;
             fpu_do_pop(emu);
             break;
         case 0xF0:  /* FDIVRP STx, ST0 */
@@ -113,6 +117,7 @@ uintptr_t RunDE(x64emu_t *emu, rex_t rex, uintptr_t addr)
         case 0xF6:
         case 0xF7:
             ST(nextop&7).d = ST0.d / ST(nextop&7).d;
+            if(!emu->cw.f.C87_PC) ST(nextop&7).d = (float)ST(nextop&7).d;
             fpu_do_pop(emu);
             break;
         case 0xF8:  /* FDIVP STx, ST0 */
@@ -124,6 +129,7 @@ uintptr_t RunDE(x64emu_t *emu, rex_t rex, uintptr_t addr)
         case 0xFE:
         case 0xFF:
             ST(nextop&7).d /= ST0.d;
+            if(!emu->cw.f.C87_PC) ST(nextop&7).d = (float)ST(nextop&7).d;
             fpu_do_pop(emu);
             break;
 
@@ -135,26 +141,32 @@ uintptr_t RunDE(x64emu_t *emu, rex_t rex, uintptr_t addr)
             case 0:     /* FIADD ST0, Ew int */
                 GETEW(0);
                 ST0.d += EW->sword[0];
+                if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;
                 break;
             case 1:     /* FIMUL ST0, Ew int */
                 GETEW(0);
                 ST0.d *= EW->sword[0];
+                if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;
                 break;
             case 4:     /* FISUB ST0, Ew int */
                 GETEW(0);
                 ST0.d -= EW->sword[0];
+                if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;
                 break;
             case 5:     /* FISUBR ST0, Ew int */
                 GETEW(0);
                 ST0.d = (double)EW->sword[0] - ST0.d;
+                if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;
                 break;
             case 6:     /* FIDIV ST0, Ew int */
                 GETEW(0);
                 ST0.d /= EW->sword[0];
+                if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;
                 break;
             case 7:     /* FIDIVR ST0, Ew int */
                 GETEW(0);
                 ST0.d = (double)EW->sword[0] / ST0.d;
+                if(!emu->cw.f.C87_PC) ST0.d = (float)ST0.d;
                 break;
            default:
                 fesetround(oldround);
diff --git a/src/include/regs.h b/src/include/regs.h
index 58070c8a..d83fbcbd 100644
--- a/src/include/regs.h
+++ b/src/include/regs.h
@@ -245,6 +245,12 @@ typedef union {
     } f;
     uint16_t    x16;
 } x87control_t;
+/*
+Precision Controls: 00b = 24bits, 01b=reserved, 10b=53bits and 11b=64bits
+The precision-control bits only affect the results of the following floating-point instructions: FADD, FADDP, FIADD, 
+FSUB, FSUBP, FISUB, FSUBR, FSUBRP, FISUBR, FMUL, FMULP, FIMUL, FDIV, FDIVP, FIDIV, FDIVR, FDIVRP, FIDIVR, 
+and FSQRT.
+*/
 
 typedef union {
 	struct __attribute__ ((__packed__)) {