i386: FPU rewritten using softfloat [Carl]

This commit is contained in:
Miodrag Milanovic 2012-01-26 19:13:47 +00:00
parent 829b301e47
commit 6b857b37e0

View File

@ -5,6 +5,9 @@
// - opcode cycles (every single CPU has different counting on it); // - opcode cycles (every single CPU has different counting on it);
// - clean-ups; // - clean-ups;
#include "../../../lib/softfloat/milieu.h"
#include "../../../lib/softfloat/softfloat.h"
#define ST(x) (cpustate->fpu_reg[(cpustate->fpu_top + (x)) & 7]) #define ST(x) (cpustate->fpu_reg[(cpustate->fpu_top + (x)) & 7])
#define FPU_INFINITY_DOUBLE U64(0x7ff0000000000000) #define FPU_INFINITY_DOUBLE U64(0x7ff0000000000000)
#define FPU_INFINITY_SINGLE (0x7f800000) #define FPU_INFINITY_SINGLE (0x7f800000)
@ -74,62 +77,75 @@ INLINE X87_REG FPU_POP(i386_state *cpustate)
return value; return value;
} }
INLINE X87_REG X87_FROUND(i386_state *cpustate, X87_REG t) INLINE INT64 X87_FROUND(i386_state *cpustate, X87_REG t)
{ {
switch((cpustate->fpu_control_word >> 10) & 3) switch((cpustate->fpu_control_word >> 10) & 3)
{ {
case 0: t.f = (INT64)t.f + 0.5; break; /* Nearest */ case 0: return (INT64)(t.f + 0.5); break; /* Nearest */
case 1: t.f = (INT64)floor(t.f); break; /* Down */ case 1: return (INT64)floor(t.f); break; /* Down */
case 2: t.f = (INT64)ceil(t.f); break; /* Up */ case 2: return (INT64)ceil(t.f); break; /* Up */
case 3: t.f = (INT64)t.f; break; /* Chop */ case 3: return (INT64)t.f; break; /* Chop */
} }
return t; return 0;
} }
INLINE X87_REG READ80(i386_state *cpustate,UINT32 ea) INLINE X87_REG READ80(i386_state *cpustate,UINT32 ea)
{ {
X87_REG t; X87_REG t;
UINT16 begin; floatx80 f;
f.high = READ16(cpustate,ea+8);
f.low = READ64(cpustate,ea);
/* UINT16 begin;
INT64 exp; INT64 exp;
INT64 mantissa; INT64 mantissa;
UINT8 sign; UINT8 sign;
t.i = READ64(cpustate,ea); t.i = READ64(cpustate,ea);
begin = READ16(cpustate,ea+8); begin = READ16(cpustate,ea+8);
sign = (begin&0x8000) >> 15;
if((t.i == FPU_SIGN_BIT_DOUBLE) && ((begin & 0x7fff) == 0x7fff))
{
t.f = HUGE_VAL * (sign?(-1.0):(1.0));
return t;
}
exp = (begin&0x7fff) - 16383; exp = (begin&0x7fff) - 16383;
exp = (exp > 0) ? (exp&0x3ff) : (-exp&0x3ff); exp = (exp > 0) ? (exp&0x3ff) : (-1)*(-exp&0x3ff);
exp += 1023; exp += 1023;
mantissa = (t.i >> 11) & (FPU_MANTISSA_DOUBLE); mantissa = (t.i >> 11) & (FPU_MANTISSA_DOUBLE);
sign = (begin&0x8000) >> 15;
if(t.i & 0x400) if(t.i & 0x400)
mantissa++; mantissa++;
t.i = ((UINT64)sign << 63)|((UINT64)exp << 52)|((UINT64)mantissa); t.i = ((UINT64)sign << 63)|((UINT64)exp << 52)|((UINT64)mantissa);*/
t.f = floatx80_to_float64(f);
return t; return t;
} }
INLINE void WRITE80(i386_state *cpustate,UINT32 ea, X87_REG t) INLINE void WRITE80(i386_state *cpustate,UINT32 ea, X87_REG t)
{ {
UINT8 sign = (t.i & FPU_SIGN_BIT_DOUBLE) ? 1 : 0; floatx80 f;
/* UINT16 sign = (t.i & FPU_SIGN_BIT_DOUBLE) ? 1 : 0;
INT64 exp = (t.i & FPU_INFINITY_DOUBLE) >> 52; INT64 exp = (t.i & FPU_INFINITY_DOUBLE) >> 52;
INT64 mantissa = (t.i & FPU_MANTISSA_DOUBLE) << 11; INT64 mantissa = (t.i & FPU_MANTISSA_DOUBLE) << 11;
INT16 begin; INT16 begin;
if(t.f != 0) if(t.f != 0)
{ {
logerror("Check WRITE80 with t.f != 0\n"); mantissa |= FPU_SIGN_BIT_DOUBLE;
//mantissa |= FPU_SIGN_BIT_DOUBLE; exp += (16383 - 1023);
//exp += (16383 - 1023);
} }
begin = (sign<<15)|(INT16)(exp); begin = (sign<<15)|(INT16)(exp);
t.i = mantissa; t.i = mantissa;*/
WRITE64(cpustate,ea,t.i);
WRITE16(cpustate,ea+8,begin); f = float64_to_floatx80(t.f);
WRITE64(cpustate,ea,f.low);
WRITE16(cpustate,ea+8,f.high);
} }
static void I386OP(fpu_group_d8)(i386_state *cpustate) // Opcode 0xd8 static void I386OP(fpu_group_d8)(i386_state *cpustate) // Opcode 0xd8
@ -199,7 +215,12 @@ static void I386OP(fpu_group_d8)(i386_state *cpustate) // Opcode 0xd8
case 6: // FDIV case 6: // FDIV
{ {
if(src == 0) if(src == 0)
fatalerror("FPU: Unimplemented Divide-by-zero exception at %08X.\n", cpustate->pc-2); {
if(cpustate->fpu_control_word & FPU_MASK_ZERO_DIVIDE)
ST(0).i |= FPU_INFINITY_DOUBLE;
else
cpustate->fpu_status_word |= FPU_EXCEPTION_ZERO_DIVIDE;
}
else else
ST(0).f = ST(0).f / src; ST(0).f = ST(0).f / src;
CYCLES(cpustate,73); CYCLES(cpustate,73);
@ -209,7 +230,12 @@ static void I386OP(fpu_group_d8)(i386_state *cpustate) // Opcode 0xd8
case 7: // FDIVR case 7: // FDIVR
{ {
if(src == 0) if(src == 0)
fatalerror("FPU: Unimplemented Divide-by-zero exception at %08X.\n", cpustate->pc-2); {
if(cpustate->fpu_control_word & FPU_MASK_ZERO_DIVIDE)
ST(0).i |= FPU_INFINITY_DOUBLE;
else
cpustate->fpu_status_word |= FPU_EXCEPTION_ZERO_DIVIDE;
}
else else
ST(0).f = src / ST(0).f; ST(0).f = src / ST(0).f;
CYCLES(cpustate,73); CYCLES(cpustate,73);
@ -272,20 +298,30 @@ static void I386OP(fpu_group_d8)(i386_state *cpustate) // Opcode 0xd8
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: // FDIV case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: // FDIV
{ {
if(ST(modrm & 7).f != 0) if(ST(modrm & 7).f != 0.0)
ST(0).f/=ST(modrm & 7).f; ST(0).f/=ST(modrm & 7).f;
else else
fatalerror("Divide by zero on FDIV 0xd8 0x30"); {
if(cpustate->fpu_control_word & FPU_MASK_ZERO_DIVIDE)
ST(0).i |= FPU_INFINITY_DOUBLE;
else
cpustate->fpu_status_word |= FPU_EXCEPTION_ZERO_DIVIDE;
}
CYCLES(cpustate,73); CYCLES(cpustate,73);
break; break;
} }
case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: // FDIVR case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: // FDIVR
{ {
if(ST(0).f != 0) if(ST(0).f != 0.0)
ST(0).f = ST(modrm & 7).f / ST(0).f; ST(0).f = ST(modrm & 7).f / ST(0).f;
else else
fatalerror("Divide by zero on FDIVR 0xd8 0x38"); {
if(cpustate->fpu_control_word & FPU_MASK_ZERO_DIVIDE)
ST(0).i |= FPU_INFINITY_DOUBLE;
else
cpustate->fpu_status_word |= FPU_EXCEPTION_ZERO_DIVIDE;
}
CYCLES(cpustate,73); CYCLES(cpustate,73);
break; break;
} }
@ -479,8 +515,11 @@ static void I386OP(fpu_group_d9)(i386_state *cpustate) // Opcode 0xd9
case 0x25: // FXAM case 0x25: // FXAM
{ {
cpustate->fpu_status_word &= ~(FPU_C3 | FPU_C2 | FPU_C0); cpustate->fpu_status_word &= ~(FPU_C3 | FPU_C2 | FPU_C0);
if(((cpustate->fpu_tag_word>>((cpustate->fpu_top&1)<<1))&3)==3) if(!(cpustate->fpu_tag_word&(1<<cpustate->fpu_top)))
{
cpustate->fpu_status_word |= FPU_C3 | FPU_C0; cpustate->fpu_status_word |= FPU_C3 | FPU_C0;
return;
}
else if(ST(0).f == 0.0) else if(ST(0).f == 0.0)
cpustate->fpu_status_word |= FPU_C3; cpustate->fpu_status_word |= FPU_C3;
else else
@ -506,6 +545,7 @@ static void I386OP(fpu_group_d9)(i386_state *cpustate) // Opcode 0xd9
t.f = 3.3219280948873623; t.f = 3.3219280948873623;
FPU_PUSH(cpustate,t); FPU_PUSH(cpustate,t);
CYCLES(cpustate,8); CYCLES(cpustate,8);
break;
} }
case 0x2a: // FLDL2E case 0x2a: // FLDL2E
@ -514,6 +554,7 @@ static void I386OP(fpu_group_d9)(i386_state *cpustate) // Opcode 0xd9
t.f = 1.4426950408889634; t.f = 1.4426950408889634;
FPU_PUSH(cpustate,t); FPU_PUSH(cpustate,t);
CYCLES(cpustate,8); CYCLES(cpustate,8);
break;
} }
case 0x2b: // FLDPI case 0x2b: // FLDPI
@ -522,6 +563,7 @@ static void I386OP(fpu_group_d9)(i386_state *cpustate) // Opcode 0xd9
t.f = 3.141592653589793; t.f = 3.141592653589793;
FPU_PUSH(cpustate,t); FPU_PUSH(cpustate,t);
CYCLES(cpustate,8); CYCLES(cpustate,8);
break;
} }
case 0x2c: // FLDEG2 case 0x2c: // FLDEG2
@ -530,6 +572,7 @@ static void I386OP(fpu_group_d9)(i386_state *cpustate) // Opcode 0xd9
t.f = 0.3010299956639812; t.f = 0.3010299956639812;
FPU_PUSH(cpustate,t); FPU_PUSH(cpustate,t);
CYCLES(cpustate,8); CYCLES(cpustate,8);
break;
} }
case 0x2d: // FLDLN2 case 0x2d: // FLDLN2
@ -538,6 +581,7 @@ static void I386OP(fpu_group_d9)(i386_state *cpustate) // Opcode 0xd9
t.f = 0.693147180559945; t.f = 0.693147180559945;
FPU_PUSH(cpustate,t); FPU_PUSH(cpustate,t);
CYCLES(cpustate,8); CYCLES(cpustate,8);
break;
} }
case 0x2e: // FLDZ case 0x2e: // FLDZ
@ -603,22 +647,25 @@ static void I386OP(fpu_group_d9)(i386_state *cpustate) // Opcode 0xd9
case 0x38: // FPREM case 0x38: // FPREM
{ {
X87_REG t; INT64 t;
if(ST(1).i == 0) if(ST(1).f == 0.0)
fatalerror("Divide by zero on x87 FPREM opcode"); {
logerror("FPREM divide by zero");
t.i = ST(0).i / ST(1).i; break;
ST(0).f = ST(0).f-(ST(1).i*t.f); }
else
t = ST(0).f / ST(1).f;
ST(0).f = ST(0).f-(ST(1).i*t);
cpustate->fpu_status_word &= ~(FPU_C0 | FPU_C1 | FPU_C2 | FPU_C3); cpustate->fpu_status_word &= ~(FPU_C0 | FPU_C1 | FPU_C2 | FPU_C3);
if(t.i & 4) if(t & 4)
cpustate->fpu_status_word |= FPU_C0; cpustate->fpu_status_word |= FPU_C0;
if(t.i & 2) if(t & 2)
cpustate->fpu_status_word |= FPU_C3; cpustate->fpu_status_word |= FPU_C3;
if(t.i & 1) if(t & 1)
cpustate->fpu_status_word |= FPU_C1; cpustate->fpu_status_word |= FPU_C1;
CYCLES(cpustate,100); CYCLES(cpustate,100);
@ -646,17 +693,16 @@ static void I386OP(fpu_group_d9)(i386_state *cpustate) // Opcode 0xd9
case 0x3c: // FRNDINT case 0x3c: // FRNDINT
{ {
ST(0) = X87_FROUND(cpustate,ST(0)); ST(0).f = (double)X87_FROUND(cpustate,ST(0));
CYCLES(cpustate,21); CYCLES(cpustate,21);
break; break;
} }
case 0x3d: // FSCALE case 0x3d: // FSCALE
{ {
X87_REG t; ST(0).f *= pow(2.0,(INT64)(ST(1).f));
t = ST(1);
ST(0).f = ST(0).f*pow(2.0,t.f);
CYCLES(cpustate,30); CYCLES(cpustate,30);
break;
} }
case 0x3e: // FSIN case 0x3e: // FSIN
@ -690,33 +736,33 @@ static void I386OP(fpu_group_da)(i386_state *cpustate) // Opcode 0xda
if (modrm < 0xc0) if (modrm < 0xc0)
{ {
UINT32 ea = GetEA(cpustate,modrm); UINT32 ea = GetEA(cpustate,modrm);
X87_REG t; double t;
t.i = READ32(cpustate,ea); t = (double)READ32(cpustate,ea);
switch ((modrm >> 3) & 0x7) switch ((modrm >> 3) & 0x7)
{ {
case 0: // FIADD case 0: // FIADD
ST(0).i+=t.i; ST(0).f+=t;
CYCLES(cpustate,20); CYCLES(cpustate,20);
break; break;
case 1: // FIMUL case 1: // FIMUL
ST(0).i*=t.i; ST(0).f*=t;
CYCLES(cpustate,22); CYCLES(cpustate,22);
break; break;
case 2: // FICOM case 2: // FICOM
cpustate->fpu_status_word &= ~(FPU_C3 | FPU_C2 | FPU_C0); cpustate->fpu_status_word &= ~(FPU_C3 | FPU_C2 | FPU_C0);
if(ST(0).i == t.i) if(ST(0).f == t)
cpustate->fpu_status_word |= FPU_C3; cpustate->fpu_status_word |= FPU_C3;
if(ST(0).i < t.i) if(ST(0).f < t)
cpustate->fpu_status_word |= FPU_C0; cpustate->fpu_status_word |= FPU_C0;
CYCLES(cpustate,15); CYCLES(cpustate,15);
break; break;
case 3: // FICOMP case 3: // FICOMP
cpustate->fpu_status_word &= ~(FPU_C3 | FPU_C2 | FPU_C0); cpustate->fpu_status_word &= ~(FPU_C3 | FPU_C2 | FPU_C0);
if(ST(0).i == t.i) if(ST(0).f == t)
cpustate->fpu_status_word |= FPU_C3; cpustate->fpu_status_word |= FPU_C3;
if(ST(0).i < t.i) if(ST(0).f < t)
cpustate->fpu_status_word |= FPU_C0; cpustate->fpu_status_word |= FPU_C0;
FPU_POP(cpustate); FPU_POP(cpustate);
@ -724,28 +770,38 @@ static void I386OP(fpu_group_da)(i386_state *cpustate) // Opcode 0xda
break; break;
case 4: // FISUB case 4: // FISUB
ST(0).i-=t.i; ST(0).f-=t;
CYCLES(cpustate,15); CYCLES(cpustate,15);
break; break;
case 5: // FISUBR case 5: // FISUBR
ST(0).i = t.i - ST(0).i; ST(0).f = t - ST(0).f;
CYCLES(cpustate,15); CYCLES(cpustate,15);
break; break;
case 6: // FIDIV case 6: // FIDIV
if(t.i) if(t == 0.0)
ST(0).i/=t.i; ST(0).f/=t;
else else
fatalerror("Divide-by-zero on FIDIV 0xda 0x06 opcode"); {
if(cpustate->fpu_control_word & FPU_MASK_ZERO_DIVIDE)
ST(0).i |= FPU_INFINITY_DOUBLE;
else
cpustate->fpu_status_word |= FPU_EXCEPTION_ZERO_DIVIDE;
}
CYCLES(cpustate,84); CYCLES(cpustate,84);
break; break;
case 7: // FIDIVR case 7: // FIDIVR
if(ST(0).i) if(ST(0).f == 0.0)
ST(0).i = t.i / ST(0).i; ST(0).f = t / ST(0).f;
else else
fatalerror("Divide-by-zero on FIDIV 0xda 0x07 opcode"); {
if(cpustate->fpu_control_word & FPU_MASK_ZERO_DIVIDE)
ST(0).i |= FPU_INFINITY_DOUBLE;
else
cpustate->fpu_status_word |= FPU_EXCEPTION_ZERO_DIVIDE;
}
CYCLES(cpustate,84); CYCLES(cpustate,84);
break; break;
@ -788,7 +844,7 @@ static void I386OP(fpu_group_db)(i386_state *cpustate) // Opcode 0xdb
{ {
X87_REG t; X87_REG t;
t.f=(INT32)READ32(cpustate,ea); t.f=(double)READ32(cpustate,ea);
FPU_PUSH(cpustate,t); FPU_PUSH(cpustate,t);
CYCLES(cpustate,9); CYCLES(cpustate,9);
break; break;
@ -796,20 +852,20 @@ static void I386OP(fpu_group_db)(i386_state *cpustate) // Opcode 0xdb
case 2: // FIST case 2: // FIST
{ {
X87_REG t; INT32 t;
t = X87_FROUND(cpustate,ST(0)); t = X87_FROUND(cpustate,ST(0));
WRITE32(cpustate,ea,(INT32)t.i); WRITE32(cpustate,ea,t);
CYCLES(cpustate,28); CYCLES(cpustate,28);
break; break;
} }
case 3: // FISTP case 3: // FISTP
{ {
X87_REG t; INT32 t;
t = X87_FROUND(cpustate,ST(0)); t = X87_FROUND(cpustate,ST(0));
WRITE32(cpustate,ea,(INT32)t.i); WRITE32(cpustate,ea,t);
FPU_POP(cpustate); FPU_POP(cpustate);
CYCLES(cpustate,28); CYCLES(cpustate,28);
break; break;
@ -948,10 +1004,15 @@ static void I386OP(fpu_group_dc)(i386_state *cpustate) // Opcode 0xdc
case 6: /* FDIV double */ case 6: /* FDIV double */
{ {
if(t.f) if(t.f != 0.0)
ST(0).f /= t.f; ST(0).f /= t.f;
else else
fatalerror("FPU Op DC 6 Divide by zero unhandled exception"); {
if(cpustate->fpu_control_word & FPU_MASK_ZERO_DIVIDE)
ST(0).i |= FPU_INFINITY_DOUBLE;
else
cpustate->fpu_status_word |= FPU_EXCEPTION_ZERO_DIVIDE;
}
CYCLES(cpustate,73); CYCLES(cpustate,73);
break; break;
@ -959,11 +1020,15 @@ static void I386OP(fpu_group_dc)(i386_state *cpustate) // Opcode 0xdc
case 7: /* FDIV double */ case 7: /* FDIV double */
{ {
if(ST(0).f) if(ST(0).f != 0.0)
ST(0).f = t.f / ST(0).f; ST(0).f = t.f / ST(0).f;
else else
fatalerror("FPU Op DC 6 Divide by zero unhandled exception"); {
if(cpustate->fpu_control_word & FPU_MASK_ZERO_DIVIDE)
ST(0).i |= FPU_INFINITY_DOUBLE;
else
cpustate->fpu_status_word |= FPU_EXCEPTION_ZERO_DIVIDE;
}
CYCLES(cpustate,73); CYCLES(cpustate,73);
break; break;
} }
@ -1187,7 +1252,7 @@ static void I386OP(fpu_group_dd)(i386_state *cpustate) // Opcode 0xdd
case 7: // FSTSW case 7: // FSTSW
{ {
WRITE16(cpustate,ea, (cpustate->fpu_status_word & ~FPU_STACK_TOP_MASK) | (cpustate->fpu_top << 10)); WRITE16(cpustate,ea, (cpustate->fpu_status_word & ~FPU_STACK_TOP_MASK) | (cpustate->fpu_top << 11));
CYCLES(cpustate,1); // TODO CYCLES(cpustate,1); // TODO
break; break;
} }
@ -1336,6 +1401,7 @@ static void I386OP(fpu_group_de)(i386_state *cpustate) // Opcode 0xde
cpustate->fpu_status_word |= (FPU_C3 | FPU_C2 | FPU_C0); cpustate->fpu_status_word |= (FPU_C3 | FPU_C2 | FPU_C0);
} }
CYCLES(cpustate,15); CYCLES(cpustate,15);
break;
} }
case 3: // FICOMP case 3: // FICOMP
@ -1360,6 +1426,7 @@ static void I386OP(fpu_group_de)(i386_state *cpustate) // Opcode 0xde
} }
FPU_POP(cpustate); FPU_POP(cpustate);
CYCLES(cpustate,15); CYCLES(cpustate,15);
break;
} }
case 4: // FISUB single precision case 4: // FISUB single precision
@ -1379,7 +1446,12 @@ static void I386OP(fpu_group_de)(i386_state *cpustate) // Opcode 0xde
case 6: // FIDIV single precision case 6: // FIDIV single precision
{ {
if((double)t == 0) if((double)t == 0)
fatalerror("Divide by zero on x87 opcode 0xde 0x06"); {
if(cpustate->fpu_control_word & FPU_MASK_ZERO_DIVIDE)
ST(0).i = FPU_INFINITY_DOUBLE;
else
cpustate->fpu_status_word |= FPU_EXCEPTION_ZERO_DIVIDE;
}
else else
ST(0).f/=(double)t; ST(0).f/=(double)t;
CYCLES(cpustate,84); CYCLES(cpustate,84);
@ -1389,7 +1461,12 @@ static void I386OP(fpu_group_de)(i386_state *cpustate) // Opcode 0xde
case 7: // FIDIVR single precision case 7: // FIDIVR single precision
{ {
if(ST(0).f == 0) if(ST(0).f == 0)
fatalerror("Divide by zero on x87 opcode 0xde 0x07"); {
if(cpustate->fpu_control_word & FPU_MASK_ZERO_DIVIDE)
ST(0).i = FPU_INFINITY_DOUBLE;
else
cpustate->fpu_status_word |= FPU_EXCEPTION_ZERO_DIVIDE;
}
else else
ST(0).f = (double)t / ST(0).f; ST(0).f = (double)t / ST(0).f;
CYCLES(cpustate,84); CYCLES(cpustate,84);
@ -1407,7 +1484,7 @@ static void I386OP(fpu_group_de)(i386_state *cpustate) // Opcode 0xde
{ {
case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: // FADDP case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: // FADDP
{ {
ST(modrm & 7).f += ST(cpustate->fpu_top).f; ST(modrm & 7).f += ST(0).f;
FPU_POP(cpustate); FPU_POP(cpustate);
CYCLES(cpustate,8); CYCLES(cpustate,8);
break; break;
@ -1415,7 +1492,7 @@ static void I386OP(fpu_group_de)(i386_state *cpustate) // Opcode 0xde
case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: // FMULP case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: // FMULP
{ {
ST(modrm & 7).f *= ST(cpustate->fpu_top).f; ST(modrm & 7).f *= ST(0).f;
FPU_POP(cpustate); FPU_POP(cpustate);
CYCLES(cpustate,16); CYCLES(cpustate,16);
break; break;
@ -1457,7 +1534,7 @@ static void I386OP(fpu_group_de)(i386_state *cpustate) // Opcode 0xde
case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: // FSUBP case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: // FSUBP
{ {
ST(modrm & 7).f -= ST(cpustate->fpu_top).f; ST(modrm & 7).f -= ST(0).f;
FPU_POP(cpustate); FPU_POP(cpustate);
CYCLES(cpustate,8); CYCLES(cpustate,8);
break; break;
@ -1531,20 +1608,20 @@ static void I386OP(fpu_group_df)(i386_state *cpustate) // Opcode 0xdf
case 2: // FIST case 2: // FIST
{ {
X87_REG t; INT16 t;
t = X87_FROUND(cpustate,ST(0)); t = X87_FROUND(cpustate,ST(0));
WRITE16(cpustate,ea,(INT16)t.i); WRITE16(cpustate,ea,t);
CYCLES(cpustate,1); // TODO CYCLES(cpustate,1); // TODO
break; break;
} }
case 3: // FISTP short case 3: // FISTP short
{ {
X87_REG t; INT16 t;
t = X87_FROUND(cpustate,ST(0)); t = X87_FROUND(cpustate,ST(0));
WRITE16(cpustate,ea,(INT16)t.i); WRITE16(cpustate,ea,t);
FPU_POP(cpustate); FPU_POP(cpustate);
CYCLES(cpustate,29); CYCLES(cpustate,29);
break; break;
@ -1612,10 +1689,10 @@ static void I386OP(fpu_group_df)(i386_state *cpustate) // Opcode 0xdf
case 7: // FISTP long case 7: // FISTP long
{ {
X87_REG t; INT64 t;
t = X87_FROUND(cpustate,ST(0)); t = X87_FROUND(cpustate,ST(0));
WRITE64(cpustate,ea,t.i); WRITE64(cpustate,ea,t);
FPU_POP(cpustate); FPU_POP(cpustate);
CYCLES(cpustate,29); CYCLES(cpustate,29);
break; break;
@ -1631,7 +1708,7 @@ static void I386OP(fpu_group_df)(i386_state *cpustate) // Opcode 0xdf
{ {
case 0x20: // FSTSW AX case 0x20: // FSTSW AX
{ {
REG16(AX) = (cpustate->fpu_status_word & ~FPU_STACK_TOP_MASK) | (cpustate->fpu_top << 10); REG16(AX) = (cpustate->fpu_status_word & ~FPU_STACK_TOP_MASK) | (cpustate->fpu_top << 11);
CYCLES(cpustate,1); // TODO CYCLES(cpustate,1); // TODO
break; break;
} }