OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gdb-7.1/] [sim/] [rx/] [fpu.c] - Diff between revs 834 and 842

Only display areas with differences | Details | Blame | View Log

Rev 834 Rev 842
/* fpu.c --- FPU emulator for stand-alone RX simulator.
/* fpu.c --- FPU emulator for stand-alone RX simulator.
 
 
Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
Contributed by Red Hat, Inc.
Contributed by Red Hat, Inc.
 
 
This file is part of the GNU simulators.
This file is part of the GNU simulators.
 
 
This program is free software; you can redistribute it and/or modify
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
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
(at your option) any later version.
 
 
This program is distributed in the hope that it will be useful,
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
GNU General Public License for more details.
 
 
You should have received a copy of the GNU General Public License
You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
 
 
#include "cpu.h"
#include "cpu.h"
#include "fpu.h"
#include "fpu.h"
 
 
/* FPU encodings are as follows:
/* FPU encodings are as follows:
 
 
   S EXPONENT MANTISSA
   S EXPONENT MANTISSA
   1 12345678 12345678901234567890123
   1 12345678 12345678901234567890123
 
 
   0 00000000 00000000000000000000000   +0
   0 00000000 00000000000000000000000   +0
   1 00000000 00000000000000000000000   -0
   1 00000000 00000000000000000000000   -0
 
 
   X 00000000 00000000000000000000001   Denormals
   X 00000000 00000000000000000000001   Denormals
   X 00000000 11111111111111111111111
   X 00000000 11111111111111111111111
 
 
   X 00000001 XXXXXXXXXXXXXXXXXXXXXXX   Normals
   X 00000001 XXXXXXXXXXXXXXXXXXXXXXX   Normals
   X 11111110 XXXXXXXXXXXXXXXXXXXXXXX
   X 11111110 XXXXXXXXXXXXXXXXXXXXXXX
 
 
   0 11111111 00000000000000000000000   +Inf
   0 11111111 00000000000000000000000   +Inf
   1 11111111 00000000000000000000000   -Inf
   1 11111111 00000000000000000000000   -Inf
 
 
   X 11111111 0XXXXXXXXXXXXXXXXXXXXXX   SNaN (X != 0)
   X 11111111 0XXXXXXXXXXXXXXXXXXXXXX   SNaN (X != 0)
   X 11111111 1XXXXXXXXXXXXXXXXXXXXXX   QNaN (X != 0)
   X 11111111 1XXXXXXXXXXXXXXXXXXXXXX   QNaN (X != 0)
 
 
*/
*/
 
 
#define trace 0
#define trace 0
#define tprintf if (trace) printf
#define tprintf if (trace) printf
 
 
/* Some magic numbers.  */
/* Some magic numbers.  */
#define PLUS_MAX   0x7f7fffffUL
#define PLUS_MAX   0x7f7fffffUL
#define MINUS_MAX  0xff7fffffUL
#define MINUS_MAX  0xff7fffffUL
#define PLUS_INF   0x7f800000UL
#define PLUS_INF   0x7f800000UL
#define MINUS_INF  0xff800000UL
#define MINUS_INF  0xff800000UL
#define PLUS_ZERO  0x00000000UL
#define PLUS_ZERO  0x00000000UL
#define MINUS_ZERO 0x80000000UL
#define MINUS_ZERO 0x80000000UL
 
 
#define FP_RAISE(e) fp_raise(FPSWBITS_C##e)
#define FP_RAISE(e) fp_raise(FPSWBITS_C##e)
static void
static void
fp_raise (int mask)
fp_raise (int mask)
{
{
  regs.r_fpsw |= mask;
  regs.r_fpsw |= mask;
  if (mask != FPSWBITS_CE)
  if (mask != FPSWBITS_CE)
    {
    {
      if (regs.r_fpsw & (mask << FPSW_CESH))
      if (regs.r_fpsw & (mask << FPSW_CESH))
        regs.r_fpsw |= (mask << FPSW_CFSH);
        regs.r_fpsw |= (mask << FPSW_CFSH);
      if (regs.r_fpsw & FPSWBITS_FMASK)
      if (regs.r_fpsw & FPSWBITS_FMASK)
        regs.r_fpsw |= FPSWBITS_FSUM;
        regs.r_fpsw |= FPSWBITS_FSUM;
      else
      else
        regs.r_fpsw &= ~FPSWBITS_FSUM;
        regs.r_fpsw &= ~FPSWBITS_FSUM;
    }
    }
}
}
 
 
/* We classify all numbers as one of these.  They correspond to the
/* We classify all numbers as one of these.  They correspond to the
   rows/colums in the exception tables.  */
   rows/colums in the exception tables.  */
