1 /////////////////////////////////////////////////////////////////////////
2 // $Id: fpu_trans.cc 13466 2018-02-16 07:57:32Z sshwarts $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (c) 2003-2018 Stanislav Shwartsman
6 // Written by Stanislav Shwartsman [sshwarts at sourceforge net]
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Lesser General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 //
22 /////////////////////////////////////////////////////////////////////////
23
24 #define NEED_CPU_REG_SHORTCUTS 1
25 #include "bochs.h"
26 #include "cpu/cpu.h"
27 #define LOG_THIS BX_CPU_THIS_PTR
28
29 #if BX_SUPPORT_FPU
30
31 #include "softfloatx80.h"
32 #include "softfloat-specialize.h"
33
34 extern float_status_t i387cw_to_softfloat_status_word(Bit16u control_word);
35
36 /* D9 F0 */
F2XM1(bxInstruction_c * i)37 void BX_CPP_AttrRegparmN(1) BX_CPU_C::F2XM1(bxInstruction_c *i)
38 {
39 BX_CPU_THIS_PTR prepareFPU(i);
40 BX_CPU_THIS_PTR FPU_update_last_instruction(i);
41
42 clear_C1();
43
44 if (IS_TAG_EMPTY(0)) {
45 FPU_stack_underflow(i, 0);
46 BX_NEXT_INSTR(i);
47 }
48
49 float_status_t status =
50 i387cw_to_softfloat_status_word(BX_CPU_THIS_PTR the_i387.get_control_word() | FPU_PR_80_BITS);
51
52 floatx80 result = f2xm1(BX_READ_FPU_REG(0), status);
53
54 if (! FPU_exception(i, status.float_exception_flags))
55 BX_WRITE_FPU_REG(result, 0);
56
57 BX_NEXT_INSTR(i);
58 }
59
60 /* D9 F1 */
FYL2X(bxInstruction_c * i)61 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FYL2X(bxInstruction_c *i)
62 {
63 BX_CPU_THIS_PTR prepareFPU(i);
64 BX_CPU_THIS_PTR FPU_update_last_instruction(i);
65
66 clear_C1();
67
68 if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(1))
69 {
70 FPU_stack_underflow(i, 1, 1 /* pop_stack */);
71 BX_NEXT_INSTR(i);
72 }
73
74 float_status_t status =
75 i387cw_to_softfloat_status_word(BX_CPU_THIS_PTR the_i387.get_control_word() | FPU_PR_80_BITS);
76
77 floatx80 result = fyl2x(BX_READ_FPU_REG(0), BX_READ_FPU_REG(1), status);
78
79 if (! FPU_exception(i, status.float_exception_flags)) {
80 BX_CPU_THIS_PTR the_i387.FPU_pop();
81 BX_WRITE_FPU_REG(result, 0);
82 }
83
84 BX_NEXT_INSTR(i);
85 }
86
87 /* D9 F2 */
FPTAN(bxInstruction_c * i)88 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FPTAN(bxInstruction_c *i)
89 {
90 BX_CPU_THIS_PTR prepareFPU(i);
91 BX_CPU_THIS_PTR FPU_update_last_instruction(i);
92
93 clear_C1();
94 clear_C2();
95
96 if (IS_TAG_EMPTY(0) || ! IS_TAG_EMPTY(-1))
97 {
98 if(IS_TAG_EMPTY(0))
99 FPU_exception(i, FPU_EX_Stack_Underflow);
100 else
101 FPU_exception(i, FPU_EX_Stack_Overflow);
102
103 /* The masked response */
104 if (BX_CPU_THIS_PTR the_i387.is_IA_masked())
105 {
106 BX_WRITE_FPU_REG(floatx80_default_nan, 0);
107 BX_CPU_THIS_PTR the_i387.FPU_push();
108 BX_WRITE_FPU_REG(floatx80_default_nan, 0);
109 }
110
111 BX_NEXT_INSTR(i);
112 }
113
114 extern const floatx80 Const_1;
115
116 float_status_t status =
117 i387cw_to_softfloat_status_word(BX_CPU_THIS_PTR the_i387.get_control_word() | FPU_PR_80_BITS);
118
119 floatx80 y = BX_READ_FPU_REG(0);
120 if (ftan(y, status) == -1)
121 {
122 FPU_PARTIAL_STATUS |= FPU_SW_C2;
123 BX_NEXT_INSTR(i);
124 }
125
126 if (floatx80_is_nan(y))
127 {
128 if (! FPU_exception(i, status.float_exception_flags))
129 {
130 BX_WRITE_FPU_REG(y, 0);
131 BX_CPU_THIS_PTR the_i387.FPU_push();
132 BX_WRITE_FPU_REG(y, 0);
133 }
134
135 BX_NEXT_INSTR(i);
136 }
137
138 if (! FPU_exception(i, status.float_exception_flags)) {
139 BX_WRITE_FPU_REG(y, 0);
140 BX_CPU_THIS_PTR the_i387.FPU_push();
141 BX_WRITE_FPU_REG(Const_1, 0);
142 }
143
144 BX_NEXT_INSTR(i);
145 }
146
147 /* D9 F3 */
FPATAN(bxInstruction_c * i)148 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FPATAN(bxInstruction_c *i)
149 {
150 BX_CPU_THIS_PTR prepareFPU(i);
151 BX_CPU_THIS_PTR FPU_update_last_instruction(i);
152
153 clear_C1();
154
155 if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(1))
156 {
157 FPU_stack_underflow(i, 1, 1 /* pop_stack */);
158 BX_NEXT_INSTR(i);
159 }
160
161 float_status_t status =
162 i387cw_to_softfloat_status_word(BX_CPU_THIS_PTR the_i387.get_control_word() | FPU_PR_80_BITS);
163
164 floatx80 result = fpatan(BX_READ_FPU_REG(0), BX_READ_FPU_REG(1), status);
165
166 if (! FPU_exception(i, status.float_exception_flags)) {
167 BX_CPU_THIS_PTR the_i387.FPU_pop();
168 BX_WRITE_FPU_REG(result, 0);
169 }
170
171 BX_NEXT_INSTR(i);
172 }
173
174 /* D9 F4 */
FXTRACT(bxInstruction_c * i)175 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FXTRACT(bxInstruction_c *i)
176 {
177 BX_CPU_THIS_PTR prepareFPU(i);
178 BX_CPU_THIS_PTR FPU_update_last_instruction(i);
179
180 clear_C1();
181
182 if (IS_TAG_EMPTY(0) || ! IS_TAG_EMPTY(-1))
183 {
184 if(IS_TAG_EMPTY(0))
185 FPU_exception(i, FPU_EX_Stack_Underflow);
186 else
187 FPU_exception(i, FPU_EX_Stack_Overflow);
188
189 /* The masked response */
190 if (BX_CPU_THIS_PTR the_i387.is_IA_masked())
191 {
192 BX_WRITE_FPU_REG(floatx80_default_nan, 0);
193 BX_CPU_THIS_PTR the_i387.FPU_push();
194 BX_WRITE_FPU_REG(floatx80_default_nan, 0);
195 }
196
197 BX_NEXT_INSTR(i);
198 }
199
200 float_status_t status =
201 i387cw_to_softfloat_status_word(BX_CPU_THIS_PTR the_i387.get_control_word());
202
203 floatx80 a = BX_READ_FPU_REG(0);
204 floatx80 b = floatx80_extract(a, status);
205
206 if (! FPU_exception(i, status.float_exception_flags)) {
207 BX_WRITE_FPU_REG(b, 0); // exponent
208 BX_CPU_THIS_PTR the_i387.FPU_push();
209 BX_WRITE_FPU_REG(a, 0); // fraction
210 }
211
212 BX_NEXT_INSTR(i);
213 }
214
215 /* D9 F5 */
FPREM1(bxInstruction_c * i)216 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FPREM1(bxInstruction_c *i)
217 {
218 BX_CPU_THIS_PTR prepareFPU(i);
219 BX_CPU_THIS_PTR FPU_update_last_instruction(i);
220
221 clear_C1();
222 clear_C2();
223
224 if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(1))
225 {
226 FPU_stack_underflow(i, 0);
227 BX_NEXT_INSTR(i);
228 }
229
230 float_status_t status =
231 i387cw_to_softfloat_status_word(BX_CPU_THIS_PTR the_i387.get_control_word());
232
233 Bit64u quotient;
234
235 floatx80 a = BX_READ_FPU_REG(0);
236 floatx80 b = BX_READ_FPU_REG(1);
237 floatx80 result;
238
239 int flags = floatx80_ieee754_remainder(a, b, result, quotient, status);
240
241 if (! FPU_exception(i, status.float_exception_flags)) {
242 if (flags >= 0) {
243 int cc = 0;
244 if (flags) cc = FPU_SW_C2;
245 else {
246 if (quotient & 1) cc |= FPU_SW_C1;
247 if (quotient & 2) cc |= FPU_SW_C3;
248 if (quotient & 4) cc |= FPU_SW_C0;
249 }
250 setcc(cc);
251 }
252 BX_WRITE_FPU_REG(result, 0);
253 }
254
255 BX_NEXT_INSTR(i);
256 }
257
258 /* D9 F8 */
FPREM(bxInstruction_c * i)259 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FPREM(bxInstruction_c *i)
260 {
261 BX_CPU_THIS_PTR prepareFPU(i);
262 BX_CPU_THIS_PTR FPU_update_last_instruction(i);
263
264 clear_C1();
265 clear_C2();
266
267 if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(1))
268 {
269 FPU_stack_underflow(i, 0);
270 BX_NEXT_INSTR(i);
271 }
272
273 float_status_t status =
274 i387cw_to_softfloat_status_word(BX_CPU_THIS_PTR the_i387.get_control_word());
275
276 Bit64u quotient;
277
278 floatx80 a = BX_READ_FPU_REG(0);
279 floatx80 b = BX_READ_FPU_REG(1);
280 floatx80 result;
281
282 int flags = floatx80_remainder(a, b, result, quotient, status);
283
284 if (! FPU_exception(i, status.float_exception_flags)) {
285 if (flags >= 0) {
286 int cc = 0;
287 if (flags) cc = FPU_SW_C2;
288 else {
289 if (quotient & 1) cc |= FPU_SW_C1;
290 if (quotient & 2) cc |= FPU_SW_C3;
291 if (quotient & 4) cc |= FPU_SW_C0;
292 }
293 setcc(cc);
294 }
295 BX_WRITE_FPU_REG(result, 0);
296 }
297
298 BX_NEXT_INSTR(i);
299 }
300
301 /* D9 F9 */
FYL2XP1(bxInstruction_c * i)302 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FYL2XP1(bxInstruction_c *i)
303 {
304 BX_CPU_THIS_PTR prepareFPU(i);
305 BX_CPU_THIS_PTR FPU_update_last_instruction(i);
306
307 clear_C1();
308
309 if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(1))
310 {
311 FPU_stack_underflow(i, 1, 1 /* pop_stack */);
312 BX_NEXT_INSTR(i);
313 }
314
315 float_status_t status =
316 i387cw_to_softfloat_status_word(BX_CPU_THIS_PTR the_i387.get_control_word() | FPU_PR_80_BITS);
317
318 floatx80 result = fyl2xp1(BX_READ_FPU_REG(0), BX_READ_FPU_REG(1), status);
319
320 if (! FPU_exception(i, status.float_exception_flags)) {
321 BX_CPU_THIS_PTR the_i387.FPU_pop();
322 BX_WRITE_FPU_REG(result, 0);
323 }
324
325 BX_NEXT_INSTR(i);
326 }
327
328 /* D9 FB */
FSINCOS(bxInstruction_c * i)329 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FSINCOS(bxInstruction_c *i)
330 {
331 BX_CPU_THIS_PTR prepareFPU(i);
332 BX_CPU_THIS_PTR FPU_update_last_instruction(i);
333
334 clear_C1();
335 clear_C2();
336
337 if (IS_TAG_EMPTY(0) || ! IS_TAG_EMPTY(-1))
338 {
339 if(IS_TAG_EMPTY(0))
340 FPU_exception(i, FPU_EX_Stack_Underflow);
341 else
342 FPU_exception(i, FPU_EX_Stack_Overflow);
343
344 /* The masked response */
345 if (BX_CPU_THIS_PTR the_i387.is_IA_masked())
346 {
347 BX_WRITE_FPU_REG(floatx80_default_nan, 0);
348 BX_CPU_THIS_PTR the_i387.FPU_push();
349 BX_WRITE_FPU_REG(floatx80_default_nan, 0);
350 }
351
352 BX_NEXT_INSTR(i);
353 }
354
355 float_status_t status =
356 i387cw_to_softfloat_status_word(BX_CPU_THIS_PTR the_i387.get_control_word() | FPU_PR_80_BITS);
357
358 floatx80 y = BX_READ_FPU_REG(0);
359 floatx80 sin_y, cos_y;
360 if (fsincos(y, &sin_y, &cos_y, status) == -1)
361 {
362 FPU_PARTIAL_STATUS |= FPU_SW_C2;
363 BX_NEXT_INSTR(i);
364 }
365
366 if (! FPU_exception(i, status.float_exception_flags)) {
367 BX_WRITE_FPU_REG(sin_y, 0);
368 BX_CPU_THIS_PTR the_i387.FPU_push();
369 BX_WRITE_FPU_REG(cos_y, 0);
370 }
371
372 BX_NEXT_INSTR(i);
373 }
374
375 /* D9 FD */
FSCALE(bxInstruction_c * i)376 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FSCALE(bxInstruction_c *i)
377 {
378 BX_CPU_THIS_PTR prepareFPU(i);
379 BX_CPU_THIS_PTR FPU_update_last_instruction(i);
380
381 clear_C1();
382
383 if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(1))
384 {
385 FPU_stack_underflow(i, 0);
386 BX_NEXT_INSTR(i);
387 }
388
389 float_status_t status =
390 i387cw_to_softfloat_status_word(BX_CPU_THIS_PTR the_i387.get_control_word());
391
392 floatx80 result = floatx80_scale(BX_READ_FPU_REG(0), BX_READ_FPU_REG(1), status);
393
394 if (! FPU_exception(i, status.float_exception_flags))
395 BX_WRITE_FPU_REG(result, 0);
396
397 BX_NEXT_INSTR(i);
398 }
399
400 /* D9 FE */
FSIN(bxInstruction_c * i)401 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FSIN(bxInstruction_c *i)
402 {
403 BX_CPU_THIS_PTR prepareFPU(i);
404 BX_CPU_THIS_PTR FPU_update_last_instruction(i);
405
406 clear_C1();
407 clear_C2();
408
409 if (IS_TAG_EMPTY(0)) {
410 FPU_stack_underflow(i, 0);
411 BX_NEXT_INSTR(i);
412 }
413
414 float_status_t status =
415 i387cw_to_softfloat_status_word(BX_CPU_THIS_PTR the_i387.get_control_word() | FPU_PR_80_BITS);
416
417 floatx80 y = BX_READ_FPU_REG(0);
418 if (fsin(y, status) == -1)
419 {
420 FPU_PARTIAL_STATUS |= FPU_SW_C2;
421 BX_NEXT_INSTR(i);
422 }
423
424 if (! FPU_exception(i, status.float_exception_flags))
425 BX_WRITE_FPU_REG(y, 0);
426
427 BX_NEXT_INSTR(i);
428 }
429
430 /* D9 FF */
FCOS(bxInstruction_c * i)431 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FCOS(bxInstruction_c *i)
432 {
433 BX_CPU_THIS_PTR prepareFPU(i);
434 BX_CPU_THIS_PTR FPU_update_last_instruction(i);
435
436 clear_C1();
437 clear_C2();
438
439 if (IS_TAG_EMPTY(0)) {
440 FPU_stack_underflow(i, 0);
441 BX_NEXT_INSTR(i);
442 }
443
444 float_status_t status =
445 i387cw_to_softfloat_status_word(BX_CPU_THIS_PTR the_i387.get_control_word() | FPU_PR_80_BITS);
446
447 floatx80 y = BX_READ_FPU_REG(0);
448 if (fcos(y, status) == -1)
449 {
450 FPU_PARTIAL_STATUS |= FPU_SW_C2;
451 BX_NEXT_INSTR(i);
452 }
453
454 if (! FPU_exception(i, status.float_exception_flags))
455 BX_WRITE_FPU_REG(y, 0);
456
457 BX_NEXT_INSTR(i);
458 }
459
460 #endif
461