]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - sim/common/sim-fpu.c
This commit was manufactured by cvs2svn to create branch 'gdb_7_2-branch'.
[thirdparty/binutils-gdb.git] / sim / common / sim-fpu.c
index 47b7c89c101cf077b26aa1aae935098d92e23ff9..6f1bad516bb4c1ba6051a1e11e8efe96a725c07a 100644 (file)
@@ -2,29 +2,21 @@
    of the floating point routines in libgcc1.c for targets without
    hardware floating point.  */
 
-/* Copyright (C) 1994,1997 Free Software Foundation, Inc.
-
-This file is free software; you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the
-Free Software Foundation; either version 2, or (at your option) any
-later version.
-
-In addition to the permissions in the GNU General Public License, the
-Free Software Foundation gives you unlimited permission to link the
-compiled version of this file with other programs, and to distribute
-those programs without any restriction coming from the use of this
-file.  (The General Public License restrictions do apply in other
-respects; for example, they cover modification of the file, and
-distribution when not linked into another program.)
-
-This file is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-General Public License for more details.
+/* Copyright 1994, 1997, 1998, 2003, 2007, 2008, 2009, 2010
+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; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+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,
@@ -51,25 +43,30 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "sim-assert.h"
 
 
-/* Debugging support. */
+/* Debugging support. 
+   If digits is -1, then print all digits.  */
 
 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)
+  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;
     }
 }