typedef enum {
typedef enum {
  FP_NORMAL,
  FP_NORMAL,
  FP_PZERO,
  FP_PZERO,
  FP_NZERO,
  FP_NZERO,
  FP_PINFINITY,
  FP_PINFINITY,
  FP_NINFINITY,
  FP_NINFINITY,
  FP_DENORMAL,
  FP_DENORMAL,
  FP_QNAN,
  FP_QNAN,
  FP_SNAN
  FP_SNAN
} FP_Type;
} FP_Type;
 
 
#if defined DEBUG0
#if defined DEBUG0
static const char *fpt_names[] = {
static const char *fpt_names[] = {
  "Normal", "+0", "-0", "+Inf", "-Inf", "Denormal", "QNaN", "SNaN"
  "Normal", "+0", "-0", "+Inf", "-Inf", "Denormal", "QNaN", "SNaN"
};
};
#endif
#endif
 
 
#define EXP_BIAS  127
#define EXP_BIAS  127
#define EXP_ZERO -127
#define EXP_ZERO -127
#define EXP_INF   128
#define EXP_INF   128
 
 
#define MANT_BIAS 0x00080000UL
#define MANT_BIAS 0x00080000UL
 
 
typedef struct {
typedef struct {
  int exp;
  int exp;
  unsigned int mant; /* 24 bits */
  unsigned int mant; /* 24 bits */
  char type;
  char type;
  char sign;
  char sign;
  fp_t orig_value;
  fp_t orig_value;
} FP_Parts;
} FP_Parts;
 
 
static void
static void
fp_explode (fp_t f, FP_Parts *p)
fp_explode (fp_t f, FP_Parts *p)
{
{
  int exp, mant, sign;
  int exp, mant, sign;
 
 
  exp = ((f & 0x7f800000UL) >> 23);
  exp = ((f & 0x7f800000UL) >> 23);
  mant = f & 0x007fffffUL;
  mant = f & 0x007fffffUL;
  sign = f & 0x80000000UL;
  sign = f & 0x80000000UL;
  /*printf("explode: %08x %x %2x %6x\n", f, sign, exp, mant);*/
  /*printf("explode: %08x %x %2x %6x\n", f, sign, exp, mant);*/
 
 
  p->sign = sign ? -1 : 1;
  p->sign = sign ? -1 : 1;
  p->exp = exp - EXP_BIAS;
  p->exp = exp - EXP_BIAS;
  p->orig_value = f;
  p->orig_value = f;
  p->mant = mant | 0x00800000UL;
  p->mant = mant | 0x00800000UL;
 
 
  if (p->exp == EXP_ZERO)
  if (p->exp == EXP_ZERO)
    {
    {
      if (regs.r_fpsw & FPSWBITS_DN)
      if (regs.r_fpsw & FPSWBITS_DN)
        mant = 0;
        mant = 0;
      if (mant)
      if (mant)
        p->type = FP_DENORMAL;
        p->type = FP_DENORMAL;
      else
      else
        {
        {
          p->mant = 0;
          p->mant = 0;
          p->type = sign ? FP_NZERO : FP_PZERO;
          p->type = sign ? FP_NZERO : FP_PZERO;
        }
        }
    }
    }
  else if (p->exp == EXP_INF)
  else if (p->exp == EXP_INF)
    {
    {
      if (mant == 0)
      if (mant == 0)
        p->type = sign ? FP_NINFINITY : FP_PINFINITY;
        p->type = sign ? FP_NINFINITY : FP_PINFINITY;
      else if (mant & 0x00400000UL)
      else if (mant & 0x00400000UL)
        p->type = FP_QNAN;
        p->type = FP_QNAN;
      else
      else
        p->type = FP_SNAN;
        p->type = FP_SNAN;
    }
    }
  else
  else
    p->type = FP_NORMAL;
    p->type = FP_NORMAL;
}
}
 
 
static fp_t
static fp_t
fp_implode (FP_Parts *p)
fp_implode (FP_Parts *p)
{
{
  int exp, mant;
  int exp, mant;
 
 
  exp = p->exp + EXP_BIAS;
  exp = p->exp + EXP_BIAS;
  mant = p->mant;
  mant = p->mant;
  /*printf("implode: exp %d mant 0x%x\n", exp, mant);*/
  /*printf("implode: exp %d mant 0x%x\n", exp, mant);*/
  if (p->type == FP_NORMAL)
  if (p->type == FP_NORMAL)
    {
    {
      while (mant
      while (mant
             && exp > 0
             && exp > 0
             && mant < 0x00800000UL)
             && mant < 0x00800000UL)
        {
        {
          mant <<= 1;
          mant <<= 1;
          exp --;
          exp --;
        }
        }
      while (mant > 0x00ffffffUL)
      while (mant > 0x00ffffffUL)
        {
        {
          mant >>= 1;
          mant >>= 1;
          exp ++;
          exp ++;
        }
        }
      if (exp < 0)
      if (exp < 0)
        {
        {
          /* underflow */
          /* underflow */
          exp = 0;
          exp = 0;
          mant = 0;
          mant = 0;
          FP_RAISE (E);
          FP_RAISE (E);
        }
        }
      if (exp >= 255)
      if (exp >= 255)
        {
        {
          /* overflow */
          /* overflow */
          exp = 255;
          exp = 255;
          mant = 0;
          mant = 0;
          FP_RAISE (O);
          FP_RAISE (O);
        }
        }
    }
    }
  mant &= 0x007fffffUL;
  mant &= 0x007fffffUL;
  exp &= 0xff;
  exp &= 0xff;
  mant |= exp << 23;
  mant |= exp << 23;
  if (p->sign < 0)
  if (p->sign < 0)
    mant |= 0x80000000UL;
    mant |= 0x80000000UL;
 
 
  return mant;
  return mant;
}
}
 
 
typedef union {
typedef union {
  unsigned long long ll;
  unsigned long long ll;
  double d;
  double d;
} U_d_ll;
} U_d_ll;
 
 
static int checked_format = 0;
static int checked_format = 0;
 
 
/* We assume a double format like this:
/* We assume a double format like this:
   S[1] E[11] M[52]
   S[1] E[11] M[52]
*/
*/
 
 
static double
static double
fp_to_double (FP_Parts *p)
fp_to_double (FP_Parts *p)
{
{
  U_d_ll u;
  U_d_ll u;
 
 
  if (!checked_format)
  if (!checked_format)
    {
    {
      u.d = 1.5;
      u.d = 1.5;
      if (u.ll != 0x3ff8000000000000ULL)
      if (u.ll != 0x3ff8000000000000ULL)
        abort ();
        abort ();
      u.d = -225;
      u.d = -225;
      if (u.ll != 0xc06c200000000000ULL)
      if (u.ll != 0xc06c200000000000ULL)
        abort ();
        abort ();
      u.d = 10.1;
      u.d = 10.1;
      if (u.ll != 0x4024333333333333ULL)
      if (u.ll != 0x4024333333333333ULL)
        abort ();
        abort ();
      checked_format = 1;
      checked_format = 1;
    }
    }
 
 
  u.ll = 0;
  u.ll = 0;
  if (p->sign < 0)
  if (p->sign < 0)
    u.ll |= (1ULL << 63);
    u.ll |= (1ULL << 63);
  /* Make sure a zero encoding stays a zero.  */
  /* Make sure a zero encoding stays a zero.  */
  if (p->exp != -EXP_BIAS)
  if (p->exp != -EXP_BIAS)
    u.ll |= ((unsigned long long)p->exp + 1023ULL) << 52;
    u.ll |= ((unsigned long long)p->exp + 1023ULL) << 52;
  u.ll |= (unsigned long long) (p->mant & 0x007fffffUL) << (52 - 23);
  u.ll |= (unsigned long long) (p->mant & 0x007fffffUL) << (52 - 23);
  return u.d;
  return u.d;
}
}
 
 
static void
static void
double_to_fp (double d, FP_Parts *p)
double_to_fp (double d, FP_Parts *p)
{
{
  int exp;
  int exp;
  U_d_ll u;
  U_d_ll u;
  int sign;
  int sign;
 
 
  u.d = d;
  u.d = d;
 
 
  sign = (u.ll & 0x8000000000000000ULL) ? 1 : 0;
  sign = (u.ll & 0x8000000000000000ULL) ? 1 : 0;
  exp = u.ll >> 52;
  exp = u.ll >> 52;
  exp = (exp & 0x7ff);
  exp = (exp & 0x7ff);
 
 
  if (exp == 0)
  if (exp == 0)
    {
    {
      /* A generated denormal should show up as an underflow, not
      /* A generated denormal should show up as an underflow, not
         here.  */
         here.  */
      if (sign)
      if (sign)
        fp_explode (MINUS_ZERO, p);
        fp_explode (MINUS_ZERO, p);
      else
      else
        fp_explode (PLUS_ZERO, p);
        fp_explode (PLUS_ZERO, p);
      return;
      return;
    }
    }
 
 
  exp = exp - 1023;
  exp = exp - 1023;
  if ((exp + EXP_BIAS) > 254)
  if ((exp + EXP_BIAS) > 254)
    {
    {
      FP_RAISE (O);
      FP_RAISE (O);
      switch (regs.r_fpsw & FPSWBITS_RM)
      switch (regs.r_fpsw & FPSWBITS_RM)
        {
        {
        case FPRM_NEAREST:
        case FPRM_NEAREST:
          if (sign)
          if (sign)
            fp_explode (MINUS_INF, p);
            fp_explode (MINUS_INF, p);
          else
          else
            fp_explode (PLUS_INF, p);
            fp_explode (PLUS_INF, p);
          break;
          break;
        case FPRM_ZERO:
        case FPRM_ZERO:
          if (sign)
          if (sign)
            fp_explode (MINUS_MAX, p);
            fp_explode (MINUS_MAX, p);
          else
          else
            fp_explode (PLUS_MAX, p);
            fp_explode (PLUS_MAX, p);
          break;
          break;
        case FPRM_PINF:
        case FPRM_PINF:
          if (sign)
          if (sign)
            fp_explode (MINUS_MAX, p);
            fp_explode (MINUS_MAX, p);
          else
          else
            fp_explode (PLUS_INF, p);
            fp_explode (PLUS_INF, p);
          break;
          break;
        case FPRM_NINF:
        case FPRM_NINF:
          if (sign)
          if (sign)
            fp_explode (MINUS_INF, p);
            fp_explode (MINUS_INF, p);
          else
          else
            fp_explode (PLUS_MAX, p);
            fp_explode (PLUS_MAX, p);
          break;
          break;
        }
        }
      return;
      return;
    }
    }
  if ((exp + EXP_BIAS) < 1)
  if ((exp + EXP_BIAS) < 1)
    {
    {
      if (sign)
      if (sign)
        fp_explode (MINUS_ZERO, p);
        fp_explode (MINUS_ZERO, p);
      else
      else
        fp_explode (PLUS_ZERO, p);
        fp_explode (PLUS_ZERO, p);
      FP_RAISE (U);
      FP_RAISE (U);
    }
    }
 
 
  p->sign = sign ? -1 : 1;
  p->sign = sign ? -1 : 1;
  p->exp = exp;
  p->exp = exp;
  p->mant = u.ll >> (52-23) & 0x007fffffUL;
  p->mant = u.ll >> (52-23) & 0x007fffffUL;
  p->mant |= 0x00800000UL;
  p->mant |= 0x00800000UL;
  p->type = FP_NORMAL;
  p->type = FP_NORMAL;
 
 
  if (u.ll & 0x1fffffffULL)
  if (u.ll & 0x1fffffffULL)
    {
    {
      switch (regs.r_fpsw & FPSWBITS_RM)
      switch (regs.r_fpsw & FPSWBITS_RM)
        {
        {
        case FPRM_NEAREST:
        case FPRM_NEAREST:
          if (u.ll & 0x10000000ULL)
          if (u.ll & 0x10000000ULL)
            p->mant ++;
            p->mant ++;
          break;
          break;
        case FPRM_ZERO:
        case FPRM_ZERO:
          break;
          break;
        case FPRM_PINF:
        case FPRM_PINF:
          if (sign == 1)
          if (sign == 1)
            p->mant ++;
            p->mant ++;
          break;
          break;
        case FPRM_NINF:
        case FPRM_NINF:
          if (sign == -1)
          if (sign == -1)
            p->mant ++;
            p->mant ++;
          break;
          break;
        }
        }
      FP_RAISE (X);
      FP_RAISE (X);
    }
    }
 
 
}
}
 
 
typedef enum {
typedef enum {
  eNR,          /* Use the normal result.  */
  eNR,          /* Use the normal result.  */
  ePZ, eNZ,     /* +- zero */
  ePZ, eNZ,     /* +- zero */
  eSZ,          /* signed zero - XOR signs of ops together.  */
  eSZ,          /* signed zero - XOR signs of ops together.  */
  eRZ,          /* +- zero depending on rounding mode.  */
  eRZ,          /* +- zero depending on rounding mode.  */
  ePI, eNI,     /* +- Infinity */
  ePI, eNI,     /* +- Infinity */
  eSI,          /* signed infinity - XOR signs of ops together.  */
  eSI,          /* signed infinity - XOR signs of ops together.  */
  eQN, eSN,     /* Quiet/Signalling NANs */
  eQN, eSN,     /* Quiet/Signalling NANs */
  eIn,          /* Invalid.  */
  eIn,          /* Invalid.  */
  eUn,          /* Unimplemented.  */
  eUn,          /* Unimplemented.  */
  eDZ,          /* Divide-by-zero.  */
  eDZ,          /* Divide-by-zero.  */
  eLT,          /* less than */
  eLT,          /* less than */
  eGT,          /* greater than */
  eGT,          /* greater than */
  eEQ,          /* equal to */
  eEQ,          /* equal to */
} FP_ExceptionCases;
} FP_ExceptionCases;
 
 
#if defined DEBUG0
#if defined DEBUG0
static const char *ex_names[] = {
static const char *ex_names[] = {
  "NR", "PZ", "NZ", "SZ", "RZ", "PI", "NI", "SI", "QN", "SN", "IN", "Un", "DZ", "LT", "GT", "EQ"
  "NR", "PZ", "NZ", "SZ", "RZ", "PI", "NI", "SI", "QN", "SN", "IN", "Un", "DZ", "LT", "GT", "EQ"
};
};
#endif
#endif
 
 
/* This checks for all exceptional cases (not all FP exceptions) and
/* This checks for all exceptional cases (not all FP exceptions) and
   returns TRUE if it is providing the result in *c.  If it returns
   returns TRUE if it is providing the result in *c.  If it returns
   FALSE, the caller should do the "normal" operation.  */
   FALSE, the caller should do the "normal" operation.  */
