diff options
Diffstat (limited to 'sim/common/sim-fpu.c')
-rw-r--r-- | sim/common/sim-fpu.c | 2566 |
1 files changed, 0 insertions, 2566 deletions
diff --git a/sim/common/sim-fpu.c b/sim/common/sim-fpu.c deleted file mode 100644 index 8931ad3..0000000 --- a/sim/common/sim-fpu.c +++ /dev/null @@ -1,2566 +0,0 @@ -/* This is a software floating point library which can be used instead - of the floating point routines in libgcc1.c for targets without - hardware floating point. */ - -/* Copyright (C) 1994,1997-1998 Free Software Foundation, Inc. - -This file is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2, or (at your option) any -later version. - -In addition to the permissions in the GNU General Public License, the -Free Software Foundation gives you unlimited permission to link the -compiled version of this file with other programs, and to distribute -those programs without any restriction coming from the use of this -file. (The General Public License restrictions do apply in other -respects; for example, they cover modification of the file, and -distribution when not linked into another program.) - -This file is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -/* As a special exception, if you link this library with other files, - some of which are compiled with GCC, to produce an executable, - this library does not by itself cause the resulting executable - to be covered by the GNU General Public License. - This exception does not however invalidate any other reasons why - the executable file might be covered by the GNU General Public License. */ - -/* This implements IEEE 754 format arithmetic, but does not provide a - mechanism for setting the rounding mode, or for generating or handling - exceptions. - - The original code by Steve Chamberlain, hacked by Mark Eichin and Jim - Wilson, all of Cygnus Support. */ - - -#ifndef SIM_FPU_C -#define SIM_FPU_C - -#include "sim-basics.h" -#include "sim-fpu.h" - -#include "sim-io.h" -#include "sim-assert.h" - - -/* Debugging support. */ - -static void -print_bits (unsigned64 x, - int msbit, - sim_fpu_print_func print, - void *arg) -{ - unsigned64 bit = LSBIT64 (msbit); - int i = 4; - while (bit) - { - if (i == 0) - print (arg, ","); - if ((x & bit)) - print (arg, "1"); - else - print (arg, "0"); - bit >>= 1; - i = (i + 1) % 4; - } -} - - - -/* Quick and dirty conversion between a host double and host 64bit int */ - -typedef union { - double d; - unsigned64 i; -} sim_fpu_map; - - -/* A packed IEEE floating point number. - - Form is <SIGN:1><BIASEDEXP:NR_EXPBITS><FRAC:NR_FRACBITS> for both - 32 and 64 bit numbers. This number is interpreted as: - - Normalized (0 < BIASEDEXP && BIASEDEXP < EXPMAX): - (sign ? '-' : '+') 1.<FRAC> x 2 ^ (BIASEDEXP - EXPBIAS) - - Denormalized (0 == BIASEDEXP && FRAC != 0): - (sign ? "-" : "+") 0.<FRAC> x 2 ^ (- EXPBIAS) - - Zero (0 == BIASEDEXP && FRAC == 0): - (sign ? "-" : "+") 0.0 - - Infinity (BIASEDEXP == EXPMAX && FRAC == 0): - (sign ? "-" : "+") "infinity" - - SignalingNaN (BIASEDEXP == EXPMAX && FRAC > 0 && FRAC < QUIET_NAN): - SNaN.FRAC - - QuietNaN (BIASEDEXP == EXPMAX && FRAC > 0 && FRAC > QUIET_NAN): - QNaN.FRAC - - */ - -#define NR_EXPBITS (is_double ? 11 : 8) -#define NR_FRACBITS (is_double ? 52 : 23) -#define SIGNBIT (is_double ? MSBIT64 (0) : MSBIT64 (32)) - -#define EXPMAX32 (255) -#define EXMPAX64 (2047) -#define EXPMAX ((unsigned) (is_double ? EXMPAX64 : EXPMAX32)) - -#define EXPBIAS32 (127) -#define EXPBIAS64 (1023) -#define EXPBIAS (is_double ? EXPBIAS64 : EXPBIAS32) - -#define QUIET_NAN LSBIT64 (NR_FRACBITS - 1) - - - -/* An unpacked floating point number. - - When unpacked, the fraction of both a 32 and 64 bit floating point - number is stored using the same format: - - 64 bit - <IMPLICIT_1:1><FRACBITS:52><GUARDS:8><PAD:00> - 32 bit - <IMPLICIT_1:1><FRACBITS:23><GUARDS:7><PAD:30> */ - -#define NR_PAD32 (30) -#define NR_PAD64 (0) -#define NR_PAD (is_double ? NR_PAD64 : NR_PAD32) -#define PADMASK (is_double ? 0 : LSMASK64 (NR_PAD32 - 1, 0)) - -#define NR_GUARDS32 (7 + NR_PAD32) -#define NR_GUARDS64 (8 + NR_PAD64) -#define NR_GUARDS (is_double ? NR_GUARDS64 : NR_GUARDS32) -#define GUARDMASK LSMASK64 (NR_GUARDS - 1, 0) - -#define GUARDMSB LSBIT64 (NR_GUARDS - 1) -#define GUARDLSB LSBIT64 (NR_PAD) -#define GUARDROUND LSMASK64 (NR_GUARDS - 2, 0) - -#define NR_FRAC_GUARD (60) -#define IMPLICIT_1 LSBIT64 (NR_FRAC_GUARD) -#define IMPLICIT_2 LSBIT64 (NR_FRAC_GUARD + 1) -#define IMPLICIT_4 LSBIT64 (NR_FRAC_GUARD + 2) -#define NR_SPARE 2 - -#define FRAC32MASK LSMASK64 (63, NR_FRAC_GUARD - 32 + 1) - -#define NORMAL_EXPMIN (-(EXPBIAS)+1) - -#define NORMAL_EXPMAX32 (EXPBIAS32) -#define NORMAL_EXPMAX64 (EXPBIAS64) -#define NORMAL_EXPMAX (EXPBIAS) - - -/* Integer constants */ - -#define MAX_INT32 ((signed64) LSMASK64 (30, 0)) -#define MAX_UINT32 LSMASK64 (31, 0) -#define MIN_INT32 ((signed64) LSMASK64 (63, 31)) - -#define MAX_INT64 ((signed64) LSMASK64 (62, 0)) -#define MAX_UINT64 LSMASK64 (63, 0) -#define MIN_INT64 ((signed64) LSMASK64 (63, 63)) - -#define MAX_INT (is_64bit ? MAX_INT64 : MAX_INT32) -#define MIN_INT (is_64bit ? MIN_INT64 : MIN_INT32) -#define MAX_UINT (is_64bit ? MAX_UINT64 : MAX_UINT32) -#define NR_INTBITS (is_64bit ? 64 : 32) - -/* Squeese an unpacked sim_fpu struct into a 32/64 bit integer */ -STATIC_INLINE_SIM_FPU (unsigned64) -pack_fpu (const sim_fpu *src, - int is_double) -{ - int sign; - unsigned64 exp; - unsigned64 fraction; - unsigned64 packed; - - switch (src->class) - { - /* create a NaN */ - case sim_fpu_class_qnan: - sign = src->sign; - exp = EXPMAX; - /* force fraction to correct class */ - fraction = src->fraction; - fraction >>= NR_GUARDS; - fraction |= QUIET_NAN; - break; - case sim_fpu_class_snan: - sign = src->sign; - exp = EXPMAX; - /* force fraction to correct class */ - fraction = src->fraction; - fraction >>= NR_GUARDS; - fraction &= ~QUIET_NAN; - break; - case sim_fpu_class_infinity: - sign = src->sign; - exp = EXPMAX; - fraction = 0; - break; - case sim_fpu_class_zero: - sign = src->sign; - exp = 0; - fraction = 0; - break; - case sim_fpu_class_number: - case sim_fpu_class_denorm: - ASSERT (src->fraction >= IMPLICIT_1); - ASSERT (src->fraction < IMPLICIT_2); - if (src->normal_exp < NORMAL_EXPMIN) - { - /* This number's exponent is too low to fit into the bits - available in the number We'll denormalize the number by - storing zero in the exponent and shift the fraction to - the right to make up for it. */ - int nr_shift = NORMAL_EXPMIN - src->normal_exp; - if (nr_shift > NR_FRACBITS) - { - /* underflow, just make the number zero */ - sign = src->sign; - exp = 0; - fraction = 0; - } - else - { - sign = src->sign; - exp = 0; - /* Shift by the value */ - fraction = src->fraction; - fraction >>= NR_GUARDS; - fraction >>= nr_shift; - } - } - else if (src->normal_exp > NORMAL_EXPMAX) - { - /* Infinity */ - sign = src->sign; - exp = EXPMAX; - fraction = 0; - } - else - { - exp = (src->normal_exp + EXPBIAS); - sign = src->sign; - fraction = src->fraction; - /* FIXME: Need to round according to WITH_SIM_FPU_ROUNDING - or some such */ - /* Round to nearest: If the guard bits are the all zero, but - the first, then we're half way between two numbers, - choose the one which makes the lsb of the answer 0. */ - if ((fraction & GUARDMASK) == GUARDMSB) - { - if ((fraction & (GUARDMSB << 1))) - fraction += (GUARDMSB << 1); - } - else - { - /* Add a one to the guards to force round to nearest */ - fraction += GUARDROUND; - } - if ((fraction & IMPLICIT_2)) /* rounding resulted in carry */ - { - exp += 1; - fraction >>= 1; - } - fraction >>= NR_GUARDS; - /* When exp == EXPMAX (overflow from carry) fraction must - have been made zero */ - ASSERT ((exp == EXPMAX) <= ((fraction & ~IMPLICIT_1) == 0)); - } - break; - default: - abort (); - } - - packed = ((sign ? SIGNBIT : 0) - | (exp << NR_FRACBITS) - | LSMASKED64 (fraction, NR_FRACBITS - 1, 0)); - - /* trace operation */ -#if 0 - if (is_double) - { - } - else - { - printf ("pack_fpu: "); - printf ("-> %c%0lX.%06lX\n", - LSMASKED32 (packed, 31, 31) ? '8' : '0', - (long) LSEXTRACTED32 (packed, 30, 23), - (long) LSEXTRACTED32 (packed, 23 - 1, 0)); - } -#endif - - return packed; -} - - -/* Unpack a 32/64 bit integer into a sim_fpu structure */ -STATIC_INLINE_SIM_FPU (void) -unpack_fpu (sim_fpu *dst, unsigned64 packed, int is_double) -{ - unsigned64 fraction = LSMASKED64 (packed, NR_FRACBITS - 1, 0); - unsigned exp = LSEXTRACTED64 (packed, NR_EXPBITS + NR_FRACBITS - 1, NR_FRACBITS); - int sign = (packed & SIGNBIT) != 0; - - if (exp == 0) - { - /* Hmm. Looks like 0 */ - if (fraction == 0) - { - /* tastes like zero */ - dst->class = sim_fpu_class_zero; - dst->sign = sign; - } - else - { - /* Zero exponent with non zero fraction - it's denormalized, - so there isn't a leading implicit one - we'll shift it so - it gets one. */ - dst->normal_exp = exp - EXPBIAS + 1; - dst->class = sim_fpu_class_denorm; - dst->sign = sign; - fraction <<= NR_GUARDS; - while (fraction < IMPLICIT_1) - { - fraction <<= 1; - dst->normal_exp--; - } - dst->fraction = fraction; - } - } - else if (exp == EXPMAX) - { - /* Huge exponent*/ - if (fraction == 0) - { - /* Attached to a zero fraction - means infinity */ - dst->class = sim_fpu_class_infinity; - dst->sign = sign; - /* dst->normal_exp = EXPBIAS; */ - /* dst->fraction = 0; */ - } - else - { - /* Non zero fraction, means NaN */ - dst->sign = sign; - dst->fraction = (fraction << NR_GUARDS); - if (fraction >= QUIET_NAN) - dst->class = sim_fpu_class_qnan; - else - dst->class = sim_fpu_class_snan; - } - } - else - { - /* Nothing strange about this number */ - dst->class = sim_fpu_class_number; - dst->sign = sign; - dst->fraction = ((fraction << NR_GUARDS) | IMPLICIT_1); - dst->normal_exp = exp - EXPBIAS; - } - - /* trace operation */ -#if 0 - if (is_double) - { - } - else - { - printf ("unpack_fpu: %c%02lX.%06lX ->\n", - LSMASKED32 (packed, 31, 31) ? '8' : '0', - (long) LSEXTRACTED32 (packed, 30, 23), - (long) LSEXTRACTED32 (packed, 23 - 1, 0)); - } -#endif - - /* sanity checks */ - { - sim_fpu_map val; - val.i = pack_fpu (dst, 1); - if (is_double) - { - ASSERT (val.i == packed); - } - else - { - unsigned32 val = pack_fpu (dst, 0); - unsigned32 org = packed; - ASSERT (val == org); - } - } -} - - -/* Convert a floating point into an integer */ -STATIC_INLINE_SIM_FPU (int) -fpu2i (signed64 *i, - const sim_fpu *s, - int is_64bit, - sim_fpu_round round) -{ - unsigned64 tmp; - int shift; - int status = 0; - if (sim_fpu_is_zero (s)) - { - *i = 0; - return 0; - } - if (sim_fpu_is_snan (s)) - { - *i = MIN_INT; /* FIXME */ - return sim_fpu_status_invalid_cvi; - } - if (sim_fpu_is_qnan (s)) - { - *i = MIN_INT; /* FIXME */ - return sim_fpu_status_invalid_cvi; - } - /* map infinity onto MAX_INT... */ - if (sim_fpu_is_infinity (s)) - { - *i = s->sign ? MIN_INT : MAX_INT; - return sim_fpu_status_invalid_cvi; - } - /* it is a number, but a small one */ - if (s->normal_exp < 0) - { - *i = 0; - return sim_fpu_status_inexact; - } - /* Is the floating point MIN_INT or just close? */ - if (s->sign && s->normal_exp == (NR_INTBITS - 1)) - { - *i = MIN_INT; - ASSERT (s->fraction >= IMPLICIT_1); - if (s->fraction == IMPLICIT_1) - return 0; /* exact */ - if (is_64bit) /* can't round */ - return sim_fpu_status_invalid_cvi; /* must be overflow */ - /* For a 32bit with MAX_INT, rounding is possible */ - switch (round) - { - case sim_fpu_round_default: - abort (); - case sim_fpu_round_zero: - if ((s->fraction & FRAC32MASK) != IMPLICIT_1) - return sim_fpu_status_invalid_cvi; - else - return sim_fpu_status_inexact; - break; - case sim_fpu_round_near: - { - if ((s->fraction & FRAC32MASK) != IMPLICIT_1) - return sim_fpu_status_invalid_cvi; - else if ((s->fraction & !FRAC32MASK) >= (~FRAC32MASK >> 1)) - return sim_fpu_status_invalid_cvi; - else - return sim_fpu_status_inexact; - } - case sim_fpu_round_up: - if ((s->fraction & FRAC32MASK) == IMPLICIT_1) - return sim_fpu_status_inexact; - else - return sim_fpu_status_invalid_cvi; - case sim_fpu_round_down: - return sim_fpu_status_invalid_cvi; - } - } - /* Would right shifting result in the FRAC being shifted into - (through) the integer's sign bit? */ - if (s->normal_exp > (NR_INTBITS - 2)) - { - *i = s->sign ? MIN_INT : MAX_INT; - return sim_fpu_status_invalid_cvi; - } - /* normal number shift it into place */ - tmp = s->fraction; - shift = (s->normal_exp - (NR_FRAC_GUARD)); - if (shift > 0) - { - tmp <<= shift; - } - else - { - shift = -shift; - if (tmp & ((SIGNED64 (1) << shift) - 1)) - status |= sim_fpu_status_inexact; - tmp >>= shift; - } - *i = s->sign ? (-tmp) : (tmp); - return status; -} - -/* convert an integer into a floating point */ -STATIC_INLINE_SIM_FPU (int) -i2fpu (sim_fpu *f, signed64 i, int is_64bit) -{ - int status = 0; - if (i == 0) - { - f->class = sim_fpu_class_zero; - f->sign = 0; - } - else - { - f->class = sim_fpu_class_number; - f->sign = (i < 0); - f->normal_exp = NR_FRAC_GUARD; - - if (f->sign) - { - /* Special case for minint, since there is no corresponding - +ve integer representation for it */ - if (i == MIN_INT) - { - f->fraction = IMPLICIT_1; - f->normal_exp = NR_INTBITS - 1; - } - else - f->fraction = (-i); - } - else - f->fraction = i; - - if (f->fraction >= IMPLICIT_2) - { - do - { - f->fraction >>= 1; - f->normal_exp += 1; - } - while (f->fraction >= IMPLICIT_2); - } - else if (f->fraction < IMPLICIT_1) - { - do - { - f->fraction <<= 1; - f->normal_exp -= 1; - } - while (f->fraction < IMPLICIT_1); - } - } - - /* trace operation */ -#if 0 - { - printf ("i2fpu: 0x%08lX ->\n", (long) i); - } -#endif - - /* sanity check */ - { - signed64 val; - fpu2i (&val, f, is_64bit, sim_fpu_round_zero); - if (i >= MIN_INT32 && i <= MAX_INT32) - { - ASSERT (val == i); - } - } - - return status; -} - - -/* Convert a floating point into an integer */ -STATIC_INLINE_SIM_FPU (int) -fpu2u (unsigned64 *u, const sim_fpu *s, int is_64bit) -{ - const int is_double = 1; - unsigned64 tmp; - int shift; - if (sim_fpu_is_zero (s)) - { - *u = 0; - return 0; - } - if (sim_fpu_is_nan (s)) - { - *u = 0; - return 0; - } - /* it is a negative number */ - if (s->sign) - { - *u = 0; - return 0; - } - /* get reasonable MAX_USI_INT... */ - if (sim_fpu_is_infinity (s)) - { - *u = MAX_UINT; - return 0; - } - /* it is a number, but a small one */ - if (s->normal_exp < 0) - { - *u = 0; - return 0; - } - /* overflow */ - if (s->normal_exp > (NR_INTBITS - 1)) - { - *u = MAX_UINT; - return 0; - } - /* normal number */ - tmp = (s->fraction & ~PADMASK); - shift = (s->normal_exp - (NR_FRACBITS + NR_GUARDS)); - if (shift > 0) - { - tmp <<= shift; - } - else - { - shift = -shift; - tmp >>= shift; - } - *u = tmp; - return 0; -} - -/* Convert an unsigned integer into a floating point */ -STATIC_INLINE_SIM_FPU (int) -u2fpu (sim_fpu *f, unsigned64 u, int is_64bit) -{ - if (u == 0) - { - f->class = sim_fpu_class_zero; - f->sign = 0; - } - else - { - f->class = sim_fpu_class_number; - f->sign = 0; - f->normal_exp = NR_FRAC_GUARD; - f->fraction = u; - - while (f->fraction < IMPLICIT_1) - { - f->fraction <<= 1; - f->normal_exp -= 1; - } - } - return 0; -} - - -/* register <-> sim_fpu */ - -INLINE_SIM_FPU (void) -sim_fpu_32to (sim_fpu *f, unsigned32 s) -{ - unpack_fpu (f, s, 0); -} - - -INLINE_SIM_FPU (void) -sim_fpu_232to (sim_fpu *f, unsigned32 h, unsigned32 l) -{ - unsigned64 s = h; - s = (s << 32) | l; - unpack_fpu (f, s, 1); -} - - -INLINE_SIM_FPU (void) -sim_fpu_64to (sim_fpu *f, unsigned64 s) -{ - unpack_fpu (f, s, 1); -} - - -INLINE_SIM_FPU (void) -sim_fpu_to32 (unsigned32 *s, - const sim_fpu *f) -{ - *s = pack_fpu (f, 0); -} - - -INLINE_SIM_FPU (void) -sim_fpu_to232 (unsigned32 *h, unsigned32 *l, - const sim_fpu *f) -{ - unsigned64 s = pack_fpu (f, 1); - *l = s; - *h = (s >> 32); -} - - -INLINE_SIM_FPU (void) -sim_fpu_to64 (unsigned64 *u, - const sim_fpu *f) -{ - *u = pack_fpu (f, 1); -} - - -INLINE_SIM_FPU (void) -sim_fpu_fractionto (sim_fpu *f, - int sign, - int normal_exp, - unsigned64 fraction, - int precision) -{ - int shift = (NR_FRAC_GUARD - precision); - f->class = sim_fpu_class_number; - f->sign = sign; - f->normal_exp = normal_exp; - /* shift the fraction to where sim-fpu expects it */ - if (shift >= 0) - f->fraction = (fraction << shift); - else - f->fraction = (fraction >> -shift); - f->fraction |= IMPLICIT_1; -} - - -INLINE_SIM_FPU (unsigned64) -sim_fpu_tofraction (const sim_fpu *d, - int precision) -{ - /* we have NR_FRAC_GUARD bits, we want only PRECISION bits */ - int shift = (NR_FRAC_GUARD - precision); - unsigned64 fraction = (d->fraction & ~IMPLICIT_1); - if (shift >= 0) - return fraction >> shift; - else - return fraction << -shift; -} - - -/* Rounding */ - -STATIC_INLINE_SIM_FPU (int) -do_normal_overflow (sim_fpu *f, - int is_double, - sim_fpu_round round) -{ - switch (round) - { - case sim_fpu_round_default: - return 0; - case sim_fpu_round_near: - f->class = sim_fpu_class_infinity; - break; - case sim_fpu_round_up: - if (!f->sign) - f->class = sim_fpu_class_infinity; - break; - case sim_fpu_round_down: - if (f->sign) - f->class = sim_fpu_class_infinity; - break; - case sim_fpu_round_zero: - break; - } - f->normal_exp = NORMAL_EXPMAX; - f->fraction = LSMASK64 (NR_FRAC_GUARD, NR_GUARDS); - return (sim_fpu_status_overflow | sim_fpu_status_inexact); -} - -STATIC_INLINE_SIM_FPU (int) -do_normal_underflow (sim_fpu *f, - int is_double, - sim_fpu_round round) -{ - switch (round) - { - case sim_fpu_round_default: - return 0; - case sim_fpu_round_near: - f->class = sim_fpu_class_zero; - break; - case sim_fpu_round_up: - if (f->sign) - f->class = sim_fpu_class_zero; - break; - case sim_fpu_round_down: - if (!f->sign) - f->class = sim_fpu_class_zero; - break; - case sim_fpu_round_zero: - f->class = sim_fpu_class_zero; - break; - } - f->normal_exp = NORMAL_EXPMIN - NR_FRACBITS; - f->fraction = IMPLICIT_1; - return (sim_fpu_status_inexact | sim_fpu_status_underflow); -} - - - -/* Round a number using NR_GUARDS. - Will return the rounded number or F->FRACTION == 0 when underflow */ - -STATIC_INLINE_SIM_FPU (int) -do_normal_round (sim_fpu *f, - int nr_guards, - sim_fpu_round round) -{ - unsigned64 guardmask = LSMASK64 (nr_guards - 1, 0); - unsigned64 guardmsb = LSBIT64 (nr_guards - 1); - unsigned64 fraclsb = guardmsb << 1; - if ((f->fraction & guardmask)) - { - int status = sim_fpu_status_inexact; - switch (round) - { - case sim_fpu_round_default: - return 0; - case sim_fpu_round_near: - if ((f->fraction & guardmsb)) - { - if ((f->fraction & fraclsb)) - { - status |= sim_fpu_status_rounded; - } - else if ((f->fraction & (guardmask >> 1))) - { - status |= sim_fpu_status_rounded; - } - } - break; - case sim_fpu_round_up: - if (!f->sign) - status |= sim_fpu_status_rounded; - break; - case sim_fpu_round_down: - if (f->sign) - status |= sim_fpu_status_rounded; - break; - case sim_fpu_round_zero: - break; - } - f->fraction &= ~guardmask; - /* round if needed, handle resulting overflow */ - if ((status & sim_fpu_status_rounded)) - { - f->fraction += fraclsb; - if ((f->fraction & IMPLICIT_2)) - { - f->fraction >>= 1; - f->normal_exp += 1; - } - } - return status; - } - else - return 0; -} - - -STATIC_INLINE_SIM_FPU (int) -do_round (sim_fpu *f, - int is_double, - sim_fpu_round round, - sim_fpu_denorm denorm) -{ - switch (f->class) - { - case sim_fpu_class_qnan: - case sim_fpu_class_zero: - case sim_fpu_class_infinity: - return 0; - break; - case sim_fpu_class_snan: - /* Quieten a SignalingNaN */ - f->class = sim_fpu_class_qnan; - return sim_fpu_status_invalid_snan; - break; - case sim_fpu_class_number: - case sim_fpu_class_denorm: - { - int status; - ASSERT (f->fraction < IMPLICIT_2); - ASSERT (f->fraction >= IMPLICIT_1); - if (f->normal_exp < NORMAL_EXPMIN) - { - /* This number's exponent is too low to fit into the bits - available in the number. Round off any bits that will be - discarded as a result of denormalization. Edge case is - the implicit bit shifted to GUARD0 and then rounded - up. */ - int shift = NORMAL_EXPMIN - f->normal_exp; - if (shift + NR_GUARDS <= NR_FRAC_GUARD + 1 - && !(denorm & sim_fpu_denorm_zero)) - { - status = do_normal_round (f, shift + NR_GUARDS, round); - if (f->fraction == 0) /* rounding underflowed */ - { - status |= do_normal_underflow (f, is_double, round); - } - else if (f->normal_exp < NORMAL_EXPMIN) /* still underflow? */ - { - status |= sim_fpu_status_denorm; - /* Any loss of precision when denormalizing is - underflow. Some processors check for underflow - before rounding, some after! */ - if (status & sim_fpu_status_inexact) - status |= sim_fpu_status_underflow; - /* Flag that resultant value has been denormalized */ - f->class = sim_fpu_class_denorm; - } - else if ((denorm & sim_fpu_denorm_underflow_inexact)) - { - if ((status & sim_fpu_status_inexact)) - status |= sim_fpu_status_underflow; - } - } - else - { - status = do_normal_underflow (f, is_double, round); - } - } - else if (f->normal_exp > NORMAL_EXPMAX) - { - /* Infinity */ - status = do_normal_overflow (f, is_double, round); - } - else - { - status = do_normal_round (f, NR_GUARDS, round); - if (f->fraction == 0) - /* f->class = sim_fpu_class_zero; */ - status |= do_normal_underflow (f, is_double, round); - else if (f->normal_exp > NORMAL_EXPMAX) - /* oops! rounding caused overflow */ - status |= do_normal_overflow (f, is_double, round); - } - ASSERT ((f->class == sim_fpu_class_number - || f->class == sim_fpu_class_denorm) - <= (f->fraction < IMPLICIT_2 && f->fraction >= IMPLICIT_1)); - return status; - } - } - return 0; -} - -INLINE_SIM_FPU (int) -sim_fpu_round_32 (sim_fpu *f, - sim_fpu_round round, - sim_fpu_denorm denorm) -{ - return do_round (f, 0, round, denorm); -} - -INLINE_SIM_FPU (int) -sim_fpu_round_64 (sim_fpu *f, - sim_fpu_round round, - sim_fpu_denorm denorm) -{ - return do_round (f, 1, round, denorm); -} - - - -/* Arithmetic ops */ - -INLINE_SIM_FPU (int) -sim_fpu_add (sim_fpu *f, - const sim_fpu *l, - const sim_fpu *r) -{ - if (sim_fpu_is_snan (l)) - { - *f = *l; - f->class = sim_fpu_class_qnan; - return sim_fpu_status_invalid_snan; - } - if (sim_fpu_is_snan (r)) - { - *f = *r; - f->class = sim_fpu_class_qnan; - return sim_fpu_status_invalid_snan; - } - if (sim_fpu_is_qnan (l)) - { - *f = *l; - return 0; - } - if (sim_fpu_is_qnan (r)) - { - *f = *r; - return 0; - } - if (sim_fpu_is_infinity (l)) - { - if (sim_fpu_is_infinity (r) - && l->sign != r->sign) - { - *f = sim_fpu_qnan; - return sim_fpu_status_invalid_isi; - } - *f = *l; - return 0; - } - if (sim_fpu_is_infinity (r)) - { - *f = *r; - return 0; - } - if (sim_fpu_is_zero (l)) - { - if (sim_fpu_is_zero (r)) - { - *f = sim_fpu_zero; - f->sign = l->sign & r->sign; - } - else - *f = *r; - return 0; - } - if (sim_fpu_is_zero (r)) - { - *f = *l; - return 0; - } - { - int status = 0; - int shift = l->normal_exp - r->normal_exp; - unsigned64 lfraction; - unsigned64 rfraction; - /* use exp of larger */ - if (shift >= NR_FRAC_GUARD) - { - /* left has much bigger magnitute */ - *f = *l; - return sim_fpu_status_inexact; - } - if (shift <= - NR_FRAC_GUARD) - { - /* right has much bigger magnitute */ - *f = *r; - return sim_fpu_status_inexact; - } - lfraction = l->fraction; - rfraction = r->fraction; - if (shift > 0) - { - f->normal_exp = l->normal_exp; - if (rfraction & LSMASK64 (shift - 1, 0)) - { - status |= sim_fpu_status_inexact; - rfraction |= LSBIT64 (shift); /* stick LSBit */ - } - rfraction >>= shift; - } - else if (shift < 0) - { - f->normal_exp = r->normal_exp; - if (lfraction & LSMASK64 (- shift - 1, 0)) - { - status |= sim_fpu_status_inexact; - lfraction |= LSBIT64 (- shift); /* stick LSBit */ - } - lfraction >>= -shift; - } - else - { - f->normal_exp = r->normal_exp; - } - - /* perform the addition */ - if (l->sign) - lfraction = - lfraction; - if (r->sign) - rfraction = - rfraction; - f->fraction = lfraction + rfraction; - - /* zero? */ - if (f->fraction == 0) - { - *f = sim_fpu_zero; - return 0; - } - - /* sign? */ - f->class = sim_fpu_class_number; - if ((signed64) f->fraction >= 0) - f->sign = 0; - else - { - f->sign = 1; - f->fraction = - f->fraction; - } - - /* normalize it */ - if ((f->fraction & IMPLICIT_2)) - { - f->fraction = (f->fraction >> 1) | (f->fraction & 1); - f->normal_exp ++; - } - else if (f->fraction < IMPLICIT_1) - { - do - { - f->fraction <<= 1; - f->normal_exp --; - } - while (f->fraction < IMPLICIT_1); - } - ASSERT (f->fraction >= IMPLICIT_1 && f->fraction < IMPLICIT_2); - return status; - } -} - - -INLINE_SIM_FPU (int) -sim_fpu_sub (sim_fpu *f, - const sim_fpu *l, - const sim_fpu *r) -{ - if (sim_fpu_is_snan (l)) - { - *f = *l; - f->class = sim_fpu_class_qnan; - return sim_fpu_status_invalid_snan; - } - if (sim_fpu_is_snan (r)) - { - *f = *r; - f->class = sim_fpu_class_qnan; - return sim_fpu_status_invalid_snan; - } - if (sim_fpu_is_qnan (l)) - { - *f = *l; - return 0; - } - if (sim_fpu_is_qnan (r)) - { - *f = *r; - return 0; - } - if (sim_fpu_is_infinity (l)) - { - if (sim_fpu_is_infinity (r) - && l->sign == r->sign) - { - *f = sim_fpu_qnan; - return sim_fpu_status_invalid_isi; - } - *f = *l; - return 0; - } - if (sim_fpu_is_infinity (r)) - { - *f = *r; - f->sign = !r->sign; - return 0; - } - if (sim_fpu_is_zero (l)) - { - if (sim_fpu_is_zero (r)) - { - *f = sim_fpu_zero; - f->sign = l->sign & !r->sign; - } - else - { - *f = *r; - f->sign = !r->sign; - } - return 0; - } - if (sim_fpu_is_zero (r)) - { - *f = *l; - return 0; - } - { - int status = 0; - int shift = l->normal_exp - r->normal_exp; - unsigned64 lfraction; - unsigned64 rfraction; - /* use exp of larger */ - if (shift >= NR_FRAC_GUARD) - { - /* left has much bigger magnitute */ - *f = *l; - return sim_fpu_status_inexact; - } - if (shift <= - NR_FRAC_GUARD) - { - /* right has much bigger magnitute */ - *f = *r; - f->sign = !r->sign; - return sim_fpu_status_inexact; - } - lfraction = l->fraction; - rfraction = r->fraction; - if (shift > 0) - { - f->normal_exp = l->normal_exp; - if (rfraction & LSMASK64 (shift - 1, 0)) - { - status |= sim_fpu_status_inexact; - rfraction |= LSBIT64 (shift); /* stick LSBit */ - } - rfraction >>= shift; - } - else if (shift < 0) - { - f->normal_exp = r->normal_exp; - if (lfraction & LSMASK64 (- shift - 1, 0)) - { - status |= sim_fpu_status_inexact; - lfraction |= LSBIT64 (- shift); /* stick LSBit */ - } - lfraction >>= -shift; - } - else - { - f->normal_exp = r->normal_exp; - } - - /* perform the subtraction */ - if (l->sign) - lfraction = - lfraction; - if (!r->sign) - rfraction = - rfraction; - f->fraction = lfraction + rfraction; - - /* zero? */ - if (f->fraction == 0) - { - *f = sim_fpu_zero; - return 0; - } - - /* sign? */ - f->class = sim_fpu_class_number; - if ((signed64) f->fraction >= 0) - f->sign = 0; - else - { - f->sign = 1; - f->fraction = - f->fraction; - } - - /* normalize it */ - if ((f->fraction & IMPLICIT_2)) - { - f->fraction = (f->fraction >> 1) | (f->fraction & 1); - f->normal_exp ++; - } - else if (f->fraction < IMPLICIT_1) - { - do - { - f->fraction <<= 1; - f->normal_exp --; - } - while (f->fraction < IMPLICIT_1); - } - ASSERT (f->fraction >= IMPLICIT_1 && f->fraction < IMPLICIT_2); - return status; - } -} - - -INLINE_SIM_FPU (int) -sim_fpu_mul (sim_fpu *f, - const sim_fpu *l, - const sim_fpu *r) -{ - if (sim_fpu_is_snan (l)) - { - *f = *l; - f->class = sim_fpu_class_qnan; - return sim_fpu_status_invalid_snan; - } - if (sim_fpu_is_snan (r)) - { - *f = *r; - f->class = sim_fpu_class_qnan; - return sim_fpu_status_invalid_snan; - } - if (sim_fpu_is_qnan (l)) - { - *f = *l; - return 0; - } - if (sim_fpu_is_qnan (r)) - { - *f = *r; - return 0; - } - if (sim_fpu_is_infinity (l)) - { - if (sim_fpu_is_zero (r)) - { - *f = sim_fpu_qnan; - return sim_fpu_status_invalid_imz; - } - *f = *l; - f->sign = l->sign ^ r->sign; - return 0; - } - if (sim_fpu_is_infinity (r)) - { - if (sim_fpu_is_zero (l)) - { - *f = sim_fpu_qnan; - return sim_fpu_status_invalid_imz; - } - *f = *r; - f->sign = l->sign ^ r->sign; - return 0; - } - if (sim_fpu_is_zero (l) || sim_fpu_is_zero (r)) - { - *f = sim_fpu_zero; - f->sign = l->sign ^ r->sign; - return 0; - } - /* Calculate the mantissa by multiplying both 64bit numbers to get a - 128 bit number */ - { - unsigned64 low; - unsigned64 high; - unsigned64 nl = l->fraction & 0xffffffff; - unsigned64 nh = l->fraction >> 32; - unsigned64 ml = r->fraction & 0xffffffff; - unsigned64 mh = r->fraction >>32; - unsigned64 pp_ll = ml * nl; - unsigned64 pp_hl = mh * nl; - unsigned64 pp_lh = ml * nh; - unsigned64 pp_hh = mh * nh; - unsigned64 res2 = 0; - unsigned64 res0 = 0; - unsigned64 ps_hh__ = pp_hl + pp_lh; - if (ps_hh__ < pp_hl) - res2 += UNSIGNED64 (0x100000000); - pp_hl = (ps_hh__ << 32) & UNSIGNED64 (0xffffffff00000000); - res0 = pp_ll + pp_hl; - if (res0 < pp_ll) - res2++; - res2 += ((ps_hh__ >> 32) & 0xffffffff) + pp_hh; - high = res2; - low = res0; - - f->normal_exp = l->normal_exp + r->normal_exp; - f->sign = l->sign ^ r->sign; - f->class = sim_fpu_class_number; - - /* Input is bounded by [1,2) ; [2^60,2^61) - Output is bounded by [1,4) ; [2^120,2^122) */ - - /* Adjust the exponent according to where the decimal point ended - up in the high 64 bit word. In the source the decimal point - was at NR_FRAC_GUARD. */ - f->normal_exp += NR_FRAC_GUARD + 64 - (NR_FRAC_GUARD * 2); - - /* The high word is bounded according to the above. Consequently - it has never overflowed into IMPLICIT_2. */ - ASSERT (high < LSBIT64 (((NR_FRAC_GUARD + 1) * 2) - 64)); - ASSERT (high >= LSBIT64 ((NR_FRAC_GUARD * 2) - 64)); - ASSERT (LSBIT64 (((NR_FRAC_GUARD + 1) * 2) - 64) < IMPLICIT_1); - -#if 0 - printf ("\n"); - print_bits (high, 63, (sim_fpu_print_func*)fprintf, stdout); - printf (";"); - print_bits (low, 63, (sim_fpu_print_func*)fprintf, stdout); - printf ("\n"); -#endif - - /* normalize */ - do - { - f->normal_exp--; - high <<= 1; - if (low & LSBIT64 (63)) - high |= 1; - low <<= 1; - } - while (high < IMPLICIT_1); - -#if 0 - print_bits (high, 63, (sim_fpu_print_func*)fprintf, stdout); - printf (";"); - print_bits (low, 63, (sim_fpu_print_func*)fprintf, stdout); - printf ("\n"); -#endif - - ASSERT (high >= IMPLICIT_1 && high < IMPLICIT_2); - if (low != 0) - { - f->fraction = (high | 1); /* sticky */ - return sim_fpu_status_inexact; - } - else - { - f->fraction = high; - return 0; - } - return 0; - } -} - -INLINE_SIM_FPU (int) -sim_fpu_div (sim_fpu *f, - const sim_fpu *l, - const sim_fpu *r) -{ - if (sim_fpu_is_snan (l)) - { - *f = *l; - f->class = sim_fpu_class_qnan; - return sim_fpu_status_invalid_snan; - } - if (sim_fpu_is_snan (r)) - { - *f = *r; - f->class = sim_fpu_class_qnan; - return sim_fpu_status_invalid_snan; - } - if (sim_fpu_is_qnan (l)) - { - *f = *l; - f->class = sim_fpu_class_qnan; - return 0; - } - if (sim_fpu_is_qnan (r)) - { - *f = *r; - f->class = sim_fpu_class_qnan; - return 0; - } - if (sim_fpu_is_infinity (l)) - { - if (sim_fpu_is_infinity (r)) - { - *f = sim_fpu_qnan; - return sim_fpu_status_invalid_idi; - } - else - { - *f = *l; - f->sign = l->sign ^ r->sign; - return 0; - } - } - if (sim_fpu_is_zero (l)) - { - if (sim_fpu_is_zero (r)) - { - *f = sim_fpu_qnan; - return sim_fpu_status_invalid_zdz; - } - else - { - *f = *l; - f->sign = l->sign ^ r->sign; - return 0; - } - } - if (sim_fpu_is_infinity (r)) - { - *f = sim_fpu_zero; - f->sign = l->sign ^ r->sign; - return 0; - } - if (sim_fpu_is_zero (r)) - { - f->class = sim_fpu_class_infinity; - f->sign = l->sign ^ r->sign; - return sim_fpu_status_invalid_div0; - } - - /* Calculate the mantissa by multiplying both 64bit numbers to get a - 128 bit number */ - { - /* quotient = ( ( numerator / denominator) - x 2^(numerator exponent - denominator exponent) - */ - unsigned64 numerator; - unsigned64 denominator; - unsigned64 quotient; - unsigned64 bit; - - f->class = sim_fpu_class_number; - f->sign = l->sign ^ r->sign; - f->normal_exp = l->normal_exp - r->normal_exp; - - numerator = l->fraction; - denominator = r->fraction; - - /* Fraction will be less than 1.0 */ - if (numerator < denominator) - { - numerator <<= 1; - f->normal_exp--; - } - ASSERT (numerator >= denominator); - - /* Gain extra precision, already used one spare bit */ - numerator <<= NR_SPARE; - denominator <<= NR_SPARE; - - /* Does divide one bit at a time. Optimize??? */ - quotient = 0; - bit = (IMPLICIT_1 << NR_SPARE); - while (bit) - { - if (numerator >= denominator) - { - quotient |= bit; - numerator -= denominator; - } - bit >>= 1; - numerator <<= 1; - } - -#if 0 - printf ("\n"); - print_bits (quotient, 63, (sim_fpu_print_func*)fprintf, stdout); - printf ("\n"); - print_bits (numerator, 63, (sim_fpu_print_func*)fprintf, stdout); - printf ("\n"); - print_bits (denominator, 63, (sim_fpu_print_func*)fprintf, stdout); - printf ("\n"); -#endif - - /* discard (but save) the extra bits */ - if ((quotient & LSMASK64 (NR_SPARE -1, 0))) - quotient = (quotient >> NR_SPARE) | 1; - else - quotient = (quotient >> NR_SPARE); - - f->fraction = quotient; - ASSERT (f->fraction >= IMPLICIT_1 && f->fraction < IMPLICIT_2); - if (numerator != 0) - { - f->fraction |= 1; /* stick remaining bits */ - return sim_fpu_status_inexact; - } - else - return 0; - } -} - - -INLINE_SIM_FPU (int) -sim_fpu_max (sim_fpu *f, - const sim_fpu *l, - const sim_fpu *r) -{ - if (sim_fpu_is_snan (l)) - { - *f = *l; - f->class = sim_fpu_class_qnan; - return sim_fpu_status_invalid_snan; - } - if (sim_fpu_is_snan (r)) - { - *f = *r; - f->class = sim_fpu_class_qnan; - return sim_fpu_status_invalid_snan; - } - if (sim_fpu_is_qnan (l)) - { - *f = *l; - return 0; - } - if (sim_fpu_is_qnan (r)) - { - *f = *r; - return 0; - } - if (sim_fpu_is_infinity (l)) - { - if (sim_fpu_is_infinity (r) - && l->sign == r->sign) - { - *f = sim_fpu_qnan; - return sim_fpu_status_invalid_isi; - } - if (l->sign) - *f = *r; /* -inf < anything */ - else - *f = *l; /* +inf > anthing */ - return 0; - } - if (sim_fpu_is_infinity (r)) - { - if (r->sign) - *f = *l; /* anything > -inf */ - else - *f = *r; /* anthing < +inf */ - return 0; - } - if (l->sign > r->sign) - { - *f = *r; /* -ve < +ve */ - return 0; - } - if (l->sign < r->sign) - { - *f = *l; /* +ve > -ve */ - return 0; - } - ASSERT (l->sign == r->sign); - if (l->normal_exp > r->normal_exp - || (l->normal_exp == r->normal_exp && - l->fraction > r->fraction)) - { - /* |l| > |r| */ - if (l->sign) - *f = *r; /* -ve < -ve */ - else - *f = *l; /* +ve > +ve */ - return 0; - } - else - { - /* |l| <= |r| */ - if (l->sign) - *f = *l; /* -ve > -ve */ - else - *f = *r; /* +ve < +ve */ - return 0; - } -} - - -INLINE_SIM_FPU (int) -sim_fpu_min (sim_fpu *f, - const sim_fpu *l, - const sim_fpu *r) -{ - if (sim_fpu_is_snan (l)) - { - *f = *l; - f->class = sim_fpu_class_qnan; - return sim_fpu_status_invalid_snan; - } - if (sim_fpu_is_snan (r)) - { - *f = *r; - f->class = sim_fpu_class_qnan; - return sim_fpu_status_invalid_snan; - } - if (sim_fpu_is_qnan (l)) - { - *f = *l; - return 0; - } - if (sim_fpu_is_qnan (r)) - { - *f = *r; - return 0; - } - if (sim_fpu_is_infinity (l)) - { - if (sim_fpu_is_infinity (r) - && l->sign == r->sign) - { - *f = sim_fpu_qnan; - return sim_fpu_status_invalid_isi; - } - if (l->sign) - *f = *l; /* -inf < anything */ - else - *f = *r; /* +inf > anthing */ - return 0; - } - if (sim_fpu_is_infinity (r)) - { - if (r->sign) - *f = *r; /* anything > -inf */ - else - *f = *l; /* anything < +inf */ - return 0; - } - if (l->sign > r->sign) - { - *f = *l; /* -ve < +ve */ - return 0; - } - if (l->sign < r->sign) - { - *f = *r; /* +ve > -ve */ - return 0; - } - ASSERT (l->sign == r->sign); - if (l->normal_exp > r->normal_exp - || (l->normal_exp == r->normal_exp && - l->fraction > r->fraction)) - { - /* |l| > |r| */ - if (l->sign) - *f = *l; /* -ve < -ve */ - else - *f = *r; /* +ve > +ve */ - return 0; - } - else - { - /* |l| <= |r| */ - if (l->sign) - *f = *r; /* -ve > -ve */ - else - *f = *l; /* +ve < +ve */ - return 0; - } -} - - -INLINE_SIM_FPU (int) -sim_fpu_neg (sim_fpu *f, - const sim_fpu *r) -{ - if (sim_fpu_is_snan (r)) - { - *f = *r; - f->class = sim_fpu_class_qnan; - return sim_fpu_status_invalid_snan; - } - if (sim_fpu_is_qnan (r)) - { - *f = *r; - return 0; - } - *f = *r; - f->sign = !r->sign; - return 0; -} - - -INLINE_SIM_FPU (int) -sim_fpu_abs (sim_fpu *f, - const sim_fpu *r) -{ - if (sim_fpu_is_snan (r)) - { - *f = *r; - f->class = sim_fpu_class_qnan; - return sim_fpu_status_invalid_snan; - } - if (sim_fpu_is_qnan (r)) - { - *f = *r; - return 0; - } - *f = *r; - f->sign = 0; - return 0; -} - - -INLINE_SIM_FPU (int) -sim_fpu_inv (sim_fpu *f, - const sim_fpu *r) -{ - if (sim_fpu_is_snan (r)) - { - *f = *r; - f->class = sim_fpu_class_qnan; - return sim_fpu_status_invalid_snan; - } - if (sim_fpu_is_qnan (r)) - { - *f = *r; - f->class = sim_fpu_class_qnan; - return 0; - } - if (sim_fpu_is_infinity (r)) - { - *f = sim_fpu_zero; - f->sign = r->sign; - return 0; - } - if (sim_fpu_is_zero (r)) - { - f->class = sim_fpu_class_infinity; - f->sign = r->sign; - return sim_fpu_status_invalid_div0; - } - *f = *r; - f->normal_exp = - r->normal_exp; - return 0; -} - - -INLINE_SIM_FPU (int) -sim_fpu_sqrt (sim_fpu *f, - const sim_fpu *r) -{ - if (sim_fpu_is_snan (r)) - { - *f = sim_fpu_qnan; - return sim_fpu_status_invalid_snan; - } - if (sim_fpu_is_qnan (r)) - { - *f = sim_fpu_qnan; - return 0; - } - if (sim_fpu_is_zero (r)) - { - f->class = sim_fpu_class_zero; - f->sign = r->sign; - return 0; - } - if (sim_fpu_is_infinity (r)) - { - if (r->sign) - { - *f = sim_fpu_qnan; - return sim_fpu_status_invalid_sqrt; - } - else - { - f->class = sim_fpu_class_infinity; - f->sign = 0; - f->sign = 0; - return 0; - } - } - if (r->sign) - { - *f = sim_fpu_qnan; - return sim_fpu_status_invalid_sqrt; - } - - /* @(#)e_sqrt.c 5.1 93/09/24 */ - /* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - - /* __ieee754_sqrt(x) - * Return correctly rounded sqrt. - * ------------------------------------------ - * | Use the hardware sqrt if you have one | - * ------------------------------------------ - * Method: - * Bit by bit method using integer arithmetic. (Slow, but portable) - * 1. Normalization - * Scale x to y in [1,4) with even powers of 2: - * find an integer k such that 1 <= (y=x*2^(2k)) < 4, then - * sqrt(x) = 2^k * sqrt(y) - - - - Since: - - sqrt ( x*2^(2m) ) = sqrt(x).2^m ; m even - - sqrt ( x*2^(2m + 1) ) = sqrt(2.x).2^m ; m odd - - Define: - - y = ((m even) ? x : 2.x) - - Then: - - y in [1, 4) ; [IMPLICIT_1,IMPLICIT_4) - - And: - - sqrt (y) in [1, 2) ; [IMPLICIT_1,IMPLICIT_2) - - - * 2. Bit by bit computation - * Let q = sqrt(y) truncated to i bit after binary point (q = 1), - * i 0 - * i+1 2 - * s = 2*q , and y = 2 * ( y - q ). (1) - * i i i i - * - * To compute q from q , one checks whether - * i+1 i - * - * -(i+1) 2 - * (q + 2 ) <= y. (2) - * i - * -(i+1) - * If (2) is false, then q = q ; otherwise q = q + 2 . - * i+1 i i+1 i - * - * With some algebric manipulation, it is not difficult to see - * that (2) is equivalent to - * -(i+1) - * s + 2 <= y (3) - * i i - * - * The advantage of (3) is that s and y can be computed by - * i i - * the following recurrence formula: - * if (3) is false - * - * s = s , y = y ; (4) - * i+1 i i+1 i - * - - - - NOTE: y = 2*y - - i+1 i - - - * otherwise, - * -i -(i+1) - * s = s + 2 , y = y - s - 2 (5) - * i+1 i i+1 i i - * - - - - -(i+1) - - NOTE: y = 2 (y - s - 2 ) - - i+1 i i - - - * One may easily use induction to prove (4) and (5). - * Note. Since the left hand side of (3) contain only i+2 bits, - * it does not necessary to do a full (53-bit) comparison - * in (3). - * 3. Final rounding - * After generating the 53 bits result, we compute one more bit. - * Together with the remainder, we can decide whether the - * result is exact, bigger than 1/2ulp, or less than 1/2ulp - * (it will never equal to 1/2ulp). - * The rounding mode can be detected by checking whether - * huge + tiny is equal to huge, and whether huge - tiny is - * equal to huge for some floating point number "huge" and "tiny". - * - * Special cases: - * sqrt(+-0) = +-0 ... exact - * sqrt(inf) = inf - * sqrt(-ve) = NaN ... with invalid signal - * sqrt(NaN) = NaN ... with invalid signal for signaling NaN - * - * Other methods : see the appended file at the end of the program below. - *--------------- - */ - - { - /* generate sqrt(x) bit by bit */ - unsigned64 y; - unsigned64 q; - unsigned64 s; - unsigned64 b; - - f->class = sim_fpu_class_number; - f->sign = 0; - y = r->fraction; - f->normal_exp = (r->normal_exp >> 1); /* exp = [exp/2] */ - - /* odd exp, double x to make it even */ - ASSERT (y >= IMPLICIT_1 && y < IMPLICIT_4); - if ((r->normal_exp & 1)) - { - y += y; - } - ASSERT (y >= IMPLICIT_1 && y < (IMPLICIT_2 << 1)); - - /* Let loop determine first value of s (either 1 or 2) */ - b = IMPLICIT_1; - q = 0; - s = 0; - - while (b) - { - unsigned64 t = s + b; - if (t <= y) - { - s |= (b << 1); - y -= t; - q |= b; - } - y <<= 1; - b >>= 1; - } - - ASSERT (q >= IMPLICIT_1 && q < IMPLICIT_2); - f->fraction = q; - if (y != 0) - { - f->fraction |= 1; /* stick remaining bits */ - return sim_fpu_status_inexact; - } - else - return 0; - } -} - - -/* int/long <-> sim_fpu */ - -INLINE_SIM_FPU (int) -sim_fpu_i32to (sim_fpu *f, - signed32 i, - sim_fpu_round round) -{ - i2fpu (f, i, 0); - return 0; -} - -INLINE_SIM_FPU (int) -sim_fpu_u32to (sim_fpu *f, - unsigned32 u, - sim_fpu_round round) -{ - u2fpu (f, u, 0); - return 0; -} - -INLINE_SIM_FPU (int) -sim_fpu_i64to (sim_fpu *f, - signed64 i, - sim_fpu_round round) -{ - i2fpu (f, i, 1); - return 0; -} - -INLINE_SIM_FPU (int) -sim_fpu_u64to (sim_fpu *f, - unsigned64 u, - sim_fpu_round round) -{ - u2fpu (f, u, 1); - return 0; -} - - -INLINE_SIM_FPU (int) -sim_fpu_to32i (signed32 *i, - const sim_fpu *f, - sim_fpu_round round) -{ - signed64 i64; - int status = fpu2i (&i64, f, 0, round); - *i = i64; - return status; -} - -INLINE_SIM_FPU (int) -sim_fpu_to32u (unsigned32 *u, - const sim_fpu *f, - sim_fpu_round round) -{ - unsigned64 u64; - int status = fpu2u (&u64, f, 0); - *u = u64; - return status; -} - -INLINE_SIM_FPU (int) -sim_fpu_to64i (signed64 *i, - const sim_fpu *f, - sim_fpu_round round) -{ - return fpu2i (i, f, 1, round); -} - - -INLINE_SIM_FPU (int) -sim_fpu_to64u (unsigned64 *u, - const sim_fpu *f, - sim_fpu_round round) -{ - return fpu2u (u, f, 1); -} - - - -/* sim_fpu -> host format */ - -#if 0 -INLINE_SIM_FPU (float) -sim_fpu_2f (const sim_fpu *f) -{ - return fval.d; -} -#endif - - -INLINE_SIM_FPU (double) -sim_fpu_2d (const sim_fpu *s) -{ - sim_fpu_map val; - val.i = pack_fpu (s, 1); - return val.d; -} - - -#if 0 -INLINE_SIM_FPU (void) -sim_fpu_f2 (sim_fpu *f, - float s) -{ - sim_fpu_map val; - val.d = s; - unpack_fpu (f, val.i, 1); -} -#endif - - -INLINE_SIM_FPU (void) -sim_fpu_d2 (sim_fpu *f, - double d) -{ - sim_fpu_map val; - val.d = d; - unpack_fpu (f, val.i, 1); -} - - -/* General */ - -INLINE_SIM_FPU (int) -sim_fpu_is_nan (const sim_fpu *d) -{ - switch (d->class) - { - case sim_fpu_class_qnan: - case sim_fpu_class_snan: - return 1; - default: - return 0; - } -} - -INLINE_SIM_FPU (int) -sim_fpu_is_qnan (const sim_fpu *d) -{ - switch (d->class) - { - case sim_fpu_class_qnan: - return 1; - default: - return 0; - } -} - -INLINE_SIM_FPU (int) -sim_fpu_is_snan (const sim_fpu *d) -{ - switch (d->class) - { - case sim_fpu_class_snan: - return 1; - default: - return 0; - } -} - -INLINE_SIM_FPU (int) -sim_fpu_is_zero (const sim_fpu *d) -{ - switch (d->class) - { - case sim_fpu_class_zero: - return 1; - default: - return 0; - } -} - -INLINE_SIM_FPU (int) -sim_fpu_is_infinity (const sim_fpu *d) -{ - switch (d->class) - { - case sim_fpu_class_infinity: - return 1; - default: - return 0; - } -} - -INLINE_SIM_FPU (int) -sim_fpu_is_number (const sim_fpu *d) -{ - switch (d->class) - { - case sim_fpu_class_denorm: - case sim_fpu_class_number: - return 1; - default: - return 0; - } -} - -INLINE_SIM_FPU (int) -sim_fpu_is_denorm (const sim_fpu *d) -{ - switch (d->class) - { - case sim_fpu_class_denorm: - return 1; - default: - return 0; - } -} - - -INLINE_SIM_FPU (int) -sim_fpu_sign (const sim_fpu *d) -{ - return d->sign; -} - - -INLINE_SIM_FPU (int) -sim_fpu_exp (const sim_fpu *d) -{ - return d->normal_exp; -} - - - -INLINE_SIM_FPU (int) -sim_fpu_is (const sim_fpu *d) -{ - switch (d->class) - { - case sim_fpu_class_qnan: - return SIM_FPU_IS_QNAN; - case sim_fpu_class_snan: - return SIM_FPU_IS_SNAN; - case sim_fpu_class_infinity: - if (d->sign) - return SIM_FPU_IS_NINF; - else - return SIM_FPU_IS_PINF; - case sim_fpu_class_number: - if (d->sign) - return SIM_FPU_IS_NNUMBER; - else - return SIM_FPU_IS_PNUMBER; - case sim_fpu_class_denorm: - if (d->sign) - return SIM_FPU_IS_NDENORM; - else - return SIM_FPU_IS_PDENORM; - case sim_fpu_class_zero: - if (d->sign) - return SIM_FPU_IS_NZERO; - else - return SIM_FPU_IS_PZERO; - default: - return -1; - abort (); - } -} - -INLINE_SIM_FPU (int) -sim_fpu_cmp (const sim_fpu *l, const sim_fpu *r) -{ - sim_fpu res; - sim_fpu_sub (&res, l, r); - return sim_fpu_is (&res); -} - -INLINE_SIM_FPU (int) -sim_fpu_is_lt (const sim_fpu *l, const sim_fpu *r) -{ - int status; - sim_fpu_lt (&status, l, r); - return status; -} - -INLINE_SIM_FPU (int) -sim_fpu_is_le (const sim_fpu *l, const sim_fpu *r) -{ - int is; - sim_fpu_le (&is, l, r); - return is; -} - -INLINE_SIM_FPU (int) -sim_fpu_is_eq (const sim_fpu *l, const sim_fpu *r) -{ - int is; - sim_fpu_eq (&is, l, r); - return is; -} - -INLINE_SIM_FPU (int) -sim_fpu_is_ne (const sim_fpu *l, const sim_fpu *r) -{ - int is; - sim_fpu_ne (&is, l, r); - return is; -} - -INLINE_SIM_FPU (int) -sim_fpu_is_ge (const sim_fpu *l, const sim_fpu *r) -{ - int is; - sim_fpu_ge (&is, l, r); - return is; -} - -INLINE_SIM_FPU (int) -sim_fpu_is_gt (const sim_fpu *l, const sim_fpu *r) -{ - int is; - sim_fpu_gt (&is, l, r); - return is; -} - - -/* Compare operators */ - -INLINE_SIM_FPU (int) -sim_fpu_lt (int *is, - const sim_fpu *l, - const sim_fpu *r) -{ - if (!sim_fpu_is_nan (l) && !sim_fpu_is_nan (r)) - { - sim_fpu_map lval; - sim_fpu_map rval; - lval.i = pack_fpu (l, 1); - rval.i = pack_fpu (r, 1); - (*is) = (lval.d < rval.d); - return 0; - } - else if (sim_fpu_is_snan (l) || sim_fpu_is_snan (r)) - { - *is = 0; - return sim_fpu_status_invalid_snan; - } - else - { - *is = 0; - return sim_fpu_status_invalid_qnan; - } -} - -INLINE_SIM_FPU (int) -sim_fpu_le (int *is, - const sim_fpu *l, - const sim_fpu *r) -{ - if (!sim_fpu_is_nan (l) && !sim_fpu_is_nan (r)) - { - sim_fpu_map lval; - sim_fpu_map rval; - lval.i = pack_fpu (l, 1); - rval.i = pack_fpu (r, 1); - *is = (lval.d <= rval.d); - return 0; - } - else if (sim_fpu_is_snan (l) || sim_fpu_is_snan (r)) - { - *is = 0; - return sim_fpu_status_invalid_snan; - } - else - { - *is = 0; - return sim_fpu_status_invalid_qnan; - } -} - -INLINE_SIM_FPU (int) -sim_fpu_eq (int *is, - const sim_fpu *l, - const sim_fpu *r) -{ - if (!sim_fpu_is_nan (l) && !sim_fpu_is_nan (r)) - { - sim_fpu_map lval; - sim_fpu_map rval; - lval.i = pack_fpu (l, 1); - rval.i = pack_fpu (r, 1); - (*is) = (lval.d == rval.d); - return 0; - } - else if (sim_fpu_is_snan (l) || sim_fpu_is_snan (r)) - { - *is = 0; - return sim_fpu_status_invalid_snan; - } - else - { - *is = 0; - return sim_fpu_status_invalid_qnan; - } -} - -INLINE_SIM_FPU (int) -sim_fpu_ne (int *is, - const sim_fpu *l, - const sim_fpu *r) -{ - if (!sim_fpu_is_nan (l) && !sim_fpu_is_nan (r)) - { - sim_fpu_map lval; - sim_fpu_map rval; - lval.i = pack_fpu (l, 1); - rval.i = pack_fpu (r, 1); - (*is) = (lval.d != rval.d); - return 0; - } - else if (sim_fpu_is_snan (l) || sim_fpu_is_snan (r)) - { - *is = 0; - return sim_fpu_status_invalid_snan; - } - else - { - *is = 0; - return sim_fpu_status_invalid_qnan; - } -} - -INLINE_SIM_FPU (int) -sim_fpu_ge (int *is, - const sim_fpu *l, - const sim_fpu *r) -{ - return sim_fpu_le (is, r, l); -} - -INLINE_SIM_FPU (int) -sim_fpu_gt (int *is, - const sim_fpu *l, - const sim_fpu *r) -{ - return sim_fpu_lt (is, r, l); -} - - -/* A number of useful constants */ - -EXTERN_SIM_FPU (const sim_fpu) sim_fpu_zero = { - sim_fpu_class_zero, -}; -EXTERN_SIM_FPU (const sim_fpu) sim_fpu_qnan = { - sim_fpu_class_qnan, -}; -EXTERN_SIM_FPU (const sim_fpu) sim_fpu_one = { - sim_fpu_class_number, 0, IMPLICIT_1, 1 -}; -EXTERN_SIM_FPU (const sim_fpu) sim_fpu_two = { - sim_fpu_class_number, 0, IMPLICIT_1, 2 -}; -EXTERN_SIM_FPU (const sim_fpu) sim_fpu_max32 = { - sim_fpu_class_number, 0, LSMASK64 (NR_FRAC_GUARD, NR_GUARDS32), NORMAL_EXPMAX32 -}; -EXTERN_SIM_FPU (const sim_fpu) sim_fpu_max64 = { - sim_fpu_class_number, 0, LSMASK64 (NR_FRAC_GUARD, NR_GUARDS64), NORMAL_EXPMAX64 -}; - - -/* For debugging */ - -INLINE_SIM_FPU (void) -sim_fpu_print_fpu (const sim_fpu *f, - sim_fpu_print_func *print, - void *arg) -{ - print (arg, "%s", f->sign ? "-" : "+"); - switch (f->class) - { - case sim_fpu_class_qnan: - print (arg, "0."); - print_bits (f->fraction, NR_FRAC_GUARD - 1, print, arg); - print (arg, "*QuietNaN"); - break; - case sim_fpu_class_snan: - print (arg, "0."); - print_bits (f->fraction, NR_FRAC_GUARD - 1, print, arg); - print (arg, "*SignalNaN"); - break; - case sim_fpu_class_zero: - print (arg, "0.0"); - break; - case sim_fpu_class_infinity: - print (arg, "INF"); - break; - case sim_fpu_class_number: - case sim_fpu_class_denorm: - print (arg, "1."); - print_bits (f->fraction, NR_FRAC_GUARD - 1, print, arg); - print (arg, "*2^%+-5d", f->normal_exp); - ASSERT (f->fraction >= IMPLICIT_1); - ASSERT (f->fraction < IMPLICIT_2); - } -} - - -INLINE_SIM_FPU (void) -sim_fpu_print_status (int status, - sim_fpu_print_func *print, - void *arg) -{ - int i = 1; - char *prefix = ""; - while (status >= i) - { - switch ((sim_fpu_status) (status & i)) - { - case sim_fpu_status_denorm: - print (arg, "%sD", prefix); - break; - case sim_fpu_status_invalid_snan: - print (arg, "%sSNaN", prefix); - break; - case sim_fpu_status_invalid_qnan: - print (arg, "%sQNaN", prefix); - break; - case sim_fpu_status_invalid_isi: - print (arg, "%sISI", prefix); - break; - case sim_fpu_status_invalid_idi: - print (arg, "%sIDI", prefix); - break; - case sim_fpu_status_invalid_zdz: - print (arg, "%sZDZ", prefix); - break; - case sim_fpu_status_invalid_imz: - print (arg, "%sIMZ", prefix); - break; - case sim_fpu_status_invalid_cvi: - print (arg, "%sCVI", prefix); - break; - case sim_fpu_status_invalid_cmp: - print (arg, "%sCMP", prefix); - break; - case sim_fpu_status_invalid_sqrt: - print (arg, "%sSQRT", prefix); - break; - break; - case sim_fpu_status_inexact: - print (arg, "%sX", prefix); - break; - break; - case sim_fpu_status_overflow: - print (arg, "%sO", prefix); - break; - break; - case sim_fpu_status_underflow: - print (arg, "%sU", prefix); - break; - break; - case sim_fpu_status_invalid_div0: - print (arg, "%s/", prefix); - break; - break; - case sim_fpu_status_rounded: - print (arg, "%sR", prefix); - break; - break; - } - i <<= 1; - prefix = ","; - } -} - -#endif |