[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 /* PRIVATE FUNCTIONS **********************************************************/
34
35 #ifndef FAST486_NO_FPU
36
37 static ULONGLONG
38 UnsignedMult128(ULONGLONG Multiplicand,
39 ULONGLONG Multiplier,
40 ULONGLONG *HighProduct)
41 {
42 ULONG MultiplicandLow, MultiplicandHigh, MultiplierLow, MultiplierHigh;
43 ULONG IntermediateLow, IntermediateHigh;
44 ULONGLONG LowProduct, Intermediate, Intermediate1, Intermediate2;
45
46 MultiplicandLow = (ULONG)(Multiplicand & 0xFFFFFFFFULL);
47 MultiplicandHigh = (ULONG)(Multiplicand >> 32);
48 MultiplierLow = (ULONG)(Multiplier & 0xFFFFFFFFULL);
49 MultiplierHigh = (ULONG)(Multiplier >> 32);
50
51 LowProduct = (ULONGLONG)MultiplicandLow * (ULONGLONG)MultiplierLow;
52 Intermediate1 = (ULONGLONG)MultiplicandLow * (ULONGLONG)MultiplierHigh;
53 Intermediate2 = (ULONGLONG)MultiplicandHigh * (ULONGLONG)MultiplierLow;
54 *HighProduct = (ULONGLONG)MultiplicandHigh * (ULONGLONG)MultiplierHigh;
55
56 Intermediate = Intermediate1 + Intermediate2;
57 if (Intermediate < Intermediate1) *HighProduct += 1ULL << 32;
58
59 IntermediateLow = (ULONG)(Intermediate & 0xFFFFFFFFULL);
60 IntermediateHigh = (ULONG)(Intermediate >> 32);
61
62 LowProduct += (ULONGLONG)IntermediateLow << 32;
63 if ((ULONG)(LowProduct >> 32) < IntermediateLow) (*HighProduct)++;
64
65 *HighProduct += IntermediateHigh;
66 return LowProduct;
67 }
68
69 static ULONGLONG
70 UnsignedDivMod128(ULONGLONG DividendLow,
71 ULONGLONG DividendHigh,
72 ULONGLONG Divisor,
73 PULONGLONG QuotientLow,
74 PULONGLONG QuotientHigh)
75 {
76 ULONGLONG ValueLow = DividendLow;
77 ULONGLONG ValueHigh = DividendHigh;
78 ULONGLONG CurrentLow = 0ULL;
79 ULONGLONG CurrentHigh = Divisor;
80 ULONG Bits;
81
82 ASSERT(Divisor != 0ULL);
83
84 /* Initialize the quotient */
85 *QuotientLow = *QuotientHigh = 0ULL;
86
87 /* Exit early if the dividend is lower than the divisor */
88 if ((DividendHigh == 0ULL) && (DividendLow < Divisor)) return ValueLow;
89
90 /* Normalize the current divisor */
91 Bits = CountLeadingZeros64(CurrentHigh);
92 CurrentHigh <<= Bits;
93
94 while (TRUE)
95 {
96 /* Shift the quotient left by one bit */
97 *QuotientHigh <<= 1;
98 *QuotientHigh |= *QuotientLow >> 63;
99 *QuotientLow <<= 1;
100
101 /* Check if the value is higher than or equal to the current divisor */
102 if ((ValueHigh > CurrentHigh)
103 || ((ValueHigh == CurrentHigh) && (ValueLow >= CurrentLow)))
104 {
105 BOOLEAN Carry = ValueLow < CurrentLow;
106
107 /* Subtract the current divisor from the value */
108 ValueHigh -= CurrentHigh;
109 ValueLow -= CurrentLow;
110 if (Carry) ValueHigh--;
111
112 /* Set the lowest bit of the quotient */
113 *QuotientLow |= 1;
114
115 /* Stop if the value is lower than the original divisor */
116 if ((ValueHigh == 0ULL) && (ValueLow < Divisor)) break;
117 }
118
119 /* Shift the current divisor right by one bit */
120 CurrentLow >>= 1;
121 CurrentLow |= (CurrentHigh & 1) << 63;
122 CurrentHigh >>= 1;
123 }
124
125 /*
126 * Calculate the number of significant bits the current
127 * divisor has more than the original divisor
128 */
129 Bits = CountLeadingZeros64(Divisor) + 64;
130 Bits -= (CurrentHigh > 0ULL) ? CountLeadingZeros64(CurrentHigh) : 64;
131 Bits -= (CurrentLow > 0ULL) ? CountLeadingZeros64(CurrentLow) : 64;
132
133 if (Bits)
134 {
135 /* Shift the quotient left by that amount */
136 *QuotientHigh <<= Bits;
137 *QuotientHigh |= *QuotientLow >> (64 - Bits);
138 *QuotientLow <<= Bits;
139 }
140
141 /* Return the remainder */
142 return ValueLow;
143 }
144
145 static inline VOID FASTCALL
146 Fast486FpuFromInteger(PFAST486_STATE State,
147 LONGLONG Value,
148 PFAST486_FPU_DATA_REG Result)
149 {
150 ULONG ZeroCount;
151
152 Result->Sign = Result->Exponent = Result->Mantissa = 0;
153 if (Value == 0LL) return;
154
155 if (Value < 0LL)
156 {
157 Result->Sign = 1;
158 Value = -Value;
159 }
160
161 Result->Mantissa = (ULONGLONG)Value;
162 ZeroCount = CountLeadingZeros64(Result->Mantissa);
163
164 Result->Mantissa <<= ZeroCount;
165 Result->Exponent = FPU_REAL10_BIAS + 63 - ZeroCount;
166 }
167
168 static inline BOOLEAN FASTCALL
169 Fast486FpuToInteger(PFAST486_STATE State,
170 PFAST486_FPU_DATA_REG Value,
171 PLONGLONG Result)
172 {
173 ULONG Bits;
174 ULONGLONG Remainder;
175 SHORT UnbiasedExp = (SHORT)Value->Exponent - FPU_REAL10_BIAS;
176
177 if (FPU_IS_ZERO(Value))
178 {
179 *Result = 0LL;
180 return TRUE;
181 }
182
183 if (FPU_IS_NAN(Value) || !FPU_IS_NORMALIZED(Value)
184 || (UnbiasedExp < 0) || (UnbiasedExp > 63))
185 {
186 /* Raise an invalid operation exception */
187 State->FpuStatus.Ie = TRUE;
188
189 if (State->FpuControl.Im)
190 {
191 *Result = 0LL;
192 return TRUE;
193 }
194 else
195 {
196 Fast486FpuException(State);
197 return FALSE;
198 }
199 }
200
201 Bits = 63 - UnbiasedExp;
202
203 /* Calculate the result and the remainder */
204 *Result = (LONGLONG)(Value->Mantissa >> Bits);
205 Remainder = Value->Mantissa & ((1 << Bits) - 1);
206
207 /* The result must be positive here */
208 ASSERT(*Result >= 0LL);
209
210 switch (State->FpuControl.Rc)
211 {
212 case FPU_ROUND_NEAREST:
213 {
214 /* Check if the highest bit of the remainder is set */
215 if (Remainder & (1 << (Bits - 1)))
216 {
217 (*Result)++;
218
219 /* Check if all the other bits are clear */
220 if (!(Remainder & ((1 << (Bits - 1)) - 1)))
221 {
222 /* Round to even */
223 *Result &= ~1;
224 }
225 }
226
227 break;
228 }
229
230 case FPU_ROUND_DOWN:
231 {
232 if ((Remainder != 0ULL) && Value->Sign) (*Result)++;
233 break;
234 }
235
236 case FPU_ROUND_UP:
237 {
238 if ((Remainder != 0ULL) && !Value->Sign) (*Result)++;
239 break;
240 }
241
242 default:
243 {
244 /* Leave it truncated */
245 }
246 }
247
248 if (Value->Sign) *Result = -*Result;
249 return TRUE;
250 }
251
252 static inline VOID FASTCALL
253 Fast486FpuFromSingleReal(PFAST486_STATE State,
254 ULONG Value,
255 PFAST486_FPU_DATA_REG Result)
256 {
257 /* Extract the sign, exponent and mantissa */
258 Result->Sign = (UCHAR)(Value >> 31);
259 Result->Exponent = (USHORT)((Value >> 23) & 0xFF);
260 Result->Mantissa = (((ULONGLONG)Value & 0x7FFFFFULL) | 0x800000ULL) << 40;
261
262 /* If this is a zero, we're done */
263 if (Value == 0) return;
264
265 if (Result->Exponent == 0xFF) Result->Exponent = FPU_MAX_EXPONENT + 1;
266 else
267 {
268 /* Adjust the exponent bias */
269 Result->Exponent += (FPU_REAL10_BIAS - FPU_REAL4_BIAS);
270 }
271 }
272
273 static inline VOID FASTCALL
274 Fast486FpuFromDoubleReal(PFAST486_STATE State,
275 ULONGLONG Value,
276 PFAST486_FPU_DATA_REG Result)
277 {
278 /* Extract the sign, exponent and mantissa */
279 Result->Sign = (UCHAR)(Value >> 63);
280 Result->Exponent = (USHORT)((Value >> 52) & 0x7FF);
281 Result->Mantissa = (((ULONGLONG)Value & 0xFFFFFFFFFFFFFULL) | 0x10000000000000ULL) << 11;
282
283 /* If this is a zero, we're done */
284 if (Value == 0) return;
285
286 if (Result->Exponent == 0x3FF) Result->Exponent = FPU_MAX_EXPONENT + 1;
287 else
288 {
289 /* Adjust the exponent bias */
290 Result->Exponent += (FPU_REAL10_BIAS - FPU_REAL8_BIAS);
291 }
292 }
293
294 static inline BOOLEAN FASTCALL
295 Fast486FpuToDoubleReal(PFAST486_STATE State,
296 PFAST486_FPU_DATA_REG Value,
297 PULONGLONG Result)
298 {
299 ULONGLONG Remainder;
300 SHORT UnbiasedExp = (SHORT)Value->Exponent - FPU_REAL10_BIAS;
301
302 if (FPU_IS_ZERO(Value))
303 {
304 *Result = 0LL;
305 return TRUE;
306 }
307
308 /* Calculate the mantissa */
309 *Result = (Value->Mantissa >> 11) & ((1ULL << 52) - 1);
310
311 if (FPU_IS_NAN(Value))
312 {
313 *Result |= 0x7FFULL << 52;
314 goto SetSign;
315 }
316
317 /* Check for underflow */
318 if (!FPU_IS_NORMALIZED(Value) || (UnbiasedExp < -1023))
319 {
320 /* Raise the underflow exception */
321 State->FpuStatus.Ue = TRUE;
322
323 if (State->FpuControl.Um)
324 {
325 /* The result is zero due to underflow */
326 *Result = 0ULL;
327 return TRUE;
328 }
329 else
330 {
331 Fast486FpuException(State);
332 return FALSE;
333 }
334 }
335
336 /* Check for overflow */
337 if (UnbiasedExp > 1023)
338 {
339 /* Raise the overflow exception */
340 State->FpuStatus.Oe = TRUE;
341
342 if (State->FpuControl.Om)
343 {
344 /* The result is infinity due to overflow */
345 *Result = FPU_REAL8_INFINITY;
346 goto SetSign;
347 }
348 else
349 {
350 Fast486FpuException(State);
351 return FALSE;
352 }
353 }
354
355 /* Calculate the remainder */
356 Remainder = Value->Mantissa & ((1 << 11) - 1);
357
358 switch (State->FpuControl.Rc)
359 {
360 case FPU_ROUND_NEAREST:
361 {
362 /* Check if the highest bit of the remainder is set */
363 if (Remainder & (1 << 10))
364 {
365 (*Result)++;
366
367 /* Check if all the other bits are clear */
368 if (!(Remainder & ((1 << 10) - 1)))
369 {
370 /* Round to even */
371 *Result &= ~1;
372 }
373 }
374
375 break;
376 }
377
378 case FPU_ROUND_DOWN:
379 {
380 if ((Remainder != 0ULL) && Value->Sign) (*Result)++;
381 break;
382 }
383
384 case FPU_ROUND_UP:
385 {
386 if ((Remainder != 0ULL) && !Value->Sign) (*Result)++;
387 break;
388 }
389
390 default:
391 {
392 /* Leave it truncated */
393 }
394 }
395
396 /* Store the biased exponent */
397 *Result |= (ULONGLONG)(UnbiasedExp + FPU_REAL8_BIAS) << 52;
398
399 SetSign:
400
401 if (Value->Sign) *Result |= 1ULL << 63;
402 return TRUE;
403 }
404
405 static inline VOID FASTCALL
406 Fast486FpuFromPackedBcd(PFAST486_STATE State,
407 PUCHAR Value,
408 PFAST486_FPU_DATA_REG Result)
409 {
410 INT i;
411 LONGLONG IntVal = 0LL;
412
413 for (i = 8; i >= 0; i--)
414 {
415 IntVal *= 100LL;
416 IntVal += (Value[i] >> 4) * 10 + (Value[i] & 0x0F);
417 }
418
419 /* Apply the sign */
420 if (Value[9] & 0x80) IntVal = -IntVal;
421
422 /* Now convert the integer to FP80 */
423 Fast486FpuFromInteger(State, IntVal, Result);
424 }
425
426 static inline BOOLEAN FASTCALL
427 Fast486FpuToPackedBcd(PFAST486_STATE State,
428 PFAST486_FPU_DATA_REG Value,
429 PUCHAR Result)
430 {
431 INT i;
432 LONGLONG IntVal;
433
434 /* Convert it to an integer first */
435 if (!Fast486FpuToInteger(State, Value, &IntVal)) return FALSE;
436
437 if (IntVal < 0LL)
438 {
439 IntVal = -IntVal;
440 Result[9] = 0x80;
441 }
442
443 for (i = 0; i < 9; i++)
444 {
445 Result[i] = (UCHAR)((IntVal % 10) + (((IntVal / 10) % 10) << 4));
446 IntVal /= 100LL;
447 }
448
449 return TRUE;
450 }
451
452 static inline VOID FASTCALL
453 Fast486FpuAdd(PFAST486_STATE State,
454 PFAST486_FPU_DATA_REG FirstOperand,
455 PFAST486_FPU_DATA_REG SecondOperand,
456 PFAST486_FPU_DATA_REG Result)
457 {
458 FAST486_FPU_DATA_REG FirstAdjusted = *FirstOperand;
459 FAST486_FPU_DATA_REG SecondAdjusted = *SecondOperand;
460 FAST486_FPU_DATA_REG TempResult;
461
462 if ((!FPU_IS_NORMALIZED(FirstOperand) || !FPU_IS_NORMALIZED(SecondOperand)))
463 {
464 /* Raise the denormalized exception */
465 State->FpuStatus.De = TRUE;
466
467 if (!State->FpuControl.Dm)
468 {
469 Fast486FpuException(State);
470 return;
471 }
472 }
473
474 /* Find the largest exponent */
475 TempResult.Exponent = max(FirstOperand->Exponent, SecondOperand->Exponent);
476
477 /* Adjust the first operand to it... */
478 if (FirstAdjusted.Exponent < TempResult.Exponent)
479 {
480 FirstAdjusted.Mantissa >>= (TempResult.Exponent - FirstAdjusted.Exponent);
481 FirstAdjusted.Exponent = TempResult.Exponent;
482 }
483
484 /* ... and the second one too */
485 if (SecondAdjusted.Exponent < TempResult.Exponent)
486 {
487 SecondAdjusted.Mantissa >>= (TempResult.Exponent - SecondAdjusted.Exponent);
488 SecondAdjusted.Exponent = TempResult.Exponent;
489 }
490
491 if (FirstAdjusted.Sign == SecondAdjusted.Sign)
492 {
493 /* Calculate the mantissa and sign of the result */
494 TempResult.Mantissa = FirstAdjusted.Mantissa + SecondAdjusted.Mantissa;
495 TempResult.Sign = FirstAdjusted.Sign;
496 }
497 else
498 {
499 /* Calculate the sign of the result */
500 if (FirstAdjusted.Mantissa > SecondAdjusted.Mantissa) TempResult.Sign = FirstAdjusted.Sign;
501 else if (FirstAdjusted.Mantissa < SecondAdjusted.Mantissa) TempResult.Sign = SecondAdjusted.Sign;
502 else TempResult.Sign = FALSE;
503
504 /* Invert the negative mantissa */
505 if (FirstAdjusted.Sign) FirstAdjusted.Mantissa = -FirstAdjusted.Mantissa;
506 if (SecondAdjusted.Sign) SecondAdjusted.Mantissa = -SecondAdjusted.Mantissa;
507
508 /* Calculate the mantissa of the result */
509 TempResult.Mantissa = FirstAdjusted.Mantissa + SecondAdjusted.Mantissa;
510 }
511
512 /* Did it overflow? */
513 if (FPU_IS_NORMALIZED(&FirstAdjusted) && FPU_IS_NORMALIZED(&SecondAdjusted))
514 {
515 if (TempResult.Exponent == FPU_MAX_EXPONENT)
516 {
517 /* Raise the overflow exception */
518 State->FpuStatus.Oe = TRUE;
519
520 if (State->FpuControl.Om)
521 {
522 /* Total overflow, return infinity */
523 TempResult.Mantissa = FPU_MANTISSA_HIGH_BIT;
524 TempResult.Exponent = FPU_MAX_EXPONENT + 1;
525 }
526 else
527 {
528 Fast486FpuException(State);
529 return;
530 }
531 }
532 else
533 {
534 /* Lose the LSB in favor of the carry */
535 TempResult.Mantissa >>= 1;
536 TempResult.Mantissa |= FPU_MANTISSA_HIGH_BIT;
537 TempResult.Exponent++;
538 }
539 }
540
541 /* Normalize the result and return it */
542 Fast486FpuNormalize(State, &TempResult);
543 *Result = TempResult;
544 }
545
546 static inline VOID FASTCALL
547 Fast486FpuSubtract(PFAST486_STATE State,
548 PFAST486_FPU_DATA_REG FirstOperand,
549 PFAST486_FPU_DATA_REG SecondOperand,
550 PFAST486_FPU_DATA_REG Result)
551 {
552 FAST486_FPU_DATA_REG NegativeSecondOperand = *SecondOperand;
553
554 /* Invert the sign */
555 NegativeSecondOperand.Sign = !NegativeSecondOperand.Sign;
556
557 /* And perform an addition instead */
558 Fast486FpuAdd(State, FirstOperand, &NegativeSecondOperand, Result);
559 }
560
561 static inline VOID FASTCALL
562 Fast486FpuCompare(PFAST486_STATE State,
563 PFAST486_FPU_DATA_REG FirstOperand,
564 PFAST486_FPU_DATA_REG SecondOperand)
565 {
566 if (FPU_IS_NAN(FirstOperand) || FPU_IS_NAN(SecondOperand))
567 {
568 if (FPU_IS_POS_INF(FirstOperand) && FPU_IS_NEG_INF(SecondOperand))
569 {
570 State->FpuStatus.Code0 = FALSE;
571 State->FpuStatus.Code2 = FALSE;
572 State->FpuStatus.Code3 = FALSE;
573 }
574 else if (FPU_IS_NEG_INF(FirstOperand) && FPU_IS_POS_INF(SecondOperand))
575 {
576 State->FpuStatus.Code0 = TRUE;
577 State->FpuStatus.Code2 = FALSE;
578 State->FpuStatus.Code3 = FALSE;
579 }
580 else
581 {
582 State->FpuStatus.Code0 = TRUE;
583 State->FpuStatus.Code2 = TRUE;
584 State->FpuStatus.Code3 = TRUE;
585 }
586 }
587 else
588 {
589 FAST486_FPU_DATA_REG TempResult;
590
591 Fast486FpuSubtract(State, FirstOperand, SecondOperand, &TempResult);
592
593 if (FPU_IS_ZERO(&TempResult))
594 {
595 State->FpuStatus.Code0 = FALSE;
596 State->FpuStatus.Code2 = FALSE;
597 State->FpuStatus.Code3 = TRUE;
598 }
599 else if (TempResult.Sign)
600 {
601 State->FpuStatus.Code0 = TRUE;
602 State->FpuStatus.Code2 = FALSE;
603 State->FpuStatus.Code3 = FALSE;
604 }
605 else
606 {
607 State->FpuStatus.Code0 = FALSE;
608 State->FpuStatus.Code2 = FALSE;
609 State->FpuStatus.Code3 = FALSE;
610 }
611 }
612 }
613
614 static inline VOID FASTCALL
615 Fast486FpuMultiply(PFAST486_STATE State,
616 PFAST486_FPU_DATA_REG FirstOperand,
617 PFAST486_FPU_DATA_REG SecondOperand,
618 PFAST486_FPU_DATA_REG Result)
619 {
620 FAST486_FPU_DATA_REG TempResult;
621
622 if ((!FPU_IS_NORMALIZED(FirstOperand) || !FPU_IS_NORMALIZED(SecondOperand)))
623 {
624 /* Raise the denormalized exception */
625 State->FpuStatus.De = TRUE;
626
627 if (!State->FpuControl.Dm)
628 {
629 Fast486FpuException(State);
630 return;
631 }
632 }
633
634 UnsignedMult128(FirstOperand->Mantissa,
635 SecondOperand->Mantissa,
636 &TempResult.Mantissa);
637
638 TempResult.Exponent = FirstOperand->Exponent + SecondOperand->Exponent;
639 TempResult.Sign = FirstOperand->Sign ^ SecondOperand->Sign;
640
641 /* Normalize the result */
642 Fast486FpuNormalize(State, &TempResult);
643 *Result = TempResult;
644 }
645
646 static inline VOID FASTCALL
647 Fast486FpuDivide(PFAST486_STATE State,
648 PFAST486_FPU_DATA_REG FirstOperand,
649 PFAST486_FPU_DATA_REG SecondOperand,
650 PFAST486_FPU_DATA_REG Result)
651 {
652 FAST486_FPU_DATA_REG TempResult;
653 ULONGLONG QuotientLow, QuotientHigh, Remainder;
654 LONG Exponent;
655
656 if (FPU_IS_INDEFINITE(FirstOperand)
657 || FPU_IS_INDEFINITE(SecondOperand)
658 || (FPU_IS_INFINITY(FirstOperand) && FPU_IS_INFINITY(SecondOperand))
659 || (FPU_IS_ZERO(FirstOperand) && FPU_IS_ZERO(SecondOperand)))
660 {
661 /* Raise the invalid operation exception */
662 State->FpuStatus.Ie = TRUE;
663
664 if (State->FpuControl.Im)
665 {
666 /* Return the indefinite NaN */
667 Result->Sign = TRUE;
668 Result->Exponent = FPU_MAX_EXPONENT + 1;
669 Result->Mantissa = FPU_INDEFINITE_MANTISSA;
670 }
671 else Fast486FpuException(State);
672
673 return;
674 }
675
676 if (FPU_IS_ZERO(SecondOperand) || FPU_IS_INFINITY(FirstOperand))
677 {
678 /* Raise the division by zero exception */
679 State->FpuStatus.Ze = TRUE;
680
681 if (State->FpuControl.Zm)
682 {
683 /* Return infinity */
684 Result->Sign = FirstOperand->Sign;
685 Result->Exponent = FPU_MAX_EXPONENT + 1;
686 Result->Mantissa = FPU_MANTISSA_HIGH_BIT;
687 }
688 else Fast486FpuException(State);
689
690 return;
691 }
692
693 /* Calculate the sign of the result */
694 TempResult.Sign = FirstOperand->Sign ^ SecondOperand->Sign;
695
696 if (FPU_IS_ZERO(FirstOperand) || FPU_IS_INFINITY(SecondOperand))
697 {
698 /* Return zero */
699 Result->Sign = TempResult.Sign;
700 Result->Mantissa = 0ULL;
701 Result->Exponent = 0;
702 return;
703 }
704
705 /* Calculate the exponent of the result */
706 Exponent = (LONG)FirstOperand->Exponent - (LONG)SecondOperand->Exponent - 64;
707
708 /* Divide the two mantissas */
709 Remainder = UnsignedDivMod128(0ULL,
710 /* Notice the 64 above - this is the high part */
711 FirstOperand->Mantissa,
712 SecondOperand->Mantissa,
713 &QuotientLow,
714 &QuotientHigh);
715 UNREFERENCED_PARAMETER(Remainder); // TODO: Rounding
716
717 TempResult.Mantissa = QuotientLow;
718
719 if (QuotientHigh > 0ULL)
720 {
721 ULONG BitsToShift = 64 - CountLeadingZeros64(QuotientHigh);
722
723 TempResult.Mantissa >>= BitsToShift;
724 TempResult.Mantissa |= QuotientHigh << (64 - BitsToShift);
725 Exponent += BitsToShift;
726
727 // TODO: Rounding
728 }
729
730 if (Exponent < -FPU_REAL10_BIAS)
731 {
732 TempResult.Mantissa >>= -(Exponent + FPU_REAL10_BIAS);
733 Exponent = -FPU_REAL10_BIAS;
734
735 // TODO: Rounding
736 }
737
738 TempResult.Exponent = (USHORT)(Exponent + FPU_REAL10_BIAS);
739
740 /* Normalize the result */
741 Fast486FpuNormalize(State, &TempResult);
742 *Result = TempResult;
743 }
744
745 static inline VOID FASTCALL
746 Fast486FpuArithmeticOperation(PFAST486_STATE State,
747 INT Operation,
748 PFAST486_FPU_DATA_REG SourceOperand,
749 PFAST486_FPU_DATA_REG DestOperand)
750 {
751 ASSERT(!(Operation & ~7));
752
753 /* Check the operation */
754 switch (Operation)
755 {
756 /* FADD */
757 case 0:
758 {
759 Fast486FpuAdd(State, DestOperand, SourceOperand, DestOperand);
760 break;
761 }
762
763 /* FMUL */
764 case 1:
765 {
766 Fast486FpuMultiply(State, DestOperand, SourceOperand, DestOperand);
767 break;
768 }
769
770 /* FCOM */
771 case 2:
772 /* FCOMP */
773 case 3:
774 {
775 Fast486FpuCompare(State, DestOperand, SourceOperand);
776 if (Operation == 3) Fast486FpuPop(State);
777
778 break;
779 }
780
781 /* FSUB */
782 case 4:
783 {
784 Fast486FpuSubtract(State, DestOperand, SourceOperand, DestOperand);
785 break;
786 }
787
788 /* FSUBR */
789 case 5:
790 {
791 Fast486FpuSubtract(State, SourceOperand, DestOperand, DestOperand);
792 break;
793 }
794
795 /* FDIV */
796 case 6:
797 {
798 Fast486FpuDivide(State, DestOperand, SourceOperand, DestOperand);
799 break;
800 }
801
802 /* FDIVR */
803 case 7:
804 {
805 Fast486FpuDivide(State, SourceOperand, DestOperand, DestOperand);
806 break;
807 }
808 }
809 }
810
811 #endif
812
813 /* PUBLIC FUNCTIONS ***********************************************************/
814
815 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD8)
816 {
817 FAST486_MOD_REG_RM ModRegRm;
818 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
819 PFAST486_FPU_DATA_REG SourceOperand, DestOperand;
820 FAST486_FPU_DATA_REG MemoryData;
821
822 /* Get the operands */
823 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
824 {
825 /* Exception occurred */
826 return;
827 }
828
829 FPU_CHECK();
830
831 #ifndef FAST486_NO_FPU
832
833 /* The destination operand is ST0 */
834 DestOperand = &FPU_ST(0);
835
836 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
837 {
838 /* Raise the invalid operation exception */
839 State->FpuStatus.Ie = TRUE;
840
841 if (State->FpuControl.Im)
842 {
843 /* Return the indefinite NaN */
844 DestOperand->Sign = TRUE;
845 DestOperand->Exponent = FPU_MAX_EXPONENT + 1;
846 DestOperand->Mantissa = FPU_INDEFINITE_MANTISSA;
847
848 FPU_SET_TAG(0, FPU_TAG_SPECIAL);
849 }
850 else Fast486FpuException(State);
851
852 return;
853 }
854
855 if (ModRegRm.Memory)
856 {
857 /* Load the source operand from memory */
858 ULONG Value;
859
860 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
861 {
862 /* Exception occurred */
863 return;
864 }
865
866 Fast486FpuFromSingleReal(State, Value, &MemoryData);
867 SourceOperand = &MemoryData;
868 }
869 else
870 {
871 if (FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY)
872 {
873 /* Raise the invalid operation exception */
874 State->FpuStatus.Ie = TRUE;
875
876 if (State->FpuControl.Im)
877 {
878 /* Return the indefinite NaN */
879 DestOperand->Sign = TRUE;
880 DestOperand->Exponent = FPU_MAX_EXPONENT + 1;
881 DestOperand->Mantissa = FPU_INDEFINITE_MANTISSA;
882
883 FPU_SET_TAG(0, FPU_TAG_SPECIAL);
884 }
885 else Fast486FpuException(State);
886
887 return;
888 }
889
890 /* Load the source operand from an FPU register */
891 SourceOperand = &FPU_ST(ModRegRm.SecondRegister);
892 }
893
894 /* Perform the requested operation */
895 Fast486FpuArithmeticOperation(State, ModRegRm.Register, SourceOperand, DestOperand);
896
897 #endif
898 }
899
900 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDC)
901 {
902 FAST486_MOD_REG_RM ModRegRm;
903 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
904 PFAST486_FPU_DATA_REG SourceOperand, DestOperand;
905 FAST486_FPU_DATA_REG MemoryData;
906
907 /* Get the operands */
908 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
909 {
910 /* Exception occurred */
911 return;
912 }
913
914 FPU_CHECK();
915
916 #ifndef FAST486_NO_FPU
917
918 if (ModRegRm.Memory)
919 {
920 ULONGLONG Value;
921
922 /* The destination operand is ST0 */
923 DestOperand = &FPU_ST(0);
924
925 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
926 {
927 /* Raise the invalid operation exception */
928 State->FpuStatus.Ie = TRUE;
929
930 if (State->FpuControl.Im)
931 {
932 /* Return the indefinite NaN */
933 DestOperand->Sign = TRUE;
934 DestOperand->Exponent = FPU_MAX_EXPONENT + 1;
935 DestOperand->Mantissa = FPU_INDEFINITE_MANTISSA;
936
937 FPU_SET_TAG(0, FPU_TAG_SPECIAL);
938 }
939 else Fast486FpuException(State);
940
941 return;
942 }
943
944 /* Load the source operand from memory */
945 if (!Fast486ReadMemory(State,
946 (State->PrefixFlags & FAST486_PREFIX_SEG)
947 ? State->SegmentOverride : FAST486_REG_DS,
948 ModRegRm.MemoryAddress,
949 FALSE,
950 &Value,
951 sizeof(ULONGLONG)))
952 {
953 /* Exception occurred */
954 return;
955 }
956
957 Fast486FpuFromDoubleReal(State, Value, &MemoryData);
958 SourceOperand = &MemoryData;
959 }
960 else
961 {
962 /* The source operand is ST0 */
963 SourceOperand = &FPU_ST(0);
964
965 /* Load the destination operand from an FPU register */
966 DestOperand = &FPU_ST(ModRegRm.SecondRegister);
967
968 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
969 || (FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY))
970 {
971 /* Raise the invalid operation exception */
972 State->FpuStatus.Ie = TRUE;
973
974 if (State->FpuControl.Im)
975 {
976 /* Return the indefinite NaN */
977 DestOperand->Sign = TRUE;
978 DestOperand->Exponent = FPU_MAX_EXPONENT + 1;
979 DestOperand->Mantissa = FPU_INDEFINITE_MANTISSA;
980
981 FPU_SET_TAG(ModRegRm.SecondRegister, FPU_TAG_SPECIAL);
982 }
983 else Fast486FpuException(State);
984
985 return;
986 }
987 }
988
989 /* Perform the requested operation */
990 Fast486FpuArithmeticOperation(State, ModRegRm.Register, SourceOperand, DestOperand);
991
992 #endif
993 }
994
995
996 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD9)
997 {
998 FAST486_MOD_REG_RM ModRegRm;
999 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1000
1001 /* Get the operands */
1002 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1003 {
1004 /* Exception occurred */
1005 return;
1006 }
1007
1008 FPU_CHECK();
1009
1010 #ifndef FAST486_NO_FPU
1011
1012 if (ModRegRm.Memory)
1013 {
1014 switch (ModRegRm.Register)
1015 {
1016 /* FLD */
1017 case 0:
1018 {
1019 ULONG Value;
1020 FAST486_FPU_DATA_REG MemoryData;
1021
1022 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1023 {
1024 /* Exception occurred */
1025 return;
1026 }
1027
1028 Fast486FpuFromSingleReal(State, Value, &MemoryData);
1029 Fast486FpuPush(State, &MemoryData);
1030
1031 break;
1032 }
1033
1034 /* FST */
1035 case 2:
1036 /* FSTP */
1037 case 3:
1038 {
1039 // TODO: NOT IMPLEMENTED
1040 UNIMPLEMENTED;
1041
1042 break;
1043 }
1044
1045 /* FLDENV */
1046 case 4:
1047 {
1048 // TODO: NOT IMPLEMENTED
1049 UNIMPLEMENTED;
1050
1051 break;
1052 }
1053
1054 /* FLDCW */
1055 case 5:
1056 {
1057 Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &State->FpuControl.Value);
1058 break;
1059 }
1060
1061 /* FSTENV */
1062 case 6:
1063 {
1064 // TODO: NOT IMPLEMENTED
1065 UNIMPLEMENTED;
1066
1067 break;
1068 }
1069
1070 /* FSTCW */
1071 case 7:
1072 {
1073 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, State->FpuControl.Value);
1074 break;
1075 }
1076
1077 /* Invalid */
1078 default:
1079 {
1080 Fast486Exception(State, FAST486_EXCEPTION_UD);
1081 return;
1082 }
1083 }
1084 }
1085 else
1086 {
1087 // TODO: NOT IMPLEMENTED
1088 UNIMPLEMENTED;
1089 }
1090
1091 #endif
1092 }
1093
1094 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDA)
1095 {
1096 FAST486_MOD_REG_RM ModRegRm;
1097 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1098 PFAST486_FPU_DATA_REG SourceOperand, DestOperand;
1099 LONG Value;
1100 FAST486_FPU_DATA_REG MemoryData;
1101
1102 /* Get the operands */
1103 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1104 {
1105 /* Exception occurred */
1106 return;
1107 }
1108
1109 FPU_CHECK();
1110
1111 #ifndef FAST486_NO_FPU
1112
1113 if (!ModRegRm.Memory)
1114 {
1115 /* The only valid opcode in this case is FUCOMPP (0xDA 0xE9) */
1116 if ((ModRegRm.Register != 5) && (ModRegRm.SecondRegister != 1))
1117 {
1118 Fast486Exception(State, FAST486_EXCEPTION_UD);
1119 return;
1120 }
1121
1122 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY) || (FPU_GET_TAG(1) == FPU_TAG_EMPTY))
1123 {
1124 /* Raise the invalid operation exception*/
1125 State->FpuStatus.Ie = TRUE;
1126
1127 if (!State->FpuControl.Im) Fast486FpuException(State);
1128 return;
1129 }
1130
1131 /* Compare */
1132 Fast486FpuCompare(State, &FPU_ST(0), &FPU_ST(1));
1133
1134 /* Pop twice */
1135 Fast486FpuPop(State);
1136 Fast486FpuPop(State);
1137
1138 return;
1139 }
1140
1141 /* Load the source operand from memory */
1142 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, (PULONG)&Value))
1143 {
1144 /* Exception occurred */
1145 return;
1146 }
1147
1148 /* The destination operand is always ST0 */
1149 DestOperand = &FPU_ST(0);
1150
1151 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
1152 {
1153 /* Raise the invalid operation exception */
1154 State->FpuStatus.Ie = TRUE;
1155
1156 if (State->FpuControl.Im)
1157 {
1158 /* Return the indefinite NaN */
1159 DestOperand->Sign = TRUE;
1160 DestOperand->Exponent = FPU_MAX_EXPONENT + 1;
1161 DestOperand->Mantissa = FPU_INDEFINITE_MANTISSA;
1162
1163 FPU_SET_TAG(0, FPU_TAG_SPECIAL);
1164 }
1165 else Fast486FpuException(State);
1166
1167 return;
1168 }
1169
1170 Fast486FpuFromInteger(State, (LONGLONG)Value, &MemoryData);
1171 SourceOperand = &MemoryData;
1172
1173 /* Perform the requested operation */
1174 Fast486FpuArithmeticOperation(State, ModRegRm.Register, SourceOperand, DestOperand);
1175
1176 #endif
1177 }
1178
1179 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDB)
1180 {
1181 FAST486_MOD_REG_RM ModRegRm;
1182 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1183
1184 /* Get the operands */
1185 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1186 {
1187 /* Exception occurred */
1188 return;
1189 }
1190
1191 FPU_CHECK();
1192
1193 #ifndef FAST486_NO_FPU
1194
1195 if (ModRegRm.Memory)
1196 {
1197 switch (ModRegRm.Register)
1198 {
1199 /* FILD */
1200 case 0:
1201 {
1202 LONG Value;
1203 FAST486_FPU_DATA_REG Temp;
1204
1205 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, (PULONG)&Value))
1206 {
1207 /* Exception occurred */
1208 return;
1209 }
1210
1211 Fast486FpuFromInteger(State, (LONGLONG)Value, &Temp);
1212 Fast486FpuPush(State, &Temp);
1213
1214 break;
1215 }
1216
1217 /* FIST */
1218 case 2:
1219 /* FISTP */
1220 case 3:
1221 {
1222 LONGLONG Temp = 0;
1223
1224 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY) || (FPU_GET_TAG(0) == FPU_TAG_SPECIAL))
1225 {
1226 /* Raise the invalid operation exception */
1227 State->FpuStatus.Ie = TRUE;
1228
1229 if (!State->FpuControl.Im)
1230 {
1231 Fast486FpuException(State);
1232 return;
1233 }
1234 }
1235 else if (!Fast486FpuToInteger(State, &FPU_ST(0), &Temp))
1236 {
1237 /* Exception occurred */
1238 return;
1239 }
1240
1241 /* Check if it can fit in a signed 32-bit integer */
1242 if ((((ULONGLONG)Temp >> 31) + 1ULL) > 1ULL)
1243 {
1244 State->FpuStatus.Ie = TRUE;
1245
1246 if (State->FpuControl.Im) Temp = 0LL;
1247 else
1248 {
1249 Fast486FpuException(State);
1250 return;
1251 }
1252 }
1253
1254 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, (ULONG)((LONG)Temp)))
1255 {
1256 /* Exception occurred */
1257 return;
1258 }
1259
1260 if (ModRegRm.Register == 3)
1261 {
1262 /* Pop the FPU stack too */
1263 Fast486FpuPop(State);
1264 }
1265
1266 break;
1267 }
1268
1269 /* FLD */
1270 case 5:
1271 {
1272 FAST486_FPU_DATA_REG Value;
1273 UCHAR Buffer[10];
1274
1275 if (!Fast486ReadMemory(State,
1276 (State->PrefixFlags & FAST486_PREFIX_SEG)
1277 ? State->SegmentOverride : FAST486_REG_DS,
1278 ModRegRm.MemoryAddress,
1279 FALSE,
1280 Buffer,
1281 sizeof(Buffer)))
1282 {
1283 /* Exception occurred */
1284 return;
1285 }
1286
1287 Value.Mantissa = *((PULONGLONG)Buffer);
1288 Value.Exponent = *((PUSHORT)&Buffer[8]) & (FPU_MAX_EXPONENT + 1);
1289 Value.Sign = *((PUCHAR)&Buffer[9]) >> 7;
1290
1291 Fast486FpuPush(State, &Value);
1292 break;
1293 }
1294
1295 /* FSTP */
1296 case 7:
1297 {
1298 UCHAR Buffer[10];
1299
1300 if (FPU_GET_TAG(0) != FPU_TAG_EMPTY)
1301 {
1302 *((PULONGLONG)Buffer) = FPU_ST(0).Mantissa;
1303 *((PUSHORT)&Buffer[sizeof(ULONGLONG)]) = FPU_ST(0).Exponent
1304 | (FPU_ST(0).Sign ? 0x8000 : 0);
1305 }
1306 else
1307 {
1308 /* Raise the invalid operation exception */
1309 State->FpuStatus.Ie = TRUE;
1310
1311 if (State->FpuControl.Im)
1312 {
1313 *((PULONGLONG)Buffer) = FPU_INDEFINITE_MANTISSA;
1314 *((PUSHORT)&Buffer[sizeof(ULONGLONG)]) = 0x8000 | (FPU_MAX_EXPONENT + 1);
1315 }
1316 else
1317 {
1318 Fast486FpuException(State);
1319 return;
1320 }
1321 }
1322
1323 if (!Fast486WriteMemory(State,
1324 (State->PrefixFlags & FAST486_PREFIX_SEG)
1325 ? State->SegmentOverride : FAST486_REG_DS,
1326 ModRegRm.MemoryAddress,
1327 Buffer,
1328 sizeof(Buffer)))
1329 {
1330 /* Exception occurred */
1331 return;
1332 }
1333
1334 Fast486FpuPop(State);
1335 break;
1336 }
1337
1338 /* Invalid */
1339 default:
1340 {
1341 Fast486Exception(State, FAST486_EXCEPTION_UD);
1342 return;
1343 }
1344 }
1345 }
1346 else
1347 {
1348 /* Only a few of these instructions have any meaning on a 487 */
1349 switch ((ModRegRm.Register << 3) | ModRegRm.SecondRegister)
1350 {
1351 /* FCLEX */
1352 case 0x22:
1353 {
1354 /* Clear exception data */
1355 State->FpuStatus.Ie =
1356 State->FpuStatus.De =
1357 State->FpuStatus.Ze =
1358 State->FpuStatus.Oe =
1359 State->FpuStatus.Ue =
1360 State->FpuStatus.Pe =
1361 State->FpuStatus.Sf =
1362 State->FpuStatus.Es =
1363 State->FpuStatus.Busy = FALSE;
1364
1365 break;
1366 }
1367
1368 /* FINIT */
1369 case 0x23:
1370 {
1371 /* Restore the state */
1372 State->FpuControl.Value = FAST486_FPU_DEFAULT_CONTROL;
1373 State->FpuStatus.Value = 0;
1374 State->FpuTag = 0xFFFF;
1375
1376 break;
1377 }
1378
1379 /* FENI */
1380 case 0x20:
1381 /* FDISI */
1382 case 0x21:
1383 {
1384 /* These do nothing */
1385 break;
1386 }
1387
1388 /* Invalid */
1389 default:
1390 {
1391 Fast486Exception(State, FAST486_EXCEPTION_UD);
1392 return;
1393 }
1394 }
1395 }
1396
1397 #endif
1398 }
1399
1400 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDD)
1401 {
1402 FAST486_MOD_REG_RM ModRegRm;
1403 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1404
1405 /* Get the operands */
1406 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1407 {
1408 /* Exception occurred */
1409 return;
1410 }
1411
1412 FPU_CHECK();
1413
1414 #ifndef FAST486_NO_FPU
1415
1416 if (ModRegRm.Memory)
1417 {
1418 switch (ModRegRm.Register)
1419 {
1420 /* FLD */
1421 case 0:
1422 {
1423 ULONGLONG Value;
1424 FAST486_FPU_DATA_REG MemoryData;
1425
1426 if (!Fast486ReadMemory(State,
1427 (State->PrefixFlags & FAST486_PREFIX_SEG)
1428 ? State->SegmentOverride : FAST486_REG_DS,
1429 ModRegRm.MemoryAddress,
1430 FALSE,
1431 &Value,
1432 sizeof(ULONGLONG)))
1433 {
1434 /* Exception occurred */
1435 return;
1436 }
1437
1438 Fast486FpuFromDoubleReal(State, Value, &MemoryData);
1439 Fast486FpuPush(State, &MemoryData);
1440
1441 break;
1442 }
1443
1444 /* FST */
1445 case 2:
1446 /* FSTP */
1447 case 3:
1448 {
1449 ULONGLONG Value = FPU_REAL8_INDEFINITE;
1450
1451 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
1452 {
1453 /* Raise the invalid operation exception */
1454 State->FpuStatus.Ie = TRUE;
1455
1456 if (!State->FpuControl.Im)
1457 {
1458 Fast486FpuException(State);
1459 return;
1460 }
1461 }
1462 else if (!Fast486FpuToDoubleReal(State, &FPU_ST(0), &Value))
1463 {
1464 /* Exception occurred */
1465 return;
1466 }
1467
1468 if (!Fast486WriteMemory(State,
1469 (State->PrefixFlags & FAST486_PREFIX_SEG)
1470 ? State->SegmentOverride : FAST486_REG_DS,
1471 ModRegRm.MemoryAddress,
1472 &Value,
1473 sizeof(ULONGLONG)))
1474 {
1475 /* Exception occurred */
1476 return;
1477 }
1478
1479 if (ModRegRm.Register == 3) Fast486FpuPop(State);
1480 break;
1481 }
1482
1483 /* FRSTOR */
1484 case 4:
1485 {
1486 // TODO: NOT IMPLEMENTED
1487 UNIMPLEMENTED;
1488
1489 break;
1490 }
1491
1492 /* FSAVE */
1493 case 6:
1494 {
1495 // TODO: NOT IMPLEMENTED
1496 UNIMPLEMENTED;
1497
1498 break;
1499 }
1500
1501 /* FSTSW */
1502 case 7:
1503 {
1504 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, State->FpuStatus.Value);
1505 break;
1506 }
1507
1508 /* Invalid */
1509 default:
1510 {
1511 Fast486Exception(State, FAST486_EXCEPTION_UD);
1512 }
1513 }
1514 }
1515 else
1516 {
1517 switch (ModRegRm.Register)
1518 {
1519 /* FFREE */
1520 case 0:
1521 {
1522 FPU_SET_TAG(ModRegRm.SecondRegister, FPU_TAG_EMPTY);
1523 break;
1524 }
1525
1526 /* FXCH */
1527 case 1:
1528 {
1529 FAST486_FPU_DATA_REG Temp;
1530
1531 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
1532 || FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY)
1533 {
1534 State->FpuStatus.Ie = TRUE;
1535
1536 if (!State->FpuControl.Im) Fast486FpuException(State);
1537 break;
1538 }
1539
1540 /* Exchange */
1541 Temp = FPU_ST(0);
1542 FPU_ST(0) = FPU_ST(ModRegRm.SecondRegister);
1543 FPU_ST(ModRegRm.SecondRegister) = Temp;
1544
1545 FPU_UPDATE_TAG(0);
1546 FPU_UPDATE_TAG(ModRegRm.SecondRegister);
1547
1548 break;
1549 }
1550
1551 /* FST */
1552 case 2:
1553 /* FSTP */
1554 case 3:
1555 {
1556 FPU_ST(ModRegRm.SecondRegister) = FPU_ST(0);
1557 FPU_UPDATE_TAG(ModRegRm.SecondRegister);
1558
1559 if (ModRegRm.Register == 3) Fast486FpuPop(State);
1560 break;
1561 }
1562
1563 /* FUCOM */
1564 case 4:
1565 /* FUCOMP */
1566 case 5:
1567 {
1568 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
1569 || (FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY))
1570 {
1571 State->FpuStatus.Ie = TRUE;
1572
1573 if (!State->FpuControl.Im) Fast486FpuException(State);
1574 return;
1575 }
1576
1577 Fast486FpuCompare(State, &FPU_ST(0), &FPU_ST(ModRegRm.SecondRegister));
1578 if (ModRegRm.Register == 5) Fast486FpuPop(State);
1579
1580 break;
1581 }
1582
1583 /* Invalid */
1584 default:
1585 {
1586 Fast486Exception(State, FAST486_EXCEPTION_UD);
1587 }
1588 }
1589 }
1590
1591 #endif
1592 }
1593
1594 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDE)
1595 {
1596 FAST486_MOD_REG_RM ModRegRm;
1597 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1598 PFAST486_FPU_DATA_REG SourceOperand, DestOperand;
1599
1600 /* Get the operands */
1601 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1602 {
1603 /* Exception occurred */
1604 return;
1605 }
1606
1607 FPU_CHECK();
1608
1609 #ifndef FAST486_NO_FPU
1610
1611 if (ModRegRm.Memory)
1612 {
1613 SHORT Value;
1614 FAST486_FPU_DATA_REG MemoryData;
1615
1616 /* The destination operand is ST0 */
1617 DestOperand = &FPU_ST(0);
1618
1619 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
1620 {
1621 /* Raise the invalid operation exception */
1622 State->FpuStatus.Ie = TRUE;
1623
1624 if (State->FpuControl.Im)
1625 {
1626 /* Return the indefinite NaN */
1627 DestOperand->Sign = TRUE;
1628 DestOperand->Exponent = FPU_MAX_EXPONENT + 1;
1629 DestOperand->Mantissa = FPU_INDEFINITE_MANTISSA;
1630
1631 FPU_SET_TAG(0, FPU_TAG_SPECIAL);
1632 }
1633 else Fast486FpuException(State);
1634
1635 return;
1636 }
1637
1638 /* Load the source operand from memory */
1639 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, (PUSHORT)&Value))
1640 {
1641 /* Exception occurred */
1642 return;
1643 }
1644
1645 Fast486FpuFromInteger(State, (LONGLONG)Value, &MemoryData);
1646 SourceOperand = &MemoryData;
1647 }
1648 else
1649 {
1650 /* FCOMPP check */
1651 if ((ModRegRm.Register == 3) && (ModRegRm.SecondRegister != 1))
1652 {
1653 /* Invalid */
1654 Fast486Exception(State, FAST486_EXCEPTION_UD);
1655 return;
1656 }
1657
1658 /* The source operand is ST0 */
1659 SourceOperand = &FPU_ST(0);
1660
1661 /* Load the destination operand from a register */
1662 DestOperand = &FPU_ST(ModRegRm.SecondRegister);
1663
1664 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
1665 || (FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY))
1666 {
1667 /* Raise the invalid operation exception, if unmasked */
1668 State->FpuStatus.Ie = TRUE;
1669
1670 if (!State->FpuControl.Im) Fast486FpuException(State);
1671 return;
1672 }
1673 }
1674
1675 /* Perform the requested operation */
1676 Fast486FpuArithmeticOperation(State, ModRegRm.Register, SourceOperand, DestOperand);
1677 if (!ModRegRm.Memory) Fast486FpuPop(State);
1678
1679 #endif
1680 }
1681
1682 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDF)
1683 {
1684 FAST486_MOD_REG_RM ModRegRm;
1685 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1686
1687 /* Get the operands */
1688 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1689 {
1690 /* Exception occurred */
1691 return;
1692 }
1693
1694 FPU_CHECK();
1695
1696 #ifndef FAST486_NO_FPU
1697
1698 if (ModRegRm.Memory)
1699 {
1700 switch (ModRegRm.Register)
1701 {
1702 /* FILD */
1703 case 0:
1704 {
1705 SHORT Value;
1706 FAST486_FPU_DATA_REG Temp;
1707
1708 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, (PUSHORT)&Value))
1709 {
1710 /* Exception occurred */
1711 return;
1712 }
1713
1714 Fast486FpuFromInteger(State, (LONGLONG)Value, &Temp);
1715 Fast486FpuPush(State, &Temp);
1716
1717 break;
1718 }
1719
1720 /* FIST */
1721 case 2:
1722 /* FISTP */
1723 case 3:
1724 {
1725 LONGLONG Temp = 0LL;
1726
1727 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY) || (FPU_GET_TAG(0) == FPU_TAG_SPECIAL))
1728 {
1729 /* Raise the invalid operation exception */
1730 State->FpuStatus.Ie = TRUE;
1731
1732 if (!State->FpuControl.Im)
1733 {
1734 Fast486FpuException(State);
1735 return;
1736 }
1737 }
1738 else if (!Fast486FpuToInteger(State, &FPU_ST(0), &Temp))
1739 {
1740 /* Exception occurred */
1741 return;
1742 }
1743
1744 /* Check if it can fit in a signed 16-bit integer */
1745 if ((((ULONGLONG)Temp >> 15) + 1ULL) > 1ULL)
1746 {
1747 /* Raise the invalid operation exception */
1748 State->FpuStatus.Ie = TRUE;
1749
1750 if (State->FpuControl.Im) Temp = 0LL;
1751 else
1752 {
1753 Fast486FpuException(State);
1754 return;
1755 }
1756 }
1757
1758 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, (USHORT)((SHORT)Temp)))
1759 {
1760 /* Exception occurred */
1761 return;
1762 }
1763
1764 if (ModRegRm.Register == 3)
1765 {
1766 /* Pop the FPU stack too */
1767 Fast486FpuPop(State);
1768 }
1769
1770 break;
1771 }
1772
1773 /* FBLD */
1774 case 4:
1775 {
1776 FAST486_FPU_DATA_REG Value;
1777 UCHAR Buffer[10];
1778
1779 if (!Fast486ReadMemory(State,
1780 (State->PrefixFlags & FAST486_PREFIX_SEG)
1781 ? State->SegmentOverride : FAST486_REG_DS,
1782 ModRegRm.MemoryAddress,
1783 FALSE,
1784 Buffer,
1785 sizeof(Buffer)))
1786 {
1787 /* Exception occurred */
1788 return;
1789 }
1790
1791 Fast486FpuFromPackedBcd(State, Buffer, &Value);
1792 Fast486FpuPush(State, &Value);
1793
1794 break;
1795 }
1796
1797 /* FILD (64-bit int) */
1798 case 5:
1799 {
1800 LONGLONG Value;
1801 FAST486_FPU_DATA_REG Temp;
1802
1803 if (!Fast486ReadMemory(State,
1804 (State->PrefixFlags & FAST486_PREFIX_SEG)
1805 ? State->SegmentOverride : FAST486_REG_DS,
1806 ModRegRm.MemoryAddress,
1807 FALSE,
1808 &Value,
1809 sizeof(LONGLONG)))
1810 {
1811 /* Exception occurred */
1812 return;
1813 }
1814
1815 Fast486FpuFromInteger(State, (LONGLONG)Value, &Temp);
1816 Fast486FpuPush(State, &Temp);
1817
1818 break;
1819 }
1820
1821 /* FBSTP */
1822 case 6:
1823 {
1824 UCHAR Buffer[10] = {0};
1825
1826 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
1827 {
1828 /* Raise the invalid operation exception */
1829 State->FpuStatus.Ie = TRUE;
1830
1831 if (!State->FpuControl.Im)
1832 {
1833 Fast486FpuException(State);
1834 return;
1835 }
1836 }
1837 else if (!Fast486FpuToPackedBcd(State, &FPU_ST(0), Buffer))
1838 {
1839 /* Exception occurred */
1840 return;
1841 }
1842
1843 if (!Fast486WriteMemory(State,
1844 (State->PrefixFlags & FAST486_PREFIX_SEG)
1845 ? State->SegmentOverride : FAST486_REG_DS,
1846 ModRegRm.MemoryAddress,
1847 Buffer,
1848 sizeof(Buffer)))
1849 {
1850 /* Exception occurred */
1851 return;
1852 }
1853
1854 Fast486FpuPop(State);
1855 break;
1856 }
1857
1858 /* FISTP (64-bit int) */
1859 case 7:
1860 {
1861 LONGLONG Temp = 0LL;
1862
1863 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY) || (FPU_GET_TAG(0) == FPU_TAG_SPECIAL))
1864 {
1865 /* Raise the invalid operation exception */
1866 State->FpuStatus.Ie = TRUE;
1867
1868 if (!State->FpuControl.Im)
1869 {
1870 Fast486FpuException(State);
1871 return;
1872 }
1873 }
1874 else if (!Fast486FpuToInteger(State, &FPU_ST(0), &Temp))
1875 {
1876 /* Exception occurred */
1877 return;
1878 }
1879
1880 if (!Fast486WriteMemory(State,
1881 (State->PrefixFlags & FAST486_PREFIX_SEG)
1882 ? State->SegmentOverride : FAST486_REG_DS,
1883 ModRegRm.MemoryAddress,
1884 &Temp,
1885 sizeof(LONGLONG)))
1886 {
1887 /* Exception occurred */
1888 return;
1889 }
1890
1891 /* Pop the FPU stack too */
1892 Fast486FpuPop(State);
1893
1894 break;
1895 }
1896
1897 /* Invalid */
1898 default:
1899 {
1900 Fast486Exception(State, FAST486_EXCEPTION_UD);
1901 }
1902 }
1903 }
1904 else
1905 {
1906 switch (ModRegRm.Register)
1907 {
1908 /* FFREEP */
1909 case 0:
1910 {
1911 FPU_SET_TAG(ModRegRm.SecondRegister, FPU_TAG_EMPTY);
1912 Fast486FpuPop(State);
1913
1914 break;
1915 }
1916
1917 /* FXCH */
1918 case 1:
1919 {
1920 FAST486_FPU_DATA_REG Temp;
1921
1922 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
1923 || FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY)
1924 {
1925 State->FpuStatus.Ie = TRUE;
1926
1927 if (!State->FpuControl.Im) Fast486FpuException(State);
1928 break;
1929 }
1930
1931 /* Exchange */
1932 Temp = FPU_ST(0);
1933 FPU_ST(0) = FPU_ST(ModRegRm.SecondRegister);
1934 FPU_ST(ModRegRm.SecondRegister) = Temp;
1935
1936 FPU_UPDATE_TAG(0);
1937 FPU_UPDATE_TAG(ModRegRm.SecondRegister);
1938
1939 break;
1940 }
1941
1942 /* FSTP */
1943 case 2:
1944 case 3:
1945 {
1946 FPU_ST(ModRegRm.SecondRegister) = FPU_ST(0);
1947 FPU_UPDATE_TAG(ModRegRm.SecondRegister);
1948 Fast486FpuPop(State);
1949
1950 break;
1951 }
1952
1953 /* FSTSW */
1954 case 4:
1955 {
1956 if (ModRegRm.SecondRegister != 0)
1957 {
1958 /* Invalid */
1959 Fast486Exception(State, FAST486_EXCEPTION_UD);
1960 return;
1961 }
1962
1963 /* Store the status word in AX */
1964 State->GeneralRegs[FAST486_REG_EAX].LowWord = State->FpuStatus.Value;
1965
1966 break;
1967 }
1968
1969 /* Invalid */
1970 default:
1971 {
1972 Fast486Exception(State, FAST486_EXCEPTION_UD);
1973 return;
1974 }
1975 }
1976 }
1977
1978 #endif
1979 }
1980
1981 /* EOF */