|  | /* 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 1994-2023 Free Software Foundation, Inc. | 
|  |  | 
|  | This program 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 3 of the License, or | 
|  | (at your option) any later version. | 
|  |  | 
|  | This program 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.  If not, see <http://www.gnu.org/licenses/>.  */ | 
|  |  | 
|  | /* 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 | 
|  |  | 
|  | /* This must come before any other includes.  */ | 
|  | #include "defs.h" | 
|  |  | 
|  | #include <stdlib.h> | 
|  |  | 
|  | #include "sim-basics.h" | 
|  | #include "sim-fpu.h" | 
|  |  | 
|  | #include "sim-io.h" | 
|  | #include "sim-assert.h" | 
|  |  | 
|  | /* Debugging support. | 
|  | If digits is -1, then print all digits.  */ | 
|  |  | 
|  | static void | 
|  | print_bits (uint64_t x, | 
|  | int msbit, | 
|  | int digits, | 
|  | sim_fpu_print_func print, | 
|  | void *arg) | 
|  | { | 
|  | uint64_t bit = LSBIT64 (msbit); | 
|  | int i = 4; | 
|  | while (bit && digits) | 
|  | { | 
|  | if (i == 0) | 
|  | print (arg, ","); | 
|  |  | 
|  | if ((x & bit)) | 
|  | print (arg, "1"); | 
|  | else | 
|  | print (arg, "0"); | 
|  | bit >>= 1; | 
|  |  | 
|  | if (digits > 0) | 
|  | digits--; | 
|  | i = (i + 1) % 4; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | /* Quick and dirty conversion between a host double and host 64bit int.  */ | 
|  |  | 
|  | typedef union | 
|  | { | 
|  | double d; | 
|  | uint64_t 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  ((int64_t) LSMASK64 (30, 0)) | 
|  | #define MAX_UINT32 LSMASK64 (31, 0) | 
|  | #define MIN_INT32  ((int64_t) LSMASK64 (63, 31)) | 
|  |  | 
|  | #define MAX_INT64  ((int64_t) LSMASK64 (62, 0)) | 
|  | #define MAX_UINT64 LSMASK64 (63, 0) | 
|  | #define MIN_INT64  ((int64_t) 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) | 
|  |  | 
|  | /* Squeeze an unpacked sim_fpu struct into a 32/64 bit integer.  */ | 
|  | STATIC_INLINE_SIM_FPU (uint64_t) | 
|  | pack_fpu (const sim_fpu *src, | 
|  | int is_double) | 
|  | { | 
|  | int sign; | 
|  | uint64_t exp; | 
|  | uint64_t fraction; | 
|  | uint64_t 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; | 
|  | if (sim_fpu_quiet_nan_inverted) | 
|  | fraction |= QUIET_NAN - 1; | 
|  | else | 
|  | 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; | 
|  | if (sim_fpu_quiet_nan_inverted) | 
|  | fraction |= QUIET_NAN; | 
|  | else | 
|  | 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, uint64_t packed, int is_double) | 
|  | { | 
|  | uint64_t 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; | 
|  | dst->normal_exp = 0; | 
|  | } | 
|  | 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 | 
|  | { | 
|  | int qnan; | 
|  |  | 
|  | /* Non zero fraction, means NaN.  */ | 
|  | dst->sign = sign; | 
|  | dst->fraction = (fraction << NR_GUARDS); | 
|  | if (sim_fpu_quiet_nan_inverted) | 
|  | qnan = (fraction & QUIET_NAN) == 0; | 
|  | else | 
|  | qnan = fraction >= QUIET_NAN; | 
|  | if (qnan) | 
|  | 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 | 
|  | { | 
|  | uint32_t val = pack_fpu (dst, 0); | 
|  | uint32_t org = packed; | 
|  | ASSERT (val == org); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Convert a floating point into an integer.  */ | 
|  | STATIC_INLINE_SIM_FPU (int) | 
|  | fpu2i (int64_t *i, | 
|  | const sim_fpu *s, | 
|  | int is_64bit, | 
|  | sim_fpu_round round) | 
|  | { | 
|  | uint64_t 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, int64_t i, int is_64bit) | 
|  | { | 
|  | int status = 0; | 
|  | if (i == 0) | 
|  | { | 
|  | f->class = sim_fpu_class_zero; | 
|  | f->sign = 0; | 
|  | f->normal_exp = 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 = (f->fraction >> 1) | (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 */ | 
|  | { | 
|  | int64_t 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 (uint64_t *u, const sim_fpu *s, int is_64bit) | 
|  | { | 
|  | const int is_double = 1; | 
|  | uint64_t 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, uint64_t u, int is_64bit) | 
|  | { | 
|  | if (u == 0) | 
|  | { | 
|  | f->class = sim_fpu_class_zero; | 
|  | f->sign = 0; | 
|  | f->normal_exp = 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, uint32_t s) | 
|  | { | 
|  | unpack_fpu (f, s, 0); | 
|  | } | 
|  |  | 
|  |  | 
|  | INLINE_SIM_FPU (void) | 
|  | sim_fpu_232to (sim_fpu *f, uint32_t h, uint32_t l) | 
|  | { | 
|  | uint64_t s = h; | 
|  | s = (s << 32) | l; | 
|  | unpack_fpu (f, s, 1); | 
|  | } | 
|  |  | 
|  |  | 
|  | INLINE_SIM_FPU (void) | 
|  | sim_fpu_64to (sim_fpu *f, uint64_t s) | 
|  | { | 
|  | unpack_fpu (f, s, 1); | 
|  | } | 
|  |  | 
|  |  | 
|  | INLINE_SIM_FPU (void) | 
|  | sim_fpu_to32 (uint32_t *s, | 
|  | const sim_fpu *f) | 
|  | { | 
|  | *s = pack_fpu (f, 0); | 
|  | } | 
|  |  | 
|  |  | 
|  | INLINE_SIM_FPU (void) | 
|  | sim_fpu_to232 (uint32_t *h, uint32_t *l, | 
|  | const sim_fpu *f) | 
|  | { | 
|  | uint64_t s = pack_fpu (f, 1); | 
|  | *l = s; | 
|  | *h = (s >> 32); | 
|  | } | 
|  |  | 
|  |  | 
|  | INLINE_SIM_FPU (void) | 
|  | sim_fpu_to64 (uint64_t *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, | 
|  | uint64_t 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 (uint64_t) | 
|  | 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); | 
|  | uint64_t 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) | 
|  | { | 
|  | uint64_t guardmask = LSMASK64 (nr_guards - 1, 0); | 
|  | uint64_t guardmsb = LSBIT64 (nr_guards - 1); | 
|  | uint64_t 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); | 
|  | } | 
|  |  | 
|  | /* NaN handling for binary operations.  */ | 
|  |  | 
|  | INLINE_SIM_FPU (int) | 
|  | sim_fpu_op_nan (sim_fpu *f, const sim_fpu *l, const sim_fpu *r) | 
|  | { | 
|  | if (sim_fpu_is_snan (l) || sim_fpu_is_snan (r)) | 
|  | { | 
|  | *f = sim_fpu_is_snan (l) ? *l : *r; | 
|  | f->class = sim_fpu_class_qnan; | 
|  | return sim_fpu_status_invalid_snan; | 
|  | } | 
|  | ASSERT (sim_fpu_is_nan (l) || sim_fpu_is_nan (r)); | 
|  | if (sim_fpu_is_qnan (l)) | 
|  | *f = *l; | 
|  | else /* if (sim_fpu_is_qnan (r)) */ | 
|  | *f = *r; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* NaN handling specific to min/max operations.  */ | 
|  |  | 
|  | INLINE_SIM_FPU (int) | 
|  | sim_fpu_minmax_nan (sim_fpu *f, const sim_fpu *l, const sim_fpu *r) | 
|  | { | 
|  | if (sim_fpu_is_snan (l) | 
|  | || sim_fpu_is_snan (r) | 
|  | || sim_fpu_is_ieee754_1985 ()) | 
|  | return sim_fpu_op_nan (f, l, r); | 
|  | else | 
|  | /* if sim_fpu_is_ieee754_2008() | 
|  | && ((sim_fpu_is_qnan (l) || sim_fpu_is_qnan (r)))  */ | 
|  | { | 
|  | /* In IEEE754-2008: | 
|  | "minNum/maxNum is ... the canonicalized number if one | 
|  | operand is a number and the other a quiet NaN."  */ | 
|  | if (sim_fpu_is_qnan (l)) | 
|  | *f = *r; | 
|  | else /* if (sim_fpu_is_qnan (r))  */ | 
|  | *f = *l; | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Arithmetic ops */ | 
|  |  | 
|  | INLINE_SIM_FPU (int) | 
|  | sim_fpu_add (sim_fpu *f, | 
|  | const sim_fpu *l, | 
|  | const sim_fpu *r) | 
|  | { | 
|  | if (sim_fpu_is_nan (l) || sim_fpu_is_nan (r)) | 
|  | return sim_fpu_op_nan (f, l, r); | 
|  | 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; | 
|  | uint64_t lfraction; | 
|  | uint64_t rfraction; | 
|  | /* use exp of larger */ | 
|  | if (shift >= NR_FRAC_GUARD) | 
|  | { | 
|  | /* left has much bigger magnitude */ | 
|  | *f = *l; | 
|  | return sim_fpu_status_inexact; | 
|  | } | 
|  | if (shift <= - NR_FRAC_GUARD) | 
|  | { | 
|  | /* right has much bigger magnitude */ | 
|  | *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 (((int64_t) 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_nan (l) || sim_fpu_is_nan (r)) | 
|  | return sim_fpu_op_nan (f, l, r); | 
|  | 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; | 
|  | uint64_t lfraction; | 
|  | uint64_t rfraction; | 
|  | /* use exp of larger */ | 
|  | if (shift >= NR_FRAC_GUARD) | 
|  | { | 
|  | /* left has much bigger magnitude */ | 
|  | *f = *l; | 
|  | return sim_fpu_status_inexact; | 
|  | } | 
|  | if (shift <= - NR_FRAC_GUARD) | 
|  | { | 
|  | /* right has much bigger magnitude */ | 
|  | *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 (((int64_t) 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_nan (l) || sim_fpu_is_nan (r)) | 
|  | return sim_fpu_op_nan (f, l, r); | 
|  | 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.  */ | 
|  | { | 
|  | uint64_t low; | 
|  | uint64_t high; | 
|  | uint64_t nl = l->fraction & 0xffffffff; | 
|  | uint64_t nh = l->fraction >> 32; | 
|  | uint64_t ml = r->fraction & 0xffffffff; | 
|  | uint64_t mh = r->fraction >>32; | 
|  | uint64_t pp_ll = ml * nl; | 
|  | uint64_t pp_hl = mh * nl; | 
|  | uint64_t pp_lh = ml * nh; | 
|  | uint64_t pp_hh = mh * nh; | 
|  | uint64_t res2 = 0; | 
|  | uint64_t res0 = 0; | 
|  | uint64_t 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); | 
|  |  | 
|  | /* Normalize.  */ | 
|  | do | 
|  | { | 
|  | f->normal_exp--; | 
|  | high <<= 1; | 
|  | if (low & LSBIT64 (63)) | 
|  | high |= 1; | 
|  | low <<= 1; | 
|  | } | 
|  | while (high < IMPLICIT_1); | 
|  |  | 
|  | 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_nan (l) || sim_fpu_is_nan (r)) | 
|  | return sim_fpu_op_nan (f, l, r); | 
|  | 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) | 
|  | */ | 
|  | uint64_t numerator; | 
|  | uint64_t denominator; | 
|  | uint64_t quotient; | 
|  | uint64_t 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; | 
|  | } | 
|  |  | 
|  | /* 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_rem (sim_fpu *f, | 
|  | const sim_fpu *l, | 
|  | const sim_fpu *r) | 
|  | { | 
|  | if (sim_fpu_is_nan (l) || sim_fpu_is_nan (r)) | 
|  | return sim_fpu_op_nan (f, l, r); | 
|  | if (sim_fpu_is_infinity (l)) | 
|  | { | 
|  | *f = sim_fpu_qnan; | 
|  | return sim_fpu_status_invalid_irx; | 
|  | } | 
|  | if (sim_fpu_is_zero (r)) | 
|  | { | 
|  | *f = sim_fpu_qnan; | 
|  | return sim_fpu_status_invalid_div0; | 
|  | } | 
|  | if (sim_fpu_is_zero (l)) | 
|  | { | 
|  | *f = *l; | 
|  | return 0; | 
|  | } | 
|  | if (sim_fpu_is_infinity (r)) | 
|  | { | 
|  | *f = *l; | 
|  | return 0; | 
|  | } | 
|  | { | 
|  | sim_fpu n, tmp; | 
|  |  | 
|  | /* Remainder is calculated as l-n*r, where n is l/r rounded to the | 
|  | nearest integer.  The variable n is rounded half even.  */ | 
|  |  | 
|  | sim_fpu_div (&n, l, r); | 
|  | sim_fpu_round_64 (&n, 0, 0); | 
|  |  | 
|  | if (n.normal_exp < -1) /* If n looks like zero just return l.  */ | 
|  | { | 
|  | *f = *l; | 
|  | return 0; | 
|  | } | 
|  | else if (n.class == sim_fpu_class_number | 
|  | && n.normal_exp <= (NR_FRAC_GUARD)) /* If not too large round.  */ | 
|  | do_normal_round (&n, (NR_FRAC_GUARD) - n.normal_exp, sim_fpu_round_near); | 
|  |  | 
|  | /* Mark 0's as zero so multiply can detect zero.  */ | 
|  | if (n.fraction == 0) | 
|  | n.class = sim_fpu_class_zero; | 
|  |  | 
|  | /* Calculate n*r.  */ | 
|  | sim_fpu_mul (&tmp, &n, r); | 
|  | sim_fpu_round_64 (&tmp, 0, 0); | 
|  |  | 
|  | /* Finally calculate l-n*r.  */ | 
|  | sim_fpu_sub (f, l, &tmp); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | INLINE_SIM_FPU (int) | 
|  | sim_fpu_max (sim_fpu *f, | 
|  | const sim_fpu *l, | 
|  | const sim_fpu *r) | 
|  | { | 
|  | if (sim_fpu_is_nan (l) || sim_fpu_is_nan (r)) | 
|  | return sim_fpu_minmax_nan (f, l, r); | 
|  | 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 > anything */ | 
|  | return 0; | 
|  | } | 
|  | if (sim_fpu_is_infinity (r)) | 
|  | { | 
|  | if (r->sign) | 
|  | *f = *l; /* anything > -inf */ | 
|  | else | 
|  | *f = *r; /* anything < +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_nan (l) || sim_fpu_is_nan (r)) | 
|  | return sim_fpu_minmax_nan (f, l, r); | 
|  | 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_ieee754_1985 () && 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) | 
|  | { | 
|  | *f = *r; | 
|  | f->sign = 0; | 
|  | if (sim_fpu_is_ieee754_1985 () && sim_fpu_is_snan (r)) | 
|  | { | 
|  | f->class = sim_fpu_class_qnan; | 
|  | return sim_fpu_status_invalid_snan; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | INLINE_SIM_FPU (int) | 
|  | sim_fpu_inv (sim_fpu *f, | 
|  | const sim_fpu *r) | 
|  | { | 
|  | return sim_fpu_div (f, &sim_fpu_one, r); | 
|  | } | 
|  |  | 
|  |  | 
|  | 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; | 
|  | f->normal_exp = 0; | 
|  | 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 algebraic 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 signalling NaN | 
|  | * | 
|  | * Other methods : see the appended file at the end of the program below. | 
|  | *--------------- | 
|  | */ | 
|  |  | 
|  | { | 
|  | /* Generate sqrt(x) bit by bit.  */ | 
|  | uint64_t y; | 
|  | uint64_t q; | 
|  | uint64_t s; | 
|  | uint64_t 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) | 
|  | { | 
|  | uint64_t 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, | 
|  | int32_t i, | 
|  | sim_fpu_round round) | 
|  | { | 
|  | i2fpu (f, i, 0); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | INLINE_SIM_FPU (int) | 
|  | sim_fpu_u32to (sim_fpu *f, | 
|  | uint32_t u, | 
|  | sim_fpu_round round) | 
|  | { | 
|  | u2fpu (f, u, 0); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | INLINE_SIM_FPU (int) | 
|  | sim_fpu_i64to (sim_fpu *f, | 
|  | int64_t i, | 
|  | sim_fpu_round round) | 
|  | { | 
|  | i2fpu (f, i, 1); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | INLINE_SIM_FPU (int) | 
|  | sim_fpu_u64to (sim_fpu *f, | 
|  | uint64_t u, | 
|  | sim_fpu_round round) | 
|  | { | 
|  | u2fpu (f, u, 1); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | INLINE_SIM_FPU (int) | 
|  | sim_fpu_to32i (int32_t *i, | 
|  | const sim_fpu *f, | 
|  | sim_fpu_round round) | 
|  | { | 
|  | int64_t i64; | 
|  | int status = fpu2i (&i64, f, 0, round); | 
|  | *i = i64; | 
|  | return status; | 
|  | } | 
|  |  | 
|  | INLINE_SIM_FPU (int) | 
|  | sim_fpu_to32u (uint32_t *u, | 
|  | const sim_fpu *f, | 
|  | sim_fpu_round round) | 
|  | { | 
|  | uint64_t u64; | 
|  | int status = fpu2u (&u64, f, 0); | 
|  | *u = u64; | 
|  | return status; | 
|  | } | 
|  |  | 
|  | INLINE_SIM_FPU (int) | 
|  | sim_fpu_to64i (int64_t *i, | 
|  | const sim_fpu *f, | 
|  | sim_fpu_round round) | 
|  | { | 
|  | return fpu2i (i, f, 1, round); | 
|  | } | 
|  |  | 
|  |  | 
|  | INLINE_SIM_FPU (int) | 
|  | sim_fpu_to64u (uint64_t *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; | 
|  | if (sim_fpu_is_snan (s)) | 
|  | { | 
|  | /* gag SNaN's */ | 
|  | sim_fpu n = *s; | 
|  | n.class = sim_fpu_class_qnan; | 
|  | val.i = pack_fpu (&n, 1); | 
|  | } | 
|  | else | 
|  | { | 
|  | 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 (uint64_t) | 
|  | sim_fpu_fraction (const sim_fpu *d) | 
|  | { | 
|  | return d->fraction; | 
|  | } | 
|  |  | 
|  |  | 
|  | INLINE_SIM_FPU (uint64_t) | 
|  | sim_fpu_guard (const sim_fpu *d, int is_double) | 
|  | { | 
|  | uint64_t rv; | 
|  | uint64_t guardmask = LSMASK64 (NR_GUARDS - 1, 0); | 
|  | rv = (d->fraction & guardmask) >> NR_PAD; | 
|  | return rv; | 
|  | } | 
|  |  | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | INLINE_SIM_FPU (int) | 
|  | sim_fpu_is_un (const sim_fpu *l, const sim_fpu *r) | 
|  | { | 
|  | int is; | 
|  | sim_fpu_un (&is, l, r); | 
|  | return is; | 
|  | } | 
|  |  | 
|  | INLINE_SIM_FPU (int) | 
|  | sim_fpu_is_or (const sim_fpu *l, const sim_fpu *r) | 
|  | { | 
|  | int is; | 
|  | sim_fpu_or (&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); | 
|  | } | 
|  |  | 
|  | INLINE_SIM_FPU (int) | 
|  | sim_fpu_un (int *is, const sim_fpu *l, const sim_fpu *r) | 
|  | { | 
|  | if (sim_fpu_is_nan (l) || sim_fpu_is_nan (r)) | 
|  | { | 
|  | *is = 1; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | *is = 0; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | INLINE_SIM_FPU (int) | 
|  | sim_fpu_or (int *is, const sim_fpu *l, const sim_fpu *r) | 
|  | { | 
|  | sim_fpu_un (is, l, r); | 
|  |  | 
|  | /* Invert result.  */ | 
|  | *is = !*is; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | INLINE_SIM_FPU(int) | 
|  | sim_fpu_classify (const sim_fpu *f) | 
|  | { | 
|  | switch (f->class) | 
|  | { | 
|  | case sim_fpu_class_snan: return SIM_FPU_IS_SNAN; | 
|  | case sim_fpu_class_qnan: return SIM_FPU_IS_QNAN; | 
|  | case sim_fpu_class_infinity: | 
|  | return f->sign ? SIM_FPU_IS_NINF : SIM_FPU_IS_PINF; | 
|  | case sim_fpu_class_zero: | 
|  | return f->sign ? SIM_FPU_IS_NZERO : SIM_FPU_IS_PZERO; | 
|  | case sim_fpu_class_number: | 
|  | return f->sign ? SIM_FPU_IS_NNUMBER : SIM_FPU_IS_PNUMBER; | 
|  | case sim_fpu_class_denorm: | 
|  | return f->sign ? SIM_FPU_IS_NDENORM : SIM_FPU_IS_PDENORM; | 
|  | default: | 
|  | fprintf (stderr, "Bad switch\n"); | 
|  | abort (); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* A number of useful constants */ | 
|  |  | 
|  | #if EXTERN_SIM_FPU_P | 
|  | sim_fpu_state _sim_fpu = { | 
|  | .quiet_nan_inverted = false, | 
|  | .current_mode = sim_fpu_ieee754_1985, | 
|  | }; | 
|  |  | 
|  | const sim_fpu sim_fpu_zero = { | 
|  | sim_fpu_class_zero, 0, 0, 0 | 
|  | }; | 
|  | const sim_fpu sim_fpu_qnan = { | 
|  | sim_fpu_class_qnan, 0, 0, 0 | 
|  | }; | 
|  | const sim_fpu sim_fpu_one = { | 
|  | sim_fpu_class_number, 0, IMPLICIT_1, 0 | 
|  | }; | 
|  | const sim_fpu sim_fpu_two = { | 
|  | sim_fpu_class_number, 0, IMPLICIT_1, 1 | 
|  | }; | 
|  | const sim_fpu sim_fpu_max32 = { | 
|  | sim_fpu_class_number, 0, LSMASK64 (NR_FRAC_GUARD, NR_GUARDS32), NORMAL_EXPMAX32 | 
|  | }; | 
|  | const sim_fpu sim_fpu_max64 = { | 
|  | sim_fpu_class_number, 0, LSMASK64 (NR_FRAC_GUARD, NR_GUARDS64), NORMAL_EXPMAX64 | 
|  | }; | 
|  | #endif | 
|  |  | 
|  | /* Specification swapping behaviour */ | 
|  | INLINE_SIM_FPU (bool) | 
|  | sim_fpu_is_ieee754_1985 (void) | 
|  | { | 
|  | return (sim_fpu_current_mode == sim_fpu_ieee754_1985); | 
|  | } | 
|  |  | 
|  | INLINE_SIM_FPU (bool) | 
|  | sim_fpu_is_ieee754_2008 (void) | 
|  | { | 
|  | return (sim_fpu_current_mode == sim_fpu_ieee754_2008); | 
|  | } | 
|  |  | 
|  | INLINE_SIM_FPU (void) | 
|  | sim_fpu_set_mode (const sim_fpu_mode m) | 
|  | { | 
|  | sim_fpu_current_mode = m; | 
|  | } | 
|  |  | 
|  | /* For debugging */ | 
|  |  | 
|  | INLINE_SIM_FPU (void) | 
|  | sim_fpu_print_fpu (const sim_fpu *f, | 
|  | sim_fpu_print_func *print, | 
|  | void *arg) | 
|  | { | 
|  | sim_fpu_printn_fpu (f, print, -1, arg); | 
|  | } | 
|  |  | 
|  | INLINE_SIM_FPU (void) | 
|  | sim_fpu_printn_fpu (const sim_fpu *f, | 
|  | sim_fpu_print_func *print, | 
|  | int digits, | 
|  | 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, digits, print, arg); | 
|  | print (arg, "*QuietNaN"); | 
|  | break; | 
|  | case sim_fpu_class_snan: | 
|  | print (arg, "0."); | 
|  | print_bits (f->fraction, NR_FRAC_GUARD - 1, digits, 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, digits, print, arg); | 
|  | print (arg, "*2^%+d", 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; | 
|  | const 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; | 
|  | case sim_fpu_status_invalid_irx: | 
|  | print (arg, "%sIRX", prefix); | 
|  | break; | 
|  | case sim_fpu_status_inexact: | 
|  | print (arg, "%sX", prefix); | 
|  | break; | 
|  | case sim_fpu_status_overflow: | 
|  | print (arg, "%sO", prefix); | 
|  | break; | 
|  | case sim_fpu_status_underflow: | 
|  | print (arg, "%sU", prefix); | 
|  | break; | 
|  | case sim_fpu_status_invalid_div0: | 
|  | print (arg, "%s/", prefix); | 
|  | break; | 
|  | case sim_fpu_status_rounded: | 
|  | print (arg, "%sR", prefix); | 
|  | break; | 
|  | } | 
|  | i <<= 1; | 
|  | prefix = ","; | 
|  | } | 
|  | } | 
|  |  | 
|  | #endif |