1
// Intel x87 FPU opcodes
3
#define ST(x) (cpustate->fpu_reg[(cpustate->fpu_top + (x)) & 7])
4
#define FPU_INFINITY_DOUBLE U64(0x7ff0000000000000)
5
#define FPU_INFINITY_SINGLE (0x7f800000)
6
#define FPU_SIGN_BIT_DOUBLE U64(0x8000000000000000)
7
#define FPU_SIGN_BIT_SINGLE (0x80000000)
9
// FPU control word flags
10
#define FPU_MASK_INVALID_OP 0x0001
11
#define FPU_MASK_DENORMAL_OP 0x0002
12
#define FPU_MASK_ZERO_DIVIDE 0x0004
13
#define FPU_MASK_OVERFLOW 0x0008
14
#define FPU_MASK_UNDERFLOW 0x0010
15
#define FPU_MASK_PRECISION 0x0020
17
// FPU status word flags
18
#define FPU_BUSY 0x8000
20
#define FPU_STACK_TOP_MASK 0x3800
24
#define FPU_ERROR_SUMMARY 0x0080
25
#define FPU_STACK_FAULT 0x0040
26
#define FPU_EXCEPTION_PRECISION 0x0020
27
#define FPU_EXCEPTION_UNDERFLOW 0x0010
28
#define FPU_EXCEPTION_OVERFLOW 0x0008
29
#define FPU_EXCEPTION_ZERO_DIVIDE 0x0004
30
#define FPU_EXCEPTION_DENORMAL_OP 0x0002
31
#define FPU_EXCEPTION_INVALID_OP 0x0001
33
INLINE void FPU_PUSH(i386_state *cpustate, X87_REG value)
36
if (cpustate->fpu_top < 0)
38
cpustate->fpu_top = 7;
41
cpustate->fpu_reg[cpustate->fpu_top] = value;
44
INLINE X87_REG FPU_POP(i386_state *cpustate)
46
X87_REG value = cpustate->fpu_reg[cpustate->fpu_top];
48
cpustate->fpu_tag_word |= 3 << (cpustate->fpu_top * 2); // set FPU register tag to 3 (empty)
51
if (cpustate->fpu_top > 7)
53
cpustate->fpu_top = 0;
59
static void I386OP(fpu_group_d8)(i386_state *cpustate) // Opcode 0xd8
61
UINT8 modrm = FETCH(cpustate);
64
UINT32 ea = GetEA(cpustate,modrm);
66
switch ((modrm >> 3) & 0x7)
69
UINT32 src = READ32(cpustate,ea);
71
fatalerror("FPU: Unimplemented Divide-by-zero exception at %08X.\n", cpustate->pc-2);
72
ST(0).f = ST(0).f / src;
73
CYCLES(cpustate,1); // TODO
79
fatalerror("I386: FPU Op D8 %02X at %08X", modrm, cpustate->pc-2);
83
static void I386OP(fpu_group_d9)(i386_state *cpustate) // Opcode 0xd9
85
UINT8 modrm = FETCH(cpustate);
89
UINT32 ea = GetEA(cpustate,modrm);
91
switch ((modrm >> 3) & 0x7)
95
cpustate->fpu_control_word = READ16(cpustate,ea);
96
CYCLES(cpustate,1); // TODO
101
{ // TODO: 32-bit operand size
102
WRITE16(cpustate,ea, cpustate->fpu_control_word);
103
WRITE16(cpustate,ea+2, cpustate->fpu_status_word);
104
WRITE16(cpustate,ea+4, cpustate->fpu_tag_word);
105
WRITE16(cpustate,ea+6, cpustate->fpu_inst_ptr & 0xffff);
106
WRITE16(cpustate,ea+8, (cpustate->fpu_opcode & 0x07ff) | ((cpustate->fpu_inst_ptr & 0x0f0000) >> 4));
107
WRITE16(cpustate,ea+10, cpustate->fpu_data_ptr & 0xffff);
108
WRITE16(cpustate,ea+12, ((cpustate->fpu_inst_ptr & 0x0f0000) >> 4));
109
CYCLES(cpustate,1); // TODO
115
WRITE16(cpustate,ea, cpustate->fpu_control_word);
116
CYCLES(cpustate,1); // TODO
121
fatalerror("I386: FPU Op D9 %02X at %08X", modrm, cpustate->pc-2);
126
switch (modrm & 0x3f)
129
case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
131
X87_REG t = ST(modrm & 7);
132
FPU_PUSH(cpustate,t);
133
CYCLES(cpustate,1); // TODO
139
ST(0).i ^= FPU_SIGN_BIT_DOUBLE;
140
CYCLES(cpustate,1); // TODO
148
FPU_PUSH(cpustate,t);
149
CYCLES(cpustate,1); // TODO
157
FPU_PUSH(cpustate,t);
158
CYCLES(cpustate,1); // TODO
162
fatalerror("I386: FPU Op D9 %02X at %08X", modrm, cpustate->pc-2);
167
static void I386OP(fpu_group_da)(i386_state *cpustate) // Opcode 0xda
169
UINT8 modrm = FETCH(cpustate);
170
fatalerror("I386: FPU Op DA %02X at %08X", modrm, cpustate->pc-2);
173
static void I386OP(fpu_group_db)(i386_state *cpustate) // Opcode 0xdb
175
UINT8 modrm = FETCH(cpustate);
179
fatalerror("I386: FPU Op DB %02X at %08X", modrm, cpustate->pc-2);
183
switch (modrm & 0x3f)
187
cpustate->fpu_control_word = 0x37f;
188
cpustate->fpu_status_word = 0;
189
cpustate->fpu_tag_word = 0xffff;
190
cpustate->fpu_data_ptr = 0;
191
cpustate->fpu_inst_ptr = 0;
192
cpustate->fpu_opcode = 0;
194
CYCLES(cpustate,1); // TODO
198
case 0x24: // FSETPM (treated as nop on 387+)
205
fatalerror("I386: FPU Op DB %02X at %08X", modrm, cpustate->pc-2);
210
static void I386OP(fpu_group_dc)(i386_state *cpustate) // Opcode 0xdc
212
UINT8 modrm = FETCH(cpustate);
216
//UINT32 ea = GetEA(cpustate,modrm);
218
switch ((modrm >> 3) & 0x7)
221
fatalerror("I386: FPU Op DC %02X at %08X", modrm, cpustate->pc-2);
226
switch (modrm & 0x3f)
228
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
231
if ((ST(modrm & 7).i & U64(0x7fffffffffffffff)) == 0)
233
// set result as infinity if zero divide is masked
234
if (cpustate->fpu_control_word & FPU_MASK_ZERO_DIVIDE)
236
ST(modrm & 7).i |= FPU_INFINITY_DOUBLE;
241
ST(modrm & 7).f = ST(0).f / ST(modrm & 7).f;
243
CYCLES(cpustate,1); // TODO
248
fatalerror("I386: FPU Op DC %02X at %08X", modrm, cpustate->pc-2);
253
static void I386OP(fpu_group_dd)(i386_state *cpustate) // Opcode 0xdd
255
UINT8 modrm = FETCH(cpustate);
259
UINT32 ea = GetEA(cpustate,modrm);
261
switch ((modrm >> 3) & 0x7)
265
WRITE16(cpustate,ea, (cpustate->fpu_status_word & ~FPU_STACK_TOP_MASK) | (cpustate->fpu_top << 10));
266
CYCLES(cpustate,1); // TODO
271
fatalerror("I386: FPU Op DD %02X at %08X", modrm, cpustate->pc-2);
276
switch (modrm & 0x3f)
279
fatalerror("I386: FPU Op DD %02X at %08X", modrm, cpustate->pc-2);
284
static void I386OP(fpu_group_de)(i386_state *cpustate) // Opcode 0xde
286
UINT8 modrm = FETCH(cpustate);
290
// UINT32 ea = GetEA(cpustate,modrm);
292
switch ((modrm >> 3) & 0x7)
295
fatalerror("I386: FPU Op DE %02X at %08X", modrm, cpustate->pc-2);
300
switch (modrm & 0x3f)
304
cpustate->fpu_status_word &= ~(FPU_C3 | FPU_C2 | FPU_C0);
305
if (ST(0).f > ST(1).f)
307
// C3 = 0, C2 = 0, C0 = 0
309
else if (ST(0).f < ST(1).f)
311
cpustate->fpu_status_word |= FPU_C0;
313
else if (ST(0).f == ST(1).f)
315
cpustate->fpu_status_word |= FPU_C3;
320
cpustate->fpu_status_word |= (FPU_C3 | FPU_C2 | FPU_C0);
324
CYCLES(cpustate,1); // TODO
329
case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
331
if ((ST(0).i & U64(0x7fffffffffffffff)) == 0)
333
// set result as infinity if zero divide is masked
334
if (cpustate->fpu_control_word & FPU_MASK_ZERO_DIVIDE)
336
ST(modrm & 7).i |= FPU_INFINITY_DOUBLE;
341
ST(modrm & 7).f = ST(modrm & 7).f / ST(0).f;
344
CYCLES(cpustate,1); // TODO
349
fatalerror("I386: FPU Op DE %02X at %08X", modrm, cpustate->pc-2);
354
static void I386OP(fpu_group_df)(i386_state *cpustate) // Opcode 0xdf
356
UINT8 modrm = FETCH(cpustate);
360
// UINT32 ea = GetEA(cpustate,modrm);
362
switch ((modrm >> 3) & 0x7)
365
fatalerror("I386: FPU Op DF %02X at %08X", modrm, cpustate->pc-2);
370
switch (modrm & 0x3f)
372
case 0x20: // FSTSW AX
374
REG16(AX) = (cpustate->fpu_status_word & ~FPU_STACK_TOP_MASK) | (cpustate->fpu_top << 10);
375
CYCLES(cpustate,1); // TODO
380
fatalerror("I386: FPU Op DF %02X at %08X", modrm, cpustate->pc-2);