#ifndef SIM_FPU_C
#define SIM_FPU_C
#include "sim-basics.h"
#include "sim-fpu.h"
#include "sim-io.h"
#include "sim-assert.h"
static void
print_bits (unsigned64 x,
int msbit,
int digits,
sim_fpu_print_func print,
void *arg)
{
unsigned64 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;
}
}
typedef union {
double d;
unsigned64 i;
} sim_fpu_map;
#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)
#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)
#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)
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)
{
case sim_fpu_class_qnan:
sign = src->sign;
exp = EXPMAX;
fraction = src->fraction;
fraction >>= NR_GUARDS;
fraction |= QUIET_NAN;
break;
case sim_fpu_class_snan:
sign = src->sign;
exp = EXPMAX;
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)
{
int nr_shift = NORMAL_EXPMIN - src->normal_exp;
if (nr_shift > NR_FRACBITS)
{
sign = src->sign;
exp = 0;
fraction = 0;
}
else
{
sign = src->sign;
exp = 0;
fraction = src->fraction;
fraction >>= NR_GUARDS;
fraction >>= nr_shift;
}
}
else if (src->normal_exp > NORMAL_EXPMAX)
{
sign = src->sign;
exp = EXPMAX;
fraction = 0;
}
else
{
exp = (src->normal_exp + EXPBIAS);
sign = src->sign;
fraction = src->fraction;
if ((fraction & GUARDMASK) == GUARDMSB)
{
if ((fraction & (GUARDMSB << 1)))
fraction += (GUARDMSB << 1);
}
else
{
fraction += GUARDROUND;
}
if ((fraction & IMPLICIT_2))
{
exp += 1;
fraction >>= 1;
}
fraction >>= NR_GUARDS;
ASSERT ((exp == EXPMAX) <= ((fraction & ~IMPLICIT_1) == 0));
}
break;
default:
abort ();
}
packed = ((sign ? SIGNBIT : 0)
| (exp << NR_FRACBITS)
| LSMASKED64 (fraction, NR_FRACBITS - 1, 0));
#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;
}
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)
{
if (fraction == 0)
{
dst->class = sim_fpu_class_zero;
dst->sign = sign;
dst->normal_exp = 0;
}
else
{
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)
{
if (fraction == 0)
{
dst->class = sim_fpu_class_infinity;
dst->sign = sign;
}
else
{
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
{
dst->class = sim_fpu_class_number;
dst->sign = sign;
dst->fraction = ((fraction << NR_GUARDS) | IMPLICIT_1);
dst->normal_exp = exp - EXPBIAS;
}
#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
{
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);
}
}
}
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;
return sim_fpu_status_invalid_cvi;
}
if (sim_fpu_is_qnan (s))
{
*i = MIN_INT;
return sim_fpu_status_invalid_cvi;
}
if (sim_fpu_is_infinity (s))
{
*i = s->sign ? MIN_INT : MAX_INT;
return sim_fpu_status_invalid_cvi;
}
if (s->normal_exp < 0)
{
*i = 0;
return sim_fpu_status_inexact;
}
if (s->sign && s->normal_exp == (NR_INTBITS - 1))
{
*i = MIN_INT;
ASSERT (s->fraction >= IMPLICIT_1);
if (s->fraction == IMPLICIT_1)
return 0;
if (is_64bit)
return sim_fpu_status_invalid_cvi;
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;
}
}
if (s->normal_exp > (NR_INTBITS - 2))
{
*i = s->sign ? MIN_INT : MAX_INT;
return sim_fpu_status_invalid_cvi;
}
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;
}
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;
f->normal_exp = 0;
}
else
{
f->class = sim_fpu_class_number;
f->sign = (i < 0);
f->normal_exp = NR_FRAC_GUARD;
if (f->sign)
{
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);
}
}
#if 0
{
printf ("i2fpu: 0x%08lX ->\n", (long) i);
}
#endif
{
signed64 val;
fpu2i (&val, f, is_64bit, sim_fpu_round_zero);
if (i >= MIN_INT32 && i <= MAX_INT32)
{
ASSERT (val == i);
}
}
return status;
}
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;
}
if (s->sign)
{
*u = 0;
return 0;
}
if (sim_fpu_is_infinity (s))
{
*u = MAX_UINT;
return 0;
}
if (s->normal_exp < 0)
{
*u = 0;
return 0;
}
if (s->normal_exp > (NR_INTBITS - 1))
{
*u = MAX_UINT;
return 0;
}
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;
}
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;
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;
}
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;
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)
{
int shift = (NR_FRAC_GUARD - precision);
unsigned64 fraction = (d->fraction & ~IMPLICIT_1);
if (shift >= 0)
return fraction >> shift;
else
return fraction << -shift;
}
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);
}
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;
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:
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)
{
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)
{
status |= do_normal_underflow (f, is_double, round);
}
else if (f->normal_exp < NORMAL_EXPMIN)
{
status |= sim_fpu_status_denorm;
if (status & sim_fpu_status_inexact)
status |= sim_fpu_status_underflow;
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)
{
status = do_normal_overflow (f, is_double, round);
}
else
{
status = do_normal_round (f, NR_GUARDS, round);
if (f->fraction == 0)
status |= do_normal_underflow (f, is_double, round);
else if (f->normal_exp > NORMAL_EXPMAX)
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);
}
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;
if (shift >= NR_FRAC_GUARD)
{
*f = *l;
return sim_fpu_status_inexact;
}
if (shift <= - NR_FRAC_GUARD)
{
*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);
}
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);
}
lfraction >>= -shift;
}
else
{
f->normal_exp = r->normal_exp;
}
if (l->sign)
lfraction = - lfraction;
if (r->sign)
rfraction = - rfraction;
f->fraction = lfraction + rfraction;
if (f->fraction == 0)
{
*f = sim_fpu_zero;
return 0;
}
f->class = sim_fpu_class_number;
if ((signed64) f->fraction >= 0)
f->sign = 0;
else
{
f->sign = 1;
f->fraction = - f->fraction;
}
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;
if (shift >= NR_FRAC_GUARD)
{
*f = *l;
return sim_fpu_status_inexact;
}
if (shift <= - NR_FRAC_GUARD)
{
*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);
}
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);
}
lfraction >>= -shift;
}
else
{
f->normal_exp = r->normal_exp;
}
if (l->sign)
lfraction = - lfraction;
if (!r->sign)
rfraction = - rfraction;
f->fraction = lfraction + rfraction;
if (f->fraction == 0)
{
*f = sim_fpu_zero;
return 0;
}
f->class = sim_fpu_class_number;
if ((signed64) f->fraction >= 0)
f->sign = 0;
else
{
f->sign = 1;
f->fraction = - f->fraction;
}
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;
}
{
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;
f->normal_exp += NR_FRAC_GUARD + 64 - (NR_FRAC_GUARD * 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);
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);
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;
}
{
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;
if (numerator < denominator)
{
numerator <<= 1;
f->normal_exp--;
}
ASSERT (numerator >= denominator);
numerator <<= NR_SPARE;
denominator <<= NR_SPARE;
quotient = 0;
bit = (IMPLICIT_1 << NR_SPARE);
while (bit)
{
if (numerator >= denominator)
{
quotient |= bit;
numerator -= denominator;
}
bit >>= 1;
numerator <<= 1;
}
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;
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;
else
*f = *l;
return 0;
}
if (sim_fpu_is_infinity (r))
{
if (r->sign)
*f = *l;
else
*f = *r;
return 0;
}
if (l->sign > r->sign)
{
*f = *r;
return 0;
}
if (l->sign < r->sign)
{
*f = *l;
return 0;
}
ASSERT (l->sign == r->sign);
if (l->normal_exp > r->normal_exp
|| (l->normal_exp == r->normal_exp &&
l->fraction > r->fraction))
{
if (l->sign)
*f = *r;
else
*f = *l;
return 0;
}
else
{
if (l->sign)
*f = *l;
else
*f = *r;
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;
else
*f = *r;
return 0;
}
if (sim_fpu_is_infinity (r))
{
if (r->sign)
*f = *r;
else
*f = *l;
return 0;
}
if (l->sign > r->sign)
{
*f = *l;
return 0;
}
if (l->sign < r->sign)
{
*f = *r;
return 0;
}
ASSERT (l->sign == r->sign);
if (l->normal_exp > r->normal_exp
|| (l->normal_exp == r->normal_exp &&
l->fraction > r->fraction))
{
if (l->sign)
*f = *l;
else
*f = *r;
return 0;
}
else
{
if (l->sign)
*f = *r;
else
*f = *l;
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)
{
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;
}
{
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);
ASSERT (y >= IMPLICIT_1 && y < IMPLICIT_4);
if ((r->normal_exp & 1))
{
y += y;
}
ASSERT (y >= IMPLICIT_1 && y < (IMPLICIT_2 << 1));
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;
return sim_fpu_status_inexact;
}
else
return 0;
}
}
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);
}
#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))
{
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);
}
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;
}
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);
}
#if EXTERN_SIM_FPU_P
const sim_fpu sim_fpu_zero = {
sim_fpu_class_zero,
};
const sim_fpu sim_fpu_qnan = {
sim_fpu_class_qnan,
};
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
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;
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