[FAST486]
[reactos.git] / reactos / lib / fast486 / fpu.c
1 /*
2 * Fast486 386/486 CPU Emulation Library
3 * fpu.c
4 *
5 * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 /* INCLUDES *******************************************************************/
23
24 #include <windef.h>
25
26 // #define NDEBUG
27 #include <debug.h>
28
29 #include <fast486.h>
30 #include "common.h"
31 #include "fpu.h"
32
33 /* CONSTANTS ******************************************************************/
34
35 /* 0.00 */
36 static const FAST486_FPU_DATA_REG FpuZero = {0ULL, 0, FALSE};
37
38 /* 1.00 */
39 static const FAST486_FPU_DATA_REG FpuOne = {0x8000000000000000ULL, FPU_REAL10_BIAS, FALSE};
40
41 /* Pi */
42 static const FAST486_FPU_DATA_REG FpuPi = {0xC90FDAA22168C234ULL, FPU_REAL10_BIAS + 1, FALSE};
43
44 /* lb(10) */
45 static const FAST486_FPU_DATA_REG FpuL2Ten = {0xD49A784BCD1D8AFEULL, FPU_REAL10_BIAS + 1, FALSE};
46
47 /* lb(e) */
48 static const FAST486_FPU_DATA_REG FpuL2E = {0xB8AA3B295C17F0BBULL, FPU_REAL10_BIAS, FALSE};
49
50 /* lg(2) */
51 static const FAST486_FPU_DATA_REG FpuLgTwo = {0x9A209A84FBCFF798ULL, FPU_REAL10_BIAS - 2, FALSE};
52
53 /* ln(2) */
54 static const FAST486_FPU_DATA_REG FpuLnTwo = {0xB17217F7D1CF79ABULL, FPU_REAL10_BIAS - 1, FALSE};
55
56 /* PRIVATE FUNCTIONS **********************************************************/
57
58 #ifndef FAST486_NO_FPU
59
60 static ULONGLONG
61 UnsignedMult128(ULONGLONG Multiplicand,
62 ULONGLONG Multiplier,
63 ULONGLONG *HighProduct)
64 {
65 ULONG MultiplicandLow, MultiplicandHigh, MultiplierLow, MultiplierHigh;
66 ULONG IntermediateLow, IntermediateHigh;
67 ULONGLONG LowProduct, Intermediate, Intermediate1, Intermediate2;
68
69 MultiplicandLow = (ULONG)(Multiplicand & 0xFFFFFFFFULL);
70 MultiplicandHigh = (ULONG)(Multiplicand >> 32);
71 MultiplierLow = (ULONG)(Multiplier & 0xFFFFFFFFULL);
72 MultiplierHigh = (ULONG)(Multiplier >> 32);
73
74 LowProduct = (ULONGLONG)MultiplicandLow * (ULONGLONG)MultiplierLow;
75 Intermediate1 = (ULONGLONG)MultiplicandLow * (ULONGLONG)MultiplierHigh;
76 Intermediate2 = (ULONGLONG)MultiplicandHigh * (ULONGLONG)MultiplierLow;
77 *HighProduct = (ULONGLONG)MultiplicandHigh * (ULONGLONG)MultiplierHigh;
78
79 Intermediate = Intermediate1 + Intermediate2;
80 if (Intermediate < Intermediate1) *HighProduct += 1ULL << 32;
81
82 IntermediateLow = (ULONG)(Intermediate & 0xFFFFFFFFULL);
83 IntermediateHigh = (ULONG)(Intermediate >> 32);
84
85 LowProduct += (ULONGLONG)IntermediateLow << 32;
86 if ((ULONG)(LowProduct >> 32) < IntermediateLow) (*HighProduct)++;
87
88 *HighProduct += IntermediateHigh;
89 return LowProduct;
90 }
91
92 static ULONGLONG
93 UnsignedDivMod128(ULONGLONG DividendLow,
94 ULONGLONG DividendHigh,
95 ULONGLONG Divisor,
96 PULONGLONG QuotientLow,
97 PULONGLONG QuotientHigh)
98 {
99 ULONGLONG ValueLow = DividendLow;
100 ULONGLONG ValueHigh = DividendHigh;
101 ULONGLONG CurrentLow = 0ULL;
102 ULONGLONG CurrentHigh = Divisor;
103 ULONG Bits;
104
105 ASSERT(Divisor != 0ULL);
106
107 /* Initialize the quotient */
108 *QuotientLow = *QuotientHigh = 0ULL;
109
110 /* Exit early if the dividend is lower than the divisor */
111 if ((DividendHigh == 0ULL) && (DividendLow < Divisor)) return ValueLow;
112
113 /* Normalize the current divisor */
114 Bits = CountLeadingZeros64(CurrentHigh);
115 CurrentHigh <<= Bits;
116
117 while (TRUE)
118 {
119 /* Shift the quotient left by one bit */
120 *QuotientHigh <<= 1;
121 *QuotientHigh |= *QuotientLow >> 63;
122 *QuotientLow <<= 1;
123
124 /* Check if the value is higher than or equal to the current divisor */
125 if ((ValueHigh > CurrentHigh)
126 || ((ValueHigh == CurrentHigh) && (ValueLow >= CurrentLow)))
127 {
128 BOOLEAN Carry = ValueLow < CurrentLow;
129
130 /* Subtract the current divisor from the value */
131 ValueHigh -= CurrentHigh;
132 ValueLow -= CurrentLow;
133 if (Carry) ValueHigh--;
134
135 /* Set the lowest bit of the quotient */
136 *QuotientLow |= 1;
137
138 /* Stop if the value is lower than the original divisor */
139 if ((ValueHigh == 0ULL) && (ValueLow < Divisor)) break;
140 }
141
142 /* Shift the current divisor right by one bit */
143 CurrentLow >>= 1;
144 CurrentLow |= (CurrentHigh & 1) << 63;
145 CurrentHigh >>= 1;
146 }
147
148 /*
149 * Calculate the number of significant bits the current
150 * divisor has more than the original divisor
151 */
152 Bits = CountLeadingZeros64(Divisor) + 64;
153 Bits -= (CurrentHigh > 0ULL) ? CountLeadingZeros64(CurrentHigh) : 64;
154 Bits -= (CurrentLow > 0ULL) ? CountLeadingZeros64(CurrentLow) : 64;
155
156 if (Bits)
157 {
158 /* Shift the quotient left by that amount */
159 *QuotientHigh <<= Bits;
160 *QuotientHigh |= *QuotientLow >> (64 - Bits);
161 *QuotientLow <<= Bits;
162 }
163
164 /* Return the remainder */
165 return ValueLow;
166 }
167
168 static inline VOID FASTCALL
169 Fast486FpuRound(PFAST486_STATE State,
170 PULONGLONG Result,
171 BOOLEAN Sign,
172 ULONGLONG Remainder,
173 INT RemainderHighBit)
174 {
175 switch (State->FpuControl.Rc)
176 {
177 case FPU_ROUND_NEAREST:
178 {
179 /* Check if the highest bit of the remainder is set */
180 if (Remainder & (1ULL << RemainderHighBit))
181 {
182 (*Result)++;
183
184 /* Check if all the other bits are clear */
185 if (!(Remainder & ((1ULL << RemainderHighBit) - 1)))
186 {
187 /* Round to even */
188 *Result &= ~1;
189 }
190 }
191
192 break;
193 }
194
195 case FPU_ROUND_DOWN:
196 {
197 if ((Remainder != 0ULL) && Sign) (*Result)++;
198 break;
199 }
200
201 case FPU_ROUND_UP:
202 {
203 if ((Remainder != 0ULL) && !Sign) (*Result)++;
204 break;
205 }
206
207 default:
208 {
209 /* Leave it truncated */
210 }
211 }
212 }
213
214 static inline VOID FASTCALL
215 Fast486FpuFromInteger(PFAST486_STATE State,
216 LONGLONG Value,
217 PFAST486_FPU_DATA_REG Result)
218 {
219 ULONG ZeroCount;
220
221 Result->Sign = Result->Exponent = Result->Mantissa = 0;
222 if (Value == 0LL) return;
223
224 if (Value < 0LL)
225 {
226 Result->Sign = 1;
227 Value = -Value;
228 }
229
230 Result->Mantissa = (ULONGLONG)Value;
231 ZeroCount = CountLeadingZeros64(Result->Mantissa);
232
233 Result->Mantissa <<= ZeroCount;
234 Result->Exponent = FPU_REAL10_BIAS + 63 - ZeroCount;
235 }
236
237 static inline BOOLEAN FASTCALL
238 Fast486FpuToInteger(PFAST486_STATE State,
239 PCFAST486_FPU_DATA_REG Value,
240 PLONGLONG Result)
241 {
242 ULONG Bits;
243 ULONGLONG Remainder;
244 SHORT UnbiasedExp = (SHORT)Value->Exponent - FPU_REAL10_BIAS;
245
246 if (FPU_IS_ZERO(Value))
247 {
248 *Result = 0LL;
249 return TRUE;
250 }
251
252 if (FPU_IS_NAN(Value) || !FPU_IS_NORMALIZED(Value)
253 || (UnbiasedExp < 0) || (UnbiasedExp > 63))
254 {
255 /* Raise an invalid operation exception */
256 State->FpuStatus.Ie = TRUE;
257
258 if (State->FpuControl.Im)
259 {
260 *Result = 0LL;
261 return TRUE;
262 }
263 else
264 {
265 Fast486FpuException(State);
266 return FALSE;
267 }
268 }
269
270 Bits = 63 - UnbiasedExp;
271
272 /* Calculate the result and the remainder */
273 *Result = (LONGLONG)(Value->Mantissa >> Bits);
274 Remainder = Value->Mantissa & ((1 << Bits) - 1);
275
276 /* The result must be positive here */
277 ASSERT(*Result >= 0LL);
278
279 /* Perform rounding */
280 Fast486FpuRound(State, (PULONGLONG)Result, Value->Sign, Remainder, Bits - 1);
281
282 if (Value->Sign) *Result = -*Result;
283 return TRUE;
284 }
285
286 static inline VOID FASTCALL
287 Fast486FpuFromSingleReal(PFAST486_STATE State,
288 ULONG Value,
289 PFAST486_FPU_DATA_REG Result)
290 {
291 /* Extract the sign, exponent and mantissa */
292 Result->Sign = (UCHAR)(Value >> 31);
293 Result->Exponent = (USHORT)((Value >> 23) & 0xFF);
294 Result->Mantissa = (((ULONGLONG)Value & 0x7FFFFFULL) | 0x800000ULL) << 40;
295
296 /* If this is a zero, we're done */
297 if (Value == 0) return;
298
299 if (Result->Exponent == 0xFF) Result->Exponent = FPU_MAX_EXPONENT + 1;
300 else
301 {
302 /* Adjust the exponent bias */
303 Result->Exponent += (FPU_REAL10_BIAS - FPU_REAL4_BIAS);
304 }
305 }
306
307 static inline BOOLEAN FASTCALL
308 Fast486FpuToSingleReal(PFAST486_STATE State,
309 PCFAST486_FPU_DATA_REG Value,
310 PULONG Result)
311 {
312 ULONGLONG Remainder;
313 SHORT UnbiasedExp = (SHORT)Value->Exponent - FPU_REAL10_BIAS;
314 ULONGLONG Result64;
315
316 if (FPU_IS_ZERO(Value))
317 {
318 *Result = 0;
319 return TRUE;
320 }
321
322 /* Calculate the mantissa */
323 *Result = (ULONG)(Value->Mantissa >> 40) & 0x7FFFFF;
324
325 if (FPU_IS_NAN(Value))
326 {
327 *Result |= FPU_REAL4_INFINITY;
328 goto SetSign;
329 }
330
331 /* Check for underflow */
332 if (!FPU_IS_NORMALIZED(Value) || (UnbiasedExp < -127))
333 {
334 /* Raise the underflow exception */
335 State->FpuStatus.Ue = TRUE;
336
337 if (State->FpuControl.Um)
338 {
339 /* The result is zero due to underflow */
340 *Result = 0ULL;
341 return TRUE;
342 }
343 else
344 {
345 Fast486FpuException(State);
346 return FALSE;
347 }
348 }
349
350 /* Check for overflow */
351 if (UnbiasedExp > 127)
352 {
353 /* Raise the overflow exception */
354 State->FpuStatus.Oe = TRUE;
355
356 if (State->FpuControl.Om)
357 {
358 /* The result is infinity due to overflow */
359 *Result = FPU_REAL4_INFINITY;
360 goto SetSign;
361 }
362 else
363 {
364 Fast486FpuException(State);
365 return FALSE;
366 }
367 }
368
369 /* Calculate the remainder */
370 Remainder = Value->Mantissa & ((1ULL << 40) - 1);
371
372 /* Perform rounding */
373 Result64 = (ULONGLONG)*Result;
374 Fast486FpuRound(State, &Result64, Value->Sign, Remainder, 39);
375 *Result = (ULONG)Result64;
376
377 /* Store the biased exponent */
378 *Result |= (ULONG)(UnbiasedExp + FPU_REAL4_BIAS) << 23;
379
380 SetSign:
381
382 if (Value->Sign) *Result |= 0x80000000;
383 return TRUE;
384 }
385
386 static inline VOID FASTCALL
387 Fast486FpuFromDoubleReal(PFAST486_STATE State,
388 ULONGLONG Value,
389 PFAST486_FPU_DATA_REG Result)
390 {
391 /* Extract the sign, exponent and mantissa */
392 Result->Sign = (UCHAR)(Value >> 63);
393 Result->Exponent = (USHORT)((Value >> 52) & 0x7FF);
394 Result->Mantissa = (((ULONGLONG)Value & 0xFFFFFFFFFFFFFULL) | 0x10000000000000ULL) << 11;
395
396 /* If this is a zero, we're done */
397 if (Value == 0) return;
398
399 if (Result->Exponent == 0x3FF) Result->Exponent = FPU_MAX_EXPONENT + 1;
400 else
401 {
402 /* Adjust the exponent bias */
403 Result->Exponent += (FPU_REAL10_BIAS - FPU_REAL8_BIAS);
404 }
405 }
406
407 static inline BOOLEAN FASTCALL
408 Fast486FpuToDoubleReal(PFAST486_STATE State,
409 PCFAST486_FPU_DATA_REG Value,
410 PULONGLONG Result)
411 {
412 ULONGLONG Remainder;
413 SHORT UnbiasedExp = (SHORT)Value->Exponent - FPU_REAL10_BIAS;
414
415 if (FPU_IS_ZERO(Value))
416 {
417 *Result = 0LL;
418 return TRUE;
419 }
420
421 /* Calculate the mantissa */
422 *Result = (Value->Mantissa >> 11) & ((1ULL << 52) - 1);
423
424 if (FPU_IS_NAN(Value))
425 {
426 *Result |= FPU_REAL8_INFINITY;
427 goto SetSign;
428 }
429
430 /* Check for underflow */
431 if (!FPU_IS_NORMALIZED(Value) || (UnbiasedExp < -1023))
432 {
433 /* Raise the underflow exception */
434 State->FpuStatus.Ue = TRUE;
435
436 if (State->FpuControl.Um)
437 {
438 /* The result is zero due to underflow */
439 *Result = 0ULL;
440 return TRUE;
441 }
442 else
443 {
444 Fast486FpuException(State);
445 return FALSE;
446 }
447 }
448
449 /* Check for overflow */
450 if (UnbiasedExp > 1023)
451 {
452 /* Raise the overflow exception */
453 State->FpuStatus.Oe = TRUE;
454
455 if (State->FpuControl.Om)
456 {
457 /* The result is infinity due to overflow */
458 *Result = FPU_REAL8_INFINITY;
459 goto SetSign;
460 }
461 else
462 {
463 Fast486FpuException(State);
464 return FALSE;
465 }
466 }
467
468 /* Calculate the remainder */
469 Remainder = Value->Mantissa & ((1 << 11) - 1);
470
471 /* Perform rounding */
472 Fast486FpuRound(State, Result, Value->Sign, Remainder, 10);
473
474 /* Store the biased exponent */
475 *Result |= (ULONGLONG)(UnbiasedExp + FPU_REAL8_BIAS) << 52;
476
477 SetSign:
478
479 if (Value->Sign) *Result |= 1ULL << 63;
480 return TRUE;
481 }
482
483 static inline VOID FASTCALL
484 Fast486FpuFromPackedBcd(PFAST486_STATE State,
485 PUCHAR Value,
486 PFAST486_FPU_DATA_REG Result)
487 {
488 INT i;
489 LONGLONG IntVal = 0LL;
490
491 for (i = 8; i >= 0; i--)
492 {
493 IntVal *= 100LL;
494 IntVal += (Value[i] >> 4) * 10 + (Value[i] & 0x0F);
495 }
496
497 /* Apply the sign */
498 if (Value[9] & 0x80) IntVal = -IntVal;
499
500 /* Now convert the integer to FP80 */
501 Fast486FpuFromInteger(State, IntVal, Result);
502 }
503
504 static inline BOOLEAN FASTCALL
505 Fast486FpuToPackedBcd(PFAST486_STATE State,
506 PCFAST486_FPU_DATA_REG Value,
507 PUCHAR Result)
508 {
509 INT i;
510 LONGLONG IntVal;
511
512 /* Convert it to an integer first */
513 if (!Fast486FpuToInteger(State, Value, &IntVal)) return FALSE;
514
515 if (IntVal < 0LL)
516 {
517 IntVal = -IntVal;
518 Result[9] = 0x80;
519 }
520
521 for (i = 0; i < 9; i++)
522 {
523 Result[i] = (UCHAR)((IntVal % 10) + (((IntVal / 10) % 10) << 4));
524 IntVal /= 100LL;
525 }
526
527 return TRUE;
528 }
529
530 static inline VOID FASTCALL
531 Fast486FpuAdd(PFAST486_STATE State,
532 PCFAST486_FPU_DATA_REG FirstOperand,
533 PCFAST486_FPU_DATA_REG SecondOperand,
534 PFAST486_FPU_DATA_REG Result)
535 {
536 FAST486_FPU_DATA_REG FirstAdjusted = *FirstOperand;
537 FAST486_FPU_DATA_REG SecondAdjusted = *SecondOperand;
538 FAST486_FPU_DATA_REG TempResult;
539
540 if ((!FPU_IS_NORMALIZED(FirstOperand) || !FPU_IS_NORMALIZED(SecondOperand)))
541 {
542 /* Raise the denormalized exception */
543 State->FpuStatus.De = TRUE;
544
545 if (!State->FpuControl.Dm)
546 {
547 Fast486FpuException(State);
548 return;
549 }
550 }
551
552 /* Find the largest exponent */
553 TempResult.Exponent = max(FirstOperand->Exponent, SecondOperand->Exponent);
554
555 /* Adjust the first operand to it... */
556 if (FirstAdjusted.Exponent < TempResult.Exponent)
557 {
558 FirstAdjusted.Mantissa >>= (TempResult.Exponent - FirstAdjusted.Exponent);
559 FirstAdjusted.Exponent = TempResult.Exponent;
560 }
561
562 /* ... and the second one too */
563 if (SecondAdjusted.Exponent < TempResult.Exponent)
564 {
565 SecondAdjusted.Mantissa >>= (TempResult.Exponent - SecondAdjusted.Exponent);
566 SecondAdjusted.Exponent = TempResult.Exponent;
567 }
568
569 if (FirstAdjusted.Sign == SecondAdjusted.Sign)
570 {
571 /* Calculate the mantissa and sign of the result */
572 TempResult.Mantissa = FirstAdjusted.Mantissa + SecondAdjusted.Mantissa;
573 TempResult.Sign = FirstAdjusted.Sign;
574 }
575 else
576 {
577 /* Calculate the sign of the result */
578 if (FirstAdjusted.Mantissa > SecondAdjusted.Mantissa) TempResult.Sign = FirstAdjusted.Sign;
579 else if (FirstAdjusted.Mantissa < SecondAdjusted.Mantissa) TempResult.Sign = SecondAdjusted.Sign;
580 else TempResult.Sign = FALSE;
581
582 /* Invert the negative mantissa */
583 if (FirstAdjusted.Sign) FirstAdjusted.Mantissa = -(LONGLONG)FirstAdjusted.Mantissa;
584 if (SecondAdjusted.Sign) SecondAdjusted.Mantissa = -(LONGLONG)SecondAdjusted.Mantissa;
585
586 /* Calculate the mantissa of the result */
587 TempResult.Mantissa = FirstAdjusted.Mantissa + SecondAdjusted.Mantissa;
588 }
589
590 /* Did it overflow? */
591 if (FPU_IS_NORMALIZED(&FirstAdjusted) && FPU_IS_NORMALIZED(&SecondAdjusted))
592 {
593 if (TempResult.Exponent == FPU_MAX_EXPONENT)
594 {
595 /* Raise the overflow exception */
596 State->FpuStatus.Oe = TRUE;
597
598 if (State->FpuControl.Om)
599 {
600 /* Total overflow, return infinity */
601 TempResult.Mantissa = FPU_MANTISSA_HIGH_BIT;
602 TempResult.Exponent = FPU_MAX_EXPONENT + 1;
603 }
604 else
605 {
606 Fast486FpuException(State);
607 return;
608 }
609 }
610 else
611 {
612 /* Lose the LSB in favor of the carry */
613 TempResult.Mantissa >>= 1;
614 TempResult.Mantissa |= FPU_MANTISSA_HIGH_BIT;
615 TempResult.Exponent++;
616 }
617 }
618
619 /* Normalize the result and return it */
620 Fast486FpuNormalize(State, &TempResult);
621 *Result = TempResult;
622 }
623
624 static inline VOID FASTCALL
625 Fast486FpuSubtract(PFAST486_STATE State,
626 PCFAST486_FPU_DATA_REG FirstOperand,
627 PCFAST486_FPU_DATA_REG SecondOperand,
628 PFAST486_FPU_DATA_REG Result)
629 {
630 FAST486_FPU_DATA_REG NegativeSecondOperand = *SecondOperand;
631
632 /* Invert the sign */
633 NegativeSecondOperand.Sign = !NegativeSecondOperand.Sign;
634
635 /* And perform an addition instead */
636 Fast486FpuAdd(State, FirstOperand, &NegativeSecondOperand, Result);
637 }
638
639 static inline VOID FASTCALL
640 Fast486FpuCompare(PFAST486_STATE State,
641 PCFAST486_FPU_DATA_REG FirstOperand,
642 PCFAST486_FPU_DATA_REG SecondOperand)
643 {
644 if (FPU_IS_NAN(FirstOperand) || FPU_IS_NAN(SecondOperand))
645 {
646 if (FPU_IS_POS_INF(FirstOperand) && FPU_IS_NEG_INF(SecondOperand))
647 {
648 State->FpuStatus.Code0 = FALSE;
649 State->FpuStatus.Code2 = FALSE;
650 State->FpuStatus.Code3 = FALSE;
651 }
652 else if (FPU_IS_NEG_INF(FirstOperand) && FPU_IS_POS_INF(SecondOperand))
653 {
654 State->FpuStatus.Code0 = TRUE;
655 State->FpuStatus.Code2 = FALSE;
656 State->FpuStatus.Code3 = FALSE;
657 }
658 else
659 {
660 State->FpuStatus.Code0 = TRUE;
661 State->FpuStatus.Code2 = TRUE;
662 State->FpuStatus.Code3 = TRUE;
663 }
664 }
665 else
666 {
667 FAST486_FPU_DATA_REG TempResult;
668
669 Fast486FpuSubtract(State, FirstOperand, SecondOperand, &TempResult);
670
671 if (FPU_IS_ZERO(&TempResult))
672 {
673 State->FpuStatus.Code0 = FALSE;
674 State->FpuStatus.Code2 = FALSE;
675 State->FpuStatus.Code3 = TRUE;
676 }
677 else if (TempResult.Sign)
678 {
679 State->FpuStatus.Code0 = TRUE;
680 State->FpuStatus.Code2 = FALSE;
681 State->FpuStatus.Code3 = FALSE;
682 }
683 else
684 {
685 State->FpuStatus.Code0 = FALSE;
686 State->FpuStatus.Code2 = FALSE;
687 State->FpuStatus.Code3 = FALSE;
688 }
689 }
690 }
691
692 static inline VOID FASTCALL
693 Fast486FpuMultiply(PFAST486_STATE State,
694 PCFAST486_FPU_DATA_REG FirstOperand,
695 PCFAST486_FPU_DATA_REG SecondOperand,
696 PFAST486_FPU_DATA_REG Result)
697 {
698 FAST486_FPU_DATA_REG TempResult;
699 LONG Exponent;
700
701 if (FPU_IS_INDEFINITE(FirstOperand)
702 || FPU_IS_INDEFINITE(SecondOperand)
703 || (FPU_IS_ZERO(FirstOperand) && FPU_IS_INFINITY(SecondOperand))
704 || (FPU_IS_INFINITY(FirstOperand) && FPU_IS_ZERO(SecondOperand)))
705 {
706 /* The result will be indefinite */
707 Result->Sign = TRUE;
708 Result->Exponent = FPU_MAX_EXPONENT + 1;
709 Result->Mantissa = FPU_INDEFINITE_MANTISSA;
710 return;
711 }
712
713 if (FPU_IS_ZERO(FirstOperand) || FPU_IS_ZERO(SecondOperand))
714 {
715 /* The result will be zero */
716 Result->Sign = FirstOperand->Sign ^ SecondOperand->Sign;
717 Result->Exponent = 0;
718 Result->Mantissa = 0ULL;
719 return;
720 }
721
722 if (FPU_IS_INFINITY(FirstOperand) || FPU_IS_INFINITY(SecondOperand))
723 {
724 /* The result will be infinity */
725 Result->Sign = FirstOperand->Sign ^ SecondOperand->Sign;
726 Result->Exponent = FPU_MAX_EXPONENT + 1;
727 Result->Mantissa = FPU_MANTISSA_HIGH_BIT;
728 return;
729 }
730
731 if ((!FPU_IS_NORMALIZED(FirstOperand) || !FPU_IS_NORMALIZED(SecondOperand)))
732 {
733 /* Raise the denormalized exception */
734 State->FpuStatus.De = TRUE;
735
736 if (!State->FpuControl.Dm)
737 {
738 Fast486FpuException(State);
739 return;
740 }
741 }
742
743 /* Calculate the sign */
744 TempResult.Sign = FirstOperand->Sign ^ SecondOperand->Sign;
745
746 /* Calculate the exponent */
747 Exponent = (LONG)FirstOperand->Exponent + (LONG)SecondOperand->Exponent - FPU_REAL10_BIAS;
748
749 /* Calculate the mantissa */
750 UnsignedMult128(FirstOperand->Mantissa,
751 SecondOperand->Mantissa,
752 &TempResult.Mantissa);
753
754 if (Exponent < 0)
755 {
756 /* Raise the underflow exception */
757 State->FpuStatus.Ue = TRUE;
758
759 if (!State->FpuControl.Um)
760 {
761 Fast486FpuException(State);
762 return;
763 }
764
765 /* The exponent will be zero */
766 TempResult.Exponent = 0;
767
768 /* If possible, denormalize the result, otherwise make it zero */
769 if (Exponent > -64) TempResult.Mantissa >>= (-Exponent);
770 else TempResult.Mantissa = 0ULL;
771 }
772 else if (Exponent > FPU_MAX_EXPONENT)
773 {
774 /* Raise the overflow exception */
775 State->FpuStatus.Oe = TRUE;
776
777 if (!State->FpuControl.Om)
778 {
779 Fast486FpuException(State);
780 return;
781 }
782
783 /* Make the result infinity */
784 TempResult.Exponent = FPU_MAX_EXPONENT + 1;
785 TempResult.Mantissa = FPU_MANTISSA_HIGH_BIT;
786 }
787 else TempResult.Exponent = (USHORT)Exponent;
788
789 /* Normalize the result */
790 Fast486FpuNormalize(State, &TempResult);
791 *Result = TempResult;
792 }
793
794 static inline VOID FASTCALL
795 Fast486FpuDivide(PFAST486_STATE State,
796 PCFAST486_FPU_DATA_REG FirstOperand,
797 PCFAST486_FPU_DATA_REG SecondOperand,
798 PFAST486_FPU_DATA_REG Result)
799 {
800 FAST486_FPU_DATA_REG TempResult;
801 ULONGLONG QuotientLow, QuotientHigh, Remainder;
802 LONG Exponent;
803
804 if (FPU_IS_INDEFINITE(FirstOperand)
805 || FPU_IS_INDEFINITE(SecondOperand)
806 || (FPU_IS_INFINITY(FirstOperand) && FPU_IS_INFINITY(SecondOperand))
807 || (FPU_IS_ZERO(FirstOperand) && FPU_IS_ZERO(SecondOperand)))
808 {
809 /* Raise the invalid operation exception */
810 State->FpuStatus.Ie = TRUE;
811
812 if (State->FpuControl.Im)
813 {
814 /* Return the indefinite NaN */
815 Result->Sign = TRUE;
816 Result->Exponent = FPU_MAX_EXPONENT + 1;
817 Result->Mantissa = FPU_INDEFINITE_MANTISSA;
818 }
819 else Fast486FpuException(State);
820
821 return;
822 }
823
824 if (FPU_IS_ZERO(SecondOperand) || FPU_IS_INFINITY(FirstOperand))
825 {
826 /* Raise the division by zero exception */
827 State->FpuStatus.Ze = TRUE;
828
829 if (State->FpuControl.Zm)
830 {
831 /* Return infinity */
832 Result->Sign = FirstOperand->Sign;
833 Result->Exponent = FPU_MAX_EXPONENT + 1;
834 Result->Mantissa = FPU_MANTISSA_HIGH_BIT;
835 }
836 else Fast486FpuException(State);
837
838 return;
839 }
840
841 /* Calculate the sign of the result */
842 TempResult.Sign = FirstOperand->Sign ^ SecondOperand->Sign;
843
844 if (FPU_IS_ZERO(FirstOperand) || FPU_IS_INFINITY(SecondOperand))
845 {
846 /* Return zero */
847 Result->Sign = TempResult.Sign;
848 Result->Mantissa = 0ULL;
849 Result->Exponent = 0;
850 return;
851 }
852
853 /* Calculate the exponent of the result */
854 Exponent = (LONG)FirstOperand->Exponent - (LONG)SecondOperand->Exponent - 64;
855
856 /* Divide the two mantissas */
857 Remainder = UnsignedDivMod128(0ULL,
858 /* Notice the 64 above - this is the high part */
859 FirstOperand->Mantissa,
860 SecondOperand->Mantissa,
861 &QuotientLow,
862 &QuotientHigh);
863 UNREFERENCED_PARAMETER(Remainder); // TODO: Rounding
864
865 TempResult.Mantissa = QuotientLow;
866
867 if (QuotientHigh > 0ULL)
868 {
869 ULONG BitsToShift = 64 - CountLeadingZeros64(QuotientHigh);
870
871 TempResult.Mantissa >>= BitsToShift;
872 TempResult.Mantissa |= QuotientHigh << (64 - BitsToShift);
873 Exponent += BitsToShift;
874
875 // TODO: Rounding
876 }
877
878 if (Exponent < -FPU_REAL10_BIAS)
879 {
880 TempResult.Mantissa >>= -(Exponent + FPU_REAL10_BIAS);
881 Exponent = -FPU_REAL10_BIAS;
882
883 // TODO: Rounding
884 }
885
886 TempResult.Exponent = (USHORT)(Exponent + FPU_REAL10_BIAS);
887
888 /* Normalize the result */
889 Fast486FpuNormalize(State, &TempResult);
890 *Result = TempResult;
891 }
892
893 static inline VOID FASTCALL
894 Fast486FpuArithmeticOperation(PFAST486_STATE State,
895 INT Operation,
896 PFAST486_FPU_DATA_REG SourceOperand,
897 PFAST486_FPU_DATA_REG DestOperand)
898 {
899 ASSERT(!(Operation & ~7));
900
901 /* Check the operation */
902 switch (Operation)
903 {
904 /* FADD */
905 case 0:
906 {
907 Fast486FpuAdd(State, DestOperand, SourceOperand, DestOperand);
908 break;
909 }
910
911 /* FMUL */
912 case 1:
913 {
914 Fast486FpuMultiply(State, DestOperand, SourceOperand, DestOperand);
915 break;
916 }
917
918 /* FCOM */
919 case 2:
920 /* FCOMP */
921 case 3:
922 {
923 Fast486FpuCompare(State, DestOperand, SourceOperand);
924 if (Operation == 3) Fast486FpuPop(State);
925
926 break;
927 }
928
929 /* FSUB */
930 case 4:
931 {
932 Fast486FpuSubtract(State, DestOperand, SourceOperand, DestOperand);
933 break;
934 }
935
936 /* FSUBR */
937 case 5:
938 {
939 Fast486FpuSubtract(State, SourceOperand, DestOperand, DestOperand);
940 break;
941 }
942
943 /* FDIV */
944 case 6:
945 {
946 Fast486FpuDivide(State, DestOperand, SourceOperand, DestOperand);
947 break;
948 }
949
950 /* FDIVR */
951 case 7:
952 {
953 Fast486FpuDivide(State, SourceOperand, DestOperand, DestOperand);
954 break;
955 }
956 }
957 }
958
959 static inline BOOLEAN FASTCALL
960 Fast486FpuLoadEnvironment(PFAST486_STATE State,
961 INT Segment,
962 ULONG Address,
963 BOOLEAN Size)
964 {
965 UCHAR Buffer[28];
966
967 if (!Fast486ReadMemory(State, Segment, Address, FALSE, Buffer, (Size + 1) * 14))
968 {
969 /* Exception occurred */
970 return FALSE;
971 }
972
973 /* Check if this is a 32-bit save or a 16-bit save */
974 if (Size)
975 {
976 PULONG Data = (PULONG)Buffer;
977
978 State->FpuControl.Value = (USHORT)Data[0];
979 State->FpuStatus.Value = (USHORT)Data[1];
980 State->FpuTag = (USHORT)Data[2];
981 State->FpuLastInstPtr.Long = Data[3];
982 State->FpuLastCodeSel = (USHORT)Data[4];
983 State->FpuLastOpPtr.Long = Data[5];
984 State->FpuLastDataSel = (USHORT)Data[6];
985 }
986 else
987 {
988 PUSHORT Data = (PUSHORT)Buffer;
989
990 State->FpuControl.Value = Data[0];
991 State->FpuStatus.Value = Data[1];
992 State->FpuTag = Data[2];
993 State->FpuLastInstPtr.LowWord = Data[3];
994 State->FpuLastCodeSel = Data[4];
995 State->FpuLastOpPtr.LowWord = Data[5];
996 State->FpuLastDataSel = Data[6];
997 }
998
999 return TRUE;
1000 }
1001
1002 static inline BOOLEAN FASTCALL
1003 Fast486FpuSaveEnvironment(PFAST486_STATE State,
1004 INT Segment,
1005 ULONG Address,
1006 BOOLEAN Size)
1007 {
1008 UCHAR Buffer[28];
1009
1010 /* Check if this is a 32-bit save or a 16-bit save */
1011 if (Size)
1012 {
1013 PULONG Data = (PULONG)Buffer;
1014
1015 Data[0] = (ULONG)State->FpuControl.Value;
1016 Data[1] = (ULONG)State->FpuStatus.Value;
1017 Data[2] = (ULONG)State->FpuTag;
1018 Data[3] = State->FpuLastInstPtr.Long;
1019 Data[4] = (ULONG)State->FpuLastCodeSel;
1020 Data[5] = State->FpuLastOpPtr.Long;
1021 Data[6] = (ULONG)State->FpuLastDataSel;
1022 }
1023 else
1024 {
1025 PUSHORT Data = (PUSHORT)Buffer;
1026
1027 Data[0] = State->FpuControl.Value;
1028 Data[1] = State->FpuStatus.Value;
1029 Data[2] = State->FpuTag;
1030 Data[3] = State->FpuLastInstPtr.LowWord;
1031 Data[4] = State->FpuLastCodeSel;
1032 Data[5] = State->FpuLastOpPtr.LowWord;
1033 Data[6] = State->FpuLastDataSel;
1034 }
1035
1036 return Fast486WriteMemory(State, Segment, Address, Buffer, (Size + 1) * 14);
1037 }
1038
1039 #endif
1040
1041 /* PUBLIC FUNCTIONS ***********************************************************/
1042
1043 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD8)
1044 {
1045 FAST486_MOD_REG_RM ModRegRm;
1046 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1047 PFAST486_FPU_DATA_REG SourceOperand, DestOperand;
1048 FAST486_FPU_DATA_REG MemoryData;
1049
1050 TOGGLE_ADSIZE(AddressSize);
1051
1052 /* Get the operands */
1053 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1054 {
1055 /* Exception occurred */
1056 return;
1057 }
1058
1059 FPU_CHECK();
1060
1061 #ifndef FAST486_NO_FPU
1062
1063 FPU_SAVE_LAST_INST();
1064
1065 /* The destination operand is ST0 */
1066 DestOperand = &FPU_ST(0);
1067
1068 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
1069 {
1070 /* Raise the invalid operation exception */
1071 State->FpuStatus.Ie = TRUE;
1072
1073 if (State->FpuControl.Im)
1074 {
1075 /* Return the indefinite NaN */
1076 DestOperand->Sign = TRUE;
1077 DestOperand->Exponent = FPU_MAX_EXPONENT + 1;
1078 DestOperand->Mantissa = FPU_INDEFINITE_MANTISSA;
1079
1080 FPU_SET_TAG(0, FPU_TAG_SPECIAL);
1081 }
1082 else Fast486FpuException(State);
1083
1084 return;
1085 }
1086
1087 if (ModRegRm.Memory)
1088 {
1089 /* Load the source operand from memory */
1090 ULONG Value;
1091
1092 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1093 {
1094 /* Exception occurred */
1095 return;
1096 }
1097
1098 Fast486FpuFromSingleReal(State, Value, &MemoryData);
1099 SourceOperand = &MemoryData;
1100
1101 FPU_SAVE_LAST_OPERAND();
1102 }
1103 else
1104 {
1105 if (FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY)
1106 {
1107 /* Raise the invalid operation exception */
1108 State->FpuStatus.Ie = TRUE;
1109
1110 if (State->FpuControl.Im)
1111 {
1112 /* Return the indefinite NaN */
1113 DestOperand->Sign = TRUE;
1114 DestOperand->Exponent = FPU_MAX_EXPONENT + 1;
1115 DestOperand->Mantissa = FPU_INDEFINITE_MANTISSA;
1116
1117 FPU_SET_TAG(0, FPU_TAG_SPECIAL);
1118 }
1119 else Fast486FpuException(State);
1120
1121 return;
1122 }
1123
1124 /* Load the source operand from an FPU register */
1125 SourceOperand = &FPU_ST(ModRegRm.SecondRegister);
1126 }
1127
1128 /* Perform the requested operation */
1129 Fast486FpuArithmeticOperation(State, ModRegRm.Register, SourceOperand, DestOperand);
1130
1131 #endif
1132 }
1133
1134 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD9)
1135 {
1136 FAST486_MOD_REG_RM ModRegRm;
1137 BOOLEAN OperandSize, AddressSize;
1138
1139 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1140 TOGGLE_OPSIZE(OperandSize);
1141 TOGGLE_ADSIZE(AddressSize);
1142
1143 /* Get the operands */
1144 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1145 {
1146 /* Exception occurred */
1147 return;
1148 }
1149
1150 FPU_CHECK();
1151
1152 #ifndef FAST486_NO_FPU
1153
1154 if (ModRegRm.Memory)
1155 {
1156 switch (ModRegRm.Register)
1157 {
1158 /* FLD */
1159 case 0:
1160 {
1161 ULONG Value;
1162 FAST486_FPU_DATA_REG MemoryData;
1163
1164 FPU_SAVE_LAST_INST();
1165 FPU_SAVE_LAST_OPERAND();
1166
1167 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1168 {
1169 /* Exception occurred */
1170 return;
1171 }
1172
1173 Fast486FpuFromSingleReal(State, Value, &MemoryData);
1174 Fast486FpuPush(State, &MemoryData);
1175
1176 break;
1177 }
1178
1179 /* FST */
1180 case 2:
1181 /* FSTP */
1182 case 3:
1183 {
1184 ULONG Value = FPU_REAL4_INDEFINITE;
1185
1186 FPU_SAVE_LAST_INST();
1187 FPU_SAVE_LAST_OPERAND();
1188
1189 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
1190 {
1191 /* Raise the invalid operation exception */
1192 State->FpuStatus.Ie = TRUE;
1193
1194 if (!State->FpuControl.Im)
1195 {
1196 Fast486FpuException(State);
1197 return;
1198 }
1199 }
1200 else if (!Fast486FpuToSingleReal(State, &FPU_ST(0), &Value))
1201 {
1202 /* Exception occurred */
1203 return;
1204 }
1205
1206 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
1207 {
1208 /* Exception occurred */
1209 return;
1210 }
1211
1212 if (ModRegRm.Register == 3) Fast486FpuPop(State);
1213 break;
1214 }
1215
1216 /* FLDENV */
1217 case 4:
1218 {
1219 Fast486FpuLoadEnvironment(State,
1220 (State->PrefixFlags & FAST486_PREFIX_SEG)
1221 ? FAST486_REG_DS : State->SegmentOverride,
1222 ModRegRm.MemoryAddress,
1223 OperandSize);
1224 break;
1225 }
1226
1227 /* FLDCW */
1228 case 5:
1229 {
1230 Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &State->FpuControl.Value);
1231 break;
1232 }
1233
1234 /* FSTENV */
1235 case 6:
1236 {
1237 Fast486FpuSaveEnvironment(State,
1238 (State->PrefixFlags & FAST486_PREFIX_SEG)
1239 ? FAST486_REG_DS : State->SegmentOverride,
1240 ModRegRm.MemoryAddress,
1241 OperandSize);
1242 break;
1243 }
1244
1245 /* FSTCW */
1246 case 7:
1247 {
1248 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, State->FpuControl.Value);
1249 break;
1250 }
1251
1252 /* Invalid */
1253 default:
1254 {
1255 Fast486Exception(State, FAST486_EXCEPTION_UD);
1256 return;
1257 }
1258 }
1259 }
1260 else
1261 {
1262 switch ((ModRegRm.Register << 3) | ModRegRm.SecondRegister)
1263 {
1264 /* FLD */
1265 case 0x00:
1266 case 0x01:
1267 case 0x02:
1268 case 0x03:
1269 case 0x04:
1270 case 0x05:
1271 case 0x06:
1272 case 0x07:
1273 {
1274 if (FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY)
1275 {
1276 /* Raise the invalid operation exception */
1277 State->FpuStatus.Ie = TRUE;
1278
1279 if (!State->FpuControl.Im)
1280 {
1281 Fast486FpuException(State);
1282 return;
1283 }
1284 }
1285
1286 Fast486FpuPush(State, &FPU_ST(ModRegRm.SecondRegister));
1287 break;
1288 }
1289
1290 /* FXCH */
1291 case 0x08:
1292 case 0x09:
1293 case 0x0A:
1294 case 0x0B:
1295 case 0x0C:
1296 case 0x0D:
1297 case 0x0E:
1298 case 0x0F:
1299 {
1300 FAST486_FPU_DATA_REG Temp;
1301
1302 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
1303 || FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY)
1304 {
1305 State->FpuStatus.Ie = TRUE;
1306
1307 if (!State->FpuControl.Im) Fast486FpuException(State);
1308 break;
1309 }
1310
1311 /* Exchange */
1312 Temp = FPU_ST(0);
1313 FPU_ST(0) = FPU_ST(ModRegRm.SecondRegister);
1314 FPU_ST(ModRegRm.SecondRegister) = Temp;
1315
1316 FPU_UPDATE_TAG(0);
1317 FPU_UPDATE_TAG(ModRegRm.SecondRegister);
1318
1319 break;
1320 }
1321
1322 /* FNOP */
1323 case 0x10:
1324 {
1325 /* Do nothing */
1326 break;
1327 }
1328
1329 /* FSTP */
1330 case 0x18:
1331 case 0x19:
1332 case 0x1A:
1333 case 0x1B:
1334 case 0x1C:
1335 case 0x1D:
1336 case 0x1E:
1337 case 0x1F:
1338 {
1339 FPU_ST(ModRegRm.SecondRegister) = FPU_ST(0);
1340 FPU_UPDATE_TAG(ModRegRm.SecondRegister);
1341
1342 Fast486FpuPop(State);
1343 break;
1344 }
1345
1346 /* FCHS */
1347 case 0x20:
1348 {
1349 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
1350 {
1351 State->FpuStatus.Ie = TRUE;
1352
1353 if (!State->FpuControl.Im) Fast486FpuException(State);
1354 break;
1355 }
1356
1357 /* Invert the sign */
1358 FPU_ST(0).Sign = !FPU_ST(0).Sign;
1359
1360 break;
1361 }
1362
1363 /* FABS */
1364 case 0x21:
1365 {
1366 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
1367 {
1368 State->FpuStatus.Ie = TRUE;
1369
1370 if (!State->FpuControl.Im) Fast486FpuException(State);
1371 break;
1372 }
1373
1374 /* Set the sign to positive */
1375 FPU_ST(0).Sign = FALSE;
1376
1377 break;
1378 }
1379
1380 /* FTST */
1381 case 0x24:
1382 {
1383 Fast486FpuCompare(State, &FPU_ST(0), &FpuZero);
1384 break;
1385 }
1386
1387 /* FXAM */
1388 case 0x25:
1389 {
1390 /* The sign bit goes in C1, even if the register's empty */
1391 State->FpuStatus.Code1 = FPU_ST(0).Sign;
1392
1393 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
1394 {
1395 State->FpuStatus.Code0 = 1;
1396 State->FpuStatus.Code2 = 0;
1397 State->FpuStatus.Code3 = 1;
1398 }
1399 else if (FPU_GET_TAG(0) == FPU_TAG_SPECIAL)
1400 {
1401 if (FPU_IS_INFINITY(&FPU_ST(0)))
1402 {
1403 State->FpuStatus.Code0 = 1;
1404 State->FpuStatus.Code2 = 1;
1405 State->FpuStatus.Code3 = 0;
1406 }
1407 else
1408 {
1409 State->FpuStatus.Code0 = 1;
1410 State->FpuStatus.Code2 = 0;
1411 State->FpuStatus.Code3 = 0;
1412 }
1413 }
1414 else if (FPU_GET_TAG(0) == FPU_TAG_ZERO)
1415 {
1416 State->FpuStatus.Code0 = 0;
1417 State->FpuStatus.Code2 = 0;
1418 State->FpuStatus.Code3 = 1;
1419 }
1420 else
1421 {
1422 if (FPU_IS_NORMALIZED(&FPU_ST(0)))
1423 {
1424 State->FpuStatus.Code0 = 0;
1425 State->FpuStatus.Code2 = 1;
1426 State->FpuStatus.Code3 = 0;
1427 }
1428 else
1429 {
1430 State->FpuStatus.Code0 = 0;
1431 State->FpuStatus.Code2 = 1;
1432 State->FpuStatus.Code3 = 1;
1433 }
1434 }
1435
1436 break;
1437 }
1438
1439 /* FLD1 */
1440 case 0x28:
1441 /* FLDL2T */
1442 case 0x29:
1443 /* FLDL2E */
1444 case 0x2A:
1445 /* FLDPI */
1446 case 0x2B:
1447 /* FLDLG2 */
1448 case 0x2C:
1449 /* FLDLN2 */
1450 case 0x2D:
1451 /* FLDZ */
1452 case 0x2E:
1453 {
1454 PCFAST486_FPU_DATA_REG Constants[] =
1455 {
1456 &FpuOne,
1457 &FpuL2Ten,
1458 &FpuL2E,
1459 &FpuPi,
1460 &FpuLgTwo,
1461 &FpuLnTwo,
1462 &FpuZero
1463 };
1464
1465 Fast486FpuPush(State, Constants[ModRegRm.SecondRegister]);
1466 break;
1467 }
1468
1469 /* F2XM1 */
1470 case 0x30:
1471 {
1472 // TODO: NOT IMPLEMENTED
1473 UNIMPLEMENTED;
1474
1475 break;
1476 }
1477
1478 /* FYL2X */
1479 case 0x31:
1480 {
1481 // TODO: NOT IMPLEMENTED
1482 UNIMPLEMENTED;
1483
1484 break;
1485 }
1486
1487 /* FPTAN */
1488 case 0x32:
1489 {
1490 // TODO: NOT IMPLEMENTED
1491 UNIMPLEMENTED;
1492
1493 break;
1494 }
1495
1496 /* FPATAN */
1497 case 0x33:
1498 {
1499 // TODO: NOT IMPLEMENTED
1500 UNIMPLEMENTED;
1501
1502 break;
1503 }
1504
1505 /* FXTRACT */
1506 case 0x34:
1507 {
1508 FAST486_FPU_DATA_REG Value = FPU_ST(0);
1509
1510 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY) || FPU_IS_INDEFINITE(&Value))
1511 {
1512 State->FpuStatus.Ie = TRUE;
1513 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY) State->FpuStatus.Sf = TRUE;
1514
1515 if (!State->FpuControl.Im) Fast486FpuException(State);
1516 break;
1517 }
1518
1519 if (FPU_IS_ZERO(&Value))
1520 {
1521 /* The exponent of zero is negative infinity */
1522 FPU_ST(0).Sign = TRUE;
1523 FPU_ST(0).Exponent = FPU_MAX_EXPONENT + 1;
1524 FPU_ST(0).Mantissa = FPU_MANTISSA_HIGH_BIT;
1525 }
1526 else if (FPU_IS_INFINITY(&Value))
1527 {
1528 /* The exponent of infinity is positive infinity */
1529 FPU_ST(0).Sign = FALSE;
1530 FPU_ST(0).Exponent = FPU_MAX_EXPONENT + 1;
1531 FPU_ST(0).Mantissa = FPU_MANTISSA_HIGH_BIT;
1532 }
1533 else
1534 {
1535 /* Store the unbiased exponent in ST0 */
1536 Fast486FpuFromInteger(State,
1537 (LONGLONG)Value.Exponent - (LONGLONG)FPU_REAL10_BIAS,
1538 &FPU_ST(0));
1539 }
1540
1541 /* Now push the mantissa as a real number, with the original sign */
1542 Value.Exponent = FPU_REAL10_BIAS;
1543 Fast486FpuPush(State, &Value);
1544
1545 break;
1546 }
1547
1548 /* FPREM1 */
1549 case 0x35:
1550 {
1551 // TODO: NOT IMPLEMENTED
1552 UNIMPLEMENTED;
1553
1554 break;
1555 }
1556
1557 /* FDECSTP */
1558 case 0x36:
1559 {
1560 State->FpuStatus.Top--;
1561 break;
1562 }
1563
1564 /* FINCSTP */
1565 case 0x37:
1566 {
1567 State->FpuStatus.Top++;
1568 break;
1569 }
1570
1571 /* FPREM */
1572 case 0x38:
1573 {
1574 // TODO: NOT IMPLEMENTED
1575 UNIMPLEMENTED;
1576
1577 break;
1578 }
1579
1580 /* FYL2XP1 */
1581 case 0x39:
1582 {
1583 // TODO: NOT IMPLEMENTED
1584 UNIMPLEMENTED;
1585
1586 break;
1587 }
1588
1589 /* FSQRT */
1590 case 0x3A:
1591 {
1592 // TODO: NOT IMPLEMENTED
1593 UNIMPLEMENTED;
1594
1595 break;
1596 }
1597
1598 /* FSINCOS */
1599 case 0x3B:
1600 {
1601 // TODO: NOT IMPLEMENTED
1602 UNIMPLEMENTED;
1603
1604 break;
1605 }
1606
1607 /* FRNDINT */
1608 case 0x3C:
1609 {
1610 INT Bits;
1611 ULONGLONG Result = 0ULL;
1612 ULONGLONG Remainder;
1613
1614 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
1615 {
1616 State->FpuStatus.Ie = TRUE;
1617
1618 if (!State->FpuControl.Im) Fast486FpuException(State);
1619 break;
1620 }
1621
1622 if (!FPU_IS_NORMALIZED(&FPU_ST(0)))
1623 {
1624 State->FpuStatus.De = TRUE;
1625
1626 if (!State->FpuControl.Dm)
1627 {
1628 Fast486FpuException(State);
1629 break;
1630 }
1631 }
1632
1633 Bits = min(max(0, (INT)FPU_ST(0).Exponent - FPU_REAL10_BIAS + 1), 64);
1634 if (Bits == 64) break;
1635
1636 if (Bits)
1637 {
1638 Result = FPU_ST(0).Mantissa >> (64 - Bits);
1639 Remainder = FPU_ST(0).Mantissa & ((1 << (64 - Bits)) - 1);
1640 }
1641 else Remainder = FPU_ST(0).Mantissa;
1642
1643 /* Perform the rounding */
1644 Fast486FpuRound(State, &Result, FPU_ST(0).Sign, Remainder, 63 - Bits);
1645
1646 State->FpuStatus.Pe = TRUE;
1647 if (!State->FpuControl.Pm) Fast486FpuException(State);
1648
1649 break;
1650 }
1651
1652 /* FSCALE */
1653 case 0x3D:
1654 {
1655 // TODO: NOT IMPLEMENTED
1656 UNIMPLEMENTED;
1657
1658 break;
1659 }
1660
1661 /* FSIN */
1662 case 0x3E:
1663 {
1664 // TODO: NOT IMPLEMENTED
1665 UNIMPLEMENTED;
1666
1667 break;
1668 }
1669
1670 /* FCOS */
1671 case 0x3F:
1672 {
1673 // TODO: NOT IMPLEMENTED
1674 UNIMPLEMENTED;
1675
1676 break;
1677 }
1678
1679 /* Invalid */
1680 default:
1681 {
1682 Fast486Exception(State, FAST486_EXCEPTION_UD);
1683 return;
1684 }
1685 }
1686 }
1687
1688 #endif
1689 }
1690
1691 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDA)
1692 {
1693 FAST486_MOD_REG_RM ModRegRm;
1694 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1695 PFAST486_FPU_DATA_REG SourceOperand, DestOperand;
1696 LONG Value;
1697 FAST486_FPU_DATA_REG MemoryData;
1698
1699 TOGGLE_ADSIZE(AddressSize);
1700
1701 /* Get the operands */
1702 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1703 {
1704 /* Exception occurred */
1705 return;
1706 }
1707
1708 FPU_CHECK();
1709
1710 #ifndef FAST486_NO_FPU
1711
1712 FPU_SAVE_LAST_INST();
1713
1714 if (!ModRegRm.Memory)
1715 {
1716 /* The only valid opcode in this case is FUCOMPP (0xDA 0xE9) */
1717 if ((ModRegRm.Register != 5) && (ModRegRm.SecondRegister != 1))
1718 {
1719 Fast486Exception(State, FAST486_EXCEPTION_UD);
1720 return;
1721 }
1722
1723 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY) || (FPU_GET_TAG(1) == FPU_TAG_EMPTY))
1724 {
1725 /* Raise the invalid operation exception*/
1726 State->FpuStatus.Ie = TRUE;
1727
1728 if (!State->FpuControl.Im) Fast486FpuException(State);
1729 return;
1730 }
1731
1732 /* Compare */
1733 Fast486FpuCompare(State, &FPU_ST(0), &FPU_ST(1));
1734
1735 /* Pop twice */
1736 Fast486FpuPop(State);
1737 Fast486FpuPop(State);
1738
1739 return;
1740 }
1741
1742 FPU_SAVE_LAST_OPERAND();
1743
1744 /* Load the source operand from memory */
1745 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, (PULONG)&Value))
1746 {
1747 /* Exception occurred */
1748 return;
1749 }
1750
1751 /* The destination operand is always ST0 */
1752 DestOperand = &FPU_ST(0);
1753
1754 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
1755 {
1756 /* Raise the invalid operation exception */
1757 State->FpuStatus.Ie = TRUE;
1758
1759 if (State->FpuControl.Im)
1760 {
1761 /* Return the indefinite NaN */
1762 DestOperand->Sign = TRUE;
1763 DestOperand->Exponent = FPU_MAX_EXPONENT + 1;
1764 DestOperand->Mantissa = FPU_INDEFINITE_MANTISSA;
1765
1766 FPU_SET_TAG(0, FPU_TAG_SPECIAL);
1767 }
1768 else Fast486FpuException(State);
1769
1770 return;
1771 }
1772
1773 Fast486FpuFromInteger(State, (LONGLONG)Value, &MemoryData);
1774 SourceOperand = &MemoryData;
1775
1776 /* Perform the requested operation */
1777 Fast486FpuArithmeticOperation(State, ModRegRm.Register, SourceOperand, DestOperand);
1778
1779 #endif
1780 }
1781
1782 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDB)
1783 {
1784 FAST486_MOD_REG_RM ModRegRm;
1785 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1786
1787 TOGGLE_ADSIZE(AddressSize);
1788
1789 /* Get the operands */
1790 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1791 {
1792 /* Exception occurred */
1793 return;
1794 }
1795
1796 FPU_CHECK();
1797
1798 #ifndef FAST486_NO_FPU
1799
1800 if (ModRegRm.Memory)
1801 {
1802 FPU_SAVE_LAST_INST();
1803 FPU_SAVE_LAST_OPERAND();
1804
1805 switch (ModRegRm.Register)
1806 {
1807 /* FILD */
1808 case 0:
1809 {
1810 LONG Value;
1811 FAST486_FPU_DATA_REG Temp;
1812
1813 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, (PULONG)&Value))
1814 {
1815 /* Exception occurred */
1816 return;
1817 }
1818
1819 Fast486FpuFromInteger(State, (LONGLONG)Value, &Temp);
1820 Fast486FpuPush(State, &Temp);
1821
1822 break;
1823 }
1824
1825 /* FIST */
1826 case 2:
1827 /* FISTP */
1828 case 3:
1829 {
1830 LONGLONG Temp = 0;
1831
1832 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY) || (FPU_GET_TAG(0) == FPU_TAG_SPECIAL))
1833 {
1834 /* Raise the invalid operation exception */
1835 State->FpuStatus.Ie = TRUE;
1836
1837 if (!State->FpuControl.Im)
1838 {
1839 Fast486FpuException(State);
1840 return;
1841 }
1842 }
1843 else if (!Fast486FpuToInteger(State, &FPU_ST(0), &Temp))
1844 {
1845 /* Exception occurred */
1846 return;
1847 }
1848
1849 /* Check if it can fit in a signed 32-bit integer */
1850 if ((((ULONGLONG)Temp >> 31) + 1ULL) > 1ULL)
1851 {
1852 State->FpuStatus.Ie = TRUE;
1853
1854 if (State->FpuControl.Im) Temp = 0LL;
1855 else
1856 {
1857 Fast486FpuException(State);
1858 return;
1859 }
1860 }
1861
1862 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, (ULONG)((LONG)Temp)))
1863 {
1864 /* Exception occurred */
1865 return;
1866 }
1867
1868 if (ModRegRm.Register == 3)
1869 {
1870 /* Pop the FPU stack too */
1871 Fast486FpuPop(State);
1872 }
1873
1874 break;
1875 }
1876
1877 /* FLD */
1878 case 5:
1879 {
1880 FAST486_FPU_DATA_REG Value;
1881 UCHAR Buffer[10];
1882
1883 if (!Fast486ReadMemory(State,
1884 (State->PrefixFlags & FAST486_PREFIX_SEG)
1885 ? State->SegmentOverride : FAST486_REG_DS,
1886 ModRegRm.MemoryAddress,
1887 FALSE,
1888 Buffer,
1889 sizeof(Buffer)))
1890 {
1891 /* Exception occurred */
1892 return;
1893 }
1894
1895 Value.Mantissa = *((PULONGLONG)Buffer);
1896 Value.Exponent = *((PUSHORT)&Buffer[8]) & (FPU_MAX_EXPONENT + 1);
1897 Value.Sign = *((PUCHAR)&Buffer[9]) >> 7;
1898
1899 Fast486FpuPush(State, &Value);
1900 break;
1901 }
1902
1903 /* FSTP */
1904 case 7:
1905 {
1906 UCHAR Buffer[10];
1907
1908 if (FPU_GET_TAG(0) != FPU_TAG_EMPTY)
1909 {
1910 *((PULONGLONG)Buffer) = FPU_ST(0).Mantissa;
1911 *((PUSHORT)&Buffer[sizeof(ULONGLONG)]) = FPU_ST(0).Exponent
1912 | (FPU_ST(0).Sign ? 0x8000 : 0);
1913 }
1914 else
1915 {
1916 /* Raise the invalid operation exception */
1917 State->FpuStatus.Ie = TRUE;
1918
1919 if (State->FpuControl.Im)
1920 {
1921 *((PULONGLONG)Buffer) = FPU_INDEFINITE_MANTISSA;
1922 *((PUSHORT)&Buffer[sizeof(ULONGLONG)]) = 0x8000 | (FPU_MAX_EXPONENT + 1);
1923 }
1924 else
1925 {
1926 Fast486FpuException(State);
1927 return;
1928 }
1929 }
1930
1931 if (!Fast486WriteMemory(State,
1932 (State->PrefixFlags & FAST486_PREFIX_SEG)
1933 ? State->SegmentOverride : FAST486_REG_DS,
1934 ModRegRm.MemoryAddress,
1935 Buffer,
1936 sizeof(Buffer)))
1937 {
1938 /* Exception occurred */
1939 return;
1940 }
1941
1942 Fast486FpuPop(State);
1943 break;
1944 }
1945
1946 /* Invalid */
1947 default:
1948 {
1949 Fast486Exception(State, FAST486_EXCEPTION_UD);
1950 return;
1951 }
1952 }
1953 }
1954 else
1955 {
1956 /* Only a few of these instructions have any meaning on a 487 */
1957 switch ((ModRegRm.Register << 3) | ModRegRm.SecondRegister)
1958 {
1959 /* FCLEX */
1960 case 0x22:
1961 {
1962 /* Clear exception data */
1963 State->FpuStatus.Ie =
1964 State->FpuStatus.De =
1965 State->FpuStatus.Ze =
1966 State->FpuStatus.Oe =
1967 State->FpuStatus.Ue =
1968 State->FpuStatus.Pe =
1969 State->FpuStatus.Sf =
1970 State->FpuStatus.Es =
1971 State->FpuStatus.Busy = FALSE;
1972
1973 break;
1974 }
1975
1976 /* FINIT */
1977 case 0x23:
1978 {
1979 /* Restore the state */
1980 State->FpuControl.Value = FAST486_FPU_DEFAULT_CONTROL;
1981 State->FpuStatus.Value = 0;
1982 State->FpuTag = 0xFFFF;
1983
1984 break;
1985 }
1986
1987 /* FENI */
1988 case 0x20:
1989 /* FDISI */
1990 case 0x21:
1991 /* FSETPM */
1992 case 0x24:
1993 /* FRSTPM */
1994 case 0x25:
1995 {
1996 /* These do nothing */
1997 break;
1998 }
1999
2000 /* Invalid */
2001 default:
2002 {
2003 Fast486Exception(State, FAST486_EXCEPTION_UD);
2004 return;
2005 }
2006 }
2007 }
2008
2009 #endif
2010 }
2011
2012 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDC)
2013 {
2014 FAST486_MOD_REG_RM ModRegRm;
2015 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2016 PFAST486_FPU_DATA_REG SourceOperand, DestOperand;
2017 FAST486_FPU_DATA_REG MemoryData;
2018
2019 TOGGLE_ADSIZE(AddressSize);
2020
2021 /* Get the operands */
2022 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2023 {
2024 /* Exception occurred */
2025 return;
2026 }
2027
2028 FPU_CHECK();
2029
2030 #ifndef FAST486_NO_FPU
2031
2032 FPU_SAVE_LAST_INST();
2033
2034 if (ModRegRm.Memory)
2035 {
2036 ULONGLONG Value;
2037
2038 /* The destination operand is ST0 */
2039 DestOperand = &FPU_ST(0);
2040
2041 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2042 {
2043 /* Raise the invalid operation exception */
2044 State->FpuStatus.Ie = TRUE;
2045
2046 if (State->FpuControl.Im)
2047 {
2048 /* Return the indefinite NaN */
2049 DestOperand->Sign = TRUE;
2050 DestOperand->Exponent = FPU_MAX_EXPONENT + 1;
2051 DestOperand->Mantissa = FPU_INDEFINITE_MANTISSA;
2052
2053 FPU_SET_TAG(0, FPU_TAG_SPECIAL);
2054 }
2055 else Fast486FpuException(State);
2056
2057 return;
2058 }
2059
2060 /* Load the source operand from memory */
2061 if (!Fast486ReadMemory(State,
2062 (State->PrefixFlags & FAST486_PREFIX_SEG)
2063 ? State->SegmentOverride : FAST486_REG_DS,
2064 ModRegRm.MemoryAddress,
2065 FALSE,
2066 &Value,
2067 sizeof(ULONGLONG)))
2068 {
2069 /* Exception occurred */
2070 return;
2071 }
2072
2073 Fast486FpuFromDoubleReal(State, Value, &MemoryData);
2074 SourceOperand = &MemoryData;
2075
2076 FPU_SAVE_LAST_OPERAND();
2077 }
2078 else
2079 {
2080 /* The source operand is ST0 */
2081 SourceOperand = &FPU_ST(0);
2082
2083 /* Load the destination operand from an FPU register */
2084 DestOperand = &FPU_ST(ModRegRm.SecondRegister);
2085
2086 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2087 || (FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY))
2088 {
2089 /* Raise the invalid operation exception */
2090 State->FpuStatus.Ie = TRUE;
2091
2092 if (State->FpuControl.Im)
2093 {
2094 /* Return the indefinite NaN */
2095 DestOperand->Sign = TRUE;
2096 DestOperand->Exponent = FPU_MAX_EXPONENT + 1;
2097 DestOperand->Mantissa = FPU_INDEFINITE_MANTISSA;
2098
2099 FPU_SET_TAG(ModRegRm.SecondRegister, FPU_TAG_SPECIAL);
2100 }
2101 else Fast486FpuException(State);
2102
2103 return;
2104 }
2105 }
2106
2107 /* Perform the requested operation */
2108 Fast486FpuArithmeticOperation(State, ModRegRm.Register, SourceOperand, DestOperand);
2109
2110 #endif
2111 }
2112
2113 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDD)
2114 {
2115 FAST486_MOD_REG_RM ModRegRm;
2116 BOOLEAN OperandSize, AddressSize;
2117
2118 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2119 TOGGLE_OPSIZE(OperandSize);
2120 TOGGLE_ADSIZE(AddressSize);
2121
2122 /* Get the operands */
2123 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2124 {
2125 /* Exception occurred */
2126 return;
2127 }
2128
2129 FPU_CHECK();
2130
2131 #ifndef FAST486_NO_FPU
2132
2133 if (ModRegRm.Memory)
2134 {
2135 switch (ModRegRm.Register)
2136 {
2137 /* FLD */
2138 case 0:
2139 {
2140 ULONGLONG Value;
2141 FAST486_FPU_DATA_REG MemoryData;
2142
2143 FPU_SAVE_LAST_INST();
2144 FPU_SAVE_LAST_OPERAND();
2145
2146 if (!Fast486ReadMemory(State,
2147 (State->PrefixFlags & FAST486_PREFIX_SEG)
2148 ? State->SegmentOverride : FAST486_REG_DS,
2149 ModRegRm.MemoryAddress,
2150 FALSE,
2151 &Value,
2152 sizeof(ULONGLONG)))
2153 {
2154 /* Exception occurred */
2155 return;
2156 }
2157
2158 Fast486FpuFromDoubleReal(State, Value, &MemoryData);
2159 Fast486FpuPush(State, &MemoryData);
2160
2161 break;
2162 }
2163
2164 /* FST */
2165 case 2:
2166 /* FSTP */
2167 case 3:
2168 {
2169 ULONGLONG Value = FPU_REAL8_INDEFINITE;
2170
2171 FPU_SAVE_LAST_INST();
2172 FPU_SAVE_LAST_OPERAND();
2173
2174 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2175 {
2176 /* Raise the invalid operation exception */
2177 State->FpuStatus.Ie = TRUE;
2178
2179 if (!State->FpuControl.Im)
2180 {
2181 Fast486FpuException(State);
2182 return;
2183 }
2184 }
2185 else if (!Fast486FpuToDoubleReal(State, &FPU_ST(0), &Value))
2186 {
2187 /* Exception occurred */
2188 return;
2189 }
2190
2191 if (!Fast486WriteMemory(State,
2192 (State->PrefixFlags & FAST486_PREFIX_SEG)
2193 ? State->SegmentOverride : FAST486_REG_DS,
2194 ModRegRm.MemoryAddress,
2195 &Value,
2196 sizeof(ULONGLONG)))
2197 {
2198 /* Exception occurred */
2199 return;
2200 }
2201
2202 if (ModRegRm.Register == 3) Fast486FpuPop(State);
2203 break;
2204 }
2205
2206 /* FRSTOR */
2207 case 4:
2208 {
2209 INT i;
2210 UCHAR AllRegs[80];
2211
2212 /* Save the environment */
2213 if (!Fast486FpuLoadEnvironment(State,
2214 (State->PrefixFlags & FAST486_PREFIX_SEG)
2215 ? FAST486_REG_DS : State->SegmentOverride,
2216 ModRegRm.MemoryAddress,
2217 OperandSize))
2218 {
2219 /* Exception occurred */
2220 return;
2221 }
2222
2223 /* Load the registers */
2224 if (!Fast486ReadMemory(State,
2225 (State->PrefixFlags & FAST486_PREFIX_SEG)
2226 ? FAST486_REG_DS : State->SegmentOverride,
2227 ModRegRm.MemoryAddress + (OperandSize + 1) * 14,
2228 FALSE,
2229 AllRegs,
2230 sizeof(AllRegs)))
2231 {
2232 /* Exception occurred */
2233 return;
2234 }
2235
2236 for (i = 0; i < FAST486_NUM_FPU_REGS; i++)
2237 {
2238 State->FpuRegisters[i].Mantissa = *((PULONGLONG)&AllRegs[i * 10]);
2239 State->FpuRegisters[i].Exponent = *((PUSHORT)&AllRegs[(i * 10) + sizeof(ULONGLONG)]) & 0x7FFF;
2240
2241 if (*((PUSHORT)&AllRegs[(i * 10) + sizeof(ULONGLONG)]) & 0x8000)
2242 {
2243 State->FpuRegisters[i].Sign = TRUE;
2244 }
2245 else
2246 {
2247 State->FpuRegisters[i].Sign = FALSE;
2248 }
2249 }
2250
2251 break;
2252 }
2253
2254 /* FSAVE */
2255 case 6:
2256 {
2257 INT i;
2258 UCHAR AllRegs[80];
2259
2260 /* Save the environment */
2261 if (!Fast486FpuSaveEnvironment(State,
2262 (State->PrefixFlags & FAST486_PREFIX_SEG)
2263 ? FAST486_REG_DS : State->SegmentOverride,
2264 ModRegRm.MemoryAddress,
2265 OperandSize))
2266 {
2267 /* Exception occurred */
2268 return;
2269 }
2270
2271 /* Save the registers */
2272 for (i = 0; i < FAST486_NUM_FPU_REGS; i++)
2273 {
2274 *((PULONGLONG)&AllRegs[i * 10]) = State->FpuRegisters[i].Mantissa;
2275 *((PUSHORT)&AllRegs[(i * 10) + sizeof(ULONGLONG)]) = State->FpuRegisters[i].Exponent;
2276
2277 if (State->FpuRegisters[i].Sign)
2278 {
2279 *((PUSHORT)&AllRegs[(i * 10) + sizeof(ULONGLONG)]) |= 0x8000;
2280 }
2281 }
2282
2283 Fast486WriteMemory(State,
2284 (State->PrefixFlags & FAST486_PREFIX_SEG)
2285 ? FAST486_REG_DS : State->SegmentOverride,
2286 ModRegRm.MemoryAddress + (OperandSize + 1) * 14,
2287 AllRegs,
2288 sizeof(AllRegs));
2289
2290 break;
2291 }
2292
2293 /* FSTSW */
2294 case 7:
2295 {
2296 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, State->FpuStatus.Value);
2297 break;
2298 }
2299
2300 /* Invalid */
2301 default:
2302 {
2303 Fast486Exception(State, FAST486_EXCEPTION_UD);
2304 }
2305 }
2306 }
2307 else
2308 {
2309 FPU_SAVE_LAST_INST();
2310
2311 switch (ModRegRm.Register)
2312 {
2313 /* FFREE */
2314 case 0:
2315 {
2316 FPU_SET_TAG(ModRegRm.SecondRegister, FPU_TAG_EMPTY);
2317 break;
2318 }
2319
2320 /* FXCH */
2321 case 1:
2322 {
2323 FAST486_FPU_DATA_REG Temp;
2324
2325 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2326 || FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY)
2327 {
2328 State->FpuStatus.Ie = TRUE;
2329
2330 if (!State->FpuControl.Im) Fast486FpuException(State);
2331 break;
2332 }
2333
2334 /* Exchange */
2335 Temp = FPU_ST(0);
2336 FPU_ST(0) = FPU_ST(ModRegRm.SecondRegister);
2337 FPU_ST(ModRegRm.SecondRegister) = Temp;
2338
2339 FPU_UPDATE_TAG(0);
2340 FPU_UPDATE_TAG(ModRegRm.SecondRegister);
2341
2342 break;
2343 }
2344
2345 /* FST */
2346 case 2:
2347 /* FSTP */
2348 case 3:
2349 {
2350 FPU_ST(ModRegRm.SecondRegister) = FPU_ST(0);
2351 FPU_UPDATE_TAG(ModRegRm.SecondRegister);
2352
2353 if (ModRegRm.Register == 3) Fast486FpuPop(State);
2354 break;
2355 }
2356
2357 /* FUCOM */
2358 case 4:
2359 /* FUCOMP */
2360 case 5:
2361 {
2362 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2363 || (FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY))
2364 {
2365 State->FpuStatus.Ie = TRUE;
2366
2367 if (!State->FpuControl.Im) Fast486FpuException(State);
2368 return;
2369 }
2370
2371 Fast486FpuCompare(State, &FPU_ST(0), &FPU_ST(ModRegRm.SecondRegister));
2372 if (ModRegRm.Register == 5) Fast486FpuPop(State);
2373
2374 break;
2375 }
2376
2377 /* Invalid */
2378 default:
2379 {
2380 Fast486Exception(State, FAST486_EXCEPTION_UD);
2381 }
2382 }
2383 }
2384
2385 #endif
2386 }
2387
2388 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDE)
2389 {
2390 FAST486_MOD_REG_RM ModRegRm;
2391 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2392 PFAST486_FPU_DATA_REG SourceOperand, DestOperand;
2393
2394 TOGGLE_ADSIZE(AddressSize);
2395
2396 /* Get the operands */
2397 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2398 {
2399 /* Exception occurred */
2400 return;
2401 }
2402
2403 FPU_CHECK();
2404
2405 #ifndef FAST486_NO_FPU
2406
2407 FPU_SAVE_LAST_INST();
2408
2409 if (ModRegRm.Memory)
2410 {
2411 SHORT Value;
2412 FAST486_FPU_DATA_REG MemoryData;
2413
2414 /* The destination operand is ST0 */
2415 DestOperand = &FPU_ST(0);
2416
2417 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2418 {
2419 /* Raise the invalid operation exception */
2420 State->FpuStatus.Ie = TRUE;
2421
2422 if (State->FpuControl.Im)
2423 {
2424 /* Return the indefinite NaN */
2425 DestOperand->Sign = TRUE;
2426 DestOperand->Exponent = FPU_MAX_EXPONENT + 1;
2427 DestOperand->Mantissa = FPU_INDEFINITE_MANTISSA;
2428
2429 FPU_SET_TAG(0, FPU_TAG_SPECIAL);
2430 }
2431 else Fast486FpuException(State);
2432
2433 return;
2434 }
2435
2436 /* Load the source operand from memory */
2437 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, (PUSHORT)&Value))
2438 {
2439 /* Exception occurred */
2440 return;
2441 }
2442
2443 Fast486FpuFromInteger(State, (LONGLONG)Value, &MemoryData);
2444 SourceOperand = &MemoryData;
2445
2446 FPU_SAVE_LAST_OPERAND();
2447 }
2448 else
2449 {
2450 /* FCOMPP check */
2451 if ((ModRegRm.Register == 3) && (ModRegRm.SecondRegister != 1))
2452 {
2453 /* Invalid */
2454 Fast486Exception(State, FAST486_EXCEPTION_UD);
2455 return;
2456 }
2457
2458 /* The source operand is ST0 */
2459 SourceOperand = &FPU_ST(0);
2460
2461 /* Load the destination operand from a register */
2462 DestOperand = &FPU_ST(ModRegRm.SecondRegister);
2463
2464 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2465 || (FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY))
2466 {
2467 /* Raise the invalid operation exception, if unmasked */
2468 State->FpuStatus.Ie = TRUE;
2469
2470 if (!State->FpuControl.Im) Fast486FpuException(State);
2471 return;
2472 }
2473 }
2474
2475 /* Perform the requested operation */
2476 Fast486FpuArithmeticOperation(State, ModRegRm.Register, SourceOperand, DestOperand);
2477 if (!ModRegRm.Memory) Fast486FpuPop(State);
2478
2479 #endif
2480 }
2481
2482 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDF)
2483 {
2484 FAST486_MOD_REG_RM ModRegRm;
2485 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2486
2487 TOGGLE_ADSIZE(AddressSize);
2488
2489 /* Get the operands */
2490 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2491 {
2492 /* Exception occurred */
2493 return;
2494 }
2495
2496 FPU_CHECK();
2497
2498 #ifndef FAST486_NO_FPU
2499
2500 FPU_SAVE_LAST_INST();
2501
2502 if (ModRegRm.Memory)
2503 {
2504 FPU_SAVE_LAST_OPERAND();
2505
2506 switch (ModRegRm.Register)
2507 {
2508 /* FILD */
2509 case 0:
2510 {
2511 SHORT Value;
2512 FAST486_FPU_DATA_REG Temp;
2513
2514 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, (PUSHORT)&Value))
2515 {
2516 /* Exception occurred */
2517 return;
2518 }
2519
2520 Fast486FpuFromInteger(State, (LONGLONG)Value, &Temp);
2521 Fast486FpuPush(State, &Temp);
2522
2523 break;
2524 }
2525
2526 /* FIST */
2527 case 2:
2528 /* FISTP */
2529 case 3:
2530 {
2531 LONGLONG Temp = 0LL;
2532
2533 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY) || (FPU_GET_TAG(0) == FPU_TAG_SPECIAL))
2534 {
2535 /* Raise the invalid operation exception */
2536 State->FpuStatus.Ie = TRUE;
2537
2538 if (!State->FpuControl.Im)
2539 {
2540 Fast486FpuException(State);
2541 return;
2542 }
2543 }
2544 else if (!Fast486FpuToInteger(State, &FPU_ST(0), &Temp))
2545 {
2546 /* Exception occurred */
2547 return;
2548 }
2549
2550 /* Check if it can fit in a signed 16-bit integer */
2551 if ((((ULONGLONG)Temp >> 15) + 1ULL) > 1ULL)
2552 {
2553 /* Raise the invalid operation exception */
2554 State->FpuStatus.Ie = TRUE;
2555
2556 if (State->FpuControl.Im) Temp = 0LL;
2557 else
2558 {
2559 Fast486FpuException(State);
2560 return;
2561 }
2562 }
2563
2564 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, (USHORT)((SHORT)Temp)))
2565 {
2566 /* Exception occurred */
2567 return;
2568 }
2569
2570 if (ModRegRm.Register == 3)
2571 {
2572 /* Pop the FPU stack too */
2573 Fast486FpuPop(State);
2574 }
2575
2576 break;
2577 }
2578
2579 /* FBLD */
2580 case 4:
2581 {
2582 FAST486_FPU_DATA_REG Value;
2583 UCHAR Buffer[10];
2584
2585 if (!Fast486ReadMemory(State,
2586 (State->PrefixFlags & FAST486_PREFIX_SEG)
2587 ? State->SegmentOverride : FAST486_REG_DS,
2588 ModRegRm.MemoryAddress,
2589 FALSE,
2590 Buffer,
2591 sizeof(Buffer)))
2592 {
2593 /* Exception occurred */
2594 return;
2595 }
2596
2597 Fast486FpuFromPackedBcd(State, Buffer, &Value);
2598 Fast486FpuPush(State, &Value);
2599
2600 break;
2601 }
2602
2603 /* FILD (64-bit int) */
2604 case 5:
2605 {
2606 LONGLONG Value;
2607 FAST486_FPU_DATA_REG Temp;
2608
2609 if (!Fast486ReadMemory(State,
2610 (State->PrefixFlags & FAST486_PREFIX_SEG)
2611 ? State->SegmentOverride : FAST486_REG_DS,
2612 ModRegRm.MemoryAddress,
2613 FALSE,
2614 &Value,
2615 sizeof(LONGLONG)))
2616 {
2617 /* Exception occurred */
2618 return;
2619 }
2620
2621 Fast486FpuFromInteger(State, (LONGLONG)Value, &Temp);
2622 Fast486FpuPush(State, &Temp);
2623
2624 break;
2625 }
2626
2627 /* FBSTP */
2628 case 6:
2629 {
2630 UCHAR Buffer[10] = {0};
2631
2632 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2633 {
2634 /* Raise the invalid operation exception */
2635 State->FpuStatus.Ie = TRUE;
2636
2637 if (!State->FpuControl.Im)
2638 {
2639 Fast486FpuException(State);
2640 return;
2641 }
2642 }
2643 else if (!Fast486FpuToPackedBcd(State, &FPU_ST(0), Buffer))
2644 {
2645 /* Exception occurred */
2646 return;
2647 }
2648
2649 if (!Fast486WriteMemory(State,
2650 (State->PrefixFlags & FAST486_PREFIX_SEG)
2651 ? State->SegmentOverride : FAST486_REG_DS,
2652 ModRegRm.MemoryAddress,
2653 Buffer,
2654 sizeof(Buffer)))
2655 {
2656 /* Exception occurred */
2657 return;
2658 }
2659
2660 Fast486FpuPop(State);
2661 break;
2662 }
2663
2664 /* FISTP (64-bit int) */
2665 case 7:
2666 {
2667 LONGLONG Temp = 0LL;
2668
2669 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY) || (FPU_GET_TAG(0) == FPU_TAG_SPECIAL))
2670 {
2671 /* Raise the invalid operation exception */
2672 State->FpuStatus.Ie = TRUE;
2673
2674 if (!State->FpuControl.Im)
2675 {
2676 Fast486FpuException(State);
2677 return;
2678 }
2679 }
2680 else if (!Fast486FpuToInteger(State, &FPU_ST(0), &Temp))
2681 {
2682 /* Exception occurred */
2683 return;
2684 }
2685
2686 if (!Fast486WriteMemory(State,
2687 (State->PrefixFlags & FAST486_PREFIX_SEG)
2688 ? State->SegmentOverride : FAST486_REG_DS,
2689 ModRegRm.MemoryAddress,
2690 &Temp,
2691 sizeof(LONGLONG)))
2692 {
2693 /* Exception occurred */
2694 return;
2695 }
2696
2697 /* Pop the FPU stack too */
2698 Fast486FpuPop(State);
2699
2700 break;
2701 }
2702
2703 /* Invalid */
2704 default:
2705 {
2706 Fast486Exception(State, FAST486_EXCEPTION_UD);
2707 }
2708 }
2709 }
2710 else
2711 {
2712 switch (ModRegRm.Register)
2713 {
2714 /* FFREEP */
2715 case 0:
2716 {
2717 FPU_SET_TAG(ModRegRm.SecondRegister, FPU_TAG_EMPTY);
2718 Fast486FpuPop(State);
2719
2720 break;
2721 }
2722
2723 /* FXCH */
2724 case 1:
2725 {
2726 FAST486_FPU_DATA_REG Temp;
2727
2728 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2729 || FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY)
2730 {
2731 State->FpuStatus.Ie = TRUE;
2732
2733 if (!State->FpuControl.Im) Fast486FpuException(State);
2734 break;
2735 }
2736
2737 /* Exchange */
2738 Temp = FPU_ST(0);
2739 FPU_ST(0) = FPU_ST(ModRegRm.SecondRegister);
2740 FPU_ST(ModRegRm.SecondRegister) = Temp;
2741
2742 FPU_UPDATE_TAG(0);
2743 FPU_UPDATE_TAG(ModRegRm.SecondRegister);
2744
2745 break;
2746 }
2747
2748 /* FSTP */
2749 case 2:
2750 case 3:
2751 {
2752 FPU_ST(ModRegRm.SecondRegister) = FPU_ST(0);
2753 FPU_UPDATE_TAG(ModRegRm.SecondRegister);
2754 Fast486FpuPop(State);
2755
2756 break;
2757 }
2758
2759 /* FSTSW */
2760 case 4:
2761 {
2762 if (ModRegRm.SecondRegister != 0)
2763 {
2764 /* Invalid */
2765 Fast486Exception(State, FAST486_EXCEPTION_UD);
2766 return;
2767 }
2768
2769 /* Store the status word in AX */
2770 State->GeneralRegs[FAST486_REG_EAX].LowWord = State->FpuStatus.Value;
2771
2772 break;
2773 }
2774
2775 /* Invalid */
2776 default:
2777 {
2778 Fast486Exception(State, FAST486_EXCEPTION_UD);
2779 return;
2780 }
2781 }
2782 }
2783
2784 #endif
2785 }
2786
2787 /* EOF */