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

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [i386/] [math-emu/] [fpu_debug.c] - Diff between revs 1765 and 1782

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

Rev 1765 Rev 1782
/* Interface with ptrace and core-dumping routines */
/* Interface with ptrace and core-dumping routines */
 
 
 
 
#include "fpu_system.h"
#include "fpu_system.h"
#include "exception.h"
#include "exception.h"
#include "reg_constant.h"
#include "reg_constant.h"
#include "fpu_emu.h"
#include "fpu_emu.h"
#include "control_w.h"
#include "control_w.h"
#include "status_w.h"
#include "status_w.h"
 
 
 
 
#define EXTENDED_Ebias 0x3fff
#define EXTENDED_Ebias 0x3fff
#define EXTENDED_Emin (-0x3ffe)  /* smallest valid exponent */
#define EXTENDED_Emin (-0x3ffe)  /* smallest valid exponent */
 
 
#define DOUBLE_Emax 1023         /* largest valid exponent */
#define DOUBLE_Emax 1023         /* largest valid exponent */
#define DOUBLE_Ebias 1023
#define DOUBLE_Ebias 1023
#define DOUBLE_Emin (-1022)      /* smallest valid exponent */
#define DOUBLE_Emin (-1022)      /* smallest valid exponent */
 
 
#define SINGLE_Emax 127          /* largest valid exponent */
#define SINGLE_Emax 127          /* largest valid exponent */
#define SINGLE_Ebias 127
#define SINGLE_Ebias 127
#define SINGLE_Emin (-126)       /* smallest valid exponent */
#define SINGLE_Emin (-126)       /* smallest valid exponent */
 
 
 
 
/* Copy and paste from round_to_int. Original comments maintained */
/* Copy and paste from round_to_int. Original comments maintained */
/*===========================================================================*/
/*===========================================================================*/
 
 
/* r gets mangled such that sig is int, sign:
/* r gets mangled such that sig is int, sign:
   it is NOT normalized */
   it is NOT normalized */
/* The return value (in eax) is zero if the result is exact,
/* The return value (in eax) is zero if the result is exact,
   if bits are changed due to rounding, truncation, etc, then
   if bits are changed due to rounding, truncation, etc, then
   a non-zero value is returned */
   a non-zero value is returned */
/* Overflow is signalled by a non-zero return value (in eax).
/* Overflow is signalled by a non-zero return value (in eax).
   In the case of overflow, the returned significand always has the
   In the case of overflow, the returned significand always has the
   largest possible value */
   largest possible value */
 
 
static int round_to_int_cwd(FPU_REG *r, long int user_control_word)
static int round_to_int_cwd(FPU_REG *r, long int user_control_word)
{
{
  char     very_big;
  char     very_big;
  unsigned eax;
  unsigned eax;
 
 
  if (r->tag == TW_Zero)
  if (r->tag == TW_Zero)
    {
    {
      /* Make sure that zero is returned */
      /* Make sure that zero is returned */
      significand(r) = 0;
      significand(r) = 0;
      return 0;        /* o.k. */
      return 0;        /* o.k. */
    }
    }
 
 
  if (r->exp > EXP_BIAS + 63)
  if (r->exp > EXP_BIAS + 63)
    {
    {
      r->sigl = r->sigh = ~0;      /* The largest representable number */
      r->sigl = r->sigh = ~0;      /* The largest representable number */
      return 1;        /* overflow */
      return 1;        /* overflow */
    }
    }
 
 
  eax = shrxs(&r->sigl, EXP_BIAS + 63 - r->exp);
  eax = shrxs(&r->sigl, EXP_BIAS + 63 - r->exp);
  very_big = !(~(r->sigh) | ~(r->sigl));  /* test for 0xfff...fff */
  very_big = !(~(r->sigh) | ~(r->sigl));  /* test for 0xfff...fff */
#define half_or_more    (eax & 0x80000000)
#define half_or_more    (eax & 0x80000000)
#define frac_part       (eax)
#define frac_part       (eax)
#define more_than_half  ((eax & 0x80000001) == 0x80000001)
#define more_than_half  ((eax & 0x80000001) == 0x80000001)
  switch (user_control_word & CW_RC)
  switch (user_control_word & CW_RC)
    {
    {
    case RC_RND:
    case RC_RND:
      if ( more_than_half                       /* nearest */
      if ( more_than_half                       /* nearest */
          || (half_or_more && (r->sigl & 1)) )  /* odd -> even */
          || (half_or_more && (r->sigl & 1)) )  /* odd -> even */
        {
        {
          if ( very_big ) return 1;        /* overflow */
          if ( very_big ) return 1;        /* overflow */
          significand(r) ++;
          significand(r) ++;
          return PRECISION_LOST_UP;
          return PRECISION_LOST_UP;
        }
        }
      break;
      break;
    case RC_DOWN:
    case RC_DOWN:
      if (frac_part && r->sign)
      if (frac_part && r->sign)
        {
        {
          if ( very_big ) return 1;        /* overflow */
          if ( very_big ) return 1;        /* overflow */
          significand(r) ++;
          significand(r) ++;
          return PRECISION_LOST_UP;
          return PRECISION_LOST_UP;
        }
        }
      break;
      break;
    case RC_UP:
    case RC_UP:
      if (frac_part && !r->sign)
      if (frac_part && !r->sign)
        {
        {
          if ( very_big ) return 1;        /* overflow */
          if ( very_big ) return 1;        /* overflow */
          significand(r) ++;
          significand(r) ++;
          return PRECISION_LOST_UP;
          return PRECISION_LOST_UP;
        }
        }
      break;
      break;
    case RC_CHOP:
    case RC_CHOP:
      break;
      break;
    }
    }
 
 
  return eax ? PRECISION_LOST_DOWN : 0;
  return eax ? PRECISION_LOST_DOWN : 0;
 
 
}
}
 
 
 
 
 
 
/* Conver a number in the emulator format to the
/* Conver a number in the emulator format to the
 * hardware format.
 * hardware format.
 * Taken from the emulator sources, function reg_load_extended
 * Taken from the emulator sources, function reg_load_extended
 */
 */
 
 
/* Get a long double from the debugger */
/* Get a long double from the debugger */
void hardreg_to_softreg(const char hardreg[10],
void hardreg_to_softreg(const char hardreg[10],
                              FPU_REG *soft_reg)
                              FPU_REG *soft_reg)
 
 
{
{
        unsigned long sigl, sigh, exp;
        unsigned long sigl, sigh, exp;
 
 
        sigl = *((unsigned long *) hardreg);
        sigl = *((unsigned long *) hardreg);
        sigh = *(1 + (unsigned long *) hardreg);
        sigh = *(1 + (unsigned long *) hardreg);
        exp = *(4 + (unsigned short *) hardreg);
        exp = *(4 + (unsigned short *) hardreg);
 
 
        soft_reg->tag = TW_Valid;   /* Default */
        soft_reg->tag = TW_Valid;   /* Default */
        soft_reg->sigl = sigl;
        soft_reg->sigl = sigl;
        soft_reg->sigh = sigh;
        soft_reg->sigh = sigh;
        if (exp & 0x8000)
        if (exp & 0x8000)
                soft_reg->sign = SIGN_NEG;
                soft_reg->sign = SIGN_NEG;
        else
        else
                soft_reg->sign = SIGN_POS;
                soft_reg->sign = SIGN_POS;
        exp &= 0x7fff;
        exp &= 0x7fff;
        soft_reg->exp = exp - EXTENDED_Ebias + EXP_BIAS;
        soft_reg->exp = exp - EXTENDED_Ebias + EXP_BIAS;
 
 
        if ( exp == 0 )
        if ( exp == 0 )
        {
        {
                if ( !(sigh | sigl) )
                if ( !(sigh | sigl) )
                {
                {
                        soft_reg->tag = TW_Zero;
                        soft_reg->tag = TW_Zero;
                        return;
                        return;
                }
                }
                /* The number is a de-normal or pseudodenormal. */
                /* The number is a de-normal or pseudodenormal. */
                if (sigh & 0x80000000)
                if (sigh & 0x80000000)
                {
                {
                        /* Is a pseudodenormal. */
                        /* Is a pseudodenormal. */
                        /* Convert it for internal use. */
                        /* Convert it for internal use. */
                        /* This is non-80486 behaviour because the number
                        /* This is non-80486 behaviour because the number
                           loses its 'denormal' identity. */
                           loses its 'denormal' identity. */
                        soft_reg->exp++;
                        soft_reg->exp++;
                        return;
                        return;
                }
                }
                else
                else
                {
                {
                        /* Is a denormal. */
                        /* Is a denormal. */
                        /* Convert it for internal use. */
                        /* Convert it for internal use. */
                        soft_reg->exp++;
                        soft_reg->exp++;
                        normalize_nuo(soft_reg);
                        normalize_nuo(soft_reg);
                        return;
                        return;
                }
                }
        }
        }
        else if ( exp == 0x7fff )
        else if ( exp == 0x7fff )
        {
        {
                if ( !((sigh ^ 0x80000000) | sigl) )
                if ( !((sigh ^ 0x80000000) | sigl) )
                {
                {
                        /* Matches the bit pattern for Infinity. */
                        /* Matches the bit pattern for Infinity. */
                        soft_reg->exp = EXP_Infinity;
                        soft_reg->exp = EXP_Infinity;
                        soft_reg->tag = TW_Infinity;
                        soft_reg->tag = TW_Infinity;
                        return;
                        return;
                }
                }
 
 
                soft_reg->exp = EXP_NaN;
                soft_reg->exp = EXP_NaN;
                soft_reg->tag = TW_NaN;
                soft_reg->tag = TW_NaN;
                if ( !(sigh & 0x80000000) )
                if ( !(sigh & 0x80000000) )
                {
                {
                        /* NaNs have the ms bit set to 1. */
                        /* NaNs have the ms bit set to 1. */
                        /* This is therefore an Unsupported NaN data type. */
                        /* This is therefore an Unsupported NaN data type. */
                        /* This is non 80486 behaviour */
                        /* This is non 80486 behaviour */
                        /* This should generate an Invalid Operand exception
                        /* This should generate an Invalid Operand exception
                           later, so we convert it to a SNaN */
                           later, so we convert it to a SNaN */
                        soft_reg->sigh = 0x80000000;
                        soft_reg->sigh = 0x80000000;
                        soft_reg->sigl = 0x00000001;
                        soft_reg->sigl = 0x00000001;
                        soft_reg->sign = SIGN_NEG;
                        soft_reg->sign = SIGN_NEG;
                        return;
                        return;
                }
                }
                return;
                return;
        }
        }
 
 
        if ( !(sigh & 0x80000000) )
        if ( !(sigh & 0x80000000) )
        {
        {
                /* Unsupported data type. */
                /* Unsupported data type. */
                /* Valid numbers have the ms bit set to 1. */
                /* Valid numbers have the ms bit set to 1. */
                /* Unnormal. */
                /* Unnormal. */
                /* Convert it for internal use. */
                /* Convert it for internal use. */
                /* This is non-80486 behaviour */
                /* This is non-80486 behaviour */
                /* This should generate an Invalid Operand exception
                /* This should generate an Invalid Operand exception
                   later, so we convert it to a SNaN */
                   later, so we convert it to a SNaN */
                soft_reg->sigh = 0x80000000;
                soft_reg->sigh = 0x80000000;
                soft_reg->sigl = 0x00000001;
                soft_reg->sigl = 0x00000001;
                soft_reg->sign = SIGN_NEG;
                soft_reg->sign = SIGN_NEG;
                soft_reg->exp = EXP_NaN;
                soft_reg->exp = EXP_NaN;
                soft_reg->tag = TW_NaN;
                soft_reg->tag = TW_NaN;
                return;
                return;
        }
        }
        return;
        return;
}
}
 
 
/* Conver a number in the emulator format to the
/* Conver a number in the emulator format to the
 * hardware format.
 * hardware format.
 * Adapted from function write_to_extended
 * Adapted from function write_to_extended
 */
 */
 
 
 
 
void softreg_to_hardreg(const FPU_REG *rp, char d[10], long int user_control_word)
void softreg_to_hardreg(const FPU_REG *rp, char d[10], long int user_control_word)
{
{
        long e;
        long e;
        FPU_REG tmp;
        FPU_REG tmp;
        e = rp->exp - EXP_BIAS + EXTENDED_Ebias;
        e = rp->exp - EXP_BIAS + EXTENDED_Ebias;
 
 
        /*
        /*
          All numbers except denormals are stored internally in a
          All numbers except denormals are stored internally in a
          format which is compatible with the extended real number
          format which is compatible with the extended real number
          format.
          format.
          */
          */
        if (e > 0) {
        if (e > 0) {
                *(unsigned long *) d = rp->sigl;
                *(unsigned long *) d = rp->sigl;
                *(unsigned long *) (d + 4) = rp->sigh;
                *(unsigned long *) (d + 4) = rp->sigh;
        } else {
        } else {
                /*
                /*
                  The number is a de-normal stored as a normal using our
                  The number is a de-normal stored as a normal using our
                  extra exponent range, or is Zero.
                  extra exponent range, or is Zero.
                  Convert it back to a de-normal, or leave it as Zero.
                  Convert it back to a de-normal, or leave it as Zero.
                  */
                  */
                reg_move(rp, &tmp);
                reg_move(rp, &tmp);
                tmp.exp += -EXTENDED_Emin + 63;  /* largest exp to be 63 */
                tmp.exp += -EXTENDED_Emin + 63;  /* largest exp to be 63 */
                round_to_int_cwd(&tmp, user_control_word);
                round_to_int_cwd(&tmp, user_control_word);
                e = 0;
                e = 0;
                *(unsigned long *) d= tmp.sigl;
                *(unsigned long *) d= tmp.sigl;
                *(unsigned long *) (d + 4) = tmp.sigh;
                *(unsigned long *) (d + 4) = tmp.sigh;
        }
        }
        e |= rp->sign == SIGN_POS ? 0 : 0x8000;
        e |= rp->sign == SIGN_POS ? 0 : 0x8000;
        *(unsigned short *) (d + 8) = e;
        *(unsigned short *) (d + 8) = e;
}
}
 
 
 
 

powered by: WebSVN 2.1.0

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