@@ -110,11 +107,16 @@ typedef union {
    */
 
 #define NR_EXPBITS  (is_double ?   11 :   8)
-#define NR_FRACBITS (is_double ?   52 :  23)
+#define NR_FRACBITS (is_double ?   52 : 23)
 #define SIGNBIT     (is_double ? MSBIT64 (0) : MSBIT64 (32))
 
-#define EXPMAX      ((unsigned) (is_double ? 2047 : 255))
-#define EXPBIAS     (is_double ? 1023 : 127)
+#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)
 
@@ -128,10 +130,16 @@ typedef union {
    64 bit - <IMPLICIT_1:1><FRACBITS:52><GUARDS:8><PAD:00>
    32 bit - <IMPLICIT_1:1><FRACBITS:23><GUARDS:7><PAD:30> */
 
-#define NR_PAD    (is_double ? 0 : 30)
-#define PADMASK   (is_double ? 0 : LSMASK64 (29, 0))
-#define NR_GUARDS  ((is_double ? 8 :  7 ) + NR_PAD)
+#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)
@@ -145,6 +153,9 @@ typedef union {
 #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)
 
 
@@ -163,6 +174,7 @@ typedef union {
 #define MAX_UINT  (is_64bit ? MAX_UINT64 : MAX_UINT32)
 #define NR_INTBITS (is_64bit ? 64 : 32)
 
+/* Squeese an unpacked sim_fpu struct into a 32/64 bit integer */
 STATIC_INLINE_SIM_FPU (unsigned64)
 pack_fpu (const sim_fpu *src,
          int is_double)
@@ -181,7 +193,11 @@ pack_fpu (const sim_fpu *src,
       /* force fraction to correct class */
       fraction = src->fraction;
       fraction >>= NR_GUARDS;
+#ifdef SIM_QUIET_NAN_NEGATED
+      fraction |= QUIET_NAN - 1;
+#else
       fraction |= QUIET_NAN;
+#endif
       break;
     case sim_fpu_class_snan:
       sign = src->sign;
@@ -189,7 +205,11 @@ pack_fpu (const sim_fpu *src,
       /* force fraction to correct class */
       fraction = src->fraction;
       fraction >>= NR_GUARDS;
+#ifdef SIM_QUIET_NAN_NEGATED
+      fraction |= QUIET_NAN;
+#else
       fraction &= ~QUIET_NAN;
+#endif
       break;
     case sim_fpu_class_infinity:
       sign = src->sign;
@@ -202,6 +222,7 @@ pack_fpu (const sim_fpu *src,
       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)
@@ -293,6 +314,7 @@ pack_fpu (const sim_fpu *src,
 }
 
 
+/* Unpack a 32/64 bit integer into a sim_fpu structure */
 STATIC_INLINE_SIM_FPU (void)
 unpack_fpu (sim_fpu *dst, unsigned64 packed, int is_double)
 {
@@ -308,6 +330,7 @@ unpack_fpu (sim_fpu *dst, unsigned64 packed, int is_double)
          /* tastes like zero */
          dst->class = sim_fpu_class_zero;
          dst->sign = sign;
+         dst->normal_exp = 0;
        }
       else
        {
@@ -315,7 +338,7 @@ unpack_fpu (sim_fpu *dst, unsigned64 packed, int is_double)
             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_number;
+         dst->class = sim_fpu_class_denorm;
          dst->sign = sign;
          fraction <<= NR_GUARDS;
          while (fraction < IMPLICIT_1)
@@ -339,10 +362,17 @@ unpack_fpu (sim_fpu *dst, unsigned64 packed, int is_double)
        }
       else
        {
+         int qnan;
+
          /* Non zero fraction, means NaN */
          dst->sign = sign;
          dst->fraction = (fraction << NR_GUARDS);
-         if (fraction >= QUIET_NAN)
+#ifdef SIM_QUIET_NAN_NEGATED
+         qnan = (fraction & QUIET_NAN) == 0;
+#else
+         qnan = fraction >= QUIET_NAN;
+#endif
+         if (qnan)
            dst->class = sim_fpu_class_qnan;
          else
            dst->class = sim_fpu_class_snan;
@@ -389,6 +419,7 @@ unpack_fpu (sim_fpu *dst, unsigned64 packed, int is_double)
 }
 
 
+/* Convert a floating point into an integer */
 STATIC_INLINE_SIM_FPU (int)
 fpu2i (signed64 *i,
        const sim_fpu *s,
@@ -488,6 +519,7 @@ fpu2i (signed64 *i,
   return status;
 }
 
+/* convert an integer into a floating point */
 STATIC_INLINE_SIM_FPU (int)
 i2fpu (sim_fpu *f, signed64 i, int is_64bit)
 {
@@ -496,6 +528,7 @@ i2fpu (sim_fpu *f, signed64 i, int is_64bit)
     {
       f->class = sim_fpu_class_zero;
       f->sign = 0;
+      f->normal_exp = 0;
     }
   else
     {
@@ -522,7 +555,7 @@ i2fpu (sim_fpu *f, signed64 i, int is_64bit)
        {
          do 
            {
-             f->fraction >>= 1;
+             f->fraction = (f->fraction >> 1) | (f->fraction & 1);
              f->normal_exp += 1;
            }
          while (f->fraction >= IMPLICIT_2);
@@ -559,6 +592,7 @@ i2fpu (sim_fpu *f, signed64 i, int is_64bit)
 }
 
 
+/* Convert a floating point into an integer */
 STATIC_INLINE_SIM_FPU (int)
 fpu2u (unsigned64 *u, const sim_fpu *s, int is_64bit)
 {
@@ -615,6 +649,7 @@ fpu2u (unsigned64 *u, const sim_fpu *s, int is_64bit)
   return 0;
 }
 
+/* Convert an unsigned integer into a floating point */
 STATIC_INLINE_SIM_FPU (int)
 u2fpu (sim_fpu *f, unsigned64 u, int is_64bit)
 {
@@ -622,6 +657,7 @@ u2fpu (sim_fpu *f, unsigned64 u, int is_64bit)
     {
       f->class = sim_fpu_class_zero;
       f->sign = 0;
+      f->normal_exp = 0;
     }
   else
     {
@@ -691,6 +727,40 @@ sim_fpu_to64 (unsigned64 *u,
 }
 
 
+INLINE_SIM_FPU (void)
+sim_fpu_fractionto (sim_fpu *f,
+                   int sign,
+                   int normal_exp,
+                   unsigned64 fraction,
+                   int precision)
+{
+  int shift = (NR_FRAC_GUARD - precision);
+  f->class = sim_fpu_class_number;
+  f->sign = sign;
+  f->normal_exp = normal_exp;
+  /* shift the fraction to where sim-fpu expects it */
+  if (shift >= 0)
+    f->fraction = (fraction << shift);
+  else
+    f->fraction = (fraction >> -shift);
+  f->fraction |= IMPLICIT_1;
+}
+
+
+INLINE_SIM_FPU (unsigned64)
+sim_fpu_tofraction (const sim_fpu *d,
+                   int precision)
+{
+  /* we have NR_FRAC_GUARD bits, we want only PRECISION bits */
+  int shift = (NR_FRAC_GUARD - precision);
+  unsigned64 fraction = (d->fraction & ~IMPLICIT_1);
+  if (shift >= 0)
+    return fraction >> shift;
+  else
+    return fraction << -shift;
+}
+
+
 /* Rounding */
 
 STATIC_INLINE_SIM_FPU (int)
@@ -831,6 +901,7 @@ do_round (sim_fpu *f,
       return sim_fpu_status_invalid_snan;
       break;
     case sim_fpu_class_number:
+    case sim_fpu_class_denorm:
       {
        int status;
        ASSERT (f->fraction < IMPLICIT_2);
@@ -846,10 +917,11 @@ do_round (sim_fpu *f,
            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);
+                 {
+                   status |= do_normal_underflow (f, is_double, round);
+                 }
                else if (f->normal_exp < NORMAL_EXPMIN) /* still underflow? */
                  {
                    status |= sim_fpu_status_denorm;
@@ -858,6 +930,8 @@ do_round (sim_fpu *f,
                       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))
                  {
@@ -885,7 +959,8 @@ do_round (sim_fpu *f,
              /* oops! rounding caused overflow */
              status |= do_normal_overflow (f, is_double, round);
          }
-       ASSERT ((f->class == sim_fpu_class_number)
+       ASSERT ((f->class == sim_fpu_class_number
+                || f->class == sim_fpu_class_denorm)
                <= (f->fraction < IMPLICIT_2 && f->fraction >= IMPLICIT_1));
        return status;
       }
@@ -1315,14 +1390,6 @@ sim_fpu_mul (sim_fpu *f,
     ASSERT (high >= LSBIT64 ((NR_FRAC_GUARD * 2) - 64));
     ASSERT (LSBIT64 (((NR_FRAC_GUARD + 1) * 2) - 64) < IMPLICIT_1);
 
-#if 0
-    printf ("\n");
-    print_bits (high, 63, (sim_fpu_print_func*)fprintf, stdout);
-    printf (";");
-    print_bits (low, 63, (sim_fpu_print_func*)fprintf, stdout);
-    printf ("\n");
-#endif
-
     /* normalize */
     do
       {
@@ -1334,13 +1401,6 @@ sim_fpu_mul (sim_fpu *f,
       }
     while (high < IMPLICIT_1);
 
-#if 0
-    print_bits (high, 63, (sim_fpu_print_func*)fprintf, stdout);
-    printf (";");
-    print_bits (low, 63, (sim_fpu_print_func*)fprintf, stdout);
-    printf ("\n");
-#endif
-
     ASSERT (high >= IMPLICIT_1 && high < IMPLICIT_2);
     if (low != 0)
       {
@@ -1470,16 +1530,6 @@ sim_fpu_div (sim_fpu *f,
        numerator <<= 1;
       }
 
-#if 0
-    printf ("\n");
-    print_bits (quotient, 63, (sim_fpu_print_func*)fprintf, stdout);
-    printf ("\n");
-    print_bits (numerator, 63, (sim_fpu_print_func*)fprintf, stdout);
-    printf ("\n");
-    print_bits (denominator, 63, (sim_fpu_print_func*)fprintf, stdout);
-    printf ("\n");
-#endif
-
     /* discard (but save) the extra bits */
     if ((quotient & LSMASK64 (NR_SPARE -1, 0)))
       quotient = (quotient >> NR_SPARE) | 1;
@@ -1500,49 +1550,173 @@ sim_fpu_div (sim_fpu *f,
 
 
 INLINE_SIM_FPU (int)
-sim_fpu_neg (sim_fpu *f,
+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;
     }
-  *f = *r;
-  f->sign = !r->sign;
-  return 0;
+  if (sim_fpu_is_infinity (l))
+    {
+      if (sim_fpu_is_infinity (r)
+         && l->sign == r->sign)
+       {
+         *f = sim_fpu_qnan;
+         return sim_fpu_status_invalid_isi;
+       }
+      if (l->sign)
+       *f = *r; /* -inf < anything */
+      else
+       *f = *l; /* +inf > anthing */
+      return 0;
+    }
+  if (sim_fpu_is_infinity (r))
+    {
+      if (r->sign)
+       *f = *l; /* anything > -inf */
+      else
+       *f = *r; /* anthing < +inf */
+      return 0;
+    }
+  if (l->sign > r->sign)
+    {
+      *f = *r; /* -ve < +ve */
+      return 0;
+    }
+  if (l->sign < r->sign)
+    {
+      *f = *l; /* +ve > -ve */
+      return 0;
+    }
+  ASSERT (l->sign == r->sign);
+  if (l->normal_exp > r->normal_exp
+      || (l->normal_exp == r->normal_exp && 
+         l->fraction > r->fraction))
+    {
+      /* |l| > |r| */
+      if (l->sign)
+       *f = *r; /* -ve < -ve */
+      else
+       *f = *l; /* +ve > +ve */
+      return 0;
+    }
+  else
+    {
+      /* |l| <= |r| */
+      if (l->sign)
+       *f = *l; /* -ve > -ve */
+      else
+       *f = *r; /* +ve < +ve */
+      return 0;
+    }
 }
 
 
 INLINE_SIM_FPU (int)
-sim_fpu_abs (sim_fpu *f,
+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;
     }
-  *f = *r;
-  f->sign = 0;
-  return 0;
+  if (sim_fpu_is_infinity (l))
+    {
+      if (sim_fpu_is_infinity (r)
+         && l->sign == r->sign)
+       {
+         *f = sim_fpu_qnan;
+         return sim_fpu_status_invalid_isi;
+       }
+      if (l->sign)
+       *f = *l; /* -inf < anything */
+      else
+       *f = *r; /* +inf > anthing */
+      return 0;
+    }
+  if (sim_fpu_is_infinity (r))
+    {
+      if (r->sign)
+       *f = *r; /* anything > -inf */
+      else
+       *f = *l; /* anything < +inf */
+      return 0;
+    }
+  if (l->sign > r->sign)
+    {
+      *f = *l; /* -ve < +ve */
+      return 0;
+    }
+  if (l->sign < r->sign)
+    {
+      *f = *r; /* +ve > -ve */
+      return 0;
+    }
+  ASSERT (l->sign == r->sign);
+  if (l->normal_exp > r->normal_exp
+      || (l->normal_exp == r->normal_exp && 
+         l->fraction > r->fraction))
+    {
+      /* |l| > |r| */
+      if (l->sign)
+       *f = *l; /* -ve < -ve */
+      else
+       *f = *r; /* +ve > +ve */
+      return 0;
+    }
+  else
+    {
+      /* |l| <= |r| */
+      if (l->sign)
+       *f = *r; /* -ve > -ve */
+      else
+       *f = *l; /* +ve < +ve */
+      return 0;
+    }
 }
 
 
 INLINE_SIM_FPU (int)
-sim_fpu_inv (sim_fpu *f,
+sim_fpu_neg (sim_fpu *f,
             const sim_fpu *r)
 {
   if (sim_fpu_is_snan (r))
@@ -1554,27 +1728,37 @@ sim_fpu_inv (sim_fpu *f,
   if (sim_fpu_is_qnan (r))
     {
       *f = *r;
-      f->class = sim_fpu_class_qnan;
       return 0;
     }
-  if (sim_fpu_is_infinity (r))
-    {
-      *f = sim_fpu_zero;
-      f->sign = r->sign;
-      return 0;
-    }
-  if (sim_fpu_is_zero (r))
+  *f = *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_snan (r))
     {
-      f->class = sim_fpu_class_infinity;
-      f->sign = r->sign;
-      return sim_fpu_status_invalid_div0;
+      f->class = sim_fpu_class_qnan;
+      return sim_fpu_status_invalid_snan;
     }
-  *f = *r;
-  f->normal_exp = - r->normal_exp;
   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)
@@ -1593,6 +1777,7 @@ sim_fpu_sqrt (sim_fpu *f,
     {
       f->class = sim_fpu_class_zero;
       f->sign = r->sign;
+      f->normal_exp = 0;
       return 0;
     }
   if (sim_fpu_is_infinity (r))
@@ -1864,7 +2049,17 @@ INLINE_SIM_FPU (double)
 sim_fpu_2d (const sim_fpu *s)
 {
   sim_fpu_map val;
-  val.i = pack_fpu (s, 1);
+  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;
 }
 
@@ -1959,6 +2154,7 @@ sim_fpu_is_number (const sim_fpu *d)
 {
   switch (d->class)
     {
+    case sim_fpu_class_denorm:
     case sim_fpu_class_number:
       return 1;
     default:
@@ -1966,6 +2162,50 @@ sim_fpu_is_number (const sim_fpu *d)
     }
 }
 
+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 (unsigned64)
+sim_fpu_fraction (const sim_fpu *d)
+{
+  return d->fraction;
+}
+
+
+INLINE_SIM_FPU (unsigned64)
+sim_fpu_guard (const sim_fpu *d, int is_double)
+{
+  unsigned64 rv;
+  unsigned64 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)
 {
@@ -1976,25 +2216,20 @@ sim_fpu_is (const sim_fpu *d)
     case sim_fpu_class_snan:
       return SIM_FPU_IS_SNAN;
     case sim_fpu_class_infinity:
-      return SIM_FPU_IS_NINF;
-      return SIM_FPU_IS_PINF;
+      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_NNUM;
+       return SIM_FPU_IS_NNUMBER;
       else
-       return SIM_FPU_IS_PNUM;
-#if 0
-      /* FIXME: Since the intermediate sim_fpu format can hold numbers
-        far smaller then the targets FP format, the test for denorm
-        is currently bogus.  Perhaphs the code converting a number to
-        the internal format should flag such situtations with
-        `ndemorm' */
-    case ???:
+       return SIM_FPU_IS_PNUMBER;
+    case sim_fpu_class_denorm:
       if (d->sign)
        return SIM_FPU_IS_NDENORM;
       else
        return SIM_FPU_IS_PDENORM;
-#endif
     case sim_fpu_class_zero:
       if (d->sign)
        return SIM_FPU_IS_NZERO;
@@ -2188,8 +2423,26 @@ sim_fpu_gt (int *is,
 
 /* A number of useful constants */
 
-const sim_fpu sim_fpu_zero = { sim_fpu_class_zero, };
-const sim_fpu sim_fpu_qnan = { sim_fpu_class_qnan, };
+#if EXTERN_SIM_FPU_P
+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
 
 
 /* For debugging */
@@ -2198,18 +2451,27 @@ 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, print, arg);
+      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, print, arg);
+      print_bits (f->fraction, NR_FRAC_GUARD - 1, digits, print, arg);
       print (arg, "*SignalNaN");
       break;
     case sim_fpu_class_zero:
@@ -2219,9 +2481,10 @@ sim_fpu_print_fpu (const sim_fpu *f,
       print (arg, "INF");
       break;
     case sim_fpu_class_number:
+    case sim_fpu_class_denorm:
       print (arg, "1.");
-      print_bits (f->fraction, NR_FRAC_GUARD - 1, print, arg);
-      print (arg, "*2^%+-5d", f->normal_exp);
+      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);
     }
@@ -2234,7 +2497,7 @@ sim_fpu_print_status (int status,
                      void *arg)
 {
   int i = 1;
-  char *prefix = "";
+  const char *prefix = "";
   while (status >= i)
     {
       switch ((sim_fpu_status) (status & i))
@@ -2269,27 +2532,21 @@ sim_fpu_print_status (int status,
        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 = ",";