int
int
check_exceptions (FP_Parts *a, FP_Parts *b, fp_t *c,
check_exceptions (FP_Parts *a, FP_Parts *b, fp_t *c,
                  FP_ExceptionCases ex_tab[5][5],
                  FP_ExceptionCases ex_tab[5][5],
                  FP_ExceptionCases *case_ret)
                  FP_ExceptionCases *case_ret)
{
{
  FP_ExceptionCases fpec;
  FP_ExceptionCases fpec;
 
 
  if (a->type == FP_SNAN
  if (a->type == FP_SNAN
      || b->type == FP_SNAN)
      || b->type == FP_SNAN)
    fpec = eIn;
    fpec = eIn;
  else if (a->type == FP_QNAN
  else if (a->type == FP_QNAN
           || b->type == FP_QNAN)
           || b->type == FP_QNAN)
    fpec = eQN;
    fpec = eQN;
  else if (a->type == FP_DENORMAL
  else if (a->type == FP_DENORMAL
           || b->type == FP_DENORMAL)
           || b->type == FP_DENORMAL)
    fpec = eUn;
    fpec = eUn;
  else
  else
    fpec = ex_tab[(int)(a->type)][(int)(b->type)];
    fpec = ex_tab[(int)(a->type)][(int)(b->type)];
 
 
  /*printf("%s %s -> %s\n", fpt_names[(int)(a->type)], fpt_names[(int)(b->type)], ex_names[(int)(fpec)]);*/
  /*printf("%s %s -> %s\n", fpt_names[(int)(a->type)], fpt_names[(int)(b->type)], ex_names[(int)(fpec)]);*/
 
 
  if (case_ret)
  if (case_ret)
    *case_ret = fpec;
    *case_ret = fpec;
 
 
  switch (fpec)
  switch (fpec)
    {
    {
    case eNR:   /* Use the normal result.  */
    case eNR:   /* Use the normal result.  */
      return 0;
      return 0;
 
 
    case ePZ:   /* + zero */
    case ePZ:   /* + zero */
      *c = 0x00000000;
      *c = 0x00000000;
      return 1;
      return 1;
 
 
    case eNZ:   /* - zero */
    case eNZ:   /* - zero */
      *c = 0x80000000;
      *c = 0x80000000;
      return 1;
      return 1;
 
 
    case eSZ:   /* signed zero */
    case eSZ:   /* signed zero */
      *c = (a->sign == b->sign) ? PLUS_ZERO : MINUS_ZERO;
      *c = (a->sign == b->sign) ? PLUS_ZERO : MINUS_ZERO;
      return 1;
      return 1;
 
 
    case eRZ:   /* +- zero depending on rounding mode.  */
    case eRZ:   /* +- zero depending on rounding mode.  */
      if ((regs.r_fpsw & FPSWBITS_RM) == FPRM_NINF)
      if ((regs.r_fpsw & FPSWBITS_RM) == FPRM_NINF)
        *c = 0x80000000;
        *c = 0x80000000;
      else
      else
        *c = 0x00000000;
        *c = 0x00000000;
      return 1;
      return 1;
 
 
    case ePI:   /* + Infinity */
    case ePI:   /* + Infinity */
      *c = 0x7F800000;
      *c = 0x7F800000;
      return 1;
      return 1;
 
 
    case eNI:   /* - Infinity */
    case eNI:   /* - Infinity */
      *c = 0xFF800000;
      *c = 0xFF800000;
      return 1;
      return 1;
 
 
    case eSI:   /* sign Infinity */
    case eSI:   /* sign Infinity */
      *c = (a->sign == b->sign) ? PLUS_INF : MINUS_INF;
      *c = (a->sign == b->sign) ? PLUS_INF : MINUS_INF;
      return 1;
      return 1;
 
 
    case eQN:   /* Quiet NANs */
    case eQN:   /* Quiet NANs */
      if (a->type == FP_QNAN)
      if (a->type == FP_QNAN)
        *c = a->orig_value;
        *c = a->orig_value;
      else
      else
        *c = b->orig_value;
        *c = b->orig_value;
      return 1;
      return 1;
 
 
    case eSN:   /* Signalling NANs */
    case eSN:   /* Signalling NANs */
      if (a->type == FP_SNAN)
      if (a->type == FP_SNAN)
        *c = a->orig_value;
        *c = a->orig_value;
      else
      else
        *c = b->orig_value;
        *c = b->orig_value;
      FP_RAISE (V);
      FP_RAISE (V);
      return 1;
      return 1;
 
 
    case eIn:   /* Invalid.  */
    case eIn:   /* Invalid.  */
      FP_RAISE (V);
      FP_RAISE (V);
      if (a->type == FP_SNAN)
      if (a->type == FP_SNAN)
        *c = a->orig_value | 0x00400000;
        *c = a->orig_value | 0x00400000;
      else if  (a->type == FP_SNAN)
      else if  (a->type == FP_SNAN)
        *c = b->orig_value | 0x00400000;
        *c = b->orig_value | 0x00400000;
      else
      else
        *c = 0x7fc00000;
        *c = 0x7fc00000;
      return 1;
      return 1;
 
 
    case eUn:   /* Unimplemented.  */
    case eUn:   /* Unimplemented.  */
      FP_RAISE (E);
      FP_RAISE (E);
      return 1;
      return 1;
 
 
    case eDZ:   /* Division-by-zero.  */
    case eDZ:   /* Division-by-zero.  */
      *c = (a->sign == b->sign) ? PLUS_INF : MINUS_INF;
      *c = (a->sign == b->sign) ? PLUS_INF : MINUS_INF;
      FP_RAISE (Z);
      FP_RAISE (Z);
      return 1;
      return 1;
 
 
    default:
    default:
      return 0;
      return 0;
    }
    }
}
}
 
 
#define CHECK_EXCEPTIONS(FPPa, FPPb, fpc, ex_tab) \
#define CHECK_EXCEPTIONS(FPPa, FPPb, fpc, ex_tab) \
  if (check_exceptions (&FPPa, &FPPb, &fpc, ex_tab, 0))  \
  if (check_exceptions (&FPPa, &FPPb, &fpc, ex_tab, 0))  \
    return fpc;
    return fpc;
 
 
