[DELAYIMP] Fix 2 Clang-Cl warnings about __pfnDliNotifyHook2Default and __pfnDliFailu...
[reactos.git] / sdk / lib / fast486 / fpu.c
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 */