80 |
|
fpu_t fpu; |
81 |
|
|
82 |
|
/* -------------------------------------------------------------------------- */ |
83 |
– |
/* --- Endianness --- */ |
84 |
– |
/* -------------------------------------------------------------------------- */ |
85 |
– |
|
86 |
– |
// Taken from glibc 2.1.x: endian.h |
87 |
– |
#define UAE_LITTLE_ENDIAN 1234 |
88 |
– |
#define UAE_BIG_ENDIAN 4321 |
89 |
– |
|
90 |
– |
#if WORDS_BIGENDIAN |
91 |
– |
#define UAE_BYTE_ORDER UAE_BIG_ENDIAN |
92 |
– |
#else |
93 |
– |
#define UAE_BYTE_ORDER UAE_LITTLE_ENDIAN |
94 |
– |
#endif |
95 |
– |
|
96 |
– |
// Some machines may need to use a different endianness for floating point values |
97 |
– |
// e.g. ARM in which case it is big endian |
98 |
– |
#define UAE_FLOAT_WORD_ORDER UAE_BYTE_ORDER |
99 |
– |
|
100 |
– |
/* -------------------------------------------------------------------------- */ |
83 |
|
/* --- Scopes Definition --- */ |
84 |
|
/* -------------------------------------------------------------------------- */ |
85 |
|
|
246 |
|
// to_exten |
247 |
|
PRIVATE inline fpu_register FFPU make_extended(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) |
248 |
|
{ |
249 |
< |
#if 1 |
250 |
< |
// FIXME: USE_QUAD_DOUBLE |
251 |
< |
fpu_extended result; |
249 |
> |
// is it zero? |
250 |
> |
if ((wrd1 & 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0) |
251 |
> |
return 0.0; |
252 |
> |
|
253 |
> |
fpu_register result; |
254 |
> |
#if USE_QUAD_DOUBLE |
255 |
> |
// is it NaN? |
256 |
> |
if ((wrd1 & 0x7fff0000) == 0x7fff0000 && wrd2 != 0 && wrd3 != 0) { |
257 |
> |
make_nan(result); |
258 |
> |
return result; |
259 |
> |
} |
260 |
> |
// is it inf? |
261 |
> |
if ((wrd1 & 0x7ffff000) == 0x7fff0000 && wrd2 == 0 && wrd3 == 0) { |
262 |
> |
if ((wrd1 & 0x80000000) == 0) |
263 |
> |
make_inf_positive(result); |
264 |
> |
else |
265 |
> |
make_inf_negative(result); |
266 |
> |
return result; |
267 |
> |
} |
268 |
> |
fp_declare_init_shape(srp, result, extended); |
269 |
> |
srp->ieee.negative = (wrd1 >> 31) & 1; |
270 |
> |
srp->ieee.exponent = (wrd1 >> 16) & FP_EXTENDED_EXP_MAX; |
271 |
> |
srp->ieee.mantissa0 = (wrd2 >> 16) & 0xffff; |
272 |
> |
srp->ieee.mantissa1 = ((wrd2 & 0xffff) << 16) | ((wrd3 >> 16) & 0xffff); |
273 |
> |
srp->ieee.mantissa2 = (wrd3 & 0xffff) << 16; |
274 |
> |
srp->ieee.mantissa3 = 0; |
275 |
> |
#elif USE_LONG_DOUBLE |
276 |
|
fp_declare_init_shape(srp, result, extended); |
277 |
|
srp->ieee.negative = (wrd1 >> 31) & 1; |
278 |
|
srp->ieee.exponent = (wrd1 >> 16) & FP_EXTENDED_EXP_MAX; |
279 |
|
srp->ieee.mantissa0 = wrd2; |
280 |
|
srp->ieee.mantissa1 = wrd3; |
281 |
< |
fpu_debug(("make_extended (%X,%X,%X) = %.04f\n",wrd1,wrd2,wrd3,(double)result)); |
282 |
< |
return result; |
283 |
< |
#elif 0 /* original code */ |
278 |
< |
if ((wrd1 & 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0) |
279 |
< |
return 0.0; |
280 |
< |
|
281 |
< |
fpu_register result; |
282 |
< |
uae_u32 *p = (uae_u32 *)&result; |
283 |
< |
|
284 |
< |
uae_u32 sign = wrd1 & 0x80000000; |
285 |
< |
uae_u32 exp = (wrd1 >> 16) & 0x7fff; |
281 |
> |
#else |
282 |
> |
uae_u32 sgn = (wrd1 >> 31) & 1; |
283 |
> |
uae_u32 exp = (wrd1 >> 16) & 0x7fff; |
284 |
|
|
285 |
< |
// The explicit integer bit is not set, must normalize. |
286 |
< |
if((wrd2 & 0x80000000) == 0) { |
285 |
> |
// the explicit integer bit is not set, must normalize |
286 |
> |
if ((wrd2 & 0x80000000) == 0) { |
287 |
|
fpu_debug(("make_extended denormalized mantissa (%X,%X,%X)\n",wrd1,wrd2,wrd3)); |
288 |
< |
if( wrd2 | wrd3 ) { |
288 |
> |
if (wrd2 | wrd3) { |
289 |
|
// mantissa, not fraction. |
290 |
|
uae_u64 man = ((uae_u64)wrd2 << 32) | wrd3; |
291 |
< |
while( exp > 0 && (man & UVAL64(0x8000000000000000)) == 0 ) { |
291 |
> |
while (exp > 0 && (man & UVAL64(0x8000000000000000)) == 0) { |
292 |
|
man <<= 1; |
293 |
|
exp--; |
294 |
|
} |
295 |
< |
wrd2 = (uae_u32)( man >> 32 ); |
296 |
< |
wrd3 = (uae_u32)( man & 0xFFFFFFFF ); |
299 |
< |
} else { |
300 |
< |
if(exp == 0x7FFF) { |
301 |
< |
// Infinity. |
302 |
< |
} else { |
303 |
< |
// Zero |
304 |
< |
exp = 16383 - 1023; |
305 |
< |
} |
295 |
> |
wrd2 = (uae_u32)(man >> 32); |
296 |
> |
wrd3 = (uae_u32)(man & 0xFFFFFFFF); |
297 |
|
} |
298 |
+ |
else if (exp != 0x7fff) // zero |
299 |
+ |
exp = FP_EXTENDED_EXP_BIAS - FP_DOUBLE_EXP_BIAS; |
300 |
|
} |
301 |
|
|
302 |
< |
if(exp < 16383 - 1023) { |
310 |
< |
// should set underflow. |
302 |
> |
if (exp < FP_EXTENDED_EXP_BIAS - FP_DOUBLE_EXP_BIAS) |
303 |
|
exp = 0; |
304 |
< |
} else if(exp > 16383 + 1023) { |
305 |
< |
// should set overflow. |
306 |
< |
exp = 2047; |
307 |
< |
} else { |
308 |
< |
exp = exp + 1023 - 16383; |
309 |
< |
} |
310 |
< |
|
311 |
< |
// drop the explicit integer bit. |
312 |
< |
p[FLO] = (wrd2 << 21) | (wrd3 >> 11); |
313 |
< |
p[FHI] = sign | (exp << 20) | ((wrd2 & 0x7FFFFFFF) >> 11); |
314 |
< |
|
323 |
< |
fpu_debug(("make_extended (%X,%X,%X) = %.04f\n",wrd1,wrd2,wrd3,(double)result)); |
324 |
< |
|
325 |
< |
return(result); |
304 |
> |
else if (exp > FP_EXTENDED_EXP_BIAS + FP_DOUBLE_EXP_BIAS) |
305 |
> |
exp = FP_DOUBLE_EXP_MAX; |
306 |
> |
else |
307 |
> |
exp += FP_DOUBLE_EXP_BIAS - FP_EXTENDED_EXP_BIAS; |
308 |
> |
|
309 |
> |
fp_declare_init_shape(srp, result, double); |
310 |
> |
srp->ieee.negative = sgn; |
311 |
> |
srp->ieee.exponent = exp; |
312 |
> |
// drop the explicit integer bit |
313 |
> |
srp->ieee.mantissa0 = (wrd2 & 0x7fffffff) >> 11; |
314 |
> |
srp->ieee.mantissa1 = (wrd2 << 21) | (wrd3 >> 11); |
315 |
|
#endif |
316 |
+ |
fpu_debug(("make_extended (%X,%X,%X) = %.04f\n",wrd1,wrd2,wrd3,(double)result)); |
317 |
+ |
return result; |
318 |
|
} |
319 |
|
|
320 |
|
/* |
326 |
|
uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3, fpu_register & result |
327 |
|
) |
328 |
|
{ |
329 |
< |
#if 1 |
330 |
< |
// FIXME: USE_QUAD_DOUBLE |
340 |
< |
fp_declare_init_shape(srp, result, extended); |
341 |
< |
srp->ieee.negative = (wrd1 & 0x80000000) != 0; |
342 |
< |
srp->ieee.exponent = (wrd1 >> 16) & 0x7fff; |
343 |
< |
srp->ieee.mantissa0 = wrd2; |
344 |
< |
srp->ieee.mantissa1 = wrd3; |
345 |
< |
#elif 0 /* original code */ |
346 |
< |
// Is it zero? |
347 |
< |
if ((wrd1 & 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0) { |
329 |
> |
// is it zero? |
330 |
> |
if ((wrd1 && 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0) { |
331 |
|
make_zero_positive(result); |
332 |
|
return; |
333 |
|
} |
334 |
< |
|
335 |
< |
// Is it NaN? |
336 |
< |
if( (wrd1 & 0x7FFF0000) == 0x7FFF0000 ) { |
337 |
< |
if( (wrd1 & 0x0000FFFF) || wrd2 || wrd3 ) { |
355 |
< |
make_nan(result); |
356 |
< |
return; |
357 |
< |
} |
334 |
> |
// is it NaN? |
335 |
> |
if ((wrd1 & 0x7fff0000) == 0x7fff0000 && wrd2 != 0 && wrd3 != 0) { |
336 |
> |
make_nan(result); |
337 |
> |
return; |
338 |
|
} |
339 |
< |
|
340 |
< |
uae_u32 sign = wrd1 & 0x80000000; |
341 |
< |
uae_u32 exp = (wrd1 >> 16) & 0x7fff; |
342 |
< |
|
343 |
< |
if(exp < 16383 - 1023) { |
344 |
< |
// should set underflow. |
345 |
< |
exp = 0; |
346 |
< |
} else if(exp > 16383 + 1023) { |
367 |
< |
// should set overflow. |
368 |
< |
exp = 2047; |
369 |
< |
} else { |
370 |
< |
exp = exp + 1023 - 16383; |
339 |
> |
#if USE_QUAD_DOUBLE |
340 |
> |
// is it inf? |
341 |
> |
if ((wrd1 & 0x7ffff000) == 0x7fff0000 && wrd2 == 0 && wrd3 == 0) { |
342 |
> |
if ((wrd1 & 0x80000000) == 0) |
343 |
> |
make_inf_positive(result); |
344 |
> |
else |
345 |
> |
make_inf_negative(result); |
346 |
> |
return; |
347 |
|
} |
348 |
< |
|
349 |
< |
// drop the explicit integer bit. |
350 |
< |
uae_u32 *p = (uae_u32 *)&result; |
351 |
< |
p[FLO] = (wrd2 << 21) | (wrd3 >> 11); |
352 |
< |
p[FHI] = sign | (exp << 20) | ((wrd2 & 0x7FFFFFFF) >> 11); |
353 |
< |
|
354 |
< |
fpu_debug(("make_extended (%X,%X,%X) = %.04f\n",wrd1,wrd2,wrd3,(float)(*(double *)p))); |
348 |
> |
fp_declare_init_shape(srp, result, extended); |
349 |
> |
srp->ieee.negative = (wrd1 >> 31) & 1; |
350 |
> |
srp->ieee.exponent = (wrd1 >> 16) & FP_EXTENDED_EXP_MAX; |
351 |
> |
srp->ieee.mantissa0 = (wrd2 >> 16) & 0xffff; |
352 |
> |
srp->ieee.mantissa1 = ((wrd2 & 0xffff) << 16) | ((wrd3 >> 16) & 0xffff); |
353 |
> |
srp->ieee.mantissa2 = (wrd3 & 0xffff) << 16; |
354 |
> |
srp->ieee.mantissa3 = 0; |
355 |
> |
#elif USE_LONG_DOUBLE |
356 |
> |
fp_declare_init_shape(srp, result, extended); |
357 |
> |
srp->ieee.negative = (wrd1 >> 31) & 1; |
358 |
> |
srp->ieee.exponent = (wrd1 >> 16) & FP_EXTENDED_EXP_MAX; |
359 |
> |
srp->ieee.mantissa0 = wrd2; |
360 |
> |
srp->ieee.mantissa1 = wrd3; |
361 |
> |
#else |
362 |
> |
uae_u32 exp = (wrd1 >> 16) & 0x7fff; |
363 |
> |
if (exp < FP_EXTENDED_EXP_BIAS - FP_DOUBLE_EXP_BIAS) |
364 |
> |
exp = 0; |
365 |
> |
else if (exp > FP_EXTENDED_EXP_BIAS + FP_DOUBLE_EXP_BIAS) |
366 |
> |
exp = FP_DOUBLE_EXP_MAX; |
367 |
> |
else |
368 |
> |
exp += FP_DOUBLE_EXP_BIAS - FP_EXTENDED_EXP_BIAS; |
369 |
> |
|
370 |
> |
fp_declare_init_shape(srp, result, double); |
371 |
> |
srp->ieee.negative = (wrd1 >> 31) & 1; |
372 |
> |
srp->ieee.exponent = exp; |
373 |
> |
// drop the explicit integer bit |
374 |
> |
srp->ieee.mantissa0 = (wrd2 & 0x7fffffff) >> 11; |
375 |
> |
srp->ieee.mantissa1 = (wrd2 << 21) | (wrd3 >> 11); |
376 |
|
#endif |
377 |
+ |
fpu_debug(("make_extended (%X,%X,%X) = %.04f\n",wrd1,wrd2,wrd3,(double)result)); |
378 |
|
} |
379 |
|
|
380 |
|
// from_exten |
382 |
|
uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3 |
383 |
|
) |
384 |
|
{ |
387 |
– |
#if 1 |
388 |
– |
// FIXME: USE_QUAD_DOUBLE and non little-endian specificities |
389 |
– |
uae_u32 *p = (uae_u32 *)&src; |
390 |
– |
*wrd3 = p[0]; |
391 |
– |
*wrd2 = p[1]; |
392 |
– |
*wrd1 = ( (uae_u32)*((uae_u16 *)&p[2]) ) << 16; |
393 |
– |
fpu_debug(("extract_extended (%.04f) = %X,%X,%X\n",(double)src,*wrd1,*wrd2,*wrd3)); |
394 |
– |
#elif 0 /* original code */ |
385 |
|
if (src == 0.0) { |
386 |
|
*wrd1 = *wrd2 = *wrd3 = 0; |
387 |
|
return; |
388 |
|
} |
389 |
< |
|
389 |
> |
#if USE_QUAD_DOUBLE |
390 |
> |
// FIXME: deal with denormals? |
391 |
> |
fp_declare_init_shape(srp, src, extended); |
392 |
> |
*wrd1 = (srp->ieee.negative << 31) | (srp->ieee.exponent << 16); |
393 |
> |
// always set the explicit integer bit. |
394 |
> |
*wrd2 = 0x80000000 | (srp->ieee.mantissa0 << 15) | ((srp->ieee.mantissa1 & 0xfffe0000) >> 17); |
395 |
> |
*wrd3 = (srp->ieee.mantissa1 << 15) | ((srp->ieee.mantissa2 & 0xfffe0000) >> 17); |
396 |
> |
#elif USE_LONG_DOUBLE |
397 |
|
uae_u32 *p = (uae_u32 *)&src; |
398 |
< |
|
399 |
< |
fpu_debug(("extract_extended (%X,%X)\n",p[FLO],p[FHI])); |
398 |
> |
#ifdef WORDS_BIGENDIAN |
399 |
> |
*wrd1 = p[0]; |
400 |
> |
*wrd2 = p[1]; |
401 |
> |
*wrd3 = p[2]; |
402 |
> |
#else |
403 |
> |
*wrd3 = p[0]; |
404 |
> |
*wrd2 = p[1]; |
405 |
> |
*wrd1 = ( (uae_u32)*((uae_u16 *)&p[2]) ) << 16; |
406 |
> |
#endif |
407 |
> |
#else |
408 |
> |
fp_declare_init_shape(srp, src, double); |
409 |
> |
fpu_debug(("extract_extended (%d,%d,%X,%X)\n", |
410 |
> |
srp->ieee.negative , srp->ieee.exponent, |
411 |
> |
srp->ieee.mantissa0, srp->ieee.mantissa1)); |
412 |
|
|
413 |
< |
uae_u32 sign = p[FHI] & 0x80000000; |
413 |
> |
uae_u32 exp = srp->ieee.exponent; |
414 |
|
|
415 |
< |
uae_u32 exp = ((p[FHI] >> 20) & 0x7ff); |
416 |
< |
// Check for maximum |
417 |
< |
if(exp == 0x7FF) { |
418 |
< |
exp = 0x7FFF; |
410 |
< |
} else { |
411 |
< |
exp += 16383 - 1023; |
412 |
< |
} |
415 |
> |
if (exp == FP_DOUBLE_EXP_MAX) |
416 |
> |
exp = FP_EXTENDED_EXP_MAX; |
417 |
> |
else |
418 |
> |
exp += FP_EXTENDED_EXP_BIAS - FP_DOUBLE_EXP_BIAS; |
419 |
|
|
420 |
< |
*wrd1 = sign | (exp << 16); |
420 |
> |
*wrd1 = (srp->ieee.negative << 31) | (exp << 16); |
421 |
|
// always set the explicit integer bit. |
422 |
< |
*wrd2 = 0x80000000 | ((p[FHI] & 0x000FFFFF) << 11) | ((p[FLO] & 0xFFE00000) >> 21); |
423 |
< |
*wrd3 = p[FLO] << 11; |
418 |
< |
|
419 |
< |
fpu_debug(("extract_extended (%.04f) = %X,%X,%X\n",(double)src,*wrd1,*wrd2,*wrd3)); |
422 |
> |
*wrd2 = 0x80000000 | (srp->ieee.mantissa0 << 11) | ((srp->ieee.mantissa1 & 0xffe00000) >> 21); |
423 |
> |
*wrd3 = srp->ieee.mantissa1 << 11; |
424 |
|
#endif |
425 |
+ |
fpu_debug(("extract_extended (%.04f) = %X,%X,%X\n",(double)src,*wrd1,*wrd2,*wrd3)); |
426 |
|
} |
427 |
|
|
428 |
|
// to_double |
430 |
|
{ |
431 |
|
union { |
432 |
|
fpu_double value; |
433 |
< |
uae_u32 parts[2]; |
433 |
> |
uae_u32 parts[2]; |
434 |
|
} dest; |
435 |
|
#ifdef WORDS_BIGENDIAN |
436 |
|
dest.parts[0] = wrd1; |
450 |
|
{ |
451 |
|
union { |
452 |
|
fpu_double value; |
453 |
< |
uae_u32 parts[2]; |
453 |
> |
uae_u32 parts[2]; |
454 |
|
} dest; |
455 |
|
dest.value = (fpu_double)src; |
456 |
|
#ifdef WORDS_BIGENDIAN |
1626 |
|
FPU registers[reg] = 1.0e256; |
1627 |
|
fpu_debug(("FP const: 1.0e256\n")); |
1628 |
|
break; |
1629 |
< |
#if USE_LONG_DOUBLE |
1629 |
> |
#if USE_LONG_DOUBLE || USE_QUAD_DOUBLE |
1630 |
|
case 0x3c: |
1631 |
|
FPU registers[reg] = 1.0e512; |
1632 |
|
fpu_debug(("FP const: 1.0e512\n")); |
1994 |
|
|
1995 |
|
case 0x26: /* FSCALE */ |
1996 |
|
fpu_debug(("FSCALE %.04f\n",(double)src)); |
1997 |
< |
|
1998 |
< |
// TODO: |
1999 |
< |
// Overflow, underflow |
2000 |
< |
|
1996 |
< |
if( isinf(FPU registers[reg]) ) { |
1997 |
< |
make_nan( FPU registers[reg] ); |
1998 |
< |
} |
1999 |
< |
else { |
1997 |
> |
// TODO: overflow flags |
1998 |
> |
get_dest_flags(FPU registers[reg]); |
1999 |
> |
get_source_flags(src); |
2000 |
> |
if (fl_source.in_range && fl_dest.in_range) { |
2001 |
|
// When the absolute value of the source operand is >= 2^14, |
2002 |
|
// an overflow or underflow always results. |
2003 |
|
// Here (int) cast is okay. |
2004 |
< |
fast_scale( FPU registers[reg], (int)fp_round_to_zero(src) ); |
2004 |
> |
int scale_factor = (int)fp_round_to_zero(src); |
2005 |
> |
#if USE_LONG_DOUBLE || USE_QUAD_DOUBLE |
2006 |
> |
fp_declare_init_shape(sxp, FPU registers[reg], extended); |
2007 |
> |
sxp->ieee.exponent += scale_factor; |
2008 |
> |
#else |
2009 |
> |
fp_declare_init_shape(sxp, FPU registers[reg], double); |
2010 |
> |
uae_u32 exp = sxp->ieee.exponent + scale_factor; |
2011 |
> |
if (exp < FP_EXTENDED_EXP_BIAS - FP_DOUBLE_EXP_BIAS) |
2012 |
> |
exp = 0; |
2013 |
> |
else if (exp > FP_EXTENDED_EXP_BIAS + FP_DOUBLE_EXP_BIAS) |
2014 |
> |
exp = FP_DOUBLE_EXP_MAX; |
2015 |
> |
else |
2016 |
> |
exp += FP_DOUBLE_EXP_BIAS - FP_EXTENDED_EXP_BIAS; |
2017 |
> |
sxp->ieee.exponent = exp; |
2018 |
> |
#endif |
2019 |
> |
} |
2020 |
> |
else if (fl_source.infinity) { |
2021 |
> |
// Returns NaN for any Infinity source |
2022 |
> |
make_nan( FPU registers[reg] ); |
2023 |
|
} |
2024 |
|
make_fpsr(FPU registers[reg]); |
2025 |
|
break; |
2105 |
|
#if defined(FPU_USE_X86_ROUNDING) |
2106 |
|
// Initial state after boot, reset and frestore(null frame) |
2107 |
|
x86_control_word = CW_INITIAL; |
2108 |
< |
#elif defined(__i386__) && defined(X86_ASSEMBLY) |
2108 |
> |
#elif defined(USE_X87_ASSEMBLY) |
2109 |
|
volatile unsigned short int cw; |
2110 |
|
__asm__ __volatile__("fnstcw %0" : "=m" (cw)); |
2111 |
|
cw &= ~0x0300; cw |= 0x0300; // CW_PC_EXTENDED |