/* For each operation, we have two tables of how nonnormal cases are
/* For each operation, we have two tables of how nonnormal cases are
   handled.  The DN=0 case is first, followed by the DN=1 case, with
   handled.  The DN=0 case is first, followed by the DN=1 case, with
   each table using the following layout: */
   each table using the following layout: */
 
 
static FP_ExceptionCases ex_add_tab[5][5] = {
static FP_ExceptionCases ex_add_tab[5][5] = {
  /* N   +0   -0   +In  -In */
  /* N   +0   -0   +In  -In */
  { eNR, eNR, eNR, ePI, eNI }, /* Normal */
  { eNR, eNR, eNR, ePI, eNI }, /* Normal */
  { eNR, ePZ, eRZ, ePI, eNI }, /* +0   */
  { eNR, ePZ, eRZ, ePI, eNI }, /* +0   */
  { eNR, eRZ, eNZ, ePI, eNI }, /* -0   */
  { eNR, eRZ, eNZ, ePI, eNI }, /* -0   */
  { ePI, ePI, ePI, ePI, eIn }, /* +Inf */
  { ePI, ePI, ePI, ePI, eIn }, /* +Inf */
  { eNI, eNI, eNI, eIn, eNI }, /* -Inf */
  { eNI, eNI, eNI, eIn, eNI }, /* -Inf */
};
};
 
 
fp_t
fp_t
rxfp_add (fp_t fa, fp_t fb)
rxfp_add (fp_t fa, fp_t fb)
{
{
  FP_Parts a, b, c;
  FP_Parts a, b, c;
  fp_t rv;
  fp_t rv;
  double da, db;
  double da, db;
 
 
  fp_explode (fa, &a);
  fp_explode (fa, &a);
  fp_explode (fb, &b);
  fp_explode (fb, &b);
  CHECK_EXCEPTIONS (a, b, rv, ex_add_tab);
  CHECK_EXCEPTIONS (a, b, rv, ex_add_tab);
 
 
  da = fp_to_double (&a);
  da = fp_to_double (&a);
  db = fp_to_double (&b);
  db = fp_to_double (&b);
  tprintf("%g + %g = %g\n", da, db, da+db);
  tprintf("%g + %g = %g\n", da, db, da+db);
 
 
  double_to_fp (da+db, &c);
  double_to_fp (da+db, &c);
  rv = fp_implode (&c);
  rv = fp_implode (&c);
  return rv;
  return rv;
}
}
 
 
static FP_ExceptionCases ex_sub_tab[5][5] = {
static FP_ExceptionCases ex_sub_tab[5][5] = {
  /* N   +0   -0   +In  -In */
  /* N   +0   -0   +In  -In */
  { eNR, eNR, eNR, eNI, ePI }, /* Normal */
  { eNR, eNR, eNR, eNI, ePI }, /* Normal */
  { eNR, eRZ, ePZ, eNI, ePI }, /* +0   */
  { eNR, eRZ, ePZ, eNI, ePI }, /* +0   */
  { eNR, eNZ, eRZ, eNI, ePI }, /* -0   */
  { eNR, eNZ, eRZ, eNI, ePI }, /* -0   */
  { ePI, ePI, ePI, eIn, ePI }, /* +Inf */
  { ePI, ePI, ePI, eIn, ePI }, /* +Inf */
  { eNI, eNI, eNI, eNI, eIn }, /* -Inf */
  { eNI, eNI, eNI, eNI, eIn }, /* -Inf */
};
};
 
 
fp_t
fp_t
rxfp_sub (fp_t fa, fp_t fb)
rxfp_sub (fp_t fa, fp_t fb)
{
{
  FP_Parts a, b, c;
  FP_Parts a, b, c;
  fp_t rv;
  fp_t rv;
  double da, db;
  double da, db;
 
 
  fp_explode (fa, &a);
  fp_explode (fa, &a);
  fp_explode (fb, &b);
  fp_explode (fb, &b);
  CHECK_EXCEPTIONS (a, b, rv, ex_sub_tab);
  CHECK_EXCEPTIONS (a, b, rv, ex_sub_tab);
 
 
  da = fp_to_double (&a);
  da = fp_to_double (&a);
  db = fp_to_double (&b);
  db = fp_to_double (&b);
  tprintf("%g - %g = %g\n", da, db, da-db);
  tprintf("%g - %g = %g\n", da, db, da-db);
 
 
  double_to_fp (da-db, &c);
  double_to_fp (da-db, &c);
  rv = fp_implode (&c);
  rv = fp_implode (&c);
 
 
  return rv;
  return rv;
}
}
 
 
static FP_ExceptionCases ex_mul_tab[5][5] = {
static FP_ExceptionCases ex_mul_tab[5][5] = {
  /* N   +0   -0   +In  -In */
  /* N   +0   -0   +In  -In */
  { eNR, eNR, eNR, eSI, eSI }, /* Normal */
  { eNR, eNR, eNR, eSI, eSI }, /* Normal */
  { eNR, ePZ, eNZ, eIn, eIn }, /* +0   */
  { eNR, ePZ, eNZ, eIn, eIn }, /* +0   */
  { eNR, eNZ, ePZ, eIn, eIn }, /* -0   */
  { eNR, eNZ, ePZ, eIn, eIn }, /* -0   */
  { eSI, eIn, eIn, ePI, eNI }, /* +Inf */
  { eSI, eIn, eIn, ePI, eNI }, /* +Inf */
  { eSI, eIn, eIn, eNI, ePI }, /* -Inf */
  { eSI, eIn, eIn, eNI, ePI }, /* -Inf */
};
};
 
 
fp_t
fp_t
rxfp_mul (fp_t fa, fp_t fb)
rxfp_mul (fp_t fa, fp_t fb)
{
{
  FP_Parts a, b, c;
  FP_Parts a, b, c;
  fp_t rv;
  fp_t rv;
  double da, db;
  double da, db;
 
 
  fp_explode (fa, &a);
  fp_explode (fa, &a);
  fp_explode (fb, &b);
  fp_explode (fb, &b);
  CHECK_EXCEPTIONS (a, b, rv, ex_mul_tab);
  CHECK_EXCEPTIONS (a, b, rv, ex_mul_tab);
 
 
  da = fp_to_double (&a);
  da = fp_to_double (&a);
  db = fp_to_double (&b);
  db = fp_to_double (&b);
  tprintf("%g x %g = %g\n", da, db, da*db);
  tprintf("%g x %g = %g\n", da, db, da*db);
 
 
  double_to_fp (da*db, &c);
  double_to_fp (da*db, &c);
  rv = fp_implode (&c);
  rv = fp_implode (&c);
 
 
  return rv;
  return rv;
}
}
 
 
static FP_ExceptionCases ex_div_tab[5][5] = {
static FP_ExceptionCases ex_div_tab[5][5] = {
  /* N   +0   -0   +In  -In */
  /* N   +0   -0   +In  -In */
  { eNR, eDZ, eDZ, eSZ, eSZ }, /* Normal */
  { eNR, eDZ, eDZ, eSZ, eSZ }, /* Normal */
  { eSZ, eIn, eIn, ePZ, eNZ }, /* +0   */
  { eSZ, eIn, eIn, ePZ, eNZ }, /* +0   */
  { eSZ, eIn, eIn, eNZ, ePZ }, /* -0   */
  { eSZ, eIn, eIn, eNZ, ePZ }, /* -0   */
  { eSI, ePI, eNI, eIn, eIn }, /* +Inf */
  { eSI, ePI, eNI, eIn, eIn }, /* +Inf */
  { eSI, eNI, ePI, eIn, eIn }, /* -Inf */
  { eSI, eNI, ePI, eIn, eIn }, /* -Inf */
};
};
 
 
fp_t
fp_t
rxfp_div (fp_t fa, fp_t fb)
rxfp_div (fp_t fa, fp_t fb)
{
{
  FP_Parts a, b, c;
  FP_Parts a, b, c;
  fp_t rv;
  fp_t rv;
  double da, db;
  double da, db;
 
 
  fp_explode (fa, &a);
  fp_explode (fa, &a);
  fp_explode (fb, &b);
  fp_explode (fb, &b);
  CHECK_EXCEPTIONS (a, b, rv, ex_div_tab);
  CHECK_EXCEPTIONS (a, b, rv, ex_div_tab);
 
 
  da = fp_to_double (&a);
  da = fp_to_double (&a);
  db = fp_to_double (&b);
  db = fp_to_double (&b);
  tprintf("%g / %g = %g\n", da, db, da/db);
  tprintf("%g / %g = %g\n", da, db, da/db);
 
 
  double_to_fp (da/db, &c);
  double_to_fp (da/db, &c);
  rv = fp_implode (&c);
  rv = fp_implode (&c);
 
 
  return rv;
  return rv;
}
}
 
 
static FP_ExceptionCases ex_cmp_tab[5][5] = {
static FP_ExceptionCases ex_cmp_tab[5][5] = {
  /* N   +0   -0   +In  -In */
  /* N   +0   -0   +In  -In */
  { eNR, eNR, eNR, eLT, eGT }, /* Normal */
  { eNR, eNR, eNR, eLT, eGT }, /* Normal */
  { eNR, eEQ, eEQ, eLT, eGT }, /* +0   */
  { eNR, eEQ, eEQ, eLT, eGT }, /* +0   */
  { eNR, eEQ, eEQ, eLT, eGT }, /* -0   */
  { eNR, eEQ, eEQ, eLT, eGT }, /* -0   */
  { eGT, eGT, eGT, eEQ, eGT }, /* +Inf */
  { eGT, eGT, eGT, eEQ, eGT }, /* +Inf */
  { eLT, eLT, eLT, eLT, eEQ }, /* -Inf */
  { eLT, eLT, eLT, eLT, eEQ }, /* -Inf */
};
};
 
 
void
void
rxfp_cmp (fp_t fa, fp_t fb)
rxfp_cmp (fp_t fa, fp_t fb)
{
{
  FP_Parts a, b;
  FP_Parts a, b;
  fp_t c;
  fp_t c;
  FP_ExceptionCases reason;
  FP_ExceptionCases reason;
  int flags = 0;
  int flags = 0;
  double da, db;
  double da, db;
 
 
  fp_explode (fa, &a);
  fp_explode (fa, &a);
  fp_explode (fb, &b);
  fp_explode (fb, &b);
 
 
  if (check_exceptions (&a, &b, &c, ex_cmp_tab, &reason))
  if (check_exceptions (&a, &b, &c, ex_cmp_tab, &reason))
    {
    {
      if (reason == eQN)
      if (reason == eQN)
        {
        {
          /* Special case - incomparable.  */
          /* Special case - incomparable.  */
          set_flags (FLAGBIT_Z | FLAGBIT_S | FLAGBIT_O, FLAGBIT_O);
          set_flags (FLAGBIT_Z | FLAGBIT_S | FLAGBIT_O, FLAGBIT_O);
          return;
          return;
        }
        }
      return;
      return;
    }
    }
 
 
  switch (reason)
  switch (reason)
    {
    {
    case eEQ:
    case eEQ:
      flags = FLAGBIT_Z;
      flags = FLAGBIT_Z;
      break;
      break;
    case eLT:
    case eLT:
      flags = FLAGBIT_S;
      flags = FLAGBIT_S;
      break;
      break;
    case eGT:
    case eGT:
      flags = 0;
      flags = 0;
      break;
      break;
    case eNR:
    case eNR:
      da = fp_to_double (&a);
      da = fp_to_double (&a);
      db = fp_to_double (&b);
      db = fp_to_double (&b);
      tprintf("fcmp: %g cmp %g\n", da, db);
      tprintf("fcmp: %g cmp %g\n", da, db);
      if (da < db)
      if (da < db)
        flags = FLAGBIT_S;
        flags = FLAGBIT_S;
      else if (da == db)
      else if (da == db)
        flags = FLAGBIT_Z;
        flags = FLAGBIT_Z;
      else
      else
        flags = 0;
        flags = 0;
      break;
      break;
    default:
    default:
      abort();
      abort();
    }
    }
 
 
  set_flags (FLAGBIT_Z | FLAGBIT_S | FLAGBIT_O, flags);
  set_flags (FLAGBIT_Z | FLAGBIT_S | FLAGBIT_O, flags);
}
}
 
 
long
long
rxfp_ftoi (fp_t fa, int round_mode)
rxfp_ftoi (fp_t fa, int round_mode)
{
{
  FP_Parts a;
  FP_Parts a;
  fp_t rv;
  fp_t rv;
  int sign;
  int sign;
  int whole_bits, frac_bits;
  int whole_bits, frac_bits;
 
 
  fp_explode (fa, &a);
  fp_explode (fa, &a);
  sign = fa & 0x80000000UL;
  sign = fa & 0x80000000UL;
 
 
  switch (a.type)
  switch (a.type)
    {
    {
    case FP_NORMAL:
    case FP_NORMAL:
      break;
      break;
    case FP_PZERO:
    case FP_PZERO:
    case FP_NZERO:
    case FP_NZERO:
      return 0;
      return 0;
    case FP_PINFINITY:
    case FP_PINFINITY:
      FP_RAISE (V);
      FP_RAISE (V);
      return 0x7fffffffL;
      return 0x7fffffffL;
    case FP_NINFINITY:
    case FP_NINFINITY:
      FP_RAISE (V);
      FP_RAISE (V);
      return 0x80000000L;
      return 0x80000000L;
    case FP_DENORMAL:
    case FP_DENORMAL:
      FP_RAISE (E);
      FP_RAISE (E);
      return 0;
      return 0;
    case FP_QNAN:
    case FP_QNAN:
    case FP_SNAN:
    case FP_SNAN:
      FP_RAISE (V);
      FP_RAISE (V);
      return sign ? 0x80000000U : 0x7fffffff;
      return sign ? 0x80000000U : 0x7fffffff;
    }
    }
 
 
  if (a.exp >= 31)
  if (a.exp >= 31)
    {
    {
      FP_RAISE (V);
      FP_RAISE (V);
      return sign ? 0x80000000U : 0x7fffffff;
      return sign ? 0x80000000U : 0x7fffffff;
    }
    }
 
 
  a.exp -= 23;
  a.exp -= 23;
 
 
  if (a.exp <= -25)
  if (a.exp <= -25)
    {
    {
      /* Less than 0.49999 */
      /* Less than 0.49999 */
      frac_bits = a.mant;
      frac_bits = a.mant;
      whole_bits = 0;
      whole_bits = 0;
    }
    }
  else if (a.exp < 0)
  else if (a.exp < 0)
    {
    {
      frac_bits = a.mant << (32 + a.exp);
      frac_bits = a.mant << (32 + a.exp);
      whole_bits = a.mant >> (-a.exp);
      whole_bits = a.mant >> (-a.exp);
    }
    }
  else
  else
    {
    {
      frac_bits = 0;
      frac_bits = 0;
      whole_bits = a.mant << a.exp;
      whole_bits = a.mant << a.exp;
    }
    }
 
 
  if (frac_bits)
  if (frac_bits)
    {
    {
      switch (round_mode & 3)
      switch (round_mode & 3)
        {
        {
        case FPRM_NEAREST:
        case FPRM_NEAREST:
          if (frac_bits & 0x80000000UL)
          if (frac_bits & 0x80000000UL)
            whole_bits ++;
            whole_bits ++;
          break;
          break;
        case FPRM_ZERO:
        case FPRM_ZERO:
          break;
          break;
        case FPRM_PINF:
        case FPRM_PINF:
          if (!sign)
          if (!sign)
            whole_bits ++;
            whole_bits ++;
          break;
          break;
        case FPRM_NINF:
        case FPRM_NINF:
          if (sign)
          if (sign)
            whole_bits ++;
            whole_bits ++;
          break;
          break;
        }
        }
    }
    }
 
 
  rv = sign ? -whole_bits : whole_bits;
  rv = sign ? -whole_bits : whole_bits;
 
 
  return rv;
  return rv;
}
}
 
 
fp_t
fp_t
rxfp_itof (long fa, int round_mode)
rxfp_itof (long fa, int round_mode)
{
{
  fp_t rv;
  fp_t rv;
  int sign = 0;
  int sign = 0;
  unsigned int frac_bits;
  unsigned int frac_bits;
  volatile unsigned int whole_bits;
  volatile unsigned int whole_bits;
  FP_Parts a;
  FP_Parts a;
 
 
  if (fa == 0)
  if (fa == 0)
    return PLUS_ZERO;
    return PLUS_ZERO;
 
 
  if (fa < 0)
  if (fa < 0)
    {
    {
      fa = -fa;
      fa = -fa;
      sign = 1;
      sign = 1;
      a.sign = -1;
      a.sign = -1;
    }
    }
  else
  else
    a.sign = 1;
    a.sign = 1;
 
 
  whole_bits = fa;
  whole_bits = fa;
  a.exp = 31;
  a.exp = 31;
 
 
  while (! (whole_bits & 0x80000000UL))
  while (! (whole_bits & 0x80000000UL))
    {
    {
      a.exp --;
      a.exp --;
      whole_bits <<= 1;
      whole_bits <<= 1;
    }
    }
  frac_bits = whole_bits & 0xff;
  frac_bits = whole_bits & 0xff;
  whole_bits = whole_bits >> 8;
  whole_bits = whole_bits >> 8;
 
 
  if (frac_bits)
  if (frac_bits)
    {
    {
      /* We must round */
      /* We must round */
      switch (round_mode & 3)
      switch (round_mode & 3)
        {
        {
        case FPRM_NEAREST:
        case FPRM_NEAREST:
          if (frac_bits & 0x80)
          if (frac_bits & 0x80)
            whole_bits ++;
            whole_bits ++;
          break;
          break;
        case FPRM_ZERO:
        case FPRM_ZERO:
          break;
          break;
        case FPRM_PINF:
        case FPRM_PINF:
          if (!sign)
          if (!sign)
            whole_bits ++;
            whole_bits ++;
          break;
          break;
        case FPRM_NINF:
        case FPRM_NINF:
          if (sign)
          if (sign)
            whole_bits ++;
            whole_bits ++;
          break;
          break;
        }
        }
    }
    }
 
 
  a.mant = whole_bits;
  a.mant = whole_bits;
  if (whole_bits & 0xff000000UL)
  if (whole_bits & 0xff000000UL)
    {
    {
      a.mant >>= 1;
      a.mant >>= 1;
      a.exp ++;
      a.exp ++;
    }
    }
 
 
  rv = fp_implode (&a);
  rv = fp_implode (&a);
  return rv;
  return rv;
}
}
 
 
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.