1 |
|
/* |
2 |
< |
* UAE - The Un*x Amiga Emulator |
2 |
> |
* fpu/fpu_ieee.cpp |
3 |
|
* |
4 |
< |
* MC68881/MC68040 emulation |
4 |
> |
* Basilisk II (C) 1997-2008 Christian Bauer |
5 |
|
* |
6 |
< |
* Copyright 1996 Herman ten Brugge |
6 |
> |
* MC68881/68040 fpu emulation |
7 |
|
* |
8 |
+ |
* Original UAE FPU, copyright 1996 Herman ten Brugge |
9 |
+ |
* Rewrite for x86, copyright 1999-2000 Lauri Pesonen |
10 |
+ |
* New framework, copyright 2000 Gwenole Beauchesne |
11 |
+ |
* Adapted for JIT compilation (c) Bernd Meyer, 2000 |
12 |
+ |
* |
13 |
+ |
* This program is free software; you can redistribute it and/or modify |
14 |
+ |
* it under the terms of the GNU General Public License as published by |
15 |
+ |
* the Free Software Foundation; either version 2 of the License, or |
16 |
+ |
* (at your option) any later version. |
17 |
|
* |
18 |
+ |
* This program is distributed in the hope that it will be useful, |
19 |
+ |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
20 |
+ |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
21 |
+ |
* GNU General Public License for more details. |
22 |
+ |
* |
23 |
+ |
* You should have received a copy of the GNU General Public License |
24 |
+ |
* along with this program; if not, write to the Free Software |
25 |
+ |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
26 |
+ |
*/ |
27 |
+ |
|
28 |
+ |
/* |
29 |
|
* Following fixes by Lauri Pesonen, July 1999: |
30 |
|
* |
31 |
|
* FMOVEM list handling: |
200 |
|
#if 1 |
201 |
|
// Use a single, otherwise some checks for NaN, Inf, Zero would have to |
202 |
|
// be performed |
203 |
< |
fpu_single result; |
203 |
> |
fpu_single result = 0; // = 0 to workaround a compiler bug on SPARC |
204 |
|
fp_declare_init_shape(srp, result, single); |
205 |
|
srp->ieee.negative = (value >> 31) & 1; |
206 |
|
srp->ieee.exponent = (value >> 23) & FP_SINGLE_EXP_MAX; |
271 |
|
return 0.0; |
272 |
|
|
273 |
|
fpu_register result; |
274 |
< |
#ifndef USE_LONG_DOUBLE |
274 |
> |
#if USE_QUAD_DOUBLE |
275 |
> |
// is it NaN? |
276 |
> |
if ((wrd1 & 0x7fff0000) == 0x7fff0000 && wrd2 != 0 && wrd3 != 0) { |
277 |
> |
make_nan(result); |
278 |
> |
return result; |
279 |
> |
} |
280 |
> |
// is it inf? |
281 |
> |
if ((wrd1 & 0x7ffff000) == 0x7fff0000 && wrd2 == 0 && wrd3 == 0) { |
282 |
> |
if ((wrd1 & 0x80000000) == 0) |
283 |
> |
make_inf_positive(result); |
284 |
> |
else |
285 |
> |
make_inf_negative(result); |
286 |
> |
return result; |
287 |
> |
} |
288 |
> |
fp_declare_init_shape(srp, result, extended); |
289 |
> |
srp->ieee.negative = (wrd1 >> 31) & 1; |
290 |
> |
srp->ieee.exponent = (wrd1 >> 16) & FP_EXTENDED_EXP_MAX; |
291 |
> |
srp->ieee.mantissa0 = (wrd2 >> 16) & 0xffff; |
292 |
> |
srp->ieee.mantissa1 = ((wrd2 & 0xffff) << 16) | ((wrd3 >> 16) & 0xffff); |
293 |
> |
srp->ieee.mantissa2 = (wrd3 & 0xffff) << 16; |
294 |
> |
srp->ieee.mantissa3 = 0; |
295 |
> |
#elif USE_LONG_DOUBLE |
296 |
> |
fp_declare_init_shape(srp, result, extended); |
297 |
> |
srp->ieee.negative = (wrd1 >> 31) & 1; |
298 |
> |
srp->ieee.exponent = (wrd1 >> 16) & FP_EXTENDED_EXP_MAX; |
299 |
> |
srp->ieee.mantissa0 = wrd2; |
300 |
> |
srp->ieee.mantissa1 = wrd3; |
301 |
> |
#else |
302 |
|
uae_u32 sgn = (wrd1 >> 31) & 1; |
303 |
|
uae_u32 exp = (wrd1 >> 16) & 0x7fff; |
304 |
|
|
332 |
|
// drop the explicit integer bit |
333 |
|
srp->ieee.mantissa0 = (wrd2 & 0x7fffffff) >> 11; |
334 |
|
srp->ieee.mantissa1 = (wrd2 << 21) | (wrd3 >> 11); |
288 |
– |
#elif USE_QUAD_DOUBLE |
289 |
– |
fp_declare_init_shape(srp, result, extended); |
290 |
– |
srp->ieee.negative = (wrd1 >> 31) & 1; |
291 |
– |
srp->ieee.exponent = (wrd1 >> 16) & FP_EXTENDED_EXP_MAX; |
292 |
– |
srp->ieee.mantissa0 = (wrd2 >> 16) & 0xffff; |
293 |
– |
srp->ieee.mantissa1 = ((wrd2 & 0xffff) << 16) | ((wrd3 >> 16) & 0xffff); |
294 |
– |
srp->ieee.mantissa2 = (wrd3 & 0xffff) << 16; |
295 |
– |
#else |
296 |
– |
fp_declare_init_shape(srp, result, extended); |
297 |
– |
srp->ieee.negative = (wrd1 >> 31) & 1; |
298 |
– |
srp->ieee.exponent = (wrd1 >> 16) & FP_EXTENDED_EXP_MAX; |
299 |
– |
srp->ieee.mantissa0 = wrd2; |
300 |
– |
srp->ieee.mantissa1 = wrd3; |
335 |
|
#endif |
336 |
|
fpu_debug(("make_extended (%X,%X,%X) = %.04f\n",wrd1,wrd2,wrd3,(double)result)); |
337 |
|
return result; |
356 |
|
make_nan(result); |
357 |
|
return; |
358 |
|
} |
359 |
< |
#ifndef USE_LONG_DOUBLE |
359 |
> |
#if USE_QUAD_DOUBLE |
360 |
> |
// is it inf? |
361 |
> |
if ((wrd1 & 0x7ffff000) == 0x7fff0000 && wrd2 == 0 && wrd3 == 0) { |
362 |
> |
if ((wrd1 & 0x80000000) == 0) |
363 |
> |
make_inf_positive(result); |
364 |
> |
else |
365 |
> |
make_inf_negative(result); |
366 |
> |
return; |
367 |
> |
} |
368 |
> |
fp_declare_init_shape(srp, result, extended); |
369 |
> |
srp->ieee.negative = (wrd1 >> 31) & 1; |
370 |
> |
srp->ieee.exponent = (wrd1 >> 16) & FP_EXTENDED_EXP_MAX; |
371 |
> |
srp->ieee.mantissa0 = (wrd2 >> 16) & 0xffff; |
372 |
> |
srp->ieee.mantissa1 = ((wrd2 & 0xffff) << 16) | ((wrd3 >> 16) & 0xffff); |
373 |
> |
srp->ieee.mantissa2 = (wrd3 & 0xffff) << 16; |
374 |
> |
srp->ieee.mantissa3 = 0; |
375 |
> |
#elif USE_LONG_DOUBLE |
376 |
> |
fp_declare_init_shape(srp, result, extended); |
377 |
> |
srp->ieee.negative = (wrd1 >> 31) & 1; |
378 |
> |
srp->ieee.exponent = (wrd1 >> 16) & FP_EXTENDED_EXP_MAX; |
379 |
> |
srp->ieee.mantissa0 = wrd2; |
380 |
> |
srp->ieee.mantissa1 = wrd3; |
381 |
> |
#else |
382 |
|
uae_u32 exp = (wrd1 >> 16) & 0x7fff; |
383 |
|
if (exp < FP_EXTENDED_EXP_BIAS - FP_DOUBLE_EXP_BIAS) |
384 |
|
exp = 0; |
393 |
|
// drop the explicit integer bit |
394 |
|
srp->ieee.mantissa0 = (wrd2 & 0x7fffffff) >> 11; |
395 |
|
srp->ieee.mantissa1 = (wrd2 << 21) | (wrd3 >> 11); |
340 |
– |
#else |
341 |
– |
// FIXME: USE_QUAD_DOUBLE |
342 |
– |
fp_declare_init_shape(srp, result, extended); |
343 |
– |
srp->ieee.negative = (wrd1 & 0x80000000) != 0; |
344 |
– |
srp->ieee.exponent = (wrd1 >> 16) & 0x7fff; |
345 |
– |
srp->ieee.mantissa0 = wrd2; |
346 |
– |
srp->ieee.mantissa1 = wrd3; |
396 |
|
#endif |
397 |
|
fpu_debug(("make_extended (%X,%X,%X) = %.04f\n",wrd1,wrd2,wrd3,(double)result)); |
398 |
|
} |
406 |
|
*wrd1 = *wrd2 = *wrd3 = 0; |
407 |
|
return; |
408 |
|
} |
409 |
< |
#ifndef USE_LONG_DOUBLE |
409 |
> |
#if USE_QUAD_DOUBLE |
410 |
> |
// FIXME: deal with denormals? |
411 |
> |
fp_declare_init_shape(srp, src, extended); |
412 |
> |
*wrd1 = (srp->ieee.negative << 31) | (srp->ieee.exponent << 16); |
413 |
> |
// always set the explicit integer bit. |
414 |
> |
*wrd2 = 0x80000000 | (srp->ieee.mantissa0 << 15) | ((srp->ieee.mantissa1 & 0xfffe0000) >> 17); |
415 |
> |
*wrd3 = (srp->ieee.mantissa1 << 15) | ((srp->ieee.mantissa2 & 0xfffe0000) >> 17); |
416 |
> |
#elif USE_LONG_DOUBLE |
417 |
> |
uae_u32 *p = (uae_u32 *)&src; |
418 |
> |
#ifdef WORDS_BIGENDIAN |
419 |
> |
*wrd1 = p[0]; |
420 |
> |
*wrd2 = p[1]; |
421 |
> |
*wrd3 = p[2]; |
422 |
> |
#else |
423 |
> |
*wrd3 = p[0]; |
424 |
> |
*wrd2 = p[1]; |
425 |
> |
*wrd1 = ( (uae_u32)*((uae_u16 *)&p[2]) ) << 16; |
426 |
> |
#endif |
427 |
> |
#else |
428 |
|
fp_declare_init_shape(srp, src, double); |
429 |
|
fpu_debug(("extract_extended (%d,%d,%X,%X)\n", |
430 |
|
srp->ieee.negative , srp->ieee.exponent, |
441 |
|
// always set the explicit integer bit. |
442 |
|
*wrd2 = 0x80000000 | (srp->ieee.mantissa0 << 11) | ((srp->ieee.mantissa1 & 0xffe00000) >> 21); |
443 |
|
*wrd3 = srp->ieee.mantissa1 << 11; |
377 |
– |
#else |
378 |
– |
// FIXME: USE_QUAD_DOUBLE |
379 |
– |
uae_u32 *p = (uae_u32 *)&src; |
380 |
– |
#ifdef WORDS_BIGENDIAN |
381 |
– |
*wrd1 = p[0]; |
382 |
– |
*wrd2 = p[1]; |
383 |
– |
*wrd3 = p[2]; |
384 |
– |
#else |
385 |
– |
*wrd3 = p[0]; |
386 |
– |
*wrd2 = p[1]; |
387 |
– |
*wrd1 = ( (uae_u32)*((uae_u16 *)&p[2]) ) << 16; |
388 |
– |
#endif |
444 |
|
#endif |
445 |
|
fpu_debug(("extract_extended (%.04f) = %X,%X,%X\n",(double)src,*wrd1,*wrd2,*wrd3)); |
446 |
|
} |
1648 |
|
break; |
1649 |
|
#if USE_LONG_DOUBLE || USE_QUAD_DOUBLE |
1650 |
|
case 0x3c: |
1651 |
< |
FPU registers[reg] = 1.0e512; |
1651 |
> |
FPU registers[reg] = 1.0e512L; |
1652 |
|
fpu_debug(("FP const: 1.0e512\n")); |
1653 |
|
break; |
1654 |
|
case 0x3d: |
1655 |
< |
FPU registers[reg] = 1.0e1024; |
1655 |
> |
FPU registers[reg] = 1.0e1024L; |
1656 |
|
fpu_debug(("FP const: 1.0e1024\n")); |
1657 |
|
break; |
1658 |
|
case 0x3e: |
1659 |
< |
FPU registers[reg] = 1.0e2048; |
1659 |
> |
FPU registers[reg] = 1.0e2048L; |
1660 |
|
fpu_debug(("FP const: 1.0e2048\n")); |
1661 |
|
break; |
1662 |
|
case 0x3f: |
1663 |
< |
FPU registers[reg] = 1.0e4096; |
1663 |
> |
FPU registers[reg] = 1.0e4096L; |
1664 |
|
fpu_debug(("FP const: 1.0e4096\n")); |
1665 |
|
#endif |
1666 |
|
break; |
2125 |
|
#if defined(FPU_USE_X86_ROUNDING) |
2126 |
|
// Initial state after boot, reset and frestore(null frame) |
2127 |
|
x86_control_word = CW_INITIAL; |
2128 |
< |
#elif defined(__i386__) && defined(X86_ASSEMBLY) |
2128 |
> |
#elif defined(USE_X87_ASSEMBLY) |
2129 |
|
volatile unsigned short int cw; |
2130 |
|
__asm__ __volatile__("fnstcw %0" : "=m" (cw)); |
2131 |
|
cw &= ~0x0300; cw |= 0x0300; // CW_PC_EXTENDED |