0c76a5304e5f136762269c75aad3f69e62fb5982
[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 {
1992 /* These do nothing */
1993 break;
1994 }
1995
1996 /* Invalid */
1997 default:
1998 {
1999 Fast486Exception(State, FAST486_EXCEPTION_UD);
2000 return;
2001 }
2002 }
2003 }
2004
2005 #endif
2006 }
2007
2008 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDC)
2009 {
2010 FAST486_MOD_REG_RM ModRegRm;
2011 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2012 PFAST486_FPU_DATA_REG SourceOperand, DestOperand;
2013 FAST486_FPU_DATA_REG MemoryData;
2014
2015 TOGGLE_ADSIZE(AddressSize);
2016
2017 /* Get the operands */
2018 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2019 {
2020 /* Exception occurred */
2021 return;
2022 }
2023
2024 FPU_CHECK();
2025
2026 #ifndef FAST486_NO_FPU
2027
2028 FPU_SAVE_LAST_INST();
2029
2030 if (ModRegRm.Memory)
2031 {
2032 ULONGLONG Value;
2033
2034 /* The destination operand is ST0 */
2035 DestOperand = &FPU_ST(0);
2036
2037 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2038 {
2039 /* Raise the invalid operation exception */
2040 State->FpuStatus.Ie = TRUE;
2041
2042 if (State->FpuControl.Im)
2043 {
2044 /* Return the indefinite NaN */
2045 DestOperand->Sign = TRUE;
2046 DestOperand->Exponent = FPU_MAX_EXPONENT + 1;
2047 DestOperand->Mantissa = FPU_INDEFINITE_MANTISSA;
2048
2049 FPU_SET_TAG(0, FPU_TAG_SPECIAL);
2050 }
2051 else Fast486FpuException(State);
2052
2053 return;
2054 }
2055
2056 /* Load the source operand from memory */
2057 if (!Fast486ReadMemory(State,
2058 (State->PrefixFlags & FAST486_PREFIX_SEG)
2059 ? State->SegmentOverride : FAST486_REG_DS,
2060 ModRegRm.MemoryAddress,
2061 FALSE,
2062 &Value,
2063 sizeof(ULONGLONG)))
2064 {
2065 /* Exception occurred */
2066 return;
2067 }
2068
2069 Fast486FpuFromDoubleReal(State, Value, &MemoryData);
2070 SourceOperand = &MemoryData;
2071
2072 FPU_SAVE_LAST_OPERAND();
2073 }
2074 else
2075 {
2076 /* The source operand is ST0 */
2077 SourceOperand = &FPU_ST(0);
2078
2079 /* Load the destination operand from an FPU register */
2080 DestOperand = &FPU_ST(ModRegRm.SecondRegister);
2081
2082 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2083 || (FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY))
2084 {
2085 /* Raise the invalid operation exception */
2086 State->FpuStatus.Ie = TRUE;
2087
2088 if (State->FpuControl.Im)
2089 {
2090 /* Return the indefinite NaN */
2091 DestOperand->Sign = TRUE;
2092 DestOperand->Exponent = FPU_MAX_EXPONENT + 1;
2093 DestOperand->Mantissa = FPU_INDEFINITE_MANTISSA;
2094
2095 FPU_SET_TAG(ModRegRm.SecondRegister, FPU_TAG_SPECIAL);
2096 }
2097 else Fast486FpuException(State);
2098
2099 return;
2100 }
2101 }
2102
2103 /* Perform the requested operation */
2104 Fast486FpuArithmeticOperation(State, ModRegRm.Register, SourceOperand, DestOperand);
2105
2106 #endif
2107 }
2108
2109 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDD)
2110 {
2111 FAST486_MOD_REG_RM ModRegRm;
2112 BOOLEAN OperandSize, AddressSize;
2113
2114 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2115 TOGGLE_OPSIZE(OperandSize);
2116 TOGGLE_ADSIZE(AddressSize);
2117
2118 /* Get the operands */
2119 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2120 {
2121 /* Exception occurred */
2122 return;
2123 }
2124
2125 FPU_CHECK();
2126
2127 #ifndef FAST486_NO_FPU
2128
2129 if (ModRegRm.Memory)
2130 {
2131 switch (ModRegRm.Register)
2132 {
2133 /* FLD */
2134 case 0:
2135 {
2136 ULONGLONG Value;
2137 FAST486_FPU_DATA_REG MemoryData;
2138
2139 FPU_SAVE_LAST_INST();
2140 FPU_SAVE_LAST_OPERAND();
2141
2142 if (!Fast486ReadMemory(State,
2143 (State->PrefixFlags & FAST486_PREFIX_SEG)
2144 ? State->SegmentOverride : FAST486_REG_DS,
2145 ModRegRm.MemoryAddress,
2146 FALSE,
2147 &Value,
2148 sizeof(ULONGLONG)))
2149 {
2150 /* Exception occurred */
2151 return;
2152 }
2153
2154 Fast486FpuFromDoubleReal(State, Value, &MemoryData);
2155 Fast486FpuPush(State, &MemoryData);
2156
2157 break;
2158 }
2159
2160 /* FST */
2161 case 2:
2162 /* FSTP */
2163 case 3:
2164 {
2165 ULONGLONG Value = FPU_REAL8_INDEFINITE;
2166
2167 FPU_SAVE_LAST_INST();
2168 FPU_SAVE_LAST_OPERAND();
2169
2170 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2171 {
2172 /* Raise the invalid operation exception */
2173 State->FpuStatus.Ie = TRUE;
2174
2175 if (!State->FpuControl.Im)
2176 {
2177 Fast486FpuException(State);
2178 return;
2179 }
2180 }
2181 else if (!Fast486FpuToDoubleReal(State, &FPU_ST(0), &Value))
2182 {
2183 /* Exception occurred */
2184 return;
2185 }
2186
2187 if (!Fast486WriteMemory(State,
2188 (State->PrefixFlags & FAST486_PREFIX_SEG)
2189 ? State->SegmentOverride : FAST486_REG_DS,
2190 ModRegRm.MemoryAddress,
2191 &Value,
2192 sizeof(ULONGLONG)))
2193 {
2194 /* Exception occurred */
2195 return;
2196 }
2197
2198 if (ModRegRm.Register == 3) Fast486FpuPop(State);
2199 break;
2200 }
2201
2202 /* FRSTOR */
2203 case 4:
2204 {
2205 INT i;
2206 UCHAR AllRegs[80];
2207
2208 /* Save the environment */
2209 if (!Fast486FpuLoadEnvironment(State,
2210 (State->PrefixFlags & FAST486_PREFIX_SEG)
2211 ? FAST486_REG_DS : State->SegmentOverride,
2212 ModRegRm.MemoryAddress,
2213 OperandSize))
2214 {
2215 /* Exception occurred */
2216 return;
2217 }
2218
2219 /* Load the registers */
2220 if (!Fast486ReadMemory(State,
2221 (State->PrefixFlags & FAST486_PREFIX_SEG)
2222 ? FAST486_REG_DS : State->SegmentOverride,
2223 ModRegRm.MemoryAddress + (OperandSize + 1) * 14,
2224 FALSE,
2225 AllRegs,
2226 sizeof(AllRegs)))
2227 {
2228 /* Exception occurred */
2229 return;
2230 }
2231
2232 for (i = 0; i < FAST486_NUM_FPU_REGS; i++)
2233 {
2234 State->FpuRegisters[i].Mantissa = *((PULONGLONG)&AllRegs[i * 10]);
2235 State->FpuRegisters[i].Exponent = *((PUSHORT)&AllRegs[(i * 10) + sizeof(ULONGLONG)]) & 0x7FFF;
2236
2237 if (*((PUSHORT)&AllRegs[(i * 10) + sizeof(ULONGLONG)]) & 0x8000)
2238 {
2239 State->FpuRegisters[i].Sign = TRUE;
2240 }
2241 else
2242 {
2243 State->FpuRegisters[i].Sign = FALSE;
2244 }
2245 }
2246
2247 break;
2248 }
2249
2250 /* FSAVE */
2251 case 6:
2252 {
2253 INT i;
2254 UCHAR AllRegs[80];
2255
2256 /* Save the environment */
2257 if (!Fast486FpuSaveEnvironment(State,
2258 (State->PrefixFlags & FAST486_PREFIX_SEG)
2259 ? FAST486_REG_DS : State->SegmentOverride,
2260 ModRegRm.MemoryAddress,
2261 OperandSize))
2262 {
2263 /* Exception occurred */
2264 return;
2265 }
2266
2267 /* Save the registers */
2268 for (i = 0; i < FAST486_NUM_FPU_REGS; i++)
2269 {
2270 *((PULONGLONG)&AllRegs[i * 10]) = State->FpuRegisters[i].Mantissa;
2271 *((PUSHORT)&AllRegs[(i * 10) + sizeof(ULONGLONG)]) = State->FpuRegisters[i].Exponent;
2272
2273 if (State->FpuRegisters[i].Sign)
2274 {
2275 *((PUSHORT)&AllRegs[(i * 10) + sizeof(ULONGLONG)]) |= 0x8000;
2276 }
2277 }
2278
2279 Fast486WriteMemory(State,
2280 (State->PrefixFlags & FAST486_PREFIX_SEG)
2281 ? FAST486_REG_DS : State->SegmentOverride,
2282 ModRegRm.MemoryAddress + (OperandSize + 1) * 14,
2283 AllRegs,
2284 sizeof(AllRegs));
2285
2286 break;
2287 }
2288
2289 /* FSTSW */
2290 case 7:
2291 {
2292 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, State->FpuStatus.Value);
2293 break;
2294 }
2295
2296 /* Invalid */
2297 default:
2298 {
2299 Fast486Exception(State, FAST486_EXCEPTION_UD);
2300 }
2301 }
2302 }
2303 else
2304 {
2305 FPU_SAVE_LAST_INST();
2306
2307 switch (ModRegRm.Register)
2308 {
2309 /* FFREE */
2310 case 0:
2311 {
2312 FPU_SET_TAG(ModRegRm.SecondRegister, FPU_TAG_EMPTY);
2313 break;
2314 }
2315
2316 /* FXCH */
2317 case 1:
2318 {
2319 FAST486_FPU_DATA_REG Temp;
2320
2321 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2322 || FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY)
2323 {
2324 State->FpuStatus.Ie = TRUE;
2325
2326 if (!State->FpuControl.Im) Fast486FpuException(State);
2327 break;
2328 }
2329
2330 /* Exchange */
2331 Temp = FPU_ST(0);
2332 FPU_ST(0) = FPU_ST(ModRegRm.SecondRegister);
2333 FPU_ST(ModRegRm.SecondRegister) = Temp;
2334
2335 FPU_UPDATE_TAG(0);
2336 FPU_UPDATE_TAG(ModRegRm.SecondRegister);
2337
2338 break;
2339 }
2340
2341 /* FST */
2342 case 2:
2343 /* FSTP */
2344 case 3:
2345 {
2346 FPU_ST(ModRegRm.SecondRegister) = FPU_ST(0);
2347 FPU_UPDATE_TAG(ModRegRm.SecondRegister);
2348
2349 if (ModRegRm.Register == 3) Fast486FpuPop(State);
2350 break;
2351 }
2352
2353 /* FUCOM */
2354 case 4:
2355 /* FUCOMP */
2356 case 5:
2357 {
2358 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2359 || (FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY))
2360 {
2361 State->FpuStatus.Ie = TRUE;
2362
2363 if (!State->FpuControl.Im) Fast486FpuException(State);
2364 return;
2365 }
2366
2367 Fast486FpuCompare(State, &FPU_ST(0), &FPU_ST(ModRegRm.SecondRegister));
2368 if (ModRegRm.Register == 5) Fast486FpuPop(State);
2369
2370 break;
2371 }
2372
2373 /* Invalid */
2374 default:
2375 {
2376 Fast486Exception(State, FAST486_EXCEPTION_UD);
2377 }
2378 }
2379 }
2380
2381 #endif
2382 }
2383
2384 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDE)
2385 {
2386 FAST486_MOD_REG_RM ModRegRm;
2387 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2388 PFAST486_FPU_DATA_REG SourceOperand, DestOperand;
2389
2390 TOGGLE_ADSIZE(AddressSize);
2391
2392 /* Get the operands */
2393 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2394 {
2395 /* Exception occurred */
2396 return;
2397 }
2398
2399 FPU_CHECK();
2400
2401 #ifndef FAST486_NO_FPU
2402
2403 FPU_SAVE_LAST_INST();
2404
2405 if (ModRegRm.Memory)
2406 {
2407 SHORT Value;
2408 FAST486_FPU_DATA_REG MemoryData;
2409
2410 /* The destination operand is ST0 */
2411 DestOperand = &FPU_ST(0);
2412
2413 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2414 {
2415 /* Raise the invalid operation exception */
2416 State->FpuStatus.Ie = TRUE;
2417
2418 if (State->FpuControl.Im)
2419 {
2420 /* Return the indefinite NaN */
2421 DestOperand->Sign = TRUE;
2422 DestOperand->Exponent = FPU_MAX_EXPONENT + 1;
2423 DestOperand->Mantissa = FPU_INDEFINITE_MANTISSA;
2424
2425 FPU_SET_TAG(0, FPU_TAG_SPECIAL);
2426 }
2427 else Fast486FpuException(State);
2428
2429 return;
2430 }
2431
2432 /* Load the source operand from memory */
2433 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, (PUSHORT)&Value))
2434 {
2435 /* Exception occurred */
2436 return;
2437 }
2438
2439 Fast486FpuFromInteger(State, (LONGLONG)Value, &MemoryData);
2440 SourceOperand = &MemoryData;
2441
2442 FPU_SAVE_LAST_OPERAND();
2443 }
2444 else
2445 {
2446 /* FCOMPP check */
2447 if ((ModRegRm.Register == 3) && (ModRegRm.SecondRegister != 1))
2448 {
2449 /* Invalid */
2450 Fast486Exception(State, FAST486_EXCEPTION_UD);
2451 return;
2452 }
2453
2454 /* The source operand is ST0 */
2455 SourceOperand = &FPU_ST(0);
2456
2457 /* Load the destination operand from a register */
2458 DestOperand = &FPU_ST(ModRegRm.SecondRegister);
2459
2460 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2461 || (FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY))
2462 {
2463 /* Raise the invalid operation exception, if unmasked */
2464 State->FpuStatus.Ie = TRUE;
2465
2466 if (!State->FpuControl.Im) Fast486FpuException(State);
2467 return;
2468 }
2469 }
2470
2471 /* Perform the requested operation */
2472 Fast486FpuArithmeticOperation(State, ModRegRm.Register, SourceOperand, DestOperand);
2473 if (!ModRegRm.Memory) Fast486FpuPop(State);
2474
2475 #endif
2476 }
2477
2478 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDF)
2479 {
2480 FAST486_MOD_REG_RM ModRegRm;
2481 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2482
2483 TOGGLE_ADSIZE(AddressSize);
2484
2485 /* Get the operands */
2486 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2487 {
2488 /* Exception occurred */
2489 return;
2490 }
2491
2492 FPU_CHECK();
2493
2494 #ifndef FAST486_NO_FPU
2495
2496 FPU_SAVE_LAST_INST();
2497
2498 if (ModRegRm.Memory)
2499 {
2500 FPU_SAVE_LAST_OPERAND();
2501
2502 switch (ModRegRm.Register)
2503 {
2504 /* FILD */
2505 case 0:
2506 {
2507 SHORT Value;
2508 FAST486_FPU_DATA_REG Temp;
2509
2510 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, (PUSHORT)&Value))
2511 {
2512 /* Exception occurred */
2513 return;
2514 }
2515
2516 Fast486FpuFromInteger(State, (LONGLONG)Value, &Temp);
2517 Fast486FpuPush(State, &Temp);
2518
2519 break;
2520 }
2521
2522 /* FIST */
2523 case 2:
2524 /* FISTP */
2525 case 3:
2526 {
2527 LONGLONG Temp = 0LL;
2528
2529 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY) || (FPU_GET_TAG(0) == FPU_TAG_SPECIAL))
2530 {
2531 /* Raise the invalid operation exception */
2532 State->FpuStatus.Ie = TRUE;
2533
2534 if (!State->FpuControl.Im)
2535 {
2536 Fast486FpuException(State);
2537 return;
2538 }
2539 }
2540 else if (!Fast486FpuToInteger(State, &FPU_ST(0), &Temp))
2541 {
2542 /* Exception occurred */
2543 return;
2544 }
2545
2546 /* Check if it can fit in a signed 16-bit integer */
2547 if ((((ULONGLONG)Temp >> 15) + 1ULL) > 1ULL)
2548 {
2549 /* Raise the invalid operation exception */
2550 State->FpuStatus.Ie = TRUE;
2551
2552 if (State->FpuControl.Im) Temp = 0LL;
2553 else
2554 {
2555 Fast486FpuException(State);
2556 return;
2557 }
2558 }
2559
2560 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, (USHORT)((SHORT)Temp)))
2561 {
2562 /* Exception occurred */
2563 return;
2564 }
2565
2566 if (ModRegRm.Register == 3)
2567 {
2568 /* Pop the FPU stack too */
2569 Fast486FpuPop(State);
2570 }
2571
2572 break;
2573 }
2574
2575 /* FBLD */
2576 case 4:
2577 {
2578 FAST486_FPU_DATA_REG Value;
2579 UCHAR Buffer[10];
2580
2581 if (!Fast486ReadMemory(State,
2582 (State->PrefixFlags & FAST486_PREFIX_SEG)
2583 ? State->SegmentOverride : FAST486_REG_DS,
2584 ModRegRm.MemoryAddress,
2585 FALSE,
2586 Buffer,
2587 sizeof(Buffer)))
2588 {
2589 /* Exception occurred */
2590 return;
2591 }
2592
2593 Fast486FpuFromPackedBcd(State, Buffer, &Value);
2594 Fast486FpuPush(State, &Value);
2595
2596 break;
2597 }
2598
2599 /* FILD (64-bit int) */
2600 case 5:
2601 {
2602 LONGLONG Value;
2603 FAST486_FPU_DATA_REG Temp;
2604
2605 if (!Fast486ReadMemory(State,
2606 (State->PrefixFlags & FAST486_PREFIX_SEG)
2607 ? State->SegmentOverride : FAST486_REG_DS,
2608 ModRegRm.MemoryAddress,
2609 FALSE,
2610 &Value,
2611 sizeof(LONGLONG)))
2612 {
2613 /* Exception occurred */
2614 return;
2615 }
2616
2617 Fast486FpuFromInteger(State, (LONGLONG)Value, &Temp);
2618 Fast486FpuPush(State, &Temp);
2619
2620 break;
2621 }
2622
2623 /* FBSTP */
2624 case 6:
2625 {
2626 UCHAR Buffer[10] = {0};
2627
2628 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2629 {
2630 /* Raise the invalid operation exception */
2631 State->FpuStatus.Ie = TRUE;
2632
2633 if (!State->FpuControl.Im)
2634 {
2635 Fast486FpuException(State);
2636 return;
2637 }
2638 }
2639 else if (!Fast486FpuToPackedBcd(State, &FPU_ST(0), Buffer))
2640 {
2641 /* Exception occurred */
2642 return;
2643 }
2644
2645 if (!Fast486WriteMemory(State,
2646 (State->PrefixFlags & FAST486_PREFIX_SEG)
2647 ? State->SegmentOverride : FAST486_REG_DS,
2648 ModRegRm.MemoryAddress,
2649 Buffer,
2650 sizeof(Buffer)))
2651 {
2652 /* Exception occurred */
2653 return;
2654 }
2655
2656 Fast486FpuPop(State);
2657 break;
2658 }
2659
2660 /* FISTP (64-bit int) */
2661 case 7:
2662 {
2663 LONGLONG Temp = 0LL;
2664
2665 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY) || (FPU_GET_TAG(0) == FPU_TAG_SPECIAL))
2666 {
2667 /* Raise the invalid operation exception */
2668 State->FpuStatus.Ie = TRUE;
2669
2670 if (!State->FpuControl.Im)
2671 {
2672 Fast486FpuException(State);
2673 return;
2674 }
2675 }
2676 else if (!Fast486FpuToInteger(State, &FPU_ST(0), &Temp))
2677 {
2678 /* Exception occurred */
2679 return;
2680 }
2681
2682 if (!Fast486WriteMemory(State,
2683 (State->PrefixFlags & FAST486_PREFIX_SEG)
2684 ? State->SegmentOverride : FAST486_REG_DS,
2685 ModRegRm.MemoryAddress,
2686 &Temp,
2687 sizeof(LONGLONG)))
2688 {
2689 /* Exception occurred */
2690 return;
2691 }
2692
2693 /* Pop the FPU stack too */
2694 Fast486FpuPop(State);
2695
2696 break;
2697 }
2698
2699 /* Invalid */
2700 default:
2701 {
2702 Fast486Exception(State, FAST486_EXCEPTION_UD);
2703 }
2704 }
2705 }
2706 else
2707 {
2708 switch (ModRegRm.Register)
2709 {
2710 /* FFREEP */
2711 case 0:
2712 {
2713 FPU_SET_TAG(ModRegRm.SecondRegister, FPU_TAG_EMPTY);
2714 Fast486FpuPop(State);
2715
2716 break;
2717 }
2718
2719 /* FXCH */
2720 case 1:
2721 {
2722 FAST486_FPU_DATA_REG Temp;
2723
2724 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2725 || FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY)
2726 {
2727 State->FpuStatus.Ie = TRUE;
2728
2729 if (!State->FpuControl.Im) Fast486FpuException(State);
2730 break;
2731 }
2732
2733 /* Exchange */
2734 Temp = FPU_ST(0);
2735 FPU_ST(0) = FPU_ST(ModRegRm.SecondRegister);
2736 FPU_ST(ModRegRm.SecondRegister) = Temp;
2737
2738 FPU_UPDATE_TAG(0);
2739 FPU_UPDATE_TAG(ModRegRm.SecondRegister);
2740
2741 break;
2742 }
2743
2744 /* FSTP */
2745 case 2:
2746 case 3:
2747 {
2748 FPU_ST(ModRegRm.SecondRegister) = FPU_ST(0);
2749 FPU_UPDATE_TAG(ModRegRm.SecondRegister);
2750 Fast486FpuPop(State);
2751
2752 break;
2753 }
2754
2755 /* FSTSW */
2756 case 4:
2757 {
2758 if (ModRegRm.SecondRegister != 0)
2759 {
2760 /* Invalid */
2761 Fast486Exception(State, FAST486_EXCEPTION_UD);
2762 return;
2763 }
2764
2765 /* Store the status word in AX */
2766 State->GeneralRegs[FAST486_REG_EAX].LowWord = State->FpuStatus.Value;
2767
2768 break;
2769 }
2770
2771 /* Invalid */
2772 default:
2773 {
2774 Fast486Exception(State, FAST486_EXCEPTION_UD);
2775 return;
2776 }
2777 }
2778 }
2779
2780 #endif
2781 }
2782
2783 /* EOF */