xref: /reactos/sdk/lib/fast486/fpu.c (revision 845faec4)
1 /*
2  * Fast486 386/486 CPU Emulation Library
3  * fpu.c
4  *
5  * Copyright (C) 2015 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 = {0xC90FDAA22168C235ULL, FPU_REAL10_BIAS + 1, FALSE};
43 
44 /* lb(10) */
45 static const FAST486_FPU_DATA_REG FpuL2Ten = {0xD49A784BCD1B8AFEULL, FPU_REAL10_BIAS + 1, FALSE};
46 
47 /* lb(e) */
48 static const FAST486_FPU_DATA_REG FpuL2E = {0xB8AA3B295C17F0BCULL, FPU_REAL10_BIAS, FALSE};
49 
50 /* lg(2) */
51 static const FAST486_FPU_DATA_REG FpuLgTwo = {0x9A209A84FBCFF799ULL, FPU_REAL10_BIAS - 2, FALSE};
52 
53 /* ln(2) */
54 static const FAST486_FPU_DATA_REG FpuLnTwo = {0xB17217F7D1CF79ACULL, FPU_REAL10_BIAS - 1, FALSE};
55 
56 /* 2.00 */
57 static const FAST486_FPU_DATA_REG FpuTwo = {0x8000000000000000ULL, FPU_REAL10_BIAS + 1, FALSE};
58 
59 /* Pi / 2 */
60 static const FAST486_FPU_DATA_REG FpuHalfPi = {0xC90FDAA22168C235ULL, FPU_REAL10_BIAS, FALSE};
61 
62 static const FAST486_FPU_DATA_REG FpuInverseNumber[INVERSE_NUMBERS_COUNT] =
63 {
64     {0x8000000000000000ULL, FPU_REAL10_BIAS,     FALSE}, /* 1 / 1 */
65     {0x8000000000000000ULL, FPU_REAL10_BIAS - 1, FALSE}, /* 1 / 2 */
66     {0xAAAAAAAAAAAAAAABULL, FPU_REAL10_BIAS - 2, FALSE}, /* 1 / 3 */
67     {0x8000000000000000ULL, FPU_REAL10_BIAS - 2, FALSE}, /* 1 / 4 */
68     {0xCCCCCCCCCCCCCCCDULL, FPU_REAL10_BIAS - 3, FALSE}, /* 1 / 5 */
69     {0xAAAAAAAAAAAAAAAAULL, FPU_REAL10_BIAS - 3, FALSE}, /* 1 / 6 */
70     {0x9249249249249249ULL, FPU_REAL10_BIAS - 3, FALSE}, /* 1 / 7 */
71     {0x8000000000000000ULL, FPU_REAL10_BIAS - 3, FALSE}, /* 1 / 8 */
72     {0xE38E38E38E38E38EULL, FPU_REAL10_BIAS - 4, FALSE}, /* 1 / 9 */
73     {0xCCCCCCCCCCCCCCCDULL, FPU_REAL10_BIAS - 4, FALSE}, /* 1 / 10 */
74     {0xBA2E8BA2E8BA2E8CULL, FPU_REAL10_BIAS - 4, FALSE}, /* 1 / 11 */
75     {0xAAAAAAAAAAAAAAABULL, FPU_REAL10_BIAS - 4, FALSE}, /* 1 / 12 */
76     {0x9D89D89D89D89D8AULL, FPU_REAL10_BIAS - 4, FALSE}, /* 1 / 13 */
77     {0x9249249249249249ULL, FPU_REAL10_BIAS - 4, FALSE}, /* 1 / 14 */
78     {0x8888888888888889ULL, FPU_REAL10_BIAS - 4, FALSE}, /* 1 / 15 */
79     {0x8000000000000000ULL, FPU_REAL10_BIAS - 4, FALSE}, /* 1 / 16 */
80     {0xF0F0F0F0F0F0F0F0ULL, FPU_REAL10_BIAS - 5, FALSE}, /* 1 / 17 */
81     {0xE38E38E38E38E38EULL, FPU_REAL10_BIAS - 5, FALSE}, /* 1 / 18 */
82     {0xD79435E50D79435EULL, FPU_REAL10_BIAS - 5, FALSE}, /* 1 / 19 */
83     {0xCCCCCCCCCCCCCCCDULL, FPU_REAL10_BIAS - 5, FALSE}, /* 1 / 20 */
84     {0xC30C30C30C30C30CULL, FPU_REAL10_BIAS - 5, FALSE}, /* 1 / 21 */
85     {0xBA2E8BA2E8BA2E8BULL, FPU_REAL10_BIAS - 5, FALSE}, /* 1 / 22 */
86     {0xB21642C8590B2164ULL, FPU_REAL10_BIAS - 5, FALSE}, /* 1 / 23 */
87     {0xAAAAAAAAAAAAAAABULL, FPU_REAL10_BIAS - 5, FALSE}, /* 1 / 24 */
88     {0xA3D70A3D70A3D70AULL, FPU_REAL10_BIAS - 5, FALSE}, /* 1 / 25 */
89     {0x9D89D89D89D89D8AULL, FPU_REAL10_BIAS - 5, FALSE}, /* 1 / 26 */
90     {0x97B425ED097B425FULL, FPU_REAL10_BIAS - 5, FALSE}, /* 1 / 27 */
91     {0x9249249249249249ULL, FPU_REAL10_BIAS - 5, FALSE}, /* 1 / 28 */
92     {0x8D3DCB08D3DCB08DULL, FPU_REAL10_BIAS - 5, FALSE}, /* 1 / 29 */
93     {0x8888888888888889ULL, FPU_REAL10_BIAS - 5, FALSE}, /* 1 / 30 */
94     {0x8421084210842108ULL, FPU_REAL10_BIAS - 5, FALSE}, /* 1 / 31 */
95     {0x8000000000000000ULL, FPU_REAL10_BIAS - 5, FALSE}, /* 1 / 32 */
96     {0xF83E0F83E0F83E0FULL, FPU_REAL10_BIAS - 6, FALSE}, /* 1 / 33 */
97     {0xF0F0F0F0F0F0F0F0ULL, FPU_REAL10_BIAS - 6, FALSE}, /* 1 / 34 */
98     {0xEA0EA0EA0EA0EA0EULL, FPU_REAL10_BIAS - 6, FALSE}, /* 1 / 35 */
99     {0xE38E38E38E38E38EULL, FPU_REAL10_BIAS - 6, FALSE}, /* 1 / 36 */
100     {0xDD67C8A60DD67C8AULL, FPU_REAL10_BIAS - 6, FALSE}, /* 1 / 37 */
101     {0xD79435E50D79435EULL, FPU_REAL10_BIAS - 6, FALSE}, /* 1 / 38 */
102     {0xD20D20D20D20D20DULL, FPU_REAL10_BIAS - 6, FALSE}, /* 1 / 39 */
103     {0xCCCCCCCCCCCCCCCDULL, FPU_REAL10_BIAS - 6, FALSE}, /* 1 / 40 */
104     {0xC7CE0C7CE0C7CE0CULL, FPU_REAL10_BIAS - 6, FALSE}, /* 1 / 41 */
105     {0xC30C30C30C30C30CULL, FPU_REAL10_BIAS - 6, FALSE}, /* 1 / 42 */
106     {0xBE82FA0BE82FA0BFULL, FPU_REAL10_BIAS - 6, FALSE}, /* 1 / 43 */
107     {0xBA2E8BA2E8BA2E8BULL, FPU_REAL10_BIAS - 6, FALSE}, /* 1 / 44 */
108     {0xB60B60B60B60B60BULL, FPU_REAL10_BIAS - 6, FALSE}, /* 1 / 45 */
109     {0xB21642C8590B2164ULL, FPU_REAL10_BIAS - 6, FALSE}, /* 1 / 46 */
110     {0xAE4C415C9882B931ULL, FPU_REAL10_BIAS - 6, FALSE}, /* 1 / 47 */
111     {0xAAAAAAAAAAAAAAABULL, FPU_REAL10_BIAS - 6, FALSE}, /* 1 / 48 */
112     {0xA72F05397829CBC1ULL, FPU_REAL10_BIAS - 6, FALSE}, /* 1 / 49 */
113     {0xA3D70A3D70A3D70AULL, FPU_REAL10_BIAS - 6, FALSE}, /* 1 / 50 */
114 };
115 
116 static const FAST486_FPU_DATA_REG FpuInverseNumberSine[INVERSE_NUMBERS_COUNT] =
117 {
118     {0xAAAAAAAAAAAAAAAAULL, FPU_REAL10_BIAS - 3, FALSE}, /* 1 / 6 */
119     {0xCCCCCCCCCCCCCCCCULL, FPU_REAL10_BIAS - 5, FALSE}, /* 1 / 20 */
120     {0xC30C30C30C30C30CULL, FPU_REAL10_BIAS - 6, FALSE}, /* 1 / 42 */
121     {0xE38E38E38E38E38EULL, FPU_REAL10_BIAS - 7, FALSE}, /* 1 / 72 */
122     {0x94F2094F2094F209ULL, FPU_REAL10_BIAS - 7, FALSE}, /* 1 / 110 */
123     {0xD20D20D20D20D20DULL, FPU_REAL10_BIAS - 8, FALSE}, /* 1 / 156 */
124     {0x9C09C09C09C09C09ULL, FPU_REAL10_BIAS - 8, FALSE}, /* 1 / 210 */
125     {0xF0F0F0F0F0F0F0F0ULL, FPU_REAL10_BIAS - 9, FALSE}, /* 1 / 272 */
126     {0xBFA02FE80BFA02FEULL, FPU_REAL10_BIAS - 9, FALSE}, /* 1 / 342 */
127     {0x9C09C09C09C09C09ULL, FPU_REAL10_BIAS - 9, FALSE}, /* 1 / 420 */
128     {0x81848DA8FAF0D277ULL, FPU_REAL10_BIAS - 9, FALSE}, /* 1 / 506 */
129     {0xDA740DA740DA740DULL, FPU_REAL10_BIAS - 10, FALSE}, /* 1 / 600 */
130     {0xBAB656100BAB6561ULL, FPU_REAL10_BIAS - 10, FALSE}, /* 1 / 702 */
131     {0xA16B312EA8FC377CULL, FPU_REAL10_BIAS - 10, FALSE}, /* 1 / 812 */
132     {0x8CF008CF008CF008ULL, FPU_REAL10_BIAS - 10, FALSE}, /* 1 / 930 */
133     {0xF83E0F83E0F83E0FULL, FPU_REAL10_BIAS - 11, FALSE}, /* 1 / 1056 */
134     {0xDC4A00DC4A00DC4AULL, FPU_REAL10_BIAS - 11, FALSE}, /* 1 / 1190 */
135     {0xC4CE07B00C4CE07BULL, FPU_REAL10_BIAS - 11, FALSE}, /* 1 / 1332 */
136     {0xB0E2A2600B0E2A26ULL, FPU_REAL10_BIAS - 11, FALSE}, /* 1 / 1482 */
137     {0x9FD809FD809FD809ULL, FPU_REAL10_BIAS - 11, FALSE}, /* 1 / 1640 */
138     {0x9126D6E4802449B5ULL, FPU_REAL10_BIAS - 11, FALSE}, /* 1 / 1806 */
139     {0x84655D9BAB2F1008ULL, FPU_REAL10_BIAS - 11, FALSE}, /* 1 / 1980 */
140     {0xF2805AF0221A0CC9ULL, FPU_REAL10_BIAS - 12, FALSE}, /* 1 / 2162 */
141     {0xDEE95C4CA037BA57ULL, FPU_REAL10_BIAS - 12, FALSE}, /* 1 / 2352 */
142     {0xCD9A673400CD9A67ULL, FPU_REAL10_BIAS - 12, FALSE}, /* 1 / 2550 */
143     {0xBE3C310B84A4F832ULL, FPU_REAL10_BIAS - 12, FALSE}, /* 1 / 2756 */
144     {0xB087277A39941560ULL, FPU_REAL10_BIAS - 12, FALSE}, /* 1 / 2970 */
145     {0xA44029100A440291ULL, FPU_REAL10_BIAS - 12, FALSE}, /* 1 / 3192 */
146     {0x9936034AA9121AA1ULL, FPU_REAL10_BIAS - 12, FALSE}, /* 1 / 3422 */
147     {0x8F3F82A86DACA008ULL, FPU_REAL10_BIAS - 12, FALSE}, /* 1 / 3660 */
148     {0x8639F00218E7C008ULL, FPU_REAL10_BIAS - 12, FALSE}, /* 1 / 3906 */
149     {0xFC0FC0FC0FC0FC0FULL, FPU_REAL10_BIAS - 13, FALSE}, /* 1 / 4160 */
150     {0xED208916CF412FD1ULL, FPU_REAL10_BIAS - 13, FALSE}, /* 1 / 4422 */
151     {0xDF7B4EC93886702DULL, FPU_REAL10_BIAS - 13, FALSE}, /* 1 / 4692 */
152     {0xD2FB287C7224E167ULL, FPU_REAL10_BIAS - 13, FALSE}, /* 1 / 4970 */
153     {0xC78031E00C78031EULL, FPU_REAL10_BIAS - 13, FALSE}, /* 1 / 5256 */
154     {0xBCEEBFB33F021F2EULL, FPU_REAL10_BIAS - 13, FALSE}, /* 1 / 5550 */
155     {0xB32EB86E96D5D441ULL, FPU_REAL10_BIAS - 13, FALSE}, /* 1 / 5852 */
156     {0xAA2B0A62E08248F3ULL, FPU_REAL10_BIAS - 13, FALSE}, /* 1 / 6162 */
157     {0xA1D139855F7268EDULL, FPU_REAL10_BIAS - 13, FALSE}, /* 1 / 6480 */
158     {0x9A1100604AA03C2EULL, FPU_REAL10_BIAS - 13, FALSE}, /* 1 / 6806 */
159     {0x92DC0092DC0092DCULL, FPU_REAL10_BIAS - 13, FALSE}, /* 1 / 7140 */
160     {0x8C258008C258008CULL, FPU_REAL10_BIAS - 13, FALSE}, /* 1 / 7482 */
161     {0x85E230A32BAB46DDULL, FPU_REAL10_BIAS - 13, FALSE}, /* 1 / 7832 */
162     {0x8008008008008008ULL, FPU_REAL10_BIAS - 13, FALSE}, /* 1 / 8190 */
163     {0xF51BE2CC2D7AAC94ULL, FPU_REAL10_BIAS - 14, FALSE}, /* 1 / 8556 */
164     {0xEAD7EC46DDA80C62ULL, FPU_REAL10_BIAS - 14, FALSE}, /* 1 / 8930 */
165     {0xE135A9C97500E135ULL, FPU_REAL10_BIAS - 14, FALSE}, /* 1 / 9312 */
166     {0xD8281B71177BDB7BULL, FPU_REAL10_BIAS - 14, FALSE}, /* 1 / 9702 */
167     {0xCFA3892CE9FFCC17ULL, FPU_REAL10_BIAS - 14, FALSE}, /* 1 / 10100 */
168 };
169 
170 static const FAST486_FPU_DATA_REG FpuInverseNumberCosine[INVERSE_NUMBERS_COUNT] =
171 {
172     {0x8000000000000000ULL, FPU_REAL10_BIAS - 1, FALSE}, /* 1 / 2 */
173     {0xAAAAAAAAAAAAAAAAULL, FPU_REAL10_BIAS - 4, FALSE}, /* 1 / 12 */
174     {0x8888888888888888ULL, FPU_REAL10_BIAS - 5, FALSE}, /* 1 / 30 */
175     {0x9249249249249249ULL, FPU_REAL10_BIAS - 6, FALSE}, /* 1 / 56 */
176     {0xB60B60B60B60B60BULL, FPU_REAL10_BIAS - 7, FALSE}, /* 1 / 90 */
177     {0xF83E0F83E0F83E0FULL, FPU_REAL10_BIAS - 8, FALSE}, /* 1 / 132 */
178     {0xB40B40B40B40B40BULL, FPU_REAL10_BIAS - 8, FALSE}, /* 1 / 182 */
179     {0x8888888888888888ULL, FPU_REAL10_BIAS - 8, FALSE}, /* 1 / 240 */
180     {0xD62B80D62B80D62BULL, FPU_REAL10_BIAS - 9, FALSE}, /* 1 / 306 */
181     {0xAC7691840AC76918ULL, FPU_REAL10_BIAS - 9, FALSE}, /* 1 / 380 */
182     {0x8DDA520237694808ULL, FPU_REAL10_BIAS - 9, FALSE}, /* 1 / 462 */
183     {0xED7303B5CC0ED730ULL, FPU_REAL10_BIAS - 10, FALSE}, /* 1 / 552 */
184     {0xC9A633FCD967300CULL, FPU_REAL10_BIAS - 10, FALSE}, /* 1 / 650 */
185     {0xAD602B580AD602B5ULL, FPU_REAL10_BIAS - 10, FALSE}, /* 1 / 756 */
186     {0x96A850096A850096ULL, FPU_REAL10_BIAS - 10, FALSE}, /* 1 / 870 */
187     {0x8421084210842108ULL, FPU_REAL10_BIAS - 10, FALSE}, /* 1 / 992 */
188     {0xE9A3D25E00E9A3D2ULL, FPU_REAL10_BIAS - 11, FALSE}, /* 1 / 1122 */
189     {0xD00D00D00D00D00DULL, FPU_REAL10_BIAS - 11, FALSE}, /* 1 / 1260 */
190     {0xBA7258200BA72582ULL, FPU_REAL10_BIAS - 11, FALSE}, /* 1 / 1406 */
191     {0xA80A80A80A80A80AULL, FPU_REAL10_BIAS - 11, FALSE}, /* 1 / 1560 */
192     {0x983B773A92E16009ULL, FPU_REAL10_BIAS - 11, FALSE}, /* 1 / 1722 */
193     {0x8A8DCD1FEEAE465CULL, FPU_REAL10_BIAS - 11, FALSE}, /* 1 / 1892 */
194     {0xFD477B6C956529CDULL, FPU_REAL10_BIAS - 12, FALSE}, /* 1 / 2070 */
195     {0xE865AC7B7603A196ULL, FPU_REAL10_BIAS - 12, FALSE}, /* 1 / 2256 */
196     {0xD5FEBF01E17D2DC4ULL, FPU_REAL10_BIAS - 12, FALSE}, /* 1 / 2450 */
197     {0xC5B200C5B200C5B2ULL, FPU_REAL10_BIAS - 12, FALSE}, /* 1 / 2652 */
198     {0xB7307B1492B1D28FULL, FPU_REAL10_BIAS - 12, FALSE}, /* 1 / 2862 */
199     {0xAA392F35DC17F00AULL, FPU_REAL10_BIAS - 12, FALSE}, /* 1 / 3080 */
200     {0x9E96394D47B46C68ULL, FPU_REAL10_BIAS - 12, FALSE}, /* 1 / 3306 */
201     {0x941A9CC82BF7E68BULL, FPU_REAL10_BIAS - 12, FALSE}, /* 1 / 3540 */
202     {0x8AA08EF5936D4008ULL, FPU_REAL10_BIAS - 12, FALSE}, /* 1 / 3782 */
203     {0x8208208208208208ULL, FPU_REAL10_BIAS - 12, FALSE}, /* 1 / 4032 */
204     {0xF46C5E0BB22F800FULL, FPU_REAL10_BIAS - 13, FALSE}, /* 1 / 4290 */
205     {0xE6271BA5329217D3ULL, FPU_REAL10_BIAS - 13, FALSE}, /* 1 / 4556 */
206     {0xD918B2EF5B7B4866ULL, FPU_REAL10_BIAS - 13, FALSE}, /* 1 / 4830 */
207     {0xCD1ED923A7DCBEB2ULL, FPU_REAL10_BIAS - 13, FALSE}, /* 1 / 5112 */
208     {0xC21BDD800C21BDD8ULL, FPU_REAL10_BIAS - 13, FALSE}, /* 1 / 5402 */
209     {0xB7F5F08CD84C2BD5ULL, FPU_REAL10_BIAS - 13, FALSE}, /* 1 / 5700 */
210     {0xAE968C517F46800AULL, FPU_REAL10_BIAS - 13, FALSE}, /* 1 / 6006 */
211     {0xA5E9F6ED347F0721ULL, FPU_REAL10_BIAS - 13, FALSE}, /* 1 / 6320 */
212     {0x9DDEDA75A1CD4726ULL, FPU_REAL10_BIAS - 13, FALSE}, /* 1 / 6642 */
213     {0x9665EE14DB2283E4ULL, FPU_REAL10_BIAS - 13, FALSE}, /* 1 / 6972 */
214     {0x8F71AD362448008FULL, FPU_REAL10_BIAS - 13, FALSE}, /* 1 / 7310 */
215     {0x88F61A371B048C2BULL, FPU_REAL10_BIAS - 13, FALSE}, /* 1 / 7656 */
216     {0x82E88A942AB2D933ULL, FPU_REAL10_BIAS - 13, FALSE}, /* 1 / 8010 */
217     {0xFA7EF5D91AC9538AULL, FPU_REAL10_BIAS - 14, FALSE}, /* 1 / 8372 */
218     {0xEFE4D31416B96CFEULL, FPU_REAL10_BIAS - 14, FALSE}, /* 1 / 8742 */
219     {0xE5F36CB00E5F36CBULL, FPU_REAL10_BIAS - 14, FALSE}, /* 1 / 9120 */
220     {0xDC9D0ECFCB6E9378ULL, FPU_REAL10_BIAS - 14, FALSE}, /* 1 / 9506 */
221     {0xD3D56292AB7E800DULL, FPU_REAL10_BIAS - 14, FALSE}, /* 1 / 9900 */
222 };
223 
224 static const FAST486_FPU_DATA_REG FpuInverseNumberAtan[INVERSE_NUMBERS_COUNT] =
225 {
226     {0xAAAAAAAAAAAAAAAAULL, FPU_REAL10_BIAS - 1, FALSE}, /* 2 / 3 */
227     {0xCCCCCCCCCCCCCCCCULL, FPU_REAL10_BIAS - 1, FALSE}, /* 4 / 5 */
228     {0xDB6DB6DB6DB6DB6DULL, FPU_REAL10_BIAS - 1, FALSE}, /* 6 / 7 */
229     {0xE38E38E38E38E38EULL, FPU_REAL10_BIAS - 1, FALSE}, /* 8 / 9 */
230     {0xE8BA2E8BA2E8BA2EULL, FPU_REAL10_BIAS - 1, FALSE}, /* 10 / 11 */
231     {0xEC4EC4EC4EC4EC4EULL, FPU_REAL10_BIAS - 1, FALSE}, /* 12 / 13 */
232     {0xEEEEEEEEEEEEEEEEULL, FPU_REAL10_BIAS - 1, FALSE}, /* 14 / 15 */
233     {0xF0F0F0F0F0F0F0F0ULL, FPU_REAL10_BIAS - 1, FALSE}, /* 16 / 17 */
234     {0xF286BCA1AF286BCAULL, FPU_REAL10_BIAS - 1, FALSE}, /* 18 / 19 */
235     {0xF3CF3CF3CF3CF3CFULL, FPU_REAL10_BIAS - 1, FALSE}, /* 20 / 21 */
236     {0xF4DE9BD37A6F4DE9ULL, FPU_REAL10_BIAS - 1, FALSE}, /* 22 / 23 */
237     {0xF5C28F5C28F5C28FULL, FPU_REAL10_BIAS - 1, FALSE}, /* 24 / 25 */
238     {0xF684BDA12F684BDAULL, FPU_REAL10_BIAS - 1, FALSE}, /* 26 / 27 */
239     {0xF72C234F72C234F7ULL, FPU_REAL10_BIAS - 1, FALSE}, /* 28 / 29 */
240     {0xF7BDEF7BDEF7BDEFULL, FPU_REAL10_BIAS - 1, FALSE}, /* 30 / 31 */
241     {0xF83E0F83E0F83E0FULL, FPU_REAL10_BIAS - 1, FALSE}, /* 32 / 33 */
242     {0xF8AF8AF8AF8AF8AFULL, FPU_REAL10_BIAS - 1, FALSE}, /* 34 / 35 */
243     {0xF914C1BACF914C1BULL, FPU_REAL10_BIAS - 1, FALSE}, /* 36 / 37 */
244     {0xF96F96F96F96F96FULL, FPU_REAL10_BIAS - 1, FALSE}, /* 38 / 39 */
245     {0xF9C18F9C18F9C18FULL, FPU_REAL10_BIAS - 1, FALSE}, /* 40 / 41 */
246     {0xFA0BE82FA0BE82FAULL, FPU_REAL10_BIAS - 1, FALSE}, /* 42 / 43 */
247     {0xFA4FA4FA4FA4FA4FULL, FPU_REAL10_BIAS - 1, FALSE}, /* 44 / 45 */
248     {0xFA8D9DF51B3BEA36ULL, FPU_REAL10_BIAS - 1, FALSE}, /* 46 / 47 */
249     {0xFAC687D6343EB1A1ULL, FPU_REAL10_BIAS - 1, FALSE}, /* 48 / 49 */
250     {0xFAFAFAFAFAFAFAFAULL, FPU_REAL10_BIAS - 1, FALSE}, /* 50 / 51 */
251     {0xFB2B78C13521CFB2ULL, FPU_REAL10_BIAS - 1, FALSE}, /* 52 / 53 */
252     {0xFB586FB586FB586FULL, FPU_REAL10_BIAS - 1, FALSE}, /* 54 / 55 */
253     {0xFB823EE08FB823EEULL, FPU_REAL10_BIAS - 1, FALSE}, /* 56 / 57 */
254     {0xFBA9386822B63CBEULL, FPU_REAL10_BIAS - 1, FALSE}, /* 58 / 59 */
255     {0xFBCDA3AC10C9714FULL, FPU_REAL10_BIAS - 1, FALSE}, /* 60 / 61 */
256     {0xFBEFBEFBEFBEFBEFULL, FPU_REAL10_BIAS - 1, FALSE}, /* 62 / 63 */
257     {0xFC0FC0FC0FC0FC0FULL, FPU_REAL10_BIAS - 1, FALSE}, /* 64 / 65 */
258     {0xFC2DD9CA81E9131AULL, FPU_REAL10_BIAS - 1, FALSE}, /* 66 / 67 */
259     {0xFC4A33F128CFC4A3ULL, FPU_REAL10_BIAS - 1, FALSE}, /* 68 / 69 */
260     {0xFC64F52EDF8C9EA5ULL, FPU_REAL10_BIAS - 1, FALSE}, /* 70 / 71 */
261     {0xFC7E3F1F8FC7E3F1ULL, FPU_REAL10_BIAS - 1, FALSE}, /* 72 / 73 */
262     {0xFC962FC962FC962FULL, FPU_REAL10_BIAS - 1, FALSE}, /* 74 / 75 */
263     {0xFCACE213F2B3884FULL, FPU_REAL10_BIAS - 1, FALSE}, /* 76 / 77 */
264     {0xFCC26E2D5DF984DCULL, FPU_REAL10_BIAS - 1, FALSE}, /* 78 / 79 */
265     {0xFCD6E9E06522C3F3ULL, FPU_REAL10_BIAS - 1, FALSE}, /* 80 / 81 */
266     {0xFCEA68DE12818ACBULL, FPU_REAL10_BIAS - 1, FALSE}, /* 82 / 83 */
267     {0xFCFCFCFCFCFCFCFCULL, FPU_REAL10_BIAS - 1, FALSE}, /* 84 / 85 */
268     {0xFD0EB66FD0EB66FDULL, FPU_REAL10_BIAS - 1, FALSE}, /* 86 / 87 */
269     {0xFD1FA3F47E8FD1FAULL, FPU_REAL10_BIAS - 1, FALSE}, /* 88 / 89 */
270     {0xFD2FD2FD2FD2FD2FULL, FPU_REAL10_BIAS - 1, FALSE}, /* 90 / 91 */
271     {0xFD3F4FD3F4FD3F4FULL, FPU_REAL10_BIAS - 1, FALSE}, /* 92 / 93 */
272     {0xFD4E25B9EFD4E25BULL, FPU_REAL10_BIAS - 1, FALSE}, /* 94 / 95 */
273     {0xFD5C5F02A3A0FD5CULL, FPU_REAL10_BIAS - 1, FALSE}, /* 96 / 97 */
274     {0xFD6A052BF5A814AFULL, FPU_REAL10_BIAS - 1, FALSE}, /* 98 / 99 */
275     {0xFD7720F353A4C0A2ULL, FPU_REAL10_BIAS - 1, FALSE}, /* 100 / 101 */
276 };
277 
278 /* PRIVATE FUNCTIONS **********************************************************/
279 
280 #ifndef FAST486_NO_FPU
281 
282 static ULONGLONG
283 UnsignedMult128(ULONGLONG Multiplicand,
284                 ULONGLONG Multiplier,
285                 ULONGLONG *HighProduct)
286 {
287     ULONG MultiplicandLow, MultiplicandHigh, MultiplierLow, MultiplierHigh;
288     ULONG IntermediateLow, IntermediateHigh;
289     ULONGLONG LowProduct, Intermediate, Intermediate1, Intermediate2;
290 
291     MultiplicandLow = (ULONG)(Multiplicand & 0xFFFFFFFFULL);
292     MultiplicandHigh = (ULONG)(Multiplicand >> 32);
293     MultiplierLow = (ULONG)(Multiplier & 0xFFFFFFFFULL);
294     MultiplierHigh = (ULONG)(Multiplier >> 32);
295 
296     LowProduct = (ULONGLONG)MultiplicandLow * (ULONGLONG)MultiplierLow;
297     Intermediate1 = (ULONGLONG)MultiplicandLow * (ULONGLONG)MultiplierHigh;
298     Intermediate2 = (ULONGLONG)MultiplicandHigh * (ULONGLONG)MultiplierLow;
299     *HighProduct = (ULONGLONG)MultiplicandHigh * (ULONGLONG)MultiplierHigh;
300 
301     Intermediate = Intermediate1 + Intermediate2;
302     if (Intermediate < Intermediate1) *HighProduct += 1ULL << 32;
303 
304     IntermediateLow = (ULONG)(Intermediate & 0xFFFFFFFFULL);
305     IntermediateHigh = (ULONG)(Intermediate >> 32);
306 
307     LowProduct += (ULONGLONG)IntermediateLow << 32;
308     if ((ULONG)(LowProduct >> 32) < IntermediateLow) (*HighProduct)++;
309 
310     *HighProduct += IntermediateHigh;
311     return LowProduct;
312 }
313 
314 static ULONGLONG
315 UnsignedDivMod128(ULONGLONG DividendLow,
316                   ULONGLONG DividendHigh,
317                   ULONGLONG Divisor,
318                   PULONGLONG QuotientLow,
319                   PULONGLONG QuotientHigh)
320 {
321     ULONGLONG ValueLow = DividendLow;
322     ULONGLONG ValueHigh = DividendHigh;
323     ULONGLONG CurrentLow = 0ULL;
324     ULONGLONG CurrentHigh = Divisor;
325     ULONG Bits;
326 
327     ASSERT(Divisor != 0ULL);
328 
329     /* Initialize the quotient */
330     *QuotientLow = *QuotientHigh = 0ULL;
331 
332     /* Exit early if the dividend is lower than the divisor */
333     if ((DividendHigh == 0ULL) && (DividendLow < Divisor)) return ValueLow;
334 
335     /* Normalize the current divisor */
336     Bits = CountLeadingZeros64(CurrentHigh);
337     CurrentHigh <<= Bits;
338 
339     while (TRUE)
340     {
341         /* Shift the quotient left by one bit */
342         *QuotientHigh <<= 1;
343         *QuotientHigh |= *QuotientLow >> 63;
344         *QuotientLow <<= 1;
345 
346         /* Check if the value is higher than or equal to the current divisor */
347         if ((ValueHigh > CurrentHigh)
348             || ((ValueHigh == CurrentHigh) && (ValueLow >= CurrentLow)))
349         {
350             BOOLEAN Carry = ValueLow < CurrentLow;
351 
352             /* Subtract the current divisor from the value */
353             ValueHigh -= CurrentHigh;
354             ValueLow -= CurrentLow;
355             if (Carry) ValueHigh--;
356 
357             /* Set the lowest bit of the quotient */
358             *QuotientLow |= 1;
359 
360             /* Stop if the value is lower than the original divisor */
361             if ((ValueHigh == 0ULL) && (ValueLow < Divisor)) break;
362         }
363 
364         /* Shift the current divisor right by one bit */
365         CurrentLow >>= 1;
366         CurrentLow |= (CurrentHigh & 1) << 63;
367         CurrentHigh >>= 1;
368     }
369 
370     /*
371      * Calculate the number of significant bits the current
372      * divisor has more than the original divisor
373      */
374     Bits = CountLeadingZeros64(Divisor);
375     if (CurrentHigh > 0ULL) Bits += 64 - CountLeadingZeros64(CurrentHigh);
376     else Bits -= CountLeadingZeros64(CurrentLow);
377 
378     if (Bits >= 64)
379     {
380         *QuotientHigh = *QuotientLow;
381         *QuotientLow = 0ULL;
382         Bits -= 64;
383     }
384 
385     if (Bits)
386     {
387         /* Shift the quotient left by that amount */
388         *QuotientHigh <<= Bits;
389         *QuotientHigh |= *QuotientLow >> (64 - Bits);
390         *QuotientLow <<= Bits;
391     }
392 
393     /* Return the remainder */
394     return ValueLow;
395 }
396 
397 static inline VOID FASTCALL
398 Fast486FpuRound(PFAST486_STATE State,
399                 PULONGLONG Result,
400                 BOOLEAN Sign,
401                 ULONGLONG Remainder,
402                 INT RemainderHighBit)
403 {
404     switch (State->FpuControl.Rc)
405     {
406         case FPU_ROUND_NEAREST:
407         {
408             /* Check if the highest bit of the remainder is set */
409             if (Remainder & (1ULL << RemainderHighBit))
410             {
411                 (*Result)++;
412 
413                 /* Check if all the other bits are clear */
414                 if (!(Remainder & ((1ULL << RemainderHighBit) - 1ULL)))
415                 {
416                     /* Round to even */
417                     *Result &= ~1ULL;
418                 }
419             }
420 
421             break;
422         }
423 
424         case FPU_ROUND_DOWN:
425         {
426             if ((Remainder != 0ULL) && Sign) (*Result)++;
427             break;
428         }
429 
430         case FPU_ROUND_UP:
431         {
432             if ((Remainder != 0ULL) && !Sign) (*Result)++;
433             break;
434         }
435 
436         default:
437         {
438             /* Leave it truncated */
439         }
440     }
441 }
442 
443 static inline VOID FASTCALL
444 Fast486FpuFromInteger(PFAST486_STATE State,
445                       LONGLONG Value,
446                       PFAST486_FPU_DATA_REG Result)
447 {
448     ULONG ZeroCount;
449 
450     Result->Sign = Result->Exponent = Result->Mantissa = 0;
451     if (Value == 0LL) return;
452 
453     if (Value < 0LL)
454     {
455         Result->Sign = TRUE;
456         Value = -Value;
457     }
458 
459     Result->Mantissa = (ULONGLONG)Value;
460     ZeroCount = CountLeadingZeros64(Result->Mantissa);
461 
462     Result->Mantissa <<= ZeroCount;
463     Result->Exponent = FPU_REAL10_BIAS + 63 - ZeroCount;
464 }
465 
466 static inline BOOLEAN FASTCALL
467 Fast486FpuToInteger(PFAST486_STATE State,
468                     PCFAST486_FPU_DATA_REG Value,
469                     PLONGLONG Result)
470 {
471     ULONG Bits;
472     ULONGLONG Remainder;
473     SHORT UnbiasedExp = (SHORT)Value->Exponent - FPU_REAL10_BIAS;
474 
475     if (FPU_IS_ZERO(Value))
476     {
477         *Result = 0LL;
478         return TRUE;
479     }
480 
481     if (FPU_IS_NAN(Value) || !FPU_IS_NORMALIZED(Value) || (UnbiasedExp >= 63))
482     {
483         /* Raise an invalid operation exception */
484         State->FpuStatus.Ie = TRUE;
485 
486         if (State->FpuControl.Im)
487         {
488             *Result = 0x8000000000000000LL;
489             return TRUE;
490         }
491         else
492         {
493             return FALSE;
494         }
495     }
496 
497     if (UnbiasedExp >= 0)
498     {
499         Bits = 63 - UnbiasedExp;
500 
501         /* Calculate the result and the remainder */
502         *Result = (LONGLONG)(Value->Mantissa >> Bits);
503         Remainder = Value->Mantissa & ((1ULL << Bits) - 1);
504     }
505     else
506     {
507         /* The result is zero */
508         *Result = 0LL;
509         Bits = 64;
510 
511         if (UnbiasedExp >= -64)
512         {
513             Remainder = Value->Mantissa >> (-1 - UnbiasedExp);
514         }
515         else
516         {
517             /* Too small to even have a remainder */
518             Remainder = 0ULL;
519         }
520     }
521 
522     /* The result must be positive here */
523     ASSERT(*Result >= 0LL);
524 
525     /* Perform rounding */
526     Fast486FpuRound(State, (PULONGLONG)Result, Value->Sign, Remainder, Bits - 1);
527 
528     if (Value->Sign) *Result = -*Result;
529     return TRUE;
530 }
531 
532 static inline VOID FASTCALL
533 Fast486FpuFromSingleReal(PFAST486_STATE State,
534                          ULONG Value,
535                          PFAST486_FPU_DATA_REG Result)
536 {
537     /* Extract the sign, exponent and mantissa */
538     Result->Sign = (UCHAR)(Value >> 31);
539     Result->Exponent = (USHORT)((Value >> 23) & 0xFF);
540     Result->Mantissa = (((ULONGLONG)Value & 0x7FFFFFULL) | 0x800000ULL) << 40;
541 
542     /* If this is a zero, we're done */
543     if (Value == 0) return;
544 
545     if (Result->Exponent == 0xFF) Result->Exponent = FPU_MAX_EXPONENT + 1;
546     else
547     {
548         /* Adjust the exponent bias */
549         Result->Exponent += (FPU_REAL10_BIAS - FPU_REAL4_BIAS);
550     }
551 }
552 
553 static inline BOOLEAN FASTCALL
554 Fast486FpuToSingleReal(PFAST486_STATE State,
555                        PCFAST486_FPU_DATA_REG Value,
556                        PULONG Result)
557 {
558     ULONGLONG Remainder;
559     SHORT UnbiasedExp = (SHORT)Value->Exponent - FPU_REAL10_BIAS;
560     ULONGLONG Result64;
561 
562     if (FPU_IS_ZERO(Value))
563     {
564         *Result = 0;
565         return TRUE;
566     }
567 
568     /* Calculate the mantissa */
569     *Result = (ULONG)(Value->Mantissa >> 40) & 0x7FFFFF;
570 
571     if (FPU_IS_NAN(Value))
572     {
573         *Result |= FPU_REAL4_INFINITY;
574         goto SetSign;
575     }
576 
577     /* Check for underflow */
578     if (!FPU_IS_NORMALIZED(Value) || (UnbiasedExp < -127))
579     {
580         /* Raise the underflow exception */
581         State->FpuStatus.Ue = TRUE;
582 
583         if (State->FpuControl.Um)
584         {
585             /* The result is zero due to underflow */
586             *Result = 0ULL;
587             return TRUE;
588         }
589         else
590         {
591             return FALSE;
592         }
593     }
594 
595     /* Check for overflow */
596     if (UnbiasedExp > 127)
597     {
598         /* Raise the overflow exception */
599         State->FpuStatus.Oe = TRUE;
600 
601         if (State->FpuControl.Om)
602         {
603             /* The result is infinity due to overflow */
604             *Result = FPU_REAL4_INFINITY;
605             goto SetSign;
606         }
607         else
608         {
609             return FALSE;
610         }
611     }
612 
613     /* Calculate the remainder */
614     Remainder = Value->Mantissa & ((1ULL << 40) - 1);
615 
616     /* Store the biased exponent */
617     *Result |= (ULONG)(UnbiasedExp + FPU_REAL4_BIAS) << 23;
618 
619     /* Perform rounding */
620     Result64 = (ULONGLONG)*Result;
621     Fast486FpuRound(State, &Result64, Value->Sign, Remainder, 39);
622     *Result = (ULONG)Result64;
623 
624 SetSign:
625 
626     if (Value->Sign) *Result |= 0x80000000;
627     return TRUE;
628 }
629 
630 static inline VOID FASTCALL
631 Fast486FpuFromDoubleReal(PFAST486_STATE State,
632                          ULONGLONG Value,
633                          PFAST486_FPU_DATA_REG Result)
634 {
635     /* Extract the sign, exponent and mantissa */
636     Result->Sign = (UCHAR)(Value >> 63);
637     Result->Exponent = (USHORT)((Value >> 52) & 0x7FF);
638     Result->Mantissa = (((ULONGLONG)Value & 0xFFFFFFFFFFFFFULL) | 0x10000000000000ULL) << 11;
639 
640     /* If this is a zero, we're done */
641     if (Value == 0) return;
642 
643     if (Result->Exponent == 0x7FF) Result->Exponent = FPU_MAX_EXPONENT + 1;
644     else
645     {
646         /* Adjust the exponent bias */
647         Result->Exponent += (FPU_REAL10_BIAS - FPU_REAL8_BIAS);
648     }
649 }
650 
651 static inline BOOLEAN FASTCALL
652 Fast486FpuToDoubleReal(PFAST486_STATE State,
653                        PCFAST486_FPU_DATA_REG Value,
654                        PULONGLONG Result)
655 {
656     ULONGLONG Remainder;
657     SHORT UnbiasedExp = (SHORT)Value->Exponent - FPU_REAL10_BIAS;
658 
659     if (FPU_IS_ZERO(Value))
660     {
661         *Result = 0LL;
662         return TRUE;
663     }
664 
665     /* Calculate the mantissa */
666     *Result = (Value->Mantissa >> 11) & ((1ULL << 52) - 1);
667 
668     if (FPU_IS_NAN(Value))
669     {
670         *Result |= FPU_REAL8_INFINITY;
671         goto SetSign;
672     }
673 
674     /* Check for underflow */
675     if (!FPU_IS_NORMALIZED(Value) || (UnbiasedExp < -1023))
676     {
677         /* Raise the underflow exception */
678         State->FpuStatus.Ue = TRUE;
679 
680         if (State->FpuControl.Um)
681         {
682             /* The result is zero due to underflow */
683             *Result = 0ULL;
684             return TRUE;
685         }
686         else
687         {
688             return FALSE;
689         }
690     }
691 
692     /* Check for overflow */
693     if (UnbiasedExp > 1023)
694     {
695         /* Raise the overflow exception */
696         State->FpuStatus.Oe = TRUE;
697 
698         if (State->FpuControl.Om)
699         {
700             /* The result is infinity due to overflow */
701             *Result = FPU_REAL8_INFINITY;
702             goto SetSign;
703         }
704         else
705         {
706             return FALSE;
707         }
708     }
709 
710     /* Calculate the remainder */
711     Remainder = Value->Mantissa & ((1ULL << 11) - 1ULL);
712 
713     /* Store the biased exponent */
714     *Result |= (ULONGLONG)(UnbiasedExp + FPU_REAL8_BIAS) << 52;
715 
716     /* Perform rounding */
717     Fast486FpuRound(State, Result, Value->Sign, Remainder, 10);
718 
719 SetSign:
720 
721     if (Value->Sign) *Result |= 1ULL << 63;
722     return TRUE;
723 }
724 
725 static inline VOID FASTCALL
726 Fast486FpuFromPackedBcd(PFAST486_STATE State,
727                         PUCHAR Value,
728                         PFAST486_FPU_DATA_REG Result)
729 {
730     INT i;
731     LONGLONG IntVal = 0LL;
732 
733     for (i = 8; i >= 0; i--)
734     {
735         IntVal *= 100LL;
736         IntVal += (Value[i] >> 4) * 10 + (Value[i] & 0x0F);
737     }
738 
739     /* Apply the sign */
740     if (Value[9] & 0x80) IntVal = -IntVal;
741 
742     /* Now convert the integer to FP80 */
743     Fast486FpuFromInteger(State, IntVal, Result);
744 }
745 
746 static inline BOOLEAN FASTCALL
747 Fast486FpuToPackedBcd(PFAST486_STATE State,
748                       PCFAST486_FPU_DATA_REG Value,
749                       PUCHAR Result)
750 {
751     INT i;
752     LONGLONG IntVal;
753 
754     /* Convert it to an integer first */
755     if (!Fast486FpuToInteger(State, Value, &IntVal)) return FALSE;
756 
757     if (IntVal < 0LL)
758     {
759         IntVal = -IntVal;
760         Result[9] = 0x80;
761     }
762 
763     for (i = 0; i < 9; i++)
764     {
765         Result[i] = (UCHAR)((IntVal % 10) + (((IntVal / 10) % 10) << 4));
766         IntVal /= 100LL;
767     }
768 
769     return TRUE;
770 }
771 
772 static inline BOOLEAN FASTCALL
773 Fast486FpuAdd(PFAST486_STATE State,
774               PCFAST486_FPU_DATA_REG FirstOperand,
775               PCFAST486_FPU_DATA_REG SecondOperand,
776               PFAST486_FPU_DATA_REG Result)
777 {
778     FAST486_FPU_DATA_REG FirstAdjusted = *FirstOperand;
779     FAST486_FPU_DATA_REG SecondAdjusted = *SecondOperand;
780     FAST486_FPU_DATA_REG TempResult;
781 
782     if (FPU_IS_INDEFINITE(FirstOperand)
783         || FPU_IS_INDEFINITE(SecondOperand)
784         || (FPU_IS_POS_INF(FirstOperand) && FPU_IS_NEG_INF(SecondOperand))
785         || (FPU_IS_NEG_INF(FirstOperand) && FPU_IS_POS_INF(SecondOperand)))
786     {
787         /* The result will be indefinite */
788         Result->Sign = TRUE;
789         Result->Exponent = FPU_MAX_EXPONENT + 1;
790         Result->Mantissa = FPU_INDEFINITE_MANTISSA;
791         return TRUE;
792     }
793 
794     if ((!FPU_IS_NORMALIZED(FirstOperand) || !FPU_IS_NORMALIZED(SecondOperand)))
795     {
796         /* Raise the denormalized exception */
797         State->FpuStatus.De = TRUE;
798 
799         if (!State->FpuControl.Dm)
800         {
801             return FALSE;
802         }
803     }
804 
805     if (FPU_IS_ZERO(FirstOperand) || FPU_IS_INFINITY(SecondOperand))
806     {
807         /* The second operand is the result */
808         *Result = *SecondOperand;
809         return TRUE;
810     }
811 
812     if (FPU_IS_ZERO(SecondOperand) || FPU_IS_INFINITY(FirstOperand))
813     {
814         /* The first operand is the result */
815         *Result = *FirstOperand;
816         return TRUE;
817     }
818 
819     /* Find the largest exponent */
820     TempResult.Exponent = max(FirstOperand->Exponent, SecondOperand->Exponent);
821 
822     /* Adjust the first operand to it... */
823     if (FirstAdjusted.Exponent < TempResult.Exponent)
824     {
825         if ((TempResult.Exponent - FirstAdjusted.Exponent) < 64)
826         {
827             FirstAdjusted.Mantissa >>= (TempResult.Exponent - FirstAdjusted.Exponent);
828             FirstAdjusted.Exponent = TempResult.Exponent;
829         }
830         else
831         {
832             /* The second operand is the result */
833             *Result = *SecondOperand;
834             return TRUE;
835         }
836     }
837 
838     /* ... and the second one too */
839     if (SecondAdjusted.Exponent < TempResult.Exponent)
840     {
841         if ((TempResult.Exponent - SecondAdjusted.Exponent) < 64)
842         {
843             SecondAdjusted.Mantissa >>= (TempResult.Exponent - SecondAdjusted.Exponent);
844             SecondAdjusted.Exponent = TempResult.Exponent;
845         }
846         else
847         {
848             /* The first operand is the result */
849             *Result = *FirstOperand;
850             return TRUE;
851         }
852     }
853 
854     if (FirstAdjusted.Sign == SecondAdjusted.Sign)
855     {
856         /* Calculate the mantissa and sign of the result */
857         TempResult.Mantissa = FirstAdjusted.Mantissa + SecondAdjusted.Mantissa;
858         TempResult.Sign = FirstAdjusted.Sign;
859     }
860     else
861     {
862         /* Calculate the sign of the result */
863         if (FirstAdjusted.Mantissa > SecondAdjusted.Mantissa) TempResult.Sign = FirstAdjusted.Sign;
864         else if (FirstAdjusted.Mantissa < SecondAdjusted.Mantissa) TempResult.Sign = SecondAdjusted.Sign;
865         else TempResult.Sign = FALSE;
866 
867         /* Invert the negative mantissa */
868         if (FirstAdjusted.Sign) FirstAdjusted.Mantissa = -(LONGLONG)FirstAdjusted.Mantissa;
869         if (SecondAdjusted.Sign) SecondAdjusted.Mantissa = -(LONGLONG)SecondAdjusted.Mantissa;
870 
871         /* Calculate the mantissa of the result */
872         TempResult.Mantissa = FirstAdjusted.Mantissa + SecondAdjusted.Mantissa;
873     }
874 
875     /* Did it overflow? */
876     if (FirstAdjusted.Sign == SecondAdjusted.Sign)
877     {
878         if (TempResult.Mantissa < FirstAdjusted.Mantissa
879             || TempResult.Mantissa < SecondAdjusted.Mantissa)
880         {
881             if (TempResult.Exponent == FPU_MAX_EXPONENT)
882             {
883                 /* Raise the overflow exception */
884                 State->FpuStatus.Oe = TRUE;
885 
886                 if (State->FpuControl.Om)
887                 {
888                     /* Total overflow, return infinity */
889                     TempResult.Mantissa = FPU_MANTISSA_HIGH_BIT;
890                     TempResult.Exponent = FPU_MAX_EXPONENT + 1;
891                 }
892                 else
893                 {
894                     return FALSE;
895                 }
896             }
897             else
898             {
899                 /* Lose the LSB in favor of the carry */
900                 TempResult.Mantissa >>= 1;
901                 TempResult.Mantissa |= FPU_MANTISSA_HIGH_BIT;
902                 TempResult.Exponent++;
903             }
904         }
905     }
906     else
907     {
908         if (TempResult.Mantissa >= FirstAdjusted.Mantissa
909             && TempResult.Mantissa >= SecondAdjusted.Mantissa)
910         {
911             /* Reverse the mantissa */
912             TempResult.Mantissa = -(LONGLONG)TempResult.Mantissa;
913         }
914     }
915 
916     /* Normalize the result and return it */
917     if (!Fast486FpuNormalize(State, &TempResult))
918     {
919         /* Exception occurred */
920         return FALSE;
921     }
922 
923     *Result = TempResult;
924     return TRUE;
925 }
926 
927 static inline BOOLEAN FASTCALL
928 Fast486FpuSubtract(PFAST486_STATE State,
929                    PCFAST486_FPU_DATA_REG FirstOperand,
930                    PCFAST486_FPU_DATA_REG SecondOperand,
931                    PFAST486_FPU_DATA_REG Result)
932 {
933     FAST486_FPU_DATA_REG NegativeSecondOperand = *SecondOperand;
934 
935     /* Invert the sign */
936     NegativeSecondOperand.Sign = !NegativeSecondOperand.Sign;
937 
938     /* And perform an addition instead */
939     return Fast486FpuAdd(State, FirstOperand, &NegativeSecondOperand, Result);
940 }
941 
942 static inline VOID FASTCALL
943 Fast486FpuCompare(PFAST486_STATE State,
944                   PCFAST486_FPU_DATA_REG FirstOperand,
945                   PCFAST486_FPU_DATA_REG SecondOperand)
946 {
947     if (FPU_IS_NAN(FirstOperand) || FPU_IS_NAN(SecondOperand))
948     {
949         if ((FPU_IS_POS_INF(FirstOperand)
950             && (!FPU_IS_NAN(SecondOperand) || FPU_IS_NEG_INF(SecondOperand)))
951             || (!FPU_IS_NAN(FirstOperand) && FPU_IS_NEG_INF(SecondOperand)))
952         {
953             State->FpuStatus.Code0 = FALSE;
954             State->FpuStatus.Code2 = FALSE;
955             State->FpuStatus.Code3 = FALSE;
956         }
957         else if ((FPU_IS_POS_INF(SecondOperand)
958                  && (!FPU_IS_NAN(FirstOperand) || FPU_IS_NEG_INF(FirstOperand)))
959                  || (!FPU_IS_NAN(SecondOperand) && FPU_IS_NEG_INF(FirstOperand)))
960         {
961             State->FpuStatus.Code0 = TRUE;
962             State->FpuStatus.Code2 = FALSE;
963             State->FpuStatus.Code3 = FALSE;
964         }
965         else
966         {
967             State->FpuStatus.Code0 = TRUE;
968             State->FpuStatus.Code2 = TRUE;
969             State->FpuStatus.Code3 = TRUE;
970         }
971     }
972     else
973     {
974         FAST486_FPU_DATA_REG TempResult;
975 
976         Fast486FpuSubtract(State, FirstOperand, SecondOperand, &TempResult);
977 
978         if (FPU_IS_ZERO(&TempResult))
979         {
980             State->FpuStatus.Code0 = FALSE;
981             State->FpuStatus.Code2 = FALSE;
982             State->FpuStatus.Code3 = TRUE;
983         }
984         else if (TempResult.Sign)
985         {
986             State->FpuStatus.Code0 = TRUE;
987             State->FpuStatus.Code2 = FALSE;
988             State->FpuStatus.Code3 = FALSE;
989         }
990         else
991         {
992             State->FpuStatus.Code0 = FALSE;
993             State->FpuStatus.Code2 = FALSE;
994             State->FpuStatus.Code3 = FALSE;
995         }
996     }
997 }
998 
999 static inline BOOLEAN FASTCALL
1000 Fast486FpuMultiply(PFAST486_STATE State,
1001                    PCFAST486_FPU_DATA_REG FirstOperand,
1002                    PCFAST486_FPU_DATA_REG SecondOperand,
1003                    PFAST486_FPU_DATA_REG Result)
1004 {
1005     FAST486_FPU_DATA_REG TempResult;
1006     LONG Exponent;
1007 
1008     if (FPU_IS_INDEFINITE(FirstOperand)
1009         || FPU_IS_INDEFINITE(SecondOperand)
1010         || (FPU_IS_ZERO(FirstOperand) && FPU_IS_INFINITY(SecondOperand))
1011         || (FPU_IS_INFINITY(FirstOperand) && FPU_IS_ZERO(SecondOperand)))
1012     {
1013         /* The result will be indefinite */
1014         Result->Sign = TRUE;
1015         Result->Exponent = FPU_MAX_EXPONENT + 1;
1016         Result->Mantissa = FPU_INDEFINITE_MANTISSA;
1017         return TRUE;
1018     }
1019 
1020     if (FPU_IS_ZERO(FirstOperand) || FPU_IS_ZERO(SecondOperand))
1021     {
1022         /* The result will be zero */
1023         Result->Sign = FirstOperand->Sign ^ SecondOperand->Sign;
1024         Result->Exponent = 0;
1025         Result->Mantissa = 0ULL;
1026         return TRUE;
1027     }
1028 
1029     if (FPU_IS_INFINITY(FirstOperand) || FPU_IS_INFINITY(SecondOperand))
1030     {
1031         /* The result will be infinity */
1032         Result->Sign = FirstOperand->Sign ^ SecondOperand->Sign;
1033         Result->Exponent = FPU_MAX_EXPONENT + 1;
1034         Result->Mantissa = FPU_MANTISSA_HIGH_BIT;
1035         return TRUE;
1036     }
1037 
1038     if ((!FPU_IS_NORMALIZED(FirstOperand) || !FPU_IS_NORMALIZED(SecondOperand)))
1039     {
1040         /* Raise the denormalized exception */
1041         State->FpuStatus.De = TRUE;
1042 
1043         if (!State->FpuControl.Dm)
1044         {
1045             return FALSE;
1046         }
1047     }
1048 
1049     /* Calculate the sign */
1050     TempResult.Sign = FirstOperand->Sign ^ SecondOperand->Sign;
1051 
1052     /* Calculate the exponent */
1053     Exponent = (LONG)FirstOperand->Exponent + (LONG)SecondOperand->Exponent - FPU_REAL10_BIAS + 1;
1054 
1055     /* Calculate the mantissa */
1056     UnsignedMult128(FirstOperand->Mantissa,
1057                     SecondOperand->Mantissa,
1058                     &TempResult.Mantissa);
1059 
1060     if (Exponent < 0)
1061     {
1062         /* Raise the underflow exception */
1063         State->FpuStatus.Ue = TRUE;
1064 
1065         if (!State->FpuControl.Um)
1066         {
1067             return FALSE;
1068         }
1069 
1070         /* The exponent will be zero */
1071         TempResult.Exponent = 0;
1072 
1073         /* If possible, denormalize the result, otherwise make it zero */
1074         if (Exponent > -64) TempResult.Mantissa >>= (-Exponent);
1075         else TempResult.Mantissa = 0ULL;
1076     }
1077     else if (Exponent > FPU_MAX_EXPONENT)
1078     {
1079         /* Raise the overflow exception */
1080         State->FpuStatus.Oe = TRUE;
1081 
1082         if (!State->FpuControl.Om)
1083         {
1084             return FALSE;
1085         }
1086 
1087         /* Make the result infinity */
1088         TempResult.Exponent = FPU_MAX_EXPONENT + 1;
1089         TempResult.Mantissa = FPU_MANTISSA_HIGH_BIT;
1090     }
1091     else TempResult.Exponent = (USHORT)Exponent;
1092 
1093     /* Normalize the result */
1094     if (!Fast486FpuNormalize(State, &TempResult))
1095     {
1096         /* Exception occurred */
1097         return FALSE;
1098     }
1099 
1100     *Result = TempResult;
1101     return TRUE;
1102 }
1103 
1104 static inline BOOLEAN FASTCALL
1105 Fast486FpuDivide(PFAST486_STATE State,
1106                  PCFAST486_FPU_DATA_REG FirstOperand,
1107                  PCFAST486_FPU_DATA_REG SecondOperand,
1108                  PFAST486_FPU_DATA_REG Result)
1109 {
1110     FAST486_FPU_DATA_REG TempResult;
1111     ULONGLONG QuotientLow, QuotientHigh, Remainder;
1112     LONG Exponent;
1113 
1114     if (FPU_IS_INDEFINITE(FirstOperand)
1115         || FPU_IS_INDEFINITE(SecondOperand)
1116         || (FPU_IS_INFINITY(FirstOperand) && FPU_IS_INFINITY(SecondOperand))
1117         || (FPU_IS_ZERO(FirstOperand) && FPU_IS_ZERO(SecondOperand)))
1118     {
1119         /* Raise the invalid operation exception */
1120         State->FpuStatus.Ie = TRUE;
1121 
1122         if (State->FpuControl.Im)
1123         {
1124             /* Return the indefinite NaN */
1125             Result->Sign = TRUE;
1126             Result->Exponent = FPU_MAX_EXPONENT + 1;
1127             Result->Mantissa = FPU_INDEFINITE_MANTISSA;
1128             return TRUE;
1129         }
1130         else
1131         {
1132             return FALSE;
1133         }
1134     }
1135 
1136     if (FPU_IS_ZERO(SecondOperand) || FPU_IS_INFINITY(FirstOperand))
1137     {
1138         /* Raise the division by zero exception */
1139         State->FpuStatus.Ze = TRUE;
1140 
1141         if (State->FpuControl.Zm)
1142         {
1143             /* Return infinity */
1144             Result->Sign = FirstOperand->Sign;
1145             Result->Exponent = FPU_MAX_EXPONENT + 1;
1146             Result->Mantissa = FPU_MANTISSA_HIGH_BIT;
1147             return TRUE;
1148         }
1149         else
1150         {
1151             return FALSE;
1152         }
1153     }
1154 
1155     /* Calculate the sign of the result */
1156     TempResult.Sign = FirstOperand->Sign ^ SecondOperand->Sign;
1157 
1158     if (FPU_IS_ZERO(FirstOperand) || FPU_IS_INFINITY(SecondOperand))
1159     {
1160         /* Return zero */
1161         Result->Sign = TempResult.Sign;
1162         Result->Mantissa = 0ULL;
1163         Result->Exponent = 0;
1164         return TRUE;
1165     }
1166 
1167     /* Calculate the exponent of the result */
1168     Exponent = (LONG)FirstOperand->Exponent - (LONG)SecondOperand->Exponent - 1;
1169 
1170     /* Divide the two mantissas */
1171     Remainder = UnsignedDivMod128(0ULL,
1172                                   FirstOperand->Mantissa,
1173                                   SecondOperand->Mantissa,
1174                                   &QuotientLow,
1175                                   &QuotientHigh);
1176     UNREFERENCED_PARAMETER(Remainder); // TODO: Rounding
1177 
1178     TempResult.Mantissa = QuotientLow;
1179 
1180     if (QuotientHigh > 0ULL)
1181     {
1182         ULONG BitsToShift = 64 - CountLeadingZeros64(QuotientHigh);
1183 
1184         TempResult.Mantissa >>= BitsToShift;
1185         TempResult.Mantissa |= QuotientHigh << (64 - BitsToShift);
1186         Exponent += BitsToShift;
1187 
1188         // TODO: Rounding
1189     }
1190 
1191     if (Exponent < -FPU_REAL10_BIAS)
1192     {
1193         TempResult.Mantissa >>= -(Exponent + FPU_REAL10_BIAS);
1194         Exponent = -FPU_REAL10_BIAS;
1195 
1196         // TODO: Rounding
1197     }
1198 
1199     TempResult.Exponent = (USHORT)(Exponent + FPU_REAL10_BIAS);
1200 
1201     /* Normalize the result */
1202     if (!Fast486FpuNormalize(State, &TempResult))
1203     {
1204         /* Exception occurred */
1205         return FALSE;
1206     }
1207 
1208     *Result = TempResult;
1209     return TRUE;
1210 }
1211 
1212 /*
1213  * Calculates using the identity:
1214  * 2 ^ x - 1 = 1 + sum { 2 * (((x - 1) * ln(2)) ^ n) / n! }
1215  */
1216 static inline VOID FASTCALL
1217 Fast486FpuCalculateTwoPowerMinusOne(PFAST486_STATE State,
1218                                     PCFAST486_FPU_DATA_REG Operand,
1219                                     PFAST486_FPU_DATA_REG Result)
1220 {
1221     INT i;
1222     FAST486_FPU_DATA_REG TempResult = FpuOne;
1223     FAST486_FPU_DATA_REG Value;
1224     FAST486_FPU_DATA_REG SeriesElement;
1225 
1226     /* Calculate the first series element, which is 2 * (x - 1) * ln(2) */
1227     if (!Fast486FpuSubtract(State, Operand, &FpuOne, &Value)) return;
1228     if (!Fast486FpuMultiply(State, &Value, &FpuLnTwo, &Value)) return;
1229     if (!Fast486FpuAdd(State, &Value, &Value, &SeriesElement)) return;
1230 
1231     for (i = 2; i <= INVERSE_NUMBERS_COUNT; i++)
1232     {
1233         /* Add the series element to the final sum */
1234         if (!Fast486FpuAdd(State, &TempResult, &SeriesElement, &TempResult))
1235         {
1236             /* An exception occurred */
1237             return;
1238         }
1239 
1240         /*
1241          * Calculate the next series element (partially) by multiplying
1242          * it with (x - 1) * ln(2)
1243          */
1244         if (!Fast486FpuMultiply(State, &SeriesElement, &Value, &SeriesElement))
1245         {
1246             /* An exception occurred */
1247             return;
1248         }
1249 
1250         /* And now multiply the series element by the inverse counter */
1251         if (!Fast486FpuMultiply(State,
1252                                 &SeriesElement,
1253                                 &FpuInverseNumber[i - 1],
1254                                 &SeriesElement))
1255         {
1256             /* An exception occurred */
1257             return;
1258         }
1259     }
1260 
1261     *Result = TempResult;
1262 }
1263 
1264 static inline BOOLEAN FASTCALL
1265 Fast486FpuCalculateLogBase2(PFAST486_STATE State,
1266                             PCFAST486_FPU_DATA_REG Operand,
1267                             PFAST486_FPU_DATA_REG Result)
1268 {
1269     INT i;
1270     FAST486_FPU_DATA_REG Value = *Operand;
1271     FAST486_FPU_DATA_REG TempResult;
1272     FAST486_FPU_DATA_REG TempValue;
1273     LONGLONG UnbiasedExp = (LONGLONG)Operand->Exponent - FPU_REAL10_BIAS;
1274 
1275     if (Operand->Sign)
1276     {
1277         /* Raise the invalid operation exception */
1278         State->FpuStatus.Ie = TRUE;
1279 
1280         if (State->FpuControl.Im)
1281         {
1282             /* Return the indefinite NaN */
1283             Result->Sign = TRUE;
1284             Result->Exponent = FPU_MAX_EXPONENT + 1;
1285             Result->Mantissa = FPU_INDEFINITE_MANTISSA;
1286             return TRUE;
1287         }
1288         else
1289         {
1290             return FALSE;
1291         }
1292     }
1293 
1294     /* Get only the mantissa as a floating-pointer number between 1 and 2 */
1295     Value.Exponent = FPU_REAL10_BIAS;
1296 
1297     /* Check if it's denormalized */
1298     if (!FPU_IS_NORMALIZED(&Value))
1299     {
1300         ULONG Bits;
1301         State->FpuStatus.De = TRUE;
1302 
1303         if (!State->FpuControl.Dm)
1304         {
1305             return FALSE;
1306         }
1307 
1308         /* Normalize the number */
1309         Bits = CountLeadingZeros64(Value.Mantissa);
1310         UnbiasedExp -= Bits;
1311         Value.Mantissa <<= Bits;
1312     }
1313 
1314     TempResult.Sign = FALSE;
1315     TempResult.Exponent = FPU_REAL10_BIAS - 1;
1316     TempResult.Mantissa = 0ULL;
1317 
1318     for (i = 63; i >= 0; i--)
1319     {
1320         /* Square the value */
1321         if (!Fast486FpuMultiply(State, &Value, &Value, &Value)) return FALSE;
1322 
1323         /* Subtract two from it */
1324         if (!Fast486FpuSubtract(State, &Value, &FpuTwo, &TempValue)) return FALSE;
1325 
1326         /* Is the result positive? */
1327         if (!TempValue.Sign)
1328         {
1329             /* Yes, set the appropriate bit in the mantissa */
1330             TempResult.Mantissa |= 1ULL << i;
1331 
1332             /* Halve the value */
1333             if (!Fast486FpuMultiply(State, &Value, &FpuInverseNumber[1], &Value)) return FALSE;
1334         }
1335     }
1336 
1337     /* Normalize the result */
1338     if (!Fast486FpuNormalize(State, &TempResult)) return FALSE;
1339 
1340     /*
1341      * Add the exponent to the result
1342      * log2(x * 2^y) = log2(x) + log2(2^y) = log2(x) + y
1343      */
1344     Fast486FpuFromInteger(State, UnbiasedExp, &TempValue);
1345     if (!Fast486FpuAdd(State, &TempValue, &TempResult, &TempResult)) return FALSE;
1346 
1347     *Result = TempResult;
1348     return TRUE;
1349 }
1350 
1351 static inline BOOLEAN FASTCALL
1352 Fast486FpuRemainder(PFAST486_STATE State,
1353                     PCFAST486_FPU_DATA_REG FirstOperand,
1354                     PCFAST486_FPU_DATA_REG SecondOperand,
1355                     BOOLEAN RoundToNearest,
1356                     PFAST486_FPU_DATA_REG Result OPTIONAL,
1357                     PLONGLONG Quotient OPTIONAL)
1358 {
1359     BOOLEAN Success = FALSE;
1360     INT OldRoundingMode = State->FpuControl.Rc;
1361     LONGLONG Integer;
1362     FAST486_FPU_DATA_REG Temp;
1363 
1364     if (!Fast486FpuDivide(State, FirstOperand, SecondOperand, &Temp)) return FALSE;
1365 
1366     State->FpuControl.Rc = RoundToNearest ? FPU_ROUND_NEAREST : FPU_ROUND_TRUNCATE;
1367 
1368     if (!Fast486FpuToInteger(State, &Temp, &Integer)) goto Cleanup;
1369 
1370     if (Result)
1371     {
1372         Fast486FpuFromInteger(State, Integer, &Temp);
1373         if (!Fast486FpuMultiply(State, &Temp, SecondOperand, &Temp)) goto Cleanup;
1374         if (!Fast486FpuSubtract(State, FirstOperand, &Temp, Result)) goto Cleanup;
1375     }
1376 
1377     if (Quotient) *Quotient = Integer;
1378     Success = TRUE;
1379 
1380 Cleanup:
1381     State->FpuControl.Rc = OldRoundingMode;
1382     return Success;
1383 }
1384 
1385 /*
1386  * Calculates using the identity:
1387  * sin(x) = sum { -1^n * x^(2n + 1) / (2n + 1)!, n >= 0 }
1388  */
1389 static inline BOOLEAN FASTCALL
1390 Fast486FpuCalculateSine(PFAST486_STATE State,
1391                         PCFAST486_FPU_DATA_REG Operand,
1392                         PFAST486_FPU_DATA_REG Result)
1393 {
1394     INT i;
1395     ULONGLONG Quadrant;
1396     FAST486_FPU_DATA_REG Normalized = *Operand;
1397     FAST486_FPU_DATA_REG TempResult;
1398     FAST486_FPU_DATA_REG OperandSquared;
1399     FAST486_FPU_DATA_REG SeriesElement;
1400     PCFAST486_FPU_DATA_REG Inverse;
1401 
1402     if (!Fast486FpuRemainder(State,
1403                              Operand,
1404                              &FpuHalfPi,
1405                              FALSE,
1406                              &Normalized,
1407                              (PLONGLONG)&Quadrant))
1408     {
1409         return FALSE;
1410     }
1411 
1412     /* Normalize the quadrant number */
1413     Quadrant &= 3;
1414 
1415     if (!(Quadrant & 1))
1416     {
1417         /* This is a sine */
1418         Inverse = FpuInverseNumberSine;
1419         TempResult = SeriesElement = Normalized;
1420     }
1421     else
1422     {
1423         /* This is a cosine */
1424         Inverse = FpuInverseNumberCosine;
1425         TempResult = SeriesElement = FpuOne;
1426     }
1427 
1428     /* Calculate the square of the operand */
1429     if (!Fast486FpuMultiply(State, &Normalized, &Normalized, &OperandSquared)) return FALSE;
1430 
1431     for (i = 0; i < INVERSE_NUMBERS_COUNT; i++)
1432     {
1433         if (!Fast486FpuMultiply(State, &SeriesElement, &OperandSquared, &SeriesElement))
1434         {
1435             /* An exception occurred */
1436             return FALSE;
1437         }
1438 
1439         if (!Fast486FpuMultiply(State,
1440                                 &SeriesElement,
1441                                 &Inverse[i],
1442                                 &SeriesElement))
1443         {
1444             /* An exception occurred */
1445             return FALSE;
1446         }
1447 
1448         /* Toggle the sign of the series element */
1449         SeriesElement.Sign = !SeriesElement.Sign;
1450 
1451         if (!Fast486FpuAdd(State, &TempResult, &SeriesElement, &TempResult))
1452         {
1453             /* An exception occurred */
1454             return FALSE;
1455         }
1456     }
1457 
1458     /* Flip the sign for the third and fourth quadrant */
1459     if (Quadrant >= 2) TempResult.Sign = !TempResult.Sign;
1460 
1461     *Result = TempResult;
1462     return TRUE;
1463 }
1464 
1465 /*
1466  * Calculates using the identity:
1467  * cos(x) = sum { -1^n * x^(2n) / (2n)!, n >= 0 }
1468  */
1469 static inline BOOLEAN FASTCALL
1470 Fast486FpuCalculateCosine(PFAST486_STATE State,
1471                           PCFAST486_FPU_DATA_REG Operand,
1472                           PFAST486_FPU_DATA_REG Result)
1473 {
1474     FAST486_FPU_DATA_REG Value = *Operand;
1475 
1476     /* Add pi / 2 */
1477     if (!Fast486FpuAdd(State, &Value, &FpuHalfPi, &Value)) return FALSE;
1478 
1479     /* Calculate the sine */
1480     return Fast486FpuCalculateSine(State, &Value, Result);
1481 }
1482 
1483 static inline VOID FASTCALL
1484 Fast486FpuArithmeticOperation(PFAST486_STATE State,
1485                               INT Operation,
1486                               PFAST486_FPU_DATA_REG Operand,
1487                               BOOLEAN TopDestination)
1488 {
1489     PFAST486_FPU_DATA_REG DestOperand = TopDestination ? &FPU_ST(0) : Operand;
1490 
1491     ASSERT(!(Operation & ~7));
1492 
1493     /* Check the operation */
1494     switch (Operation)
1495     {
1496         /* FADD */
1497         case 0:
1498         {
1499             Fast486FpuAdd(State, &FPU_ST(0), Operand, DestOperand);
1500             break;
1501         }
1502 
1503         /* FMUL */
1504         case 1:
1505         {
1506             Fast486FpuMultiply(State, &FPU_ST(0), Operand, DestOperand);
1507             break;
1508         }
1509 
1510         /* FCOM */
1511         case 2:
1512         /* FCOMP */
1513         case 3:
1514         {
1515             Fast486FpuCompare(State, &FPU_ST(0), Operand);
1516             if (Operation == 3) Fast486FpuPop(State);
1517 
1518             break;
1519         }
1520 
1521         /* FSUB */
1522         case 4:
1523         {
1524             Fast486FpuSubtract(State, &FPU_ST(0), Operand, DestOperand);
1525             break;
1526         }
1527 
1528         /* FSUBR */
1529         case 5:
1530         {
1531             Fast486FpuSubtract(State, Operand, &FPU_ST(0), DestOperand);
1532             break;
1533         }
1534 
1535         /* FDIV */
1536         case 6:
1537         {
1538             Fast486FpuDivide(State, &FPU_ST(0), Operand, DestOperand);
1539             break;
1540         }
1541 
1542         /* FDIVR */
1543         case 7:
1544         {
1545             Fast486FpuDivide(State, Operand, &FPU_ST(0), DestOperand);
1546             break;
1547         }
1548     }
1549 }
1550 
1551 /*
1552  * Calculates using:
1553  * x[0] = s
1554  * x[n + 1] = (x[n] + s / x[n]) / 2
1555  */
1556 static inline BOOLEAN FASTCALL
1557 Fast486FpuCalculateSquareRoot(PFAST486_STATE State,
1558                               PCFAST486_FPU_DATA_REG Operand,
1559                               PFAST486_FPU_DATA_REG Result)
1560 {
1561     FAST486_FPU_DATA_REG Value = *Operand;
1562     FAST486_FPU_DATA_REG PrevValue = FpuZero;
1563 
1564     if (Operand->Sign)
1565     {
1566         /* Raise the invalid operation exception */
1567         State->FpuStatus.Ie = TRUE;
1568 
1569         if (State->FpuControl.Im)
1570         {
1571             /* Return the indefinite NaN */
1572             Result->Sign = TRUE;
1573             Result->Exponent = FPU_MAX_EXPONENT + 1;
1574             Result->Mantissa = FPU_INDEFINITE_MANTISSA;
1575             return TRUE;
1576         }
1577         else
1578         {
1579             return FALSE;
1580         }
1581     }
1582 
1583     /* Loop until it converges */
1584     while (Value.Sign != PrevValue.Sign
1585            || Value.Exponent != PrevValue.Exponent
1586            || Value.Mantissa != PrevValue.Mantissa)
1587     {
1588         FAST486_FPU_DATA_REG Temp;
1589 
1590         /* Save the current value */
1591         PrevValue = Value;
1592 
1593         /* Divide the operand by the current value */
1594         if (!Fast486FpuDivide(State, Operand, &Value, &Temp)) return FALSE;
1595 
1596         /* Add the result of that division to the current value */
1597         if (!Fast486FpuAdd(State, &Value, &Temp, &Value)) return FALSE;
1598 
1599         /* Halve the current value */
1600         if (!Fast486FpuMultiply(State, &Value, &FpuInverseNumber[1], &Value)) return FALSE;
1601     }
1602 
1603     *Result = Value;
1604     return TRUE;
1605 }
1606 
1607 /*
1608  * Calculates arctan using Euler's formula:
1609  * arctan(x) = (x / (1 + x^2)) * sum { prod { (2j * x^2)
1610  * / ((2j + 1) * (1 + x^2)), j >= 1, j <= i }, i >= 0 }
1611  */
1612 static inline BOOLEAN FASTCALL
1613 Fast486FpuCalculateArcTangent(PFAST486_STATE State,
1614                               PCFAST486_FPU_DATA_REG Numerator,
1615                               PCFAST486_FPU_DATA_REG Denominator,
1616                               PFAST486_FPU_DATA_REG Result)
1617 {
1618     INT i;
1619     BOOLEAN Inverted = FALSE;
1620     FAST486_FPU_DATA_REG TempNumerator = *Numerator;
1621     FAST486_FPU_DATA_REG TempDenominator = *Denominator;
1622     FAST486_FPU_DATA_REG Value;
1623     FAST486_FPU_DATA_REG TempResult;
1624     FAST486_FPU_DATA_REG ValDivValSqP1;
1625     FAST486_FPU_DATA_REG SeriesElement = FpuOne;
1626 
1627     TempNumerator.Sign = FALSE;
1628     TempDenominator.Sign = FALSE;
1629 
1630     /* Compare the numerator to the denominator */
1631     if (!Fast486FpuSubtract(State, &TempNumerator, &TempDenominator, &TempResult))
1632     {
1633         return FALSE;
1634     }
1635 
1636     if ((Inverted = !TempResult.Sign))
1637     {
1638         if (!Fast486FpuDivide(State, &TempDenominator, &TempNumerator, &Value))
1639         {
1640             return FALSE;
1641         }
1642     }
1643     else
1644     {
1645         if (!Fast486FpuDivide(State, &TempNumerator, &TempDenominator, &Value))
1646         {
1647             return FALSE;
1648         }
1649     }
1650 
1651     /* Apparently, atan2(0, 0) = +/- 0 or +/- pi for some reason... */
1652     if (FPU_IS_INDEFINITE(&Value)) Value = FpuZero;
1653 
1654     /* Calculate the value divided by the value squared plus one */
1655     if (!Fast486FpuMultiply(State, &Value, &Value, &ValDivValSqP1)) return FALSE;
1656     if (!Fast486FpuAdd(State, &ValDivValSqP1, &FpuOne, &ValDivValSqP1)) return FALSE;
1657     if (!Fast486FpuDivide(State, &Value, &ValDivValSqP1, &ValDivValSqP1)) return FALSE;
1658 
1659     TempResult = FpuOne;
1660 
1661     for (i = 0; i < INVERSE_NUMBERS_COUNT; i++)
1662     {
1663         if (!Fast486FpuMultiply(State, &SeriesElement, &Value, &SeriesElement))
1664         {
1665             /* An exception occurred */
1666             return FALSE;
1667         }
1668 
1669         if (!Fast486FpuMultiply(State, &SeriesElement, &ValDivValSqP1, &SeriesElement))
1670         {
1671             /* An exception occurred */
1672             return FALSE;
1673         }
1674 
1675         if (!Fast486FpuMultiply(State,
1676                                 &SeriesElement,
1677                                 &FpuInverseNumberAtan[i],
1678                                 &SeriesElement))
1679         {
1680             /* An exception occurred */
1681             return FALSE;
1682         }
1683 
1684         if (!Fast486FpuAdd(State, &TempResult, &SeriesElement, &TempResult))
1685         {
1686             /* An exception occurred */
1687             return FALSE;
1688         }
1689     }
1690 
1691     if (!Fast486FpuMultiply(State, &TempResult, &ValDivValSqP1, &TempResult))
1692     {
1693         /* An exception occurred */
1694         return FALSE;
1695     }
1696 
1697     if (Inverted)
1698     {
1699         /* Since y/x is positive, arctan(y/x) = pi/2 - arctan(x/y) */
1700         if (!Fast486FpuSubtract(State, &FpuHalfPi, &TempResult, &TempResult)) return FALSE;
1701     }
1702 
1703     /* Adjust the sign */
1704     if (!(!Numerator->Sign == !Denominator->Sign)) TempResult.Sign = !TempResult.Sign;
1705 
1706     if (Denominator->Sign)
1707     {
1708         if (Numerator->Sign)
1709         {
1710             /* Subtract PI */
1711             if (!Fast486FpuSubtract(State, &TempResult, &FpuPi, &TempResult)) return FALSE;
1712         }
1713         else
1714         {
1715             /* Add PI */
1716             if (!Fast486FpuAdd(State, &TempResult, &FpuPi, &TempResult)) return FALSE;
1717         }
1718     }
1719 
1720     *Result = TempResult;
1721     return TRUE;
1722 }
1723 
1724 static inline BOOLEAN FASTCALL
1725 Fast486FpuLoadEnvironment(PFAST486_STATE State,
1726                           INT Segment,
1727                           ULONG Address,
1728                           BOOLEAN Size)
1729 {
1730     UCHAR Buffer[28];
1731 
1732     if (!Fast486ReadMemory(State, Segment, Address, FALSE, Buffer, (Size + 1) * 14))
1733     {
1734         /* Exception occurred */
1735         return FALSE;
1736     }
1737 
1738     /* Check if this is a 32-bit save or a 16-bit save */
1739     if (Size)
1740     {
1741         PULONG Data = (PULONG)Buffer;
1742 
1743         State->FpuControl.Value = (USHORT)Data[0];
1744         State->FpuStatus.Value = (USHORT)Data[1];
1745         State->FpuTag = (USHORT)Data[2];
1746         State->FpuLastInstPtr.Long = Data[3];
1747         State->FpuLastCodeSel = (USHORT)Data[4];
1748         State->FpuLastOpPtr.Long = Data[5];
1749         State->FpuLastDataSel = (USHORT)Data[6];
1750     }
1751     else
1752     {
1753         PUSHORT Data = (PUSHORT)Buffer;
1754 
1755         State->FpuControl.Value = Data[0];
1756         State->FpuStatus.Value = Data[1];
1757         State->FpuTag = Data[2];
1758         State->FpuLastInstPtr.LowWord = Data[3];
1759         State->FpuLastCodeSel = Data[4];
1760         State->FpuLastOpPtr.LowWord = Data[5];
1761         State->FpuLastDataSel = Data[6];
1762     }
1763 
1764     return TRUE;
1765 }
1766 
1767 static inline BOOLEAN FASTCALL
1768 Fast486FpuSaveEnvironment(PFAST486_STATE State,
1769                           INT Segment,
1770                           ULONG Address,
1771                           BOOLEAN Size)
1772 {
1773     UCHAR Buffer[28];
1774 
1775     /* Check if this is a 32-bit save or a 16-bit save */
1776     if (Size)
1777     {
1778         PULONG Data = (PULONG)Buffer;
1779 
1780         Data[0] = (ULONG)State->FpuControl.Value;
1781         Data[1] = (ULONG)State->FpuStatus.Value;
1782         Data[2] = (ULONG)State->FpuTag;
1783         Data[3] = State->FpuLastInstPtr.Long;
1784         Data[4] = (ULONG)State->FpuLastCodeSel;
1785         Data[5] = State->FpuLastOpPtr.Long;
1786         Data[6] = (ULONG)State->FpuLastDataSel;
1787     }
1788     else
1789     {
1790         PUSHORT Data = (PUSHORT)Buffer;
1791 
1792         Data[0] = State->FpuControl.Value;
1793         Data[1] = State->FpuStatus.Value;
1794         Data[2] = State->FpuTag;
1795         Data[3] = State->FpuLastInstPtr.LowWord;
1796         Data[4] = State->FpuLastCodeSel;
1797         Data[5] = State->FpuLastOpPtr.LowWord;
1798         Data[6] = State->FpuLastDataSel;
1799     }
1800 
1801     return Fast486WriteMemory(State, Segment, Address, Buffer, (Size + 1) * 14);
1802 }
1803 
1804 #endif
1805 
1806 /* PUBLIC FUNCTIONS ***********************************************************/
1807 
1808 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD8)
1809 {
1810     FAST486_MOD_REG_RM ModRegRm;
1811     BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1812 #ifndef FAST486_NO_FPU
1813     PFAST486_FPU_DATA_REG Operand;
1814     FAST486_FPU_DATA_REG MemoryData;
1815 #endif
1816 
1817     TOGGLE_ADSIZE(AddressSize);
1818 
1819     /* Get the operands */
1820     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1821     {
1822         /* Exception occurred */
1823         return;
1824     }
1825 
1826     FPU_CHECK();
1827 
1828 #ifndef FAST486_NO_FPU
1829 
1830     Fast486FpuExceptionCheck(State);
1831     FPU_SAVE_LAST_INST();
1832 
1833     if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
1834     {
1835         /* Raise the invalid operation exception */
1836         State->FpuStatus.Ie = TRUE;
1837 
1838         if (State->FpuControl.Im)
1839         {
1840             /* Return the indefinite NaN */
1841             FPU_ST(0).Sign = TRUE;
1842             FPU_ST(0).Exponent = FPU_MAX_EXPONENT + 1;
1843             FPU_ST(0).Mantissa = FPU_INDEFINITE_MANTISSA;
1844 
1845             FPU_SET_TAG(0, FPU_TAG_SPECIAL);
1846         }
1847 
1848         return;
1849     }
1850 
1851     if (ModRegRm.Memory)
1852     {
1853         /* Load the source operand from memory */
1854         ULONG Value;
1855 
1856         if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1857         {
1858             /* Exception occurred */
1859             return;
1860         }
1861 
1862         Fast486FpuFromSingleReal(State, Value, &MemoryData);
1863         Operand = &MemoryData;
1864 
1865         FPU_SAVE_LAST_OPERAND();
1866     }
1867     else
1868     {
1869         if (FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY)
1870         {
1871             /* Raise the invalid operation exception */
1872             State->FpuStatus.Ie = TRUE;
1873 
1874             if (State->FpuControl.Im)
1875             {
1876                 /* Return the indefinite NaN */
1877                 FPU_ST(0).Sign = TRUE;
1878                 FPU_ST(0).Exponent = FPU_MAX_EXPONENT + 1;
1879                 FPU_ST(0).Mantissa = FPU_INDEFINITE_MANTISSA;
1880 
1881                 FPU_SET_TAG(0, FPU_TAG_SPECIAL);
1882             }
1883 
1884             return;
1885         }
1886 
1887         /* Load the source operand from an FPU register */
1888         Operand = &FPU_ST(ModRegRm.SecondRegister);
1889     }
1890 
1891     /* Perform the requested operation */
1892     Fast486FpuArithmeticOperation(State, ModRegRm.Register, Operand, TRUE);
1893 
1894 #endif
1895 }
1896 
1897 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD9)
1898 {
1899     FAST486_MOD_REG_RM ModRegRm;
1900     BOOLEAN OperandSize, AddressSize;
1901 
1902     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1903     TOGGLE_OPSIZE(OperandSize);
1904     TOGGLE_ADSIZE(AddressSize);
1905 
1906     /* Get the operands */
1907     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1908     {
1909         /* Exception occurred */
1910         return;
1911     }
1912 
1913     FPU_CHECK();
1914 
1915 #ifndef FAST486_NO_FPU
1916 
1917     if (ModRegRm.Memory)
1918     {
1919         switch (ModRegRm.Register)
1920         {
1921             /* FLD */
1922             case 0:
1923             {
1924                 ULONG Value;
1925                 FAST486_FPU_DATA_REG MemoryData;
1926 
1927                 Fast486FpuExceptionCheck(State);
1928                 FPU_SAVE_LAST_INST();
1929                 FPU_SAVE_LAST_OPERAND();
1930 
1931                 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1932                 {
1933                     /* Exception occurred */
1934                     return;
1935                 }
1936 
1937                 Fast486FpuFromSingleReal(State, Value, &MemoryData);
1938                 Fast486FpuPush(State, &MemoryData);
1939 
1940                 break;
1941             }
1942 
1943             /* FST */
1944             case 2:
1945             /* FSTP */
1946             case 3:
1947             {
1948                 ULONG Value = FPU_REAL4_INDEFINITE;
1949 
1950                 Fast486FpuExceptionCheck(State);
1951                 FPU_SAVE_LAST_INST();
1952                 FPU_SAVE_LAST_OPERAND();
1953 
1954                 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
1955                 {
1956                     /* Raise the invalid operation exception */
1957                     State->FpuStatus.Ie = TRUE;
1958 
1959                     if (!State->FpuControl.Im)
1960                     {
1961                         return;
1962                     }
1963                 }
1964                 else if (!Fast486FpuToSingleReal(State, &FPU_ST(0), &Value))
1965                 {
1966                     /* Exception occurred */
1967                     return;
1968                 }
1969 
1970                 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
1971                 {
1972                     /* Exception occurred */
1973                     return;
1974                 }
1975 
1976                 if (ModRegRm.Register == 3) Fast486FpuPop(State);
1977                 break;
1978             }
1979 
1980             /* FLDENV */
1981             case 4:
1982             {
1983                 Fast486FpuLoadEnvironment(State,
1984                                           (State->PrefixFlags & FAST486_PREFIX_SEG)
1985                                           ? State->SegmentOverride : FAST486_REG_DS,
1986                                           ModRegRm.MemoryAddress,
1987                                           OperandSize);
1988                 break;
1989             }
1990 
1991             /* FLDCW */
1992             case 5:
1993             {
1994                 Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &State->FpuControl.Value);
1995                 break;
1996             }
1997 
1998             /* FSTENV */
1999             case 6:
2000             {
2001                 Fast486FpuSaveEnvironment(State,
2002                                           (State->PrefixFlags & FAST486_PREFIX_SEG)
2003                                           ? State->SegmentOverride : FAST486_REG_DS,
2004                                           ModRegRm.MemoryAddress,
2005                                           OperandSize);
2006                 break;
2007             }
2008 
2009             /* FSTCW */
2010             case 7:
2011             {
2012                 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, State->FpuControl.Value);
2013                 break;
2014             }
2015 
2016             /* Invalid */
2017             default:
2018             {
2019                 Fast486Exception(State, FAST486_EXCEPTION_UD);
2020                 return;
2021             }
2022         }
2023     }
2024     else
2025     {
2026         switch ((ModRegRm.Register << 3) | ModRegRm.SecondRegister)
2027         {
2028             /* FLD */
2029             case 0x00:
2030             case 0x01:
2031             case 0x02:
2032             case 0x03:
2033             case 0x04:
2034             case 0x05:
2035             case 0x06:
2036             case 0x07:
2037             {
2038                 Fast486FpuExceptionCheck(State);
2039                 FPU_SAVE_LAST_INST();
2040 
2041                 if (FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY)
2042                 {
2043                     /* Raise the invalid operation exception */
2044                     State->FpuStatus.Ie = TRUE;
2045 
2046                     if (!State->FpuControl.Im)
2047                     {
2048                         return;
2049                     }
2050                 }
2051 
2052                 Fast486FpuPush(State, &FPU_ST(ModRegRm.SecondRegister));
2053                 break;
2054             }
2055 
2056             /* FXCH */
2057             case 0x08:
2058             case 0x09:
2059             case 0x0A:
2060             case 0x0B:
2061             case 0x0C:
2062             case 0x0D:
2063             case 0x0E:
2064             case 0x0F:
2065             {
2066                 FAST486_FPU_DATA_REG Temp;
2067 
2068                 Fast486FpuExceptionCheck(State);
2069                 FPU_SAVE_LAST_INST();
2070 
2071                 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2072                     || FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY)
2073                 {
2074                     State->FpuStatus.Ie = TRUE;
2075                     break;
2076                 }
2077 
2078                 /* Exchange */
2079                 Temp = FPU_ST(0);
2080                 FPU_ST(0) = FPU_ST(ModRegRm.SecondRegister);
2081                 FPU_ST(ModRegRm.SecondRegister) = Temp;
2082 
2083                 FPU_UPDATE_TAG(0);
2084                 FPU_UPDATE_TAG(ModRegRm.SecondRegister);
2085 
2086                 break;
2087             }
2088 
2089             /* FNOP */
2090             case 0x10:
2091             {
2092                 /* Do nothing */
2093                 break;
2094             }
2095 
2096             /* FSTP */
2097             case 0x18:
2098             case 0x19:
2099             case 0x1A:
2100             case 0x1B:
2101             case 0x1C:
2102             case 0x1D:
2103             case 0x1E:
2104             case 0x1F:
2105             {
2106                 Fast486FpuExceptionCheck(State);
2107                 FPU_SAVE_LAST_INST();
2108 
2109                 FPU_ST(ModRegRm.SecondRegister) = FPU_ST(0);
2110                 FPU_UPDATE_TAG(ModRegRm.SecondRegister);
2111 
2112                 Fast486FpuPop(State);
2113                 break;
2114             }
2115 
2116             /* FCHS */
2117             case 0x20:
2118             {
2119                 Fast486FpuExceptionCheck(State);
2120                 FPU_SAVE_LAST_INST();
2121 
2122                 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2123                 {
2124                     State->FpuStatus.Ie = TRUE;
2125                     break;
2126                 }
2127 
2128                 /* Invert the sign */
2129                 FPU_ST(0).Sign = !FPU_ST(0).Sign;
2130 
2131                 break;
2132             }
2133 
2134             /* FABS */
2135             case 0x21:
2136             {
2137                 Fast486FpuExceptionCheck(State);
2138                 FPU_SAVE_LAST_INST();
2139 
2140                 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2141                 {
2142                     State->FpuStatus.Ie = TRUE;
2143                     break;
2144                 }
2145 
2146                 /* Set the sign to positive */
2147                 FPU_ST(0).Sign = FALSE;
2148 
2149                 break;
2150             }
2151 
2152             /* FTST */
2153             case 0x24:
2154             {
2155                 Fast486FpuExceptionCheck(State);
2156                 FPU_SAVE_LAST_INST();
2157 
2158                 Fast486FpuCompare(State, &FPU_ST(0), &FpuZero);
2159                 break;
2160             }
2161 
2162             /* FXAM */
2163             case 0x25:
2164             {
2165                 Fast486FpuExceptionCheck(State);
2166                 FPU_SAVE_LAST_INST();
2167 
2168                 /* The sign bit goes in C1, even if the register's empty */
2169                 State->FpuStatus.Code1 = FPU_ST(0).Sign;
2170 
2171                 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2172                 {
2173                     State->FpuStatus.Code0 = 1;
2174                     State->FpuStatus.Code2 = 0;
2175                     State->FpuStatus.Code3 = 1;
2176                 }
2177                 else if (FPU_GET_TAG(0) == FPU_TAG_SPECIAL)
2178                 {
2179                     if (FPU_IS_INFINITY(&FPU_ST(0)))
2180                     {
2181                         State->FpuStatus.Code0 = 1;
2182                         State->FpuStatus.Code2 = 1;
2183                         State->FpuStatus.Code3 = 0;
2184                     }
2185                     else
2186                     {
2187                         State->FpuStatus.Code0 = 1;
2188                         State->FpuStatus.Code2 = 0;
2189                         State->FpuStatus.Code3 = 0;
2190                     }
2191                 }
2192                 else if (FPU_GET_TAG(0) == FPU_TAG_ZERO)
2193                 {
2194                     State->FpuStatus.Code0 = 0;
2195                     State->FpuStatus.Code2 = 0;
2196                     State->FpuStatus.Code3 = 1;
2197                 }
2198                 else
2199                 {
2200                     if (FPU_IS_NORMALIZED(&FPU_ST(0)))
2201                     {
2202                         State->FpuStatus.Code0 = 0;
2203                         State->FpuStatus.Code2 = 1;
2204                         State->FpuStatus.Code3 = 0;
2205                     }
2206                     else
2207                     {
2208                         State->FpuStatus.Code0 = 0;
2209                         State->FpuStatus.Code2 = 1;
2210                         State->FpuStatus.Code3 = 1;
2211                     }
2212                 }
2213 
2214                 break;
2215             }
2216 
2217             /* FLD1 */
2218             case 0x28:
2219             /* FLDL2T */
2220             case 0x29:
2221             /* FLDL2E */
2222             case 0x2A:
2223             /* FLDPI */
2224             case 0x2B:
2225             /* FLDLG2 */
2226             case 0x2C:
2227             /* FLDLN2 */
2228             case 0x2D:
2229             /* FLDZ */
2230             case 0x2E:
2231             {
2232                 PCFAST486_FPU_DATA_REG Constants[] =
2233                 {
2234                     &FpuOne,
2235                     &FpuL2Ten,
2236                     &FpuL2E,
2237                     &FpuPi,
2238                     &FpuLgTwo,
2239                     &FpuLnTwo,
2240                     &FpuZero
2241                 };
2242 
2243                 Fast486FpuExceptionCheck(State);
2244                 FPU_SAVE_LAST_INST();
2245 
2246                 Fast486FpuPush(State, Constants[ModRegRm.SecondRegister]);
2247                 break;
2248             }
2249 
2250             /* F2XM1 */
2251             case 0x30:
2252             {
2253                 Fast486FpuExceptionCheck(State);
2254                 FPU_SAVE_LAST_INST();
2255 
2256                 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2257                 {
2258                     State->FpuStatus.Ie = TRUE;
2259                     break;
2260                 }
2261 
2262                 if (!FPU_IS_NORMALIZED(&FPU_ST(0)))
2263                 {
2264                     State->FpuStatus.De = TRUE;
2265 
2266                     if (!State->FpuControl.Dm)
2267                     {
2268                         break;
2269                     }
2270                 }
2271 
2272                 Fast486FpuCalculateTwoPowerMinusOne(State, &FPU_ST(0), &FPU_ST(0));
2273                 FPU_UPDATE_TAG(0);
2274 
2275                 break;
2276             }
2277 
2278             /* FYL2X */
2279             case 0x31:
2280             {
2281                 FAST486_FPU_DATA_REG Logarithm;
2282 
2283                 Fast486FpuExceptionCheck(State);
2284                 FPU_SAVE_LAST_INST();
2285 
2286                 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY || FPU_GET_TAG(1) == FPU_TAG_EMPTY)
2287                 {
2288                     State->FpuStatus.Ie = TRUE;
2289                     break;
2290                 }
2291 
2292                 if (!Fast486FpuCalculateLogBase2(State, &FPU_ST(0), &Logarithm))
2293                 {
2294                     /* Exception occurred */
2295                     break;
2296                 }
2297 
2298                 if (!Fast486FpuMultiply(State, &Logarithm, &FPU_ST(1), &FPU_ST(1)))
2299                 {
2300                     /* Exception occurred */
2301                     break;
2302                 }
2303 
2304                 /* Pop the stack so that the result ends up in ST0 */
2305                 Fast486FpuPop(State);
2306                 FPU_UPDATE_TAG(0);
2307 
2308                 break;
2309             }
2310 
2311             /* FPTAN */
2312             case 0x32:
2313             {
2314                 FAST486_FPU_DATA_REG Sine;
2315                 FAST486_FPU_DATA_REG Cosine;
2316                 ULONGLONG Quadrant;
2317 
2318                 Fast486FpuExceptionCheck(State);
2319                 FPU_SAVE_LAST_INST();
2320 
2321                 /* Compute the sine */
2322                 if (!Fast486FpuCalculateSine(State, &FPU_ST(0), &Sine)) break;
2323 
2324                 /* Normalize the angle */
2325                 if (!Fast486FpuRemainder(State,
2326                                          &FPU_ST(0),
2327                                          &FpuHalfPi,
2328                                          FALSE,
2329                                          NULL,
2330                                          (PLONGLONG)&Quadrant))
2331                 {
2332                     break;
2333                 }
2334 
2335                 /* Normalize the quadrant number */
2336                 Quadrant &= 3;
2337 
2338                 /* Find the cosine by calculating sqrt(1 - sin(x) ^ 2) */
2339                 if (!Fast486FpuMultiply(State, &Sine, &Sine, &Cosine)) break;
2340                 if (!Fast486FpuSubtract(State, &FpuOne, &Cosine, &Cosine)) break;
2341                 if (!Fast486FpuCalculateSquareRoot(State, &Cosine, &Cosine)) break;
2342 
2343                 /* Adjust the sign of the cosine */
2344                 if (Quadrant == 1 || Quadrant == 2) Cosine.Sign = TRUE;
2345 
2346                 /* Divide the sine by the cosine to get the tangent */
2347                 if (!Fast486FpuDivide(State, &Sine, &Cosine, &FPU_ST(0))) break;
2348                 FPU_UPDATE_TAG(0);
2349 
2350                 /* Push 1.00 */
2351                 Fast486FpuPush(State, &FpuOne);
2352                 break;
2353             }
2354 
2355             /* FPATAN */
2356             case 0x33:
2357             {
2358                 Fast486FpuExceptionCheck(State);
2359                 FPU_SAVE_LAST_INST();
2360 
2361                 if (!Fast486FpuCalculateArcTangent(State,
2362                                                    &FPU_ST(1),
2363                                                    &FPU_ST(0),
2364                                                    &FPU_ST(1)))
2365                 {
2366                     break;
2367                 }
2368 
2369                 FPU_UPDATE_TAG(1);
2370 
2371                 Fast486FpuPop(State);
2372                 break;
2373             }
2374 
2375             /* FXTRACT */
2376             case 0x34:
2377             {
2378                 FAST486_FPU_DATA_REG Value = FPU_ST(0);
2379 
2380                 Fast486FpuExceptionCheck(State);
2381                 FPU_SAVE_LAST_INST();
2382 
2383                 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY) || FPU_IS_INDEFINITE(&Value))
2384                 {
2385                     State->FpuStatus.Ie = TRUE;
2386                     if (FPU_GET_TAG(0) == FPU_TAG_EMPTY) State->FpuStatus.Sf = TRUE;
2387                     break;
2388                 }
2389 
2390                 if (FPU_IS_ZERO(&Value))
2391                 {
2392                     /* The exponent of zero is negative infinity */
2393                     FPU_ST(0).Sign = TRUE;
2394                     FPU_ST(0).Exponent = FPU_MAX_EXPONENT + 1;
2395                     FPU_ST(0).Mantissa = FPU_MANTISSA_HIGH_BIT;
2396                 }
2397                 else if (FPU_IS_INFINITY(&Value))
2398                 {
2399                     /* The exponent of infinity is positive infinity */
2400                     FPU_ST(0).Sign = FALSE;
2401                     FPU_ST(0).Exponent = FPU_MAX_EXPONENT + 1;
2402                     FPU_ST(0).Mantissa = FPU_MANTISSA_HIGH_BIT;
2403                 }
2404                 else
2405                 {
2406                     /* Store the unbiased exponent in ST0 */
2407                     Fast486FpuFromInteger(State,
2408                                           (LONGLONG)Value.Exponent - (LONGLONG)FPU_REAL10_BIAS,
2409                                           &FPU_ST(0));
2410                 }
2411 
2412                 /* Now push the mantissa as a real number, with the original sign */
2413                 Value.Exponent = FPU_REAL10_BIAS;
2414                 Fast486FpuPush(State, &Value);
2415 
2416                 break;
2417             }
2418 
2419             /* FPREM1 */
2420             case 0x35:
2421             /* FPREM */
2422             case 0x38:
2423             {
2424                 LONGLONG Quotient;
2425 
2426                 Fast486FpuExceptionCheck(State);
2427                 FPU_SAVE_LAST_INST();
2428 
2429                 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY || FPU_GET_TAG(1) == FPU_TAG_EMPTY)
2430                 {
2431                     State->FpuStatus.Ie = TRUE;
2432                     break;
2433                 }
2434 
2435                 if (Fast486FpuRemainder(State,
2436                                         &FPU_ST(0),
2437                                         &FPU_ST(1),
2438                                         ModRegRm.Register == 6, /* TRUE if it's FPREM1 */
2439                                         &FPU_ST(0),
2440                                         &Quotient))
2441                 {
2442                     FPU_UPDATE_TAG(0);
2443 
2444                     /* Return the lowest 3 bits of the quotient in C1, C3, C0 */
2445                     State->FpuStatus.Code1 = Quotient & 1;
2446                     State->FpuStatus.Code3 = (Quotient >> 1) & 1;
2447                     State->FpuStatus.Code0 = (Quotient >> 2) & 1;
2448                 }
2449 
2450                 break;
2451             }
2452 
2453             /* FDECSTP */
2454             case 0x36:
2455             {
2456                 State->FpuStatus.Top--;
2457                 break;
2458             }
2459 
2460             /* FINCSTP */
2461             case 0x37:
2462             {
2463                 State->FpuStatus.Top++;
2464                 break;
2465             }
2466 
2467             /* FYL2XP1 */
2468             case 0x39:
2469             {
2470                 FAST486_FPU_DATA_REG Value, Logarithm;
2471 
2472                 Fast486FpuExceptionCheck(State);
2473                 FPU_SAVE_LAST_INST();
2474 
2475                 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY || FPU_GET_TAG(1) == FPU_TAG_EMPTY)
2476                 {
2477                     State->FpuStatus.Ie = TRUE;
2478                     break;
2479                 }
2480 
2481                 if (!Fast486FpuAdd(State, &FPU_ST(0), &FpuOne, &Value))
2482                 {
2483                     /* Exception occurred */
2484                     break;
2485                 }
2486 
2487                 if (!Fast486FpuCalculateLogBase2(State, &Value, &Logarithm))
2488                 {
2489                     /* Exception occurred */
2490                     break;
2491                 }
2492 
2493                 if (!Fast486FpuMultiply(State, &Logarithm, &FPU_ST(1), &FPU_ST(1)))
2494                 {
2495                     /* Exception occurred */
2496                     break;
2497                 }
2498 
2499                 /* Pop the stack so that the result ends up in ST0 */
2500                 Fast486FpuPop(State);
2501                 FPU_UPDATE_TAG(0);
2502 
2503                 break;
2504             }
2505 
2506             /* FSQRT */
2507             case 0x3A:
2508             {
2509                 Fast486FpuExceptionCheck(State);
2510                 FPU_SAVE_LAST_INST();
2511 
2512                 Fast486FpuCalculateSquareRoot(State, &FPU_ST(0), &FPU_ST(0));
2513                 FPU_UPDATE_TAG(0);
2514 
2515                 break;
2516             }
2517 
2518             /* FSINCOS */
2519             case 0x3B:
2520             {
2521                 FAST486_FPU_DATA_REG Number = FPU_ST(0);
2522 
2523                 Fast486FpuExceptionCheck(State);
2524                 FPU_SAVE_LAST_INST();
2525 
2526                 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2527                 {
2528                     State->FpuStatus.Ie = TRUE;
2529                     break;
2530                 }
2531 
2532                 if (!FPU_IS_NORMALIZED(&FPU_ST(0)))
2533                 {
2534                     State->FpuStatus.De = TRUE;
2535 
2536                     if (!State->FpuControl.Dm)
2537                     {
2538                         break;
2539                     }
2540                 }
2541 
2542                 /* Replace FP0 with the sine */
2543                 if (!Fast486FpuCalculateSine(State, &Number, &FPU_ST(0))) break;
2544                 FPU_UPDATE_TAG(0);
2545 
2546                 /* Push the cosine */
2547                 if (!Fast486FpuCalculateCosine(State, &Number, &Number)) break;
2548                 Fast486FpuPush(State, &Number);
2549 
2550                 break;
2551             }
2552 
2553             /* FRNDINT */
2554             case 0x3C:
2555             {
2556                 LONGLONG Result = 0LL;
2557 
2558                 Fast486FpuExceptionCheck(State);
2559                 FPU_SAVE_LAST_INST();
2560 
2561                 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2562                 {
2563                     State->FpuStatus.Ie = TRUE;
2564                     break;
2565                 }
2566 
2567                 if (!FPU_IS_NORMALIZED(&FPU_ST(0)))
2568                 {
2569                     State->FpuStatus.De = TRUE;
2570 
2571                     if (!State->FpuControl.Dm)
2572                     {
2573                         break;
2574                     }
2575                 }
2576 
2577                 /* Do nothing if it's too big to not be an integer */
2578                 if (FPU_ST(0).Exponent >= FPU_REAL10_BIAS + 63) break;
2579 
2580                 /* Perform the rounding */
2581                 Fast486FpuToInteger(State, &FPU_ST(0), &Result);
2582                 Fast486FpuFromInteger(State, Result, &FPU_ST(0));
2583 
2584                 State->FpuStatus.Pe = TRUE;
2585                 break;
2586             }
2587 
2588             /* FSCALE */
2589             case 0x3D:
2590             {
2591                 LONGLONG Scale;
2592                 LONGLONG UnbiasedExp = (LONGLONG)((SHORT)FPU_ST(0).Exponent) - FPU_REAL10_BIAS;
2593                 INT OldRoundingMode = State->FpuControl.Rc;
2594 
2595                 Fast486FpuExceptionCheck(State);
2596                 FPU_SAVE_LAST_INST();
2597 
2598                 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY || FPU_GET_TAG(1) == FPU_TAG_EMPTY)
2599                 {
2600                     State->FpuStatus.Ie = TRUE;
2601                     break;
2602                 }
2603 
2604                 if (!FPU_IS_NORMALIZED(&FPU_ST(0)))
2605                 {
2606                     State->FpuStatus.De = TRUE;
2607 
2608                     if (!State->FpuControl.Dm)
2609                     {
2610                         break;
2611                     }
2612                 }
2613 
2614                 State->FpuControl.Rc = FPU_ROUND_TRUNCATE;
2615 
2616                 if (!Fast486FpuToInteger(State, &FPU_ST(1), &Scale))
2617                 {
2618                     /* Exception occurred */
2619                     State->FpuControl.Rc = OldRoundingMode;
2620                     break;
2621                 }
2622 
2623                 State->FpuControl.Rc = OldRoundingMode;
2624 
2625                 /* Adjust the unbiased exponent */
2626                 UnbiasedExp += Scale;
2627 
2628                 /* Check for underflow */
2629                 if (UnbiasedExp < -1023)
2630                 {
2631                     /* Raise the underflow exception */
2632                     State->FpuStatus.Ue = TRUE;
2633 
2634                     if (State->FpuControl.Um)
2635                     {
2636                         /* Make the result zero */
2637                         FPU_ST(0) = FpuZero;
2638                         FPU_UPDATE_TAG(0);
2639                     }
2640 
2641                     break;
2642                 }
2643 
2644                 /* Check for overflow */
2645                 if (UnbiasedExp > 1023)
2646                 {
2647                     /* Raise the overflow exception */
2648                     State->FpuStatus.Oe = TRUE;
2649 
2650                     if (State->FpuControl.Om)
2651                     {
2652                         /* Make the result infinity */
2653                         FPU_ST(0).Mantissa = FPU_MANTISSA_HIGH_BIT;
2654                         FPU_ST(0).Exponent = FPU_MAX_EXPONENT + 1;
2655                         FPU_UPDATE_TAG(0);
2656                     }
2657 
2658                     break;
2659                 }
2660 
2661                 FPU_ST(0).Exponent = (USHORT)(UnbiasedExp + FPU_REAL10_BIAS);
2662                 FPU_UPDATE_TAG(0);
2663 
2664                 break;
2665             }
2666 
2667             /* FSIN */
2668             case 0x3E:
2669             {
2670                 Fast486FpuExceptionCheck(State);
2671                 FPU_SAVE_LAST_INST();
2672 
2673                 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2674                 {
2675                     State->FpuStatus.Ie = TRUE;
2676                     break;
2677                 }
2678 
2679                 if (!FPU_IS_NORMALIZED(&FPU_ST(0)))
2680                 {
2681                     State->FpuStatus.De = TRUE;
2682 
2683                     if (!State->FpuControl.Dm)
2684                     {
2685                         break;
2686                     }
2687                 }
2688 
2689                 Fast486FpuCalculateSine(State, &FPU_ST(0), &FPU_ST(0));
2690                 FPU_UPDATE_TAG(0);
2691 
2692                 break;
2693             }
2694 
2695             /* FCOS */
2696             case 0x3F:
2697             {
2698                 Fast486FpuExceptionCheck(State);
2699                 FPU_SAVE_LAST_INST();
2700 
2701                 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2702                 {
2703                     State->FpuStatus.Ie = TRUE;
2704                     break;
2705                 }
2706 
2707                 if (!FPU_IS_NORMALIZED(&FPU_ST(0)))
2708                 {
2709                     State->FpuStatus.De = TRUE;
2710 
2711                     if (!State->FpuControl.Dm)
2712                     {
2713                         break;
2714                     }
2715                 }
2716 
2717                 Fast486FpuCalculateCosine(State, &FPU_ST(0), &FPU_ST(0));
2718                 FPU_UPDATE_TAG(0);
2719 
2720                 break;
2721             }
2722 
2723             /* Invalid */
2724             default:
2725             {
2726                 Fast486Exception(State, FAST486_EXCEPTION_UD);
2727                 return;
2728             }
2729         }
2730     }
2731 
2732 #endif
2733 }
2734 
2735 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDA)
2736 {
2737     FAST486_MOD_REG_RM ModRegRm;
2738     BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2739 #ifndef FAST486_NO_FPU
2740     LONG Value;
2741     FAST486_FPU_DATA_REG MemoryData;
2742 #endif
2743 
2744     TOGGLE_ADSIZE(AddressSize);
2745 
2746     /* Get the operands */
2747     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2748     {
2749         /* Exception occurred */
2750         return;
2751     }
2752 
2753     FPU_CHECK();
2754 
2755 #ifndef FAST486_NO_FPU
2756 
2757     Fast486FpuExceptionCheck(State);
2758     FPU_SAVE_LAST_INST();
2759 
2760     if (!ModRegRm.Memory)
2761     {
2762         /* The only valid opcode in this case is FUCOMPP (0xDA 0xE9) */
2763         if ((ModRegRm.Register != 5) && (ModRegRm.SecondRegister != 1))
2764         {
2765             Fast486Exception(State, FAST486_EXCEPTION_UD);
2766             return;
2767         }
2768 
2769         if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY) || (FPU_GET_TAG(1) == FPU_TAG_EMPTY))
2770         {
2771             /* Raise the invalid operation exception*/
2772             State->FpuStatus.Ie = TRUE;
2773             return;
2774         }
2775 
2776         /* Compare */
2777         Fast486FpuCompare(State, &FPU_ST(0), &FPU_ST(1));
2778 
2779         /* Pop twice */
2780         Fast486FpuPop(State);
2781         Fast486FpuPop(State);
2782 
2783         return;
2784     }
2785 
2786     FPU_SAVE_LAST_OPERAND();
2787 
2788     /* Load the source operand from memory */
2789     if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, (PULONG)&Value))
2790     {
2791         /* Exception occurred */
2792         return;
2793     }
2794 
2795     if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2796     {
2797         /* Raise the invalid operation exception */
2798         State->FpuStatus.Ie = TRUE;
2799 
2800         if (State->FpuControl.Im)
2801         {
2802             /* Return the indefinite NaN */
2803             FPU_ST(0).Sign = TRUE;
2804             FPU_ST(0).Exponent = FPU_MAX_EXPONENT + 1;
2805             FPU_ST(0).Mantissa = FPU_INDEFINITE_MANTISSA;
2806 
2807             FPU_SET_TAG(0, FPU_TAG_SPECIAL);
2808         }
2809 
2810         return;
2811     }
2812 
2813     Fast486FpuFromInteger(State, (LONGLONG)Value, &MemoryData);
2814 
2815     /* Perform the requested operation */
2816     Fast486FpuArithmeticOperation(State, ModRegRm.Register, &MemoryData, TRUE);
2817 
2818 #endif
2819 }
2820 
2821 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDB)
2822 {
2823     FAST486_MOD_REG_RM ModRegRm;
2824     BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2825 
2826     TOGGLE_ADSIZE(AddressSize);
2827 
2828     /* Get the operands */
2829     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2830     {
2831         /* Exception occurred */
2832         return;
2833     }
2834 
2835     FPU_CHECK();
2836 
2837 #ifndef FAST486_NO_FPU
2838 
2839     if (ModRegRm.Memory)
2840     {
2841         Fast486FpuExceptionCheck(State);
2842         FPU_SAVE_LAST_INST();
2843         FPU_SAVE_LAST_OPERAND();
2844 
2845         switch (ModRegRm.Register)
2846         {
2847             /* FILD */
2848             case 0:
2849             {
2850                 LONG Value;
2851                 FAST486_FPU_DATA_REG Temp;
2852 
2853                 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, (PULONG)&Value))
2854                 {
2855                     /* Exception occurred */
2856                     return;
2857                 }
2858 
2859                 Fast486FpuFromInteger(State, (LONGLONG)Value, &Temp);
2860                 Fast486FpuPush(State, &Temp);
2861 
2862                 break;
2863             }
2864 
2865             /* FIST */
2866             case 2:
2867             /* FISTP */
2868             case 3:
2869             {
2870                 LONGLONG Temp = 0;
2871 
2872                 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY) || (FPU_GET_TAG(0) == FPU_TAG_SPECIAL))
2873                 {
2874                     /* Raise the invalid operation exception */
2875                     State->FpuStatus.Ie = TRUE;
2876 
2877                     if (!State->FpuControl.Im)
2878                     {
2879                         return;
2880                     }
2881                 }
2882 
2883                 if (!Fast486FpuToInteger(State, &FPU_ST(0), &Temp))
2884                 {
2885                     /* Exception occurred */
2886                     return;
2887                 }
2888 
2889                 /* Check if it can fit in a signed 32-bit integer */
2890                 if ((LONGLONG)((LONG)Temp) != Temp)
2891                 {
2892                     State->FpuStatus.Ie = TRUE;
2893 
2894                     if (State->FpuControl.Im)
2895                     {
2896                         Temp = 0x80000000LL;
2897                     }
2898                     else
2899                     {
2900                         return;
2901                     }
2902                 }
2903 
2904                 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, (ULONG)((LONG)Temp)))
2905                 {
2906                     /* Exception occurred */
2907                     return;
2908                 }
2909 
2910                 if (ModRegRm.Register == 3)
2911                 {
2912                     /* Pop the FPU stack too */
2913                     Fast486FpuPop(State);
2914                 }
2915 
2916                 break;
2917             }
2918 
2919             /* FLD */
2920             case 5:
2921             {
2922                 FAST486_FPU_DATA_REG Value;
2923                 UCHAR Buffer[10];
2924 
2925                 if (!Fast486ReadMemory(State,
2926                                        (State->PrefixFlags & FAST486_PREFIX_SEG)
2927                                        ? State->SegmentOverride : FAST486_REG_DS,
2928                                        ModRegRm.MemoryAddress,
2929                                        FALSE,
2930                                        Buffer,
2931                                        sizeof(Buffer)))
2932                 {
2933                     /* Exception occurred */
2934                     return;
2935                 }
2936 
2937                 Value.Mantissa = *((PULONGLONG)Buffer);
2938                 Value.Exponent = *((PUSHORT)&Buffer[8]) & (FPU_MAX_EXPONENT + 1);
2939                 Value.Sign = *((PUCHAR)&Buffer[9]) >> 7;
2940 
2941                 Fast486FpuPush(State, &Value);
2942                 break;
2943             }
2944 
2945             /* FSTP */
2946             case 7:
2947             {
2948                 UCHAR Buffer[10];
2949 
2950                 if (FPU_GET_TAG(0) != FPU_TAG_EMPTY)
2951                 {
2952                     *((PULONGLONG)Buffer) = FPU_ST(0).Mantissa;
2953                     *((PUSHORT)&Buffer[sizeof(ULONGLONG)]) = FPU_ST(0).Exponent
2954                                                              | (FPU_ST(0).Sign ? 0x8000 : 0);
2955                 }
2956                 else
2957                 {
2958                     /* Raise the invalid operation exception */
2959                     State->FpuStatus.Ie = TRUE;
2960 
2961                     if (State->FpuControl.Im)
2962                     {
2963                         *((PULONGLONG)Buffer) = FPU_INDEFINITE_MANTISSA;
2964                         *((PUSHORT)&Buffer[sizeof(ULONGLONG)]) = 0x8000 | (FPU_MAX_EXPONENT + 1);
2965                     }
2966                     else
2967                     {
2968                         return;
2969                     }
2970                 }
2971 
2972                 if (!Fast486WriteMemory(State,
2973                                         (State->PrefixFlags & FAST486_PREFIX_SEG)
2974                                         ? State->SegmentOverride : FAST486_REG_DS,
2975                                         ModRegRm.MemoryAddress,
2976                                         Buffer,
2977                                         sizeof(Buffer)))
2978                 {
2979                     /* Exception occurred */
2980                     return;
2981                 }
2982 
2983                 Fast486FpuPop(State);
2984                 break;
2985             }
2986 
2987             /* Invalid */
2988             default:
2989             {
2990                 Fast486Exception(State, FAST486_EXCEPTION_UD);
2991                 return;
2992             }
2993         }
2994     }
2995     else
2996     {
2997         /* Only a few of these instructions have any meaning on a 487 */
2998         switch ((ModRegRm.Register << 3) | ModRegRm.SecondRegister)
2999         {
3000             /* FCLEX */
3001             case 0x22:
3002             {
3003                 /* Clear exception data */
3004                 State->FpuStatus.Ie =
3005                 State->FpuStatus.De =
3006                 State->FpuStatus.Ze =
3007                 State->FpuStatus.Oe =
3008                 State->FpuStatus.Ue =
3009                 State->FpuStatus.Pe =
3010                 State->FpuStatus.Sf =
3011                 State->FpuStatus.Es =
3012                 State->FpuStatus.Busy = FALSE;
3013 
3014                 break;
3015             }
3016 
3017             /* FINIT */
3018             case 0x23:
3019             {
3020                 /* Restore the state */
3021                 State->FpuControl.Value = FAST486_FPU_DEFAULT_CONTROL;
3022                 State->FpuStatus.Value = 0;
3023                 State->FpuTag = 0xFFFF;
3024 
3025                 break;
3026             }
3027 
3028             /* FENI */
3029             case 0x20:
3030             /* FDISI */
3031             case 0x21:
3032             /* FSETPM */
3033             case 0x24:
3034             /* FRSTPM */
3035             case 0x25:
3036             {
3037                 /* These do nothing */
3038                 break;
3039             }
3040 
3041             /* Invalid */
3042             default:
3043             {
3044                 Fast486Exception(State, FAST486_EXCEPTION_UD);
3045                 return;
3046             }
3047         }
3048     }
3049 
3050 #endif
3051 }
3052 
3053 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDC)
3054 {
3055     FAST486_MOD_REG_RM ModRegRm;
3056     BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3057 #ifndef FAST486_NO_FPU
3058     PFAST486_FPU_DATA_REG Operand;
3059     FAST486_FPU_DATA_REG MemoryData;
3060 #endif
3061 
3062     TOGGLE_ADSIZE(AddressSize);
3063 
3064     /* Get the operands */
3065     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3066     {
3067         /* Exception occurred */
3068         return;
3069     }
3070 
3071     FPU_CHECK();
3072 
3073 #ifndef FAST486_NO_FPU
3074 
3075     Fast486FpuExceptionCheck(State);
3076     FPU_SAVE_LAST_INST();
3077 
3078     if (ModRegRm.Memory)
3079     {
3080         ULONGLONG Value;
3081 
3082         if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
3083         {
3084             /* Raise the invalid operation exception */
3085             State->FpuStatus.Ie = TRUE;
3086 
3087             if (State->FpuControl.Im)
3088             {
3089                 /* Return the indefinite NaN */
3090                 FPU_ST(0).Sign = TRUE;
3091                 FPU_ST(0).Exponent = FPU_MAX_EXPONENT + 1;
3092                 FPU_ST(0).Mantissa = FPU_INDEFINITE_MANTISSA;
3093 
3094                 FPU_SET_TAG(0, FPU_TAG_SPECIAL);
3095             }
3096 
3097             return;
3098         }
3099 
3100         /* Load the source operand from memory */
3101         if (!Fast486ReadMemory(State,
3102                                (State->PrefixFlags & FAST486_PREFIX_SEG)
3103                                ? State->SegmentOverride : FAST486_REG_DS,
3104                                ModRegRm.MemoryAddress,
3105                                FALSE,
3106                                &Value,
3107                                sizeof(ULONGLONG)))
3108         {
3109             /* Exception occurred */
3110             return;
3111         }
3112 
3113         Fast486FpuFromDoubleReal(State, Value, &MemoryData);
3114         Operand = &MemoryData;
3115 
3116         FPU_SAVE_LAST_OPERAND();
3117     }
3118     else
3119     {
3120         /* Load the destination operand from an FPU register */
3121         Operand = &FPU_ST(ModRegRm.SecondRegister);
3122 
3123         if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
3124             || (FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY))
3125         {
3126             /* Raise the invalid operation exception */
3127             State->FpuStatus.Ie = TRUE;
3128 
3129             if (State->FpuControl.Im)
3130             {
3131                 /* Return the indefinite NaN */
3132                 Operand->Sign = TRUE;
3133                 Operand->Exponent = FPU_MAX_EXPONENT + 1;
3134                 Operand->Mantissa = FPU_INDEFINITE_MANTISSA;
3135 
3136                 FPU_SET_TAG(ModRegRm.SecondRegister, FPU_TAG_SPECIAL);
3137             }
3138 
3139             return;
3140         }
3141     }
3142 
3143     /* Perform the requested operation */
3144     Fast486FpuArithmeticOperation(State, ModRegRm.Register, Operand, ModRegRm.Memory);
3145 
3146 #endif
3147 }
3148 
3149 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDD)
3150 {
3151     FAST486_MOD_REG_RM ModRegRm;
3152     BOOLEAN OperandSize, AddressSize;
3153 
3154     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3155     TOGGLE_OPSIZE(OperandSize);
3156     TOGGLE_ADSIZE(AddressSize);
3157 
3158     /* Get the operands */
3159     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3160     {
3161         /* Exception occurred */
3162         return;
3163     }
3164 
3165     FPU_CHECK();
3166 
3167 #ifndef FAST486_NO_FPU
3168 
3169     if (ModRegRm.Memory)
3170     {
3171         switch (ModRegRm.Register)
3172         {
3173             /* FLD */
3174             case 0:
3175             {
3176                 ULONGLONG Value;
3177                 FAST486_FPU_DATA_REG MemoryData;
3178 
3179                 Fast486FpuExceptionCheck(State);
3180                 FPU_SAVE_LAST_INST();
3181                 FPU_SAVE_LAST_OPERAND();
3182 
3183                 if (!Fast486ReadMemory(State,
3184                                        (State->PrefixFlags & FAST486_PREFIX_SEG)
3185                                        ? State->SegmentOverride : FAST486_REG_DS,
3186                                        ModRegRm.MemoryAddress,
3187                                        FALSE,
3188                                        &Value,
3189                                        sizeof(ULONGLONG)))
3190                 {
3191                     /* Exception occurred */
3192                     return;
3193                 }
3194 
3195                 Fast486FpuFromDoubleReal(State, Value, &MemoryData);
3196                 Fast486FpuPush(State, &MemoryData);
3197 
3198                 break;
3199             }
3200 
3201             /* FST */
3202             case 2:
3203             /* FSTP */
3204             case 3:
3205             {
3206                 ULONGLONG Value = FPU_REAL8_INDEFINITE;
3207 
3208                 Fast486FpuExceptionCheck(State);
3209                 FPU_SAVE_LAST_INST();
3210                 FPU_SAVE_LAST_OPERAND();
3211 
3212                 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
3213                 {
3214                     /* Raise the invalid operation exception */
3215                     State->FpuStatus.Ie = TRUE;
3216 
3217                     if (!State->FpuControl.Im)
3218                     {
3219                         return;
3220                     }
3221                 }
3222                 else if (!Fast486FpuToDoubleReal(State, &FPU_ST(0), &Value))
3223                 {
3224                     /* Exception occurred */
3225                     return;
3226                 }
3227 
3228                 if (!Fast486WriteMemory(State,
3229                                         (State->PrefixFlags & FAST486_PREFIX_SEG)
3230                                         ? State->SegmentOverride : FAST486_REG_DS,
3231                                         ModRegRm.MemoryAddress,
3232                                         &Value,
3233                                         sizeof(ULONGLONG)))
3234                 {
3235                     /* Exception occurred */
3236                     return;
3237                 }
3238 
3239                 if (ModRegRm.Register == 3) Fast486FpuPop(State);
3240                 break;
3241             }
3242 
3243             /* FRSTOR */
3244             case 4:
3245             {
3246                 INT i;
3247                 UCHAR AllRegs[80];
3248 
3249                 /* Save the environment */
3250                 if (!Fast486FpuLoadEnvironment(State,
3251                                                (State->PrefixFlags & FAST486_PREFIX_SEG)
3252                                                ? State->SegmentOverride : FAST486_REG_DS,
3253                                                ModRegRm.MemoryAddress,
3254                                                OperandSize))
3255                 {
3256                     /* Exception occurred */
3257                     return;
3258                 }
3259 
3260                 /* Load the registers */
3261                 if (!Fast486ReadMemory(State,
3262                                        (State->PrefixFlags & FAST486_PREFIX_SEG)
3263                                        ? State->SegmentOverride : FAST486_REG_DS,
3264                                        ModRegRm.MemoryAddress + (OperandSize + 1) * 14,
3265                                        FALSE,
3266                                        AllRegs,
3267                                        sizeof(AllRegs)))
3268                 {
3269                     /* Exception occurred */
3270                     return;
3271                 }
3272 
3273                 for (i = 0; i < FAST486_NUM_FPU_REGS; i++)
3274                 {
3275                     State->FpuRegisters[i].Mantissa = *((PULONGLONG)&AllRegs[i * 10]);
3276                     State->FpuRegisters[i].Exponent = *((PUSHORT)&AllRegs[(i * 10) + sizeof(ULONGLONG)]) & 0x7FFF;
3277 
3278                     if (*((PUSHORT)&AllRegs[(i * 10) + sizeof(ULONGLONG)]) & 0x8000)
3279                     {
3280                         State->FpuRegisters[i].Sign = TRUE;
3281                     }
3282                     else
3283                     {
3284                         State->FpuRegisters[i].Sign = FALSE;
3285                     }
3286                 }
3287 
3288                 break;
3289             }
3290 
3291             /* FSAVE */
3292             case 6:
3293             {
3294                 INT i;
3295                 UCHAR AllRegs[80];
3296 
3297                 /* Save the environment */
3298                 if (!Fast486FpuSaveEnvironment(State,
3299                                                (State->PrefixFlags & FAST486_PREFIX_SEG)
3300                                                ? State->SegmentOverride : FAST486_REG_DS,
3301                                                ModRegRm.MemoryAddress,
3302                                                OperandSize))
3303                 {
3304                     /* Exception occurred */
3305                     return;
3306                 }
3307 
3308                 /* Save the registers */
3309                 for (i = 0; i < FAST486_NUM_FPU_REGS; i++)
3310                 {
3311                     *((PULONGLONG)&AllRegs[i * 10]) = State->FpuRegisters[i].Mantissa;
3312                     *((PUSHORT)&AllRegs[(i * 10) + sizeof(ULONGLONG)]) = State->FpuRegisters[i].Exponent;
3313 
3314                     if (State->FpuRegisters[i].Sign)
3315                     {
3316                         *((PUSHORT)&AllRegs[(i * 10) + sizeof(ULONGLONG)]) |= 0x8000;
3317                     }
3318                 }
3319 
3320                 Fast486WriteMemory(State,
3321                                    (State->PrefixFlags & FAST486_PREFIX_SEG)
3322                                    ? State->SegmentOverride : FAST486_REG_DS,
3323                                    ModRegRm.MemoryAddress + (OperandSize + 1) * 14,
3324                                    AllRegs,
3325                                    sizeof(AllRegs));
3326 
3327                 break;
3328             }
3329 
3330             /* FSTSW */
3331             case 7:
3332             {
3333                 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, State->FpuStatus.Value);
3334                 break;
3335             }
3336 
3337             /* Invalid */
3338             default:
3339             {
3340                 Fast486Exception(State, FAST486_EXCEPTION_UD);
3341             }
3342         }
3343     }
3344     else
3345     {
3346         switch (ModRegRm.Register)
3347         {
3348             /* FFREE */
3349             case 0:
3350             {
3351                 FPU_SET_TAG(ModRegRm.SecondRegister, FPU_TAG_EMPTY);
3352                 break;
3353             }
3354 
3355             /* FXCH */
3356             case 1:
3357             {
3358                 FAST486_FPU_DATA_REG Temp;
3359 
3360                 FPU_SAVE_LAST_INST();
3361                 Fast486FpuExceptionCheck(State);
3362 
3363                 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
3364                     || FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY)
3365                 {
3366                     State->FpuStatus.Ie = TRUE;
3367                     break;
3368                 }
3369 
3370                 /* Exchange */
3371                 Temp = FPU_ST(0);
3372                 FPU_ST(0) = FPU_ST(ModRegRm.SecondRegister);
3373                 FPU_ST(ModRegRm.SecondRegister) = Temp;
3374 
3375                 FPU_UPDATE_TAG(0);
3376                 FPU_UPDATE_TAG(ModRegRm.SecondRegister);
3377 
3378                 break;
3379             }
3380 
3381             /* FST */
3382             case 2:
3383             /* FSTP */
3384             case 3:
3385             {
3386                 FPU_SAVE_LAST_INST();
3387                 Fast486FpuExceptionCheck(State);
3388 
3389                 FPU_ST(ModRegRm.SecondRegister) = FPU_ST(0);
3390                 FPU_UPDATE_TAG(ModRegRm.SecondRegister);
3391 
3392                 if (ModRegRm.Register == 3) Fast486FpuPop(State);
3393                 break;
3394             }
3395 
3396             /* FUCOM */
3397             case 4:
3398             /* FUCOMP */
3399             case 5:
3400             {
3401                 FPU_SAVE_LAST_INST();
3402                 Fast486FpuExceptionCheck(State);
3403 
3404                 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
3405                     || (FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY))
3406                 {
3407                     State->FpuStatus.Ie = TRUE;
3408                     return;
3409                 }
3410 
3411                 Fast486FpuCompare(State, &FPU_ST(0), &FPU_ST(ModRegRm.SecondRegister));
3412                 if (ModRegRm.Register == 5) Fast486FpuPop(State);
3413 
3414                 break;
3415             }
3416 
3417             /* Invalid */
3418             default:
3419             {
3420                 Fast486Exception(State, FAST486_EXCEPTION_UD);
3421             }
3422         }
3423     }
3424 
3425 #endif
3426 }
3427 
3428 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDE)
3429 {
3430     FAST486_MOD_REG_RM ModRegRm;
3431     BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3432 #ifndef FAST486_NO_FPU
3433     PFAST486_FPU_DATA_REG Operand;
3434     FAST486_FPU_DATA_REG MemoryData;
3435 #endif
3436 
3437     TOGGLE_ADSIZE(AddressSize);
3438 
3439     /* Get the operands */
3440     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3441     {
3442         /* Exception occurred */
3443         return;
3444     }
3445 
3446     FPU_CHECK();
3447 
3448 #ifndef FAST486_NO_FPU
3449 
3450     FPU_SAVE_LAST_INST();
3451     Fast486FpuExceptionCheck(State);
3452 
3453     if (ModRegRm.Memory)
3454     {
3455         SHORT Value;
3456 
3457         if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
3458         {
3459             /* Raise the invalid operation exception */
3460             State->FpuStatus.Ie = TRUE;
3461 
3462             if (State->FpuControl.Im)
3463             {
3464                 /* Return the indefinite NaN */
3465                 FPU_ST(0).Sign = TRUE;
3466                 FPU_ST(0).Exponent = FPU_MAX_EXPONENT + 1;
3467                 FPU_ST(0).Mantissa = FPU_INDEFINITE_MANTISSA;
3468 
3469                 FPU_SET_TAG(0, FPU_TAG_SPECIAL);
3470             }
3471 
3472             return;
3473         }
3474 
3475         /* Load the source operand from memory */
3476         if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, (PUSHORT)&Value))
3477         {
3478             /* Exception occurred */
3479             return;
3480         }
3481 
3482         Fast486FpuFromInteger(State, (LONGLONG)Value, &MemoryData);
3483         Operand = &MemoryData;
3484 
3485         FPU_SAVE_LAST_OPERAND();
3486     }
3487     else
3488     {
3489         /* FCOMPP check */
3490         if ((ModRegRm.Register == 3) && (ModRegRm.SecondRegister != 1))
3491         {
3492             /* Invalid */
3493             Fast486Exception(State, FAST486_EXCEPTION_UD);
3494             return;
3495         }
3496 
3497         /* Load the destination operand from a register */
3498         Operand = &FPU_ST(ModRegRm.SecondRegister);
3499 
3500         if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
3501             || (FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY))
3502         {
3503             /* Raise the invalid operation exception, if unmasked */
3504             State->FpuStatus.Ie = TRUE;
3505             return;
3506         }
3507     }
3508 
3509     /* Perform the requested operation */
3510     Fast486FpuArithmeticOperation(State, ModRegRm.Register, Operand, ModRegRm.Memory);
3511     if (!ModRegRm.Memory) Fast486FpuPop(State);
3512 
3513 #endif
3514 }
3515 
3516 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDF)
3517 {
3518     FAST486_MOD_REG_RM ModRegRm;
3519     BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3520 
3521     TOGGLE_ADSIZE(AddressSize);
3522 
3523     /* Get the operands */
3524     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3525     {
3526         /* Exception occurred */
3527         return;
3528     }
3529 
3530     FPU_CHECK();
3531 
3532 #ifndef FAST486_NO_FPU
3533 
3534     FPU_SAVE_LAST_INST();
3535     Fast486FpuExceptionCheck(State);
3536 
3537     if (ModRegRm.Memory)
3538     {
3539         FPU_SAVE_LAST_OPERAND();
3540 
3541         switch (ModRegRm.Register)
3542         {
3543             /* FILD */
3544             case 0:
3545             {
3546                 SHORT Value;
3547                 FAST486_FPU_DATA_REG Temp;
3548 
3549                 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, (PUSHORT)&Value))
3550                 {
3551                     /* Exception occurred */
3552                     return;
3553                 }
3554 
3555                 Fast486FpuFromInteger(State, (LONGLONG)Value, &Temp);
3556                 Fast486FpuPush(State, &Temp);
3557 
3558                 break;
3559             }
3560 
3561             /* FIST */
3562             case 2:
3563             /* FISTP */
3564             case 3:
3565             {
3566                 LONGLONG Temp = 0LL;
3567 
3568                 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY) || (FPU_GET_TAG(0) == FPU_TAG_SPECIAL))
3569                 {
3570                     /* Raise the invalid operation exception */
3571                     State->FpuStatus.Ie = TRUE;
3572 
3573                     if (!State->FpuControl.Im)
3574                     {
3575                         return;
3576                     }
3577                 }
3578 
3579                 if (!Fast486FpuToInteger(State, &FPU_ST(0), &Temp))
3580                 {
3581                     /* Exception occurred */
3582                     return;
3583                 }
3584 
3585                 /* Check if it can fit in a signed 16-bit integer */
3586                 if ((LONGLONG)((SHORT)Temp) != Temp)
3587                 {
3588                     /* Raise the invalid operation exception */
3589                     State->FpuStatus.Ie = TRUE;
3590 
3591                     if (State->FpuControl.Im)
3592                     {
3593                         Temp = 0x8000LL;
3594                     }
3595                     else
3596                     {
3597                         return;
3598                     }
3599                 }
3600 
3601                 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, (USHORT)((SHORT)Temp)))
3602                 {
3603                     /* Exception occurred */
3604                     return;
3605                 }
3606 
3607                 if (ModRegRm.Register == 3)
3608                 {
3609                     /* Pop the FPU stack too */
3610                     Fast486FpuPop(State);
3611                 }
3612 
3613                 break;
3614             }
3615 
3616             /* FBLD */
3617             case 4:
3618             {
3619                 FAST486_FPU_DATA_REG Value;
3620                 UCHAR Buffer[10];
3621 
3622                 if (!Fast486ReadMemory(State,
3623                                        (State->PrefixFlags & FAST486_PREFIX_SEG)
3624                                        ? State->SegmentOverride : FAST486_REG_DS,
3625                                        ModRegRm.MemoryAddress,
3626                                        FALSE,
3627                                        Buffer,
3628                                        sizeof(Buffer)))
3629                 {
3630                     /* Exception occurred */
3631                     return;
3632                 }
3633 
3634                 Fast486FpuFromPackedBcd(State, Buffer, &Value);
3635                 Fast486FpuPush(State, &Value);
3636 
3637                 break;
3638             }
3639 
3640             /* FILD (64-bit int) */
3641             case 5:
3642             {
3643                 LONGLONG Value;
3644                 FAST486_FPU_DATA_REG Temp;
3645 
3646                 if (!Fast486ReadMemory(State,
3647                                        (State->PrefixFlags & FAST486_PREFIX_SEG)
3648                                        ? State->SegmentOverride : FAST486_REG_DS,
3649                                        ModRegRm.MemoryAddress,
3650                                        FALSE,
3651                                        &Value,
3652                                        sizeof(LONGLONG)))
3653                 {
3654                     /* Exception occurred */
3655                     return;
3656                 }
3657 
3658                 Fast486FpuFromInteger(State, (LONGLONG)Value, &Temp);
3659                 Fast486FpuPush(State, &Temp);
3660 
3661                 break;
3662             }
3663 
3664             /* FBSTP */
3665             case 6:
3666             {
3667                 UCHAR Buffer[10] = {0};
3668 
3669                 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
3670                 {
3671                     /* Raise the invalid operation exception */
3672                     State->FpuStatus.Ie = TRUE;
3673 
3674                     if (!State->FpuControl.Im)
3675                     {
3676                         return;
3677                     }
3678                 }
3679                 else if (!Fast486FpuToPackedBcd(State, &FPU_ST(0), Buffer))
3680                 {
3681                     /* Exception occurred */
3682                     return;
3683                 }
3684 
3685                 if (!Fast486WriteMemory(State,
3686                                         (State->PrefixFlags & FAST486_PREFIX_SEG)
3687                                         ? State->SegmentOverride : FAST486_REG_DS,
3688                                         ModRegRm.MemoryAddress,
3689                                         Buffer,
3690                                         sizeof(Buffer)))
3691                 {
3692                     /* Exception occurred */
3693                     return;
3694                 }
3695 
3696                 Fast486FpuPop(State);
3697                 break;
3698             }
3699 
3700             /* FISTP (64-bit int) */
3701             case 7:
3702             {
3703                 LONGLONG Temp = 0LL;
3704 
3705                 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY) || (FPU_GET_TAG(0) == FPU_TAG_SPECIAL))
3706                 {
3707                     /* Raise the invalid operation exception */
3708                     State->FpuStatus.Ie = TRUE;
3709 
3710                     if (!State->FpuControl.Im)
3711                     {
3712                         return;
3713                     }
3714                 }
3715 
3716                 if (!Fast486FpuToInteger(State, &FPU_ST(0), &Temp))
3717                 {
3718                     /* Exception occurred */
3719                     return;
3720                 }
3721 
3722                 if (!Fast486WriteMemory(State,
3723                                         (State->PrefixFlags & FAST486_PREFIX_SEG)
3724                                         ? State->SegmentOverride : FAST486_REG_DS,
3725                                         ModRegRm.MemoryAddress,
3726                                         &Temp,
3727                                         sizeof(LONGLONG)))
3728                 {
3729                     /* Exception occurred */
3730                     return;
3731                 }
3732 
3733                 /* Pop the FPU stack too */
3734                 Fast486FpuPop(State);
3735 
3736                 break;
3737             }
3738 
3739             /* Invalid */
3740             default:
3741             {
3742                 Fast486Exception(State, FAST486_EXCEPTION_UD);
3743             }
3744         }
3745     }
3746     else
3747     {
3748         switch (ModRegRm.Register)
3749         {
3750             /* FFREEP */
3751             case 0:
3752             {
3753                 FPU_SET_TAG(ModRegRm.SecondRegister, FPU_TAG_EMPTY);
3754                 Fast486FpuPop(State);
3755 
3756                 break;
3757             }
3758 
3759             /* FXCH */
3760             case 1:
3761             {
3762                 FAST486_FPU_DATA_REG Temp;
3763 
3764                 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
3765                     || FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY)
3766                 {
3767                     State->FpuStatus.Ie = TRUE;
3768                     break;
3769                 }
3770 
3771                 /* Exchange */
3772                 Temp = FPU_ST(0);
3773                 FPU_ST(0) = FPU_ST(ModRegRm.SecondRegister);
3774                 FPU_ST(ModRegRm.SecondRegister) = Temp;
3775 
3776                 FPU_UPDATE_TAG(0);
3777                 FPU_UPDATE_TAG(ModRegRm.SecondRegister);
3778 
3779                 break;
3780             }
3781 
3782             /* FSTP */
3783             case 2:
3784             case 3:
3785             {
3786                 FPU_ST(ModRegRm.SecondRegister) = FPU_ST(0);
3787                 FPU_UPDATE_TAG(ModRegRm.SecondRegister);
3788                 Fast486FpuPop(State);
3789 
3790                 break;
3791             }
3792 
3793             /* FSTSW */
3794             case 4:
3795             {
3796                 if (ModRegRm.SecondRegister != 0)
3797                 {
3798                     /* Invalid */
3799                     Fast486Exception(State, FAST486_EXCEPTION_UD);
3800                     return;
3801                 }
3802 
3803                 /* Store the status word in AX */
3804                 State->GeneralRegs[FAST486_REG_EAX].LowWord = State->FpuStatus.Value;
3805 
3806                 break;
3807             }
3808 
3809             /* Invalid */
3810             default:
3811             {
3812                 Fast486Exception(State, FAST486_EXCEPTION_UD);
3813                 return;
3814             }
3815         }
3816     }
3817 
3818 #endif
3819 }
3820 
3821 /* EOF */
3822