[FAST486]
[reactos.git] / reactos / 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 ? FAST486_REG_DS : State->SegmentOverride,
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 ? FAST486_REG_DS : State->SegmentOverride,
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 {
2422 Fast486FpuExceptionCheck(State);
2423 FPU_SAVE_LAST_INST();
2424
2425 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY || FPU_GET_TAG(1) == FPU_TAG_EMPTY)
2426 {
2427 State->FpuStatus.Ie = TRUE;
2428 break;
2429 }
2430
2431 Fast486FpuRemainder(State, &FPU_ST(0), &FPU_ST(1), TRUE, &FPU_ST(0), NULL);
2432 FPU_UPDATE_TAG(0);
2433
2434 break;
2435 }
2436
2437 /* FDECSTP */
2438 case 0x36:
2439 {
2440 State->FpuStatus.Top--;
2441 break;
2442 }
2443
2444 /* FINCSTP */
2445 case 0x37:
2446 {
2447 State->FpuStatus.Top++;
2448 break;
2449 }
2450
2451 /* FPREM */
2452 case 0x38:
2453 {
2454 Fast486FpuExceptionCheck(State);
2455 FPU_SAVE_LAST_INST();
2456
2457 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY || FPU_GET_TAG(1) == FPU_TAG_EMPTY)
2458 {
2459 State->FpuStatus.Ie = TRUE;
2460 break;
2461 }
2462
2463 Fast486FpuRemainder(State, &FPU_ST(0), &FPU_ST(1), FALSE, &FPU_ST(0), NULL);
2464 FPU_UPDATE_TAG(0);
2465
2466 break;
2467 }
2468
2469 /* FYL2XP1 */
2470 case 0x39:
2471 {
2472 FAST486_FPU_DATA_REG Value, Logarithm;
2473
2474 Fast486FpuExceptionCheck(State);
2475 FPU_SAVE_LAST_INST();
2476
2477 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY || FPU_GET_TAG(1) == FPU_TAG_EMPTY)
2478 {
2479 State->FpuStatus.Ie = TRUE;
2480 break;
2481 }
2482
2483 if (!Fast486FpuAdd(State, &FPU_ST(0), &FpuOne, &Value))
2484 {
2485 /* Exception occurred */
2486 break;
2487 }
2488
2489 if (!Fast486FpuCalculateLogBase2(State, &Value, &Logarithm))
2490 {
2491 /* Exception occurred */
2492 break;
2493 }
2494
2495 if (!Fast486FpuMultiply(State, &Logarithm, &FPU_ST(1), &FPU_ST(1)))
2496 {
2497 /* Exception occurred */
2498 break;
2499 }
2500
2501 /* Pop the stack so that the result ends up in ST0 */
2502 Fast486FpuPop(State);
2503 FPU_UPDATE_TAG(0);
2504
2505 break;
2506 }
2507
2508 /* FSQRT */
2509 case 0x3A:
2510 {
2511 Fast486FpuExceptionCheck(State);
2512 FPU_SAVE_LAST_INST();
2513
2514 Fast486FpuCalculateSquareRoot(State, &FPU_ST(0), &FPU_ST(0));
2515 FPU_UPDATE_TAG(0);
2516
2517 break;
2518 }
2519
2520 /* FSINCOS */
2521 case 0x3B:
2522 {
2523 FAST486_FPU_DATA_REG Number = FPU_ST(0);
2524
2525 Fast486FpuExceptionCheck(State);
2526 FPU_SAVE_LAST_INST();
2527
2528 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2529 {
2530 State->FpuStatus.Ie = TRUE;
2531 break;
2532 }
2533
2534 if (!FPU_IS_NORMALIZED(&FPU_ST(0)))
2535 {
2536 State->FpuStatus.De = TRUE;
2537
2538 if (!State->FpuControl.Dm)
2539 {
2540 break;
2541 }
2542 }
2543
2544 /* Replace FP0 with the sine */
2545 if (!Fast486FpuCalculateSine(State, &Number, &FPU_ST(0))) break;
2546 FPU_UPDATE_TAG(0);
2547
2548 /* Push the cosine */
2549 if (!Fast486FpuCalculateCosine(State, &Number, &Number)) break;
2550 Fast486FpuPush(State, &Number);
2551
2552 break;
2553 }
2554
2555 /* FRNDINT */
2556 case 0x3C:
2557 {
2558 LONGLONG Result = 0LL;
2559
2560 Fast486FpuExceptionCheck(State);
2561 FPU_SAVE_LAST_INST();
2562
2563 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2564 {
2565 State->FpuStatus.Ie = TRUE;
2566 break;
2567 }
2568
2569 if (!FPU_IS_NORMALIZED(&FPU_ST(0)))
2570 {
2571 State->FpuStatus.De = TRUE;
2572
2573 if (!State->FpuControl.Dm)
2574 {
2575 break;
2576 }
2577 }
2578
2579 /* Do nothing if it's too big to not be an integer */
2580 if (FPU_ST(0).Exponent >= FPU_REAL10_BIAS + 63) break;
2581
2582 /* Perform the rounding */
2583 Fast486FpuToInteger(State, &FPU_ST(0), &Result);
2584 Fast486FpuFromInteger(State, Result, &FPU_ST(0));
2585
2586 State->FpuStatus.Pe = TRUE;
2587 break;
2588 }
2589
2590 /* FSCALE */
2591 case 0x3D:
2592 {
2593 LONGLONG Scale;
2594 LONGLONG UnbiasedExp = (LONGLONG)((SHORT)FPU_ST(0).Exponent) - FPU_REAL10_BIAS;
2595 INT OldRoundingMode = State->FpuControl.Rc;
2596
2597 Fast486FpuExceptionCheck(State);
2598 FPU_SAVE_LAST_INST();
2599
2600 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY || FPU_GET_TAG(1) == FPU_TAG_EMPTY)
2601 {
2602 State->FpuStatus.Ie = TRUE;
2603 break;
2604 }
2605
2606 if (!FPU_IS_NORMALIZED(&FPU_ST(0)))
2607 {
2608 State->FpuStatus.De = TRUE;
2609
2610 if (!State->FpuControl.Dm)
2611 {
2612 break;
2613 }
2614 }
2615
2616 State->FpuControl.Rc = FPU_ROUND_TRUNCATE;
2617
2618 if (!Fast486FpuToInteger(State, &FPU_ST(1), &Scale))
2619 {
2620 /* Exception occurred */
2621 State->FpuControl.Rc = OldRoundingMode;
2622 break;
2623 }
2624
2625 State->FpuControl.Rc = OldRoundingMode;
2626
2627 /* Adjust the unbiased exponent */
2628 UnbiasedExp += Scale;
2629
2630 /* Check for underflow */
2631 if (UnbiasedExp < -1023)
2632 {
2633 /* Raise the underflow exception */
2634 State->FpuStatus.Ue = TRUE;
2635
2636 if (State->FpuControl.Um)
2637 {
2638 /* Make the result zero */
2639 FPU_ST(0) = FpuZero;
2640 FPU_UPDATE_TAG(0);
2641 }
2642
2643 break;
2644 }
2645
2646 /* Check for overflow */
2647 if (UnbiasedExp > 1023)
2648 {
2649 /* Raise the overflow exception */
2650 State->FpuStatus.Oe = TRUE;
2651
2652 if (State->FpuControl.Om)
2653 {
2654 /* Make the result infinity */
2655 FPU_ST(0).Mantissa = FPU_MANTISSA_HIGH_BIT;
2656 FPU_ST(0).Exponent = FPU_MAX_EXPONENT + 1;
2657 FPU_UPDATE_TAG(0);
2658 }
2659
2660 break;
2661 }
2662
2663 FPU_ST(0).Exponent = (USHORT)(UnbiasedExp + FPU_REAL10_BIAS);
2664 FPU_UPDATE_TAG(0);
2665
2666 break;
2667 }
2668
2669 /* FSIN */
2670 case 0x3E:
2671 {
2672 Fast486FpuExceptionCheck(State);
2673 FPU_SAVE_LAST_INST();
2674
2675 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2676 {
2677 State->FpuStatus.Ie = TRUE;
2678 break;
2679 }
2680
2681 if (!FPU_IS_NORMALIZED(&FPU_ST(0)))
2682 {
2683 State->FpuStatus.De = TRUE;
2684
2685 if (!State->FpuControl.Dm)
2686 {
2687 break;
2688 }
2689 }
2690
2691 Fast486FpuCalculateSine(State, &FPU_ST(0), &FPU_ST(0));
2692 FPU_UPDATE_TAG(0);
2693
2694 break;
2695 }
2696
2697 /* FCOS */
2698 case 0x3F:
2699 {
2700 Fast486FpuExceptionCheck(State);
2701 FPU_SAVE_LAST_INST();
2702
2703 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2704 {
2705 State->FpuStatus.Ie = TRUE;
2706 break;
2707 }
2708
2709 if (!FPU_IS_NORMALIZED(&FPU_ST(0)))
2710 {
2711 State->FpuStatus.De = TRUE;
2712
2713 if (!State->FpuControl.Dm)
2714 {
2715 break;
2716 }
2717 }
2718
2719 Fast486FpuCalculateCosine(State, &FPU_ST(0), &FPU_ST(0));
2720 FPU_UPDATE_TAG(0);
2721
2722 break;
2723 }
2724
2725 /* Invalid */
2726 default:
2727 {
2728 Fast486Exception(State, FAST486_EXCEPTION_UD);
2729 return;
2730 }
2731 }
2732 }
2733
2734 #endif
2735 }
2736
2737 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDA)
2738 {
2739 FAST486_MOD_REG_RM ModRegRm;
2740 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2741 #ifndef FAST486_NO_FPU
2742 LONG Value;
2743 FAST486_FPU_DATA_REG MemoryData;
2744 #endif
2745
2746 TOGGLE_ADSIZE(AddressSize);
2747
2748 /* Get the operands */
2749 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2750 {
2751 /* Exception occurred */
2752 return;
2753 }
2754
2755 FPU_CHECK();
2756
2757 #ifndef FAST486_NO_FPU
2758
2759 Fast486FpuExceptionCheck(State);
2760 FPU_SAVE_LAST_INST();
2761
2762 if (!ModRegRm.Memory)
2763 {
2764 /* The only valid opcode in this case is FUCOMPP (0xDA 0xE9) */
2765 if ((ModRegRm.Register != 5) && (ModRegRm.SecondRegister != 1))
2766 {
2767 Fast486Exception(State, FAST486_EXCEPTION_UD);
2768 return;
2769 }
2770
2771 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY) || (FPU_GET_TAG(1) == FPU_TAG_EMPTY))
2772 {
2773 /* Raise the invalid operation exception*/
2774 State->FpuStatus.Ie = TRUE;
2775 return;
2776 }
2777
2778 /* Compare */
2779 Fast486FpuCompare(State, &FPU_ST(0), &FPU_ST(1));
2780
2781 /* Pop twice */
2782 Fast486FpuPop(State);
2783 Fast486FpuPop(State);
2784
2785 return;
2786 }
2787
2788 FPU_SAVE_LAST_OPERAND();
2789
2790 /* Load the source operand from memory */
2791 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, (PULONG)&Value))
2792 {
2793 /* Exception occurred */
2794 return;
2795 }
2796
2797 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
2798 {
2799 /* Raise the invalid operation exception */
2800 State->FpuStatus.Ie = TRUE;
2801
2802 if (State->FpuControl.Im)
2803 {
2804 /* Return the indefinite NaN */
2805 FPU_ST(0).Sign = TRUE;
2806 FPU_ST(0).Exponent = FPU_MAX_EXPONENT + 1;
2807 FPU_ST(0).Mantissa = FPU_INDEFINITE_MANTISSA;
2808
2809 FPU_SET_TAG(0, FPU_TAG_SPECIAL);
2810 }
2811
2812 return;
2813 }
2814
2815 Fast486FpuFromInteger(State, (LONGLONG)Value, &MemoryData);
2816
2817 /* Perform the requested operation */
2818 Fast486FpuArithmeticOperation(State, ModRegRm.Register, &MemoryData, TRUE);
2819
2820 #endif
2821 }
2822
2823 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDB)
2824 {
2825 FAST486_MOD_REG_RM ModRegRm;
2826 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2827
2828 TOGGLE_ADSIZE(AddressSize);
2829
2830 /* Get the operands */
2831 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2832 {
2833 /* Exception occurred */
2834 return;
2835 }
2836
2837 FPU_CHECK();
2838
2839 #ifndef FAST486_NO_FPU
2840
2841 if (ModRegRm.Memory)
2842 {
2843 Fast486FpuExceptionCheck(State);
2844 FPU_SAVE_LAST_INST();
2845 FPU_SAVE_LAST_OPERAND();
2846
2847 switch (ModRegRm.Register)
2848 {
2849 /* FILD */
2850 case 0:
2851 {
2852 LONG Value;
2853 FAST486_FPU_DATA_REG Temp;
2854
2855 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, (PULONG)&Value))
2856 {
2857 /* Exception occurred */
2858 return;
2859 }
2860
2861 Fast486FpuFromInteger(State, (LONGLONG)Value, &Temp);
2862 Fast486FpuPush(State, &Temp);
2863
2864 break;
2865 }
2866
2867 /* FIST */
2868 case 2:
2869 /* FISTP */
2870 case 3:
2871 {
2872 LONGLONG Temp = 0;
2873
2874 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY) || (FPU_GET_TAG(0) == FPU_TAG_SPECIAL))
2875 {
2876 /* Raise the invalid operation exception */
2877 State->FpuStatus.Ie = TRUE;
2878
2879 if (!State->FpuControl.Im)
2880 {
2881 return;
2882 }
2883 }
2884
2885 if (!Fast486FpuToInteger(State, &FPU_ST(0), &Temp))
2886 {
2887 /* Exception occurred */
2888 return;
2889 }
2890
2891 /* Check if it can fit in a signed 32-bit integer */
2892 if ((LONGLONG)((LONG)Temp) != Temp)
2893 {
2894 State->FpuStatus.Ie = TRUE;
2895
2896 if (State->FpuControl.Im)
2897 {
2898 Temp = 0x80000000LL;
2899 }
2900 else
2901 {
2902 return;
2903 }
2904 }
2905
2906 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, (ULONG)((LONG)Temp)))
2907 {
2908 /* Exception occurred */
2909 return;
2910 }
2911
2912 if (ModRegRm.Register == 3)
2913 {
2914 /* Pop the FPU stack too */
2915 Fast486FpuPop(State);
2916 }
2917
2918 break;
2919 }
2920
2921 /* FLD */
2922 case 5:
2923 {
2924 FAST486_FPU_DATA_REG Value;
2925 UCHAR Buffer[10];
2926
2927 if (!Fast486ReadMemory(State,
2928 (State->PrefixFlags & FAST486_PREFIX_SEG)
2929 ? State->SegmentOverride : FAST486_REG_DS,
2930 ModRegRm.MemoryAddress,
2931 FALSE,
2932 Buffer,
2933 sizeof(Buffer)))
2934 {
2935 /* Exception occurred */
2936 return;
2937 }
2938
2939 Value.Mantissa = *((PULONGLONG)Buffer);
2940 Value.Exponent = *((PUSHORT)&Buffer[8]) & (FPU_MAX_EXPONENT + 1);
2941 Value.Sign = *((PUCHAR)&Buffer[9]) >> 7;
2942
2943 Fast486FpuPush(State, &Value);
2944 break;
2945 }
2946
2947 /* FSTP */
2948 case 7:
2949 {
2950 UCHAR Buffer[10];
2951
2952 if (FPU_GET_TAG(0) != FPU_TAG_EMPTY)
2953 {
2954 *((PULONGLONG)Buffer) = FPU_ST(0).Mantissa;
2955 *((PUSHORT)&Buffer[sizeof(ULONGLONG)]) = FPU_ST(0).Exponent
2956 | (FPU_ST(0).Sign ? 0x8000 : 0);
2957 }
2958 else
2959 {
2960 /* Raise the invalid operation exception */
2961 State->FpuStatus.Ie = TRUE;
2962
2963 if (State->FpuControl.Im)
2964 {
2965 *((PULONGLONG)Buffer) = FPU_INDEFINITE_MANTISSA;
2966 *((PUSHORT)&Buffer[sizeof(ULONGLONG)]) = 0x8000 | (FPU_MAX_EXPONENT + 1);
2967 }
2968 else
2969 {
2970 return;
2971 }
2972 }
2973
2974 if (!Fast486WriteMemory(State,
2975 (State->PrefixFlags & FAST486_PREFIX_SEG)
2976 ? State->SegmentOverride : FAST486_REG_DS,
2977 ModRegRm.MemoryAddress,
2978 Buffer,
2979 sizeof(Buffer)))
2980 {
2981 /* Exception occurred */
2982 return;
2983 }
2984
2985 Fast486FpuPop(State);
2986 break;
2987 }
2988
2989 /* Invalid */
2990 default:
2991 {
2992 Fast486Exception(State, FAST486_EXCEPTION_UD);
2993 return;
2994 }
2995 }
2996 }
2997 else
2998 {
2999 /* Only a few of these instructions have any meaning on a 487 */
3000 switch ((ModRegRm.Register << 3) | ModRegRm.SecondRegister)
3001 {
3002 /* FCLEX */
3003 case 0x22:
3004 {
3005 /* Clear exception data */
3006 State->FpuStatus.Ie =
3007 State->FpuStatus.De =
3008 State->FpuStatus.Ze =
3009 State->FpuStatus.Oe =
3010 State->FpuStatus.Ue =
3011 State->FpuStatus.Pe =
3012 State->FpuStatus.Sf =
3013 State->FpuStatus.Es =
3014 State->FpuStatus.Busy = FALSE;
3015
3016 break;
3017 }
3018
3019 /* FINIT */
3020 case 0x23:
3021 {
3022 /* Restore the state */
3023 State->FpuControl.Value = FAST486_FPU_DEFAULT_CONTROL;
3024 State->FpuStatus.Value = 0;
3025 State->FpuTag = 0xFFFF;
3026
3027 break;
3028 }
3029
3030 /* FENI */
3031 case 0x20:
3032 /* FDISI */
3033 case 0x21:
3034 /* FSETPM */
3035 case 0x24:
3036 /* FRSTPM */
3037 case 0x25:
3038 {
3039 /* These do nothing */
3040 break;
3041 }
3042
3043 /* Invalid */
3044 default:
3045 {
3046 Fast486Exception(State, FAST486_EXCEPTION_UD);
3047 return;
3048 }
3049 }
3050 }
3051
3052 #endif
3053 }
3054
3055 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDC)
3056 {
3057 FAST486_MOD_REG_RM ModRegRm;
3058 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3059 #ifndef FAST486_NO_FPU
3060 PFAST486_FPU_DATA_REG Operand;
3061 FAST486_FPU_DATA_REG MemoryData;
3062 #endif
3063
3064 TOGGLE_ADSIZE(AddressSize);
3065
3066 /* Get the operands */
3067 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3068 {
3069 /* Exception occurred */
3070 return;
3071 }
3072
3073 FPU_CHECK();
3074
3075 #ifndef FAST486_NO_FPU
3076
3077 Fast486FpuExceptionCheck(State);
3078 FPU_SAVE_LAST_INST();
3079
3080 if (ModRegRm.Memory)
3081 {
3082 ULONGLONG Value;
3083
3084 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
3085 {
3086 /* Raise the invalid operation exception */
3087 State->FpuStatus.Ie = TRUE;
3088
3089 if (State->FpuControl.Im)
3090 {
3091 /* Return the indefinite NaN */
3092 FPU_ST(0).Sign = TRUE;
3093 FPU_ST(0).Exponent = FPU_MAX_EXPONENT + 1;
3094 FPU_ST(0).Mantissa = FPU_INDEFINITE_MANTISSA;
3095
3096 FPU_SET_TAG(0, FPU_TAG_SPECIAL);
3097 }
3098
3099 return;
3100 }
3101
3102 /* Load the source operand from memory */
3103 if (!Fast486ReadMemory(State,
3104 (State->PrefixFlags & FAST486_PREFIX_SEG)
3105 ? State->SegmentOverride : FAST486_REG_DS,
3106 ModRegRm.MemoryAddress,
3107 FALSE,
3108 &Value,
3109 sizeof(ULONGLONG)))
3110 {
3111 /* Exception occurred */
3112 return;
3113 }
3114
3115 Fast486FpuFromDoubleReal(State, Value, &MemoryData);
3116 Operand = &MemoryData;
3117
3118 FPU_SAVE_LAST_OPERAND();
3119 }
3120 else
3121 {
3122 /* Load the destination operand from an FPU register */
3123 Operand = &FPU_ST(ModRegRm.SecondRegister);
3124
3125 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
3126 || (FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY))
3127 {
3128 /* Raise the invalid operation exception */
3129 State->FpuStatus.Ie = TRUE;
3130
3131 if (State->FpuControl.Im)
3132 {
3133 /* Return the indefinite NaN */
3134 Operand->Sign = TRUE;
3135 Operand->Exponent = FPU_MAX_EXPONENT + 1;
3136 Operand->Mantissa = FPU_INDEFINITE_MANTISSA;
3137
3138 FPU_SET_TAG(ModRegRm.SecondRegister, FPU_TAG_SPECIAL);
3139 }
3140
3141 return;
3142 }
3143 }
3144
3145 /* Perform the requested operation */
3146 Fast486FpuArithmeticOperation(State, ModRegRm.Register, Operand, ModRegRm.Memory);
3147
3148 #endif
3149 }
3150
3151 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDD)
3152 {
3153 FAST486_MOD_REG_RM ModRegRm;
3154 BOOLEAN OperandSize, AddressSize;
3155
3156 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3157 TOGGLE_OPSIZE(OperandSize);
3158 TOGGLE_ADSIZE(AddressSize);
3159
3160 /* Get the operands */
3161 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3162 {
3163 /* Exception occurred */
3164 return;
3165 }
3166
3167 FPU_CHECK();
3168
3169 #ifndef FAST486_NO_FPU
3170
3171 if (ModRegRm.Memory)
3172 {
3173 switch (ModRegRm.Register)
3174 {
3175 /* FLD */
3176 case 0:
3177 {
3178 ULONGLONG Value;
3179 FAST486_FPU_DATA_REG MemoryData;
3180
3181 Fast486FpuExceptionCheck(State);
3182 FPU_SAVE_LAST_INST();
3183 FPU_SAVE_LAST_OPERAND();
3184
3185 if (!Fast486ReadMemory(State,
3186 (State->PrefixFlags & FAST486_PREFIX_SEG)
3187 ? State->SegmentOverride : FAST486_REG_DS,
3188 ModRegRm.MemoryAddress,
3189 FALSE,
3190 &Value,
3191 sizeof(ULONGLONG)))
3192 {
3193 /* Exception occurred */
3194 return;
3195 }
3196
3197 Fast486FpuFromDoubleReal(State, Value, &MemoryData);
3198 Fast486FpuPush(State, &MemoryData);
3199
3200 break;
3201 }
3202
3203 /* FST */
3204 case 2:
3205 /* FSTP */
3206 case 3:
3207 {
3208 ULONGLONG Value = FPU_REAL8_INDEFINITE;
3209
3210 Fast486FpuExceptionCheck(State);
3211 FPU_SAVE_LAST_INST();
3212 FPU_SAVE_LAST_OPERAND();
3213
3214 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
3215 {
3216 /* Raise the invalid operation exception */
3217 State->FpuStatus.Ie = TRUE;
3218
3219 if (!State->FpuControl.Im)
3220 {
3221 return;
3222 }
3223 }
3224 else if (!Fast486FpuToDoubleReal(State, &FPU_ST(0), &Value))
3225 {
3226 /* Exception occurred */
3227 return;
3228 }
3229
3230 if (!Fast486WriteMemory(State,
3231 (State->PrefixFlags & FAST486_PREFIX_SEG)
3232 ? State->SegmentOverride : FAST486_REG_DS,
3233 ModRegRm.MemoryAddress,
3234 &Value,
3235 sizeof(ULONGLONG)))
3236 {
3237 /* Exception occurred */
3238 return;
3239 }
3240
3241 if (ModRegRm.Register == 3) Fast486FpuPop(State);
3242 break;
3243 }
3244
3245 /* FRSTOR */
3246 case 4:
3247 {
3248 INT i;
3249 UCHAR AllRegs[80];
3250
3251 /* Save the environment */
3252 if (!Fast486FpuLoadEnvironment(State,
3253 (State->PrefixFlags & FAST486_PREFIX_SEG)
3254 ? FAST486_REG_DS : State->SegmentOverride,
3255 ModRegRm.MemoryAddress,
3256 OperandSize))
3257 {
3258 /* Exception occurred */
3259 return;
3260 }
3261
3262 /* Load the registers */
3263 if (!Fast486ReadMemory(State,
3264 (State->PrefixFlags & FAST486_PREFIX_SEG)
3265 ? FAST486_REG_DS : State->SegmentOverride,
3266 ModRegRm.MemoryAddress + (OperandSize + 1) * 14,
3267 FALSE,
3268 AllRegs,
3269 sizeof(AllRegs)))
3270 {
3271 /* Exception occurred */
3272 return;
3273 }
3274
3275 for (i = 0; i < FAST486_NUM_FPU_REGS; i++)
3276 {
3277 State->FpuRegisters[i].Mantissa = *((PULONGLONG)&AllRegs[i * 10]);
3278 State->FpuRegisters[i].Exponent = *((PUSHORT)&AllRegs[(i * 10) + sizeof(ULONGLONG)]) & 0x7FFF;
3279
3280 if (*((PUSHORT)&AllRegs[(i * 10) + sizeof(ULONGLONG)]) & 0x8000)
3281 {
3282 State->FpuRegisters[i].Sign = TRUE;
3283 }
3284 else
3285 {
3286 State->FpuRegisters[i].Sign = FALSE;
3287 }
3288 }
3289
3290 break;
3291 }
3292
3293 /* FSAVE */
3294 case 6:
3295 {
3296 INT i;
3297 UCHAR AllRegs[80];
3298
3299 /* Save the environment */
3300 if (!Fast486FpuSaveEnvironment(State,
3301 (State->PrefixFlags & FAST486_PREFIX_SEG)
3302 ? FAST486_REG_DS : State->SegmentOverride,
3303 ModRegRm.MemoryAddress,
3304 OperandSize))
3305 {
3306 /* Exception occurred */
3307 return;
3308 }
3309
3310 /* Save the registers */
3311 for (i = 0; i < FAST486_NUM_FPU_REGS; i++)
3312 {
3313 *((PULONGLONG)&AllRegs[i * 10]) = State->FpuRegisters[i].Mantissa;
3314 *((PUSHORT)&AllRegs[(i * 10) + sizeof(ULONGLONG)]) = State->FpuRegisters[i].Exponent;
3315
3316 if (State->FpuRegisters[i].Sign)
3317 {
3318 *((PUSHORT)&AllRegs[(i * 10) + sizeof(ULONGLONG)]) |= 0x8000;
3319 }
3320 }
3321
3322 Fast486WriteMemory(State,
3323 (State->PrefixFlags & FAST486_PREFIX_SEG)
3324 ? FAST486_REG_DS : State->SegmentOverride,
3325 ModRegRm.MemoryAddress + (OperandSize + 1) * 14,
3326 AllRegs,
3327 sizeof(AllRegs));
3328
3329 break;
3330 }
3331
3332 /* FSTSW */
3333 case 7:
3334 {
3335 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, State->FpuStatus.Value);
3336 break;
3337 }
3338
3339 /* Invalid */
3340 default:
3341 {
3342 Fast486Exception(State, FAST486_EXCEPTION_UD);
3343 }
3344 }
3345 }
3346 else
3347 {
3348 switch (ModRegRm.Register)
3349 {
3350 /* FFREE */
3351 case 0:
3352 {
3353 FPU_SET_TAG(ModRegRm.SecondRegister, FPU_TAG_EMPTY);
3354 break;
3355 }
3356
3357 /* FXCH */
3358 case 1:
3359 {
3360 FAST486_FPU_DATA_REG Temp;
3361
3362 FPU_SAVE_LAST_INST();
3363 Fast486FpuExceptionCheck(State);
3364
3365 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
3366 || FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY)
3367 {
3368 State->FpuStatus.Ie = TRUE;
3369 break;
3370 }
3371
3372 /* Exchange */
3373 Temp = FPU_ST(0);
3374 FPU_ST(0) = FPU_ST(ModRegRm.SecondRegister);
3375 FPU_ST(ModRegRm.SecondRegister) = Temp;
3376
3377 FPU_UPDATE_TAG(0);
3378 FPU_UPDATE_TAG(ModRegRm.SecondRegister);
3379
3380 break;
3381 }
3382
3383 /* FST */
3384 case 2:
3385 /* FSTP */
3386 case 3:
3387 {
3388 FPU_SAVE_LAST_INST();
3389 Fast486FpuExceptionCheck(State);
3390
3391 FPU_ST(ModRegRm.SecondRegister) = FPU_ST(0);
3392 FPU_UPDATE_TAG(ModRegRm.SecondRegister);
3393
3394 if (ModRegRm.Register == 3) Fast486FpuPop(State);
3395 break;
3396 }
3397
3398 /* FUCOM */
3399 case 4:
3400 /* FUCOMP */
3401 case 5:
3402 {
3403 FPU_SAVE_LAST_INST();
3404 Fast486FpuExceptionCheck(State);
3405
3406 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
3407 || (FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY))
3408 {
3409 State->FpuStatus.Ie = TRUE;
3410 return;
3411 }
3412
3413 Fast486FpuCompare(State, &FPU_ST(0), &FPU_ST(ModRegRm.SecondRegister));
3414 if (ModRegRm.Register == 5) Fast486FpuPop(State);
3415
3416 break;
3417 }
3418
3419 /* Invalid */
3420 default:
3421 {
3422 Fast486Exception(State, FAST486_EXCEPTION_UD);
3423 }
3424 }
3425 }
3426
3427 #endif
3428 }
3429
3430 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDE)
3431 {
3432 FAST486_MOD_REG_RM ModRegRm;
3433 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3434 #ifndef FAST486_NO_FPU
3435 PFAST486_FPU_DATA_REG Operand;
3436 FAST486_FPU_DATA_REG MemoryData;
3437 #endif
3438
3439 TOGGLE_ADSIZE(AddressSize);
3440
3441 /* Get the operands */
3442 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3443 {
3444 /* Exception occurred */
3445 return;
3446 }
3447
3448 FPU_CHECK();
3449
3450 #ifndef FAST486_NO_FPU
3451
3452 FPU_SAVE_LAST_INST();
3453 Fast486FpuExceptionCheck(State);
3454
3455 if (ModRegRm.Memory)
3456 {
3457 SHORT Value;
3458
3459 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
3460 {
3461 /* Raise the invalid operation exception */
3462 State->FpuStatus.Ie = TRUE;
3463
3464 if (State->FpuControl.Im)
3465 {
3466 /* Return the indefinite NaN */
3467 FPU_ST(0).Sign = TRUE;
3468 FPU_ST(0).Exponent = FPU_MAX_EXPONENT + 1;
3469 FPU_ST(0).Mantissa = FPU_INDEFINITE_MANTISSA;
3470
3471 FPU_SET_TAG(0, FPU_TAG_SPECIAL);
3472 }
3473
3474 return;
3475 }
3476
3477 /* Load the source operand from memory */
3478 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, (PUSHORT)&Value))
3479 {
3480 /* Exception occurred */
3481 return;
3482 }
3483
3484 Fast486FpuFromInteger(State, (LONGLONG)Value, &MemoryData);
3485 Operand = &MemoryData;
3486
3487 FPU_SAVE_LAST_OPERAND();
3488 }
3489 else
3490 {
3491 /* FCOMPP check */
3492 if ((ModRegRm.Register == 3) && (ModRegRm.SecondRegister != 1))
3493 {
3494 /* Invalid */
3495 Fast486Exception(State, FAST486_EXCEPTION_UD);
3496 return;
3497 }
3498
3499 /* Load the destination operand from a register */
3500 Operand = &FPU_ST(ModRegRm.SecondRegister);
3501
3502 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
3503 || (FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY))
3504 {
3505 /* Raise the invalid operation exception, if unmasked */
3506 State->FpuStatus.Ie = TRUE;
3507 return;
3508 }
3509 }
3510
3511 /* Perform the requested operation */
3512 Fast486FpuArithmeticOperation(State, ModRegRm.Register, Operand, ModRegRm.Memory);
3513 if (!ModRegRm.Memory) Fast486FpuPop(State);
3514
3515 #endif
3516 }
3517
3518 FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDF)
3519 {
3520 FAST486_MOD_REG_RM ModRegRm;
3521 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3522
3523 TOGGLE_ADSIZE(AddressSize);
3524
3525 /* Get the operands */
3526 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3527 {
3528 /* Exception occurred */
3529 return;
3530 }
3531
3532 FPU_CHECK();
3533
3534 #ifndef FAST486_NO_FPU
3535
3536 FPU_SAVE_LAST_INST();
3537 Fast486FpuExceptionCheck(State);
3538
3539 if (ModRegRm.Memory)
3540 {
3541 FPU_SAVE_LAST_OPERAND();
3542
3543 switch (ModRegRm.Register)
3544 {
3545 /* FILD */
3546 case 0:
3547 {
3548 SHORT Value;
3549 FAST486_FPU_DATA_REG Temp;
3550
3551 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, (PUSHORT)&Value))
3552 {
3553 /* Exception occurred */
3554 return;
3555 }
3556
3557 Fast486FpuFromInteger(State, (LONGLONG)Value, &Temp);
3558 Fast486FpuPush(State, &Temp);
3559
3560 break;
3561 }
3562
3563 /* FIST */
3564 case 2:
3565 /* FISTP */
3566 case 3:
3567 {
3568 LONGLONG Temp = 0LL;
3569
3570 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY) || (FPU_GET_TAG(0) == FPU_TAG_SPECIAL))
3571 {
3572 /* Raise the invalid operation exception */
3573 State->FpuStatus.Ie = TRUE;
3574
3575 if (!State->FpuControl.Im)
3576 {
3577 return;
3578 }
3579 }
3580
3581 if (!Fast486FpuToInteger(State, &FPU_ST(0), &Temp))
3582 {
3583 /* Exception occurred */
3584 return;
3585 }
3586
3587 /* Check if it can fit in a signed 16-bit integer */
3588 if ((LONGLONG)((SHORT)Temp) != Temp)
3589 {
3590 /* Raise the invalid operation exception */
3591 State->FpuStatus.Ie = TRUE;
3592
3593 if (State->FpuControl.Im)
3594 {
3595 Temp = 0x8000LL;
3596 }
3597 else
3598 {
3599 return;
3600 }
3601 }
3602
3603 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, (USHORT)((SHORT)Temp)))
3604 {
3605 /* Exception occurred */
3606 return;
3607 }
3608
3609 if (ModRegRm.Register == 3)
3610 {
3611 /* Pop the FPU stack too */
3612 Fast486FpuPop(State);
3613 }
3614
3615 break;
3616 }
3617
3618 /* FBLD */
3619 case 4:
3620 {
3621 FAST486_FPU_DATA_REG Value;
3622 UCHAR Buffer[10];
3623
3624 if (!Fast486ReadMemory(State,
3625 (State->PrefixFlags & FAST486_PREFIX_SEG)
3626 ? State->SegmentOverride : FAST486_REG_DS,
3627 ModRegRm.MemoryAddress,
3628 FALSE,
3629 Buffer,
3630 sizeof(Buffer)))
3631 {
3632 /* Exception occurred */
3633 return;
3634 }
3635
3636 Fast486FpuFromPackedBcd(State, Buffer, &Value);
3637 Fast486FpuPush(State, &Value);
3638
3639 break;
3640 }
3641
3642 /* FILD (64-bit int) */
3643 case 5:
3644 {
3645 LONGLONG Value;
3646 FAST486_FPU_DATA_REG Temp;
3647
3648 if (!Fast486ReadMemory(State,
3649 (State->PrefixFlags & FAST486_PREFIX_SEG)
3650 ? State->SegmentOverride : FAST486_REG_DS,
3651 ModRegRm.MemoryAddress,
3652 FALSE,
3653 &Value,
3654 sizeof(LONGLONG)))
3655 {
3656 /* Exception occurred */
3657 return;
3658 }
3659
3660 Fast486FpuFromInteger(State, (LONGLONG)Value, &Temp);
3661 Fast486FpuPush(State, &Temp);
3662
3663 break;
3664 }
3665
3666 /* FBSTP */
3667 case 6:
3668 {
3669 UCHAR Buffer[10] = {0};
3670
3671 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
3672 {
3673 /* Raise the invalid operation exception */
3674 State->FpuStatus.Ie = TRUE;
3675
3676 if (!State->FpuControl.Im)
3677 {
3678 return;
3679 }
3680 }
3681 else if (!Fast486FpuToPackedBcd(State, &FPU_ST(0), Buffer))
3682 {
3683 /* Exception occurred */
3684 return;
3685 }
3686
3687 if (!Fast486WriteMemory(State,
3688 (State->PrefixFlags & FAST486_PREFIX_SEG)
3689 ? State->SegmentOverride : FAST486_REG_DS,
3690 ModRegRm.MemoryAddress,
3691 Buffer,
3692 sizeof(Buffer)))
3693 {
3694 /* Exception occurred */
3695 return;
3696 }
3697
3698 Fast486FpuPop(State);
3699 break;
3700 }
3701
3702 /* FISTP (64-bit int) */
3703 case 7:
3704 {
3705 LONGLONG Temp = 0LL;
3706
3707 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY) || (FPU_GET_TAG(0) == FPU_TAG_SPECIAL))
3708 {
3709 /* Raise the invalid operation exception */
3710 State->FpuStatus.Ie = TRUE;
3711
3712 if (!State->FpuControl.Im)
3713 {
3714 return;
3715 }
3716 }
3717
3718 if (!Fast486FpuToInteger(State, &FPU_ST(0), &Temp))
3719 {
3720 /* Exception occurred */
3721 return;
3722 }
3723
3724 if (!Fast486WriteMemory(State,
3725 (State->PrefixFlags & FAST486_PREFIX_SEG)
3726 ? State->SegmentOverride : FAST486_REG_DS,
3727 ModRegRm.MemoryAddress,
3728 &Temp,
3729 sizeof(LONGLONG)))
3730 {
3731 /* Exception occurred */
3732 return;
3733 }
3734
3735 /* Pop the FPU stack too */
3736 Fast486FpuPop(State);
3737
3738 break;
3739 }
3740
3741 /* Invalid */
3742 default:
3743 {
3744 Fast486Exception(State, FAST486_EXCEPTION_UD);
3745 }
3746 }
3747 }
3748 else
3749 {
3750 switch (ModRegRm.Register)
3751 {
3752 /* FFREEP */
3753 case 0:
3754 {
3755 FPU_SET_TAG(ModRegRm.SecondRegister, FPU_TAG_EMPTY);
3756 Fast486FpuPop(State);
3757
3758 break;
3759 }
3760
3761 /* FXCH */
3762 case 1:
3763 {
3764 FAST486_FPU_DATA_REG Temp;
3765
3766 if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
3767 || FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY)
3768 {
3769 State->FpuStatus.Ie = TRUE;
3770 break;
3771 }
3772
3773 /* Exchange */
3774 Temp = FPU_ST(0);
3775 FPU_ST(0) = FPU_ST(ModRegRm.SecondRegister);
3776 FPU_ST(ModRegRm.SecondRegister) = Temp;
3777
3778 FPU_UPDATE_TAG(0);
3779 FPU_UPDATE_TAG(ModRegRm.SecondRegister);
3780
3781 break;
3782 }
3783
3784 /* FSTP */
3785 case 2:
3786 case 3:
3787 {
3788 FPU_ST(ModRegRm.SecondRegister) = FPU_ST(0);
3789 FPU_UPDATE_TAG(ModRegRm.SecondRegister);
3790 Fast486FpuPop(State);
3791
3792 break;
3793 }
3794
3795 /* FSTSW */
3796 case 4:
3797 {
3798 if (ModRegRm.SecondRegister != 0)
3799 {
3800 /* Invalid */
3801 Fast486Exception(State, FAST486_EXCEPTION_UD);
3802 return;
3803 }
3804
3805 /* Store the status word in AX */
3806 State->GeneralRegs[FAST486_REG_EAX].LowWord = State->FpuStatus.Value;
3807
3808 break;
3809 }
3810
3811 /* Invalid */
3812 default:
3813 {
3814 Fast486Exception(State, FAST486_EXCEPTION_UD);
3815 return;
3816 }
3817 }
3818 }
3819
3820 #endif
3821 }
3822
3823 /* EOF */