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

Subversion Repositories openrisc

[/] [openrisc/] [tags/] [gdb/] [gdb-6.8/] [gdb-6.8.openrisc-2.1/] [gdb/] [dfp.c] - Diff between revs 24 and 33

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 24 Rev 33
/* Decimal floating point support for GDB.
/* Decimal floating point support for GDB.
 
 
   Copyright 2007, 2008 Free Software Foundation, Inc.
   Copyright 2007, 2008 Free Software Foundation, Inc.
 
 
   This file is part of GDB.
   This file is part of GDB.
 
 
   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 "defs.h"
#include "defs.h"
#include "expression.h"
#include "expression.h"
#include "gdbtypes.h"
#include "gdbtypes.h"
#include "value.h"
#include "value.h"
#include "dfp.h"
#include "dfp.h"
 
 
/* The order of the following headers is important for making sure
/* The order of the following headers is important for making sure
   decNumber structure is large enough to hold decimal128 digits.  */
   decNumber structure is large enough to hold decimal128 digits.  */
 
 
#include "dpd/decimal128.h"
#include "dpd/decimal128.h"
#include "dpd/decimal64.h"
#include "dpd/decimal64.h"
#include "dpd/decimal32.h"
#include "dpd/decimal32.h"
 
 
/* In GDB, we are using an array of gdb_byte to represent decimal values.
/* In GDB, we are using an array of gdb_byte to represent decimal values.
   They are stored in host byte order.  This routine does the conversion if
   They are stored in host byte order.  This routine does the conversion if
   the target byte order is different.  */
   the target byte order is different.  */
static void
static void
match_endianness (const gdb_byte *from, int len, gdb_byte *to)
match_endianness (const gdb_byte *from, int len, gdb_byte *to)
{
{
  int i;
  int i;
 
 
#if WORDS_BIGENDIAN
#if WORDS_BIGENDIAN
#define OPPOSITE_BYTE_ORDER BFD_ENDIAN_LITTLE
#define OPPOSITE_BYTE_ORDER BFD_ENDIAN_LITTLE
#else
#else
#define OPPOSITE_BYTE_ORDER BFD_ENDIAN_BIG
#define OPPOSITE_BYTE_ORDER BFD_ENDIAN_BIG
#endif
#endif
 
 
  if (gdbarch_byte_order (current_gdbarch) == OPPOSITE_BYTE_ORDER)
  if (gdbarch_byte_order (current_gdbarch) == OPPOSITE_BYTE_ORDER)
    for (i = 0; i < len; i++)
    for (i = 0; i < len; i++)
      to[i] = from[len - i - 1];
      to[i] = from[len - i - 1];
  else
  else
    for (i = 0; i < len; i++)
    for (i = 0; i < len; i++)
      to[i] = from[i];
      to[i] = from[i];
 
 
  return;
  return;
}
}
 
 
/* Helper function to get the appropriate libdecnumber context for each size
/* Helper function to get the appropriate libdecnumber context for each size
   of decimal float.  */
   of decimal float.  */
static void
static void
set_decnumber_context (decContext *ctx, int len)
set_decnumber_context (decContext *ctx, int len)
{
{
  switch (len)
  switch (len)
    {
    {
      case 4:
      case 4:
        decContextDefault (ctx, DEC_INIT_DECIMAL32);
        decContextDefault (ctx, DEC_INIT_DECIMAL32);
        break;
        break;
      case 8:
      case 8:
        decContextDefault (ctx, DEC_INIT_DECIMAL64);
        decContextDefault (ctx, DEC_INIT_DECIMAL64);
        break;
        break;
      case 16:
      case 16:
        decContextDefault (ctx, DEC_INIT_DECIMAL128);
        decContextDefault (ctx, DEC_INIT_DECIMAL128);
        break;
        break;
    }
    }
 
 
  ctx->traps = 0;
  ctx->traps = 0;
}
}
 
 
/* Check for errors signaled in the decimal context structure.  */
/* Check for errors signaled in the decimal context structure.  */
static void
static void
decimal_check_errors (decContext *ctx)
decimal_check_errors (decContext *ctx)
{
{
  /* An error here could be a division by zero, an overflow, an underflow or
  /* An error here could be a division by zero, an overflow, an underflow or
     an invalid operation (from the DEC_Errors constant in decContext.h).
     an invalid operation (from the DEC_Errors constant in decContext.h).
     Since GDB doesn't complain about division by zero, overflow or underflow
     Since GDB doesn't complain about division by zero, overflow or underflow
     errors for binary floating, we won't complain about them for decimal
     errors for binary floating, we won't complain about them for decimal
     floating either.  */
     floating either.  */
  if (ctx->status & DEC_IEEE_854_Invalid_operation)
  if (ctx->status & DEC_IEEE_854_Invalid_operation)
    {
    {
      /* Leave only the error bits in the status flags.  */
      /* Leave only the error bits in the status flags.  */
      ctx->status &= DEC_IEEE_854_Invalid_operation;
      ctx->status &= DEC_IEEE_854_Invalid_operation;
      error (_("Cannot perform operation: %s"), decContextStatusToString (ctx));
      error (_("Cannot perform operation: %s"), decContextStatusToString (ctx));
    }
    }
}
}
 
 
/* Helper function to convert from libdecnumber's appropriate representation
/* Helper function to convert from libdecnumber's appropriate representation
   for computation to each size of decimal float.  */
   for computation to each size of decimal float.  */
static void
static void
decimal_from_number (const decNumber *from, gdb_byte *to, int len)
decimal_from_number (const decNumber *from, gdb_byte *to, int len)
{
{
  decContext set;
  decContext set;
 
 
  set_decnumber_context (&set, len);
  set_decnumber_context (&set, len);
 
 
  switch (len)
  switch (len)
    {
    {
      case 4:
      case 4:
        decimal32FromNumber ((decimal32 *) to, from, &set);
        decimal32FromNumber ((decimal32 *) to, from, &set);
        break;
        break;
      case 8:
      case 8:
        decimal64FromNumber ((decimal64 *) to, from, &set);
        decimal64FromNumber ((decimal64 *) to, from, &set);
        break;
        break;
      case 16:
      case 16:
        decimal128FromNumber ((decimal128 *) to, from, &set);
        decimal128FromNumber ((decimal128 *) to, from, &set);
        break;
        break;
    }
    }
}
}
 
 
/* Helper function to convert each size of decimal float to libdecnumber's
/* Helper function to convert each size of decimal float to libdecnumber's
   appropriate representation for computation.  */
   appropriate representation for computation.  */
static void
static void
decimal_to_number (const gdb_byte *from, int len, decNumber *to)
decimal_to_number (const gdb_byte *from, int len, decNumber *to)
{
{
  switch (len)
  switch (len)
    {
    {
      case 4:
      case 4:
        decimal32ToNumber ((decimal32 *) from, to);
        decimal32ToNumber ((decimal32 *) from, to);
        break;
        break;
      case 8:
      case 8:
        decimal64ToNumber ((decimal64 *) from, to);
        decimal64ToNumber ((decimal64 *) from, to);
        break;
        break;
      case 16:
      case 16:
        decimal128ToNumber ((decimal128 *) from, to);
        decimal128ToNumber ((decimal128 *) from, to);
        break;
        break;
      default:
      default:
        error (_("Unknown decimal floating point type.\n"));
        error (_("Unknown decimal floating point type.\n"));
        break;
        break;
    }
    }
}
}
 
 
/* Convert decimal type to its string representation.  LEN is the length
/* Convert decimal type to its string representation.  LEN is the length
   of the decimal type, 4 bytes for decimal32, 8 bytes for decimal64 and
   of the decimal type, 4 bytes for decimal32, 8 bytes for decimal64 and
   16 bytes for decimal128.  */
   16 bytes for decimal128.  */
void
void
decimal_to_string (const gdb_byte *decbytes, int len, char *s)
decimal_to_string (const gdb_byte *decbytes, int len, char *s)
{
{
  gdb_byte dec[16];
  gdb_byte dec[16];
 
 
  match_endianness (decbytes, len, dec);
  match_endianness (decbytes, len, dec);
 
 
  switch (len)
  switch (len)
    {
    {
      case 4:
      case 4:
        decimal32ToString ((decimal32 *) dec, s);
        decimal32ToString ((decimal32 *) dec, s);
        break;
        break;
      case 8:
      case 8:
        decimal64ToString ((decimal64 *) dec, s);
        decimal64ToString ((decimal64 *) dec, s);
        break;
        break;
      case 16:
      case 16:
        decimal128ToString ((decimal128 *) dec, s);
        decimal128ToString ((decimal128 *) dec, s);
        break;
        break;
      default:
      default:
        error (_("Unknown decimal floating point type."));
        error (_("Unknown decimal floating point type."));
        break;
        break;
    }
    }
}
}
 
 
/* Convert the string form of a decimal value to its decimal representation.
/* Convert the string form of a decimal value to its decimal representation.
   LEN is the length of the decimal type, 4 bytes for decimal32, 8 bytes for
   LEN is the length of the decimal type, 4 bytes for decimal32, 8 bytes for
   decimal64 and 16 bytes for decimal128.  */
   decimal64 and 16 bytes for decimal128.  */
int
int
decimal_from_string (gdb_byte *decbytes, int len, const char *string)
decimal_from_string (gdb_byte *decbytes, int len, const char *string)
{
{
  decContext set;
  decContext set;
  gdb_byte dec[16];
  gdb_byte dec[16];
 
 
  set_decnumber_context (&set, len);
  set_decnumber_context (&set, len);
 
 
  switch (len)
  switch (len)
    {
    {
      case 4:
      case 4:
        decimal32FromString ((decimal32 *) dec, string, &set);
        decimal32FromString ((decimal32 *) dec, string, &set);
        break;
        break;
      case 8:
      case 8:
        decimal64FromString ((decimal64 *) dec, string, &set);
        decimal64FromString ((decimal64 *) dec, string, &set);
        break;
        break;
      case 16:
      case 16:
        decimal128FromString ((decimal128 *) dec, string, &set);
        decimal128FromString ((decimal128 *) dec, string, &set);
        break;
        break;
      default:
      default:
        error (_("Unknown decimal floating point type."));
        error (_("Unknown decimal floating point type."));
        break;
        break;
    }
    }
 
 
  match_endianness (dec, len, decbytes);
  match_endianness (dec, len, decbytes);
 
 
  /* Check for errors in the DFP operation.  */
  /* Check for errors in the DFP operation.  */
  decimal_check_errors (&set);
  decimal_check_errors (&set);
 
 
  return 1;
  return 1;
}
}
 
 
/* Converts a value of an integral type to a decimal float of
/* Converts a value of an integral type to a decimal float of
   specified LEN bytes.  */
   specified LEN bytes.  */
void
void
decimal_from_integral (struct value *from, gdb_byte *to, int len)
decimal_from_integral (struct value *from, gdb_byte *to, int len)
{
{
  LONGEST l;
  LONGEST l;
  gdb_byte dec[16];
  gdb_byte dec[16];
  decNumber number;
  decNumber number;
  struct type *type;
  struct type *type;
 
 
  type = check_typedef (value_type (from));
  type = check_typedef (value_type (from));
 
 
  if (TYPE_LENGTH (type) > 4)
  if (TYPE_LENGTH (type) > 4)
    /* libdecnumber can convert only 32-bit integers.  */
    /* libdecnumber can convert only 32-bit integers.  */
    error (_("Conversion of large integer to a decimal floating type is not supported."));
    error (_("Conversion of large integer to a decimal floating type is not supported."));
 
 
  l = value_as_long (from);
  l = value_as_long (from);
 
 
  if (TYPE_UNSIGNED (type))
  if (TYPE_UNSIGNED (type))
    decNumberFromUInt32 (&number, (unsigned int) l);
    decNumberFromUInt32 (&number, (unsigned int) l);
  else
  else
    decNumberFromInt32 (&number, (int) l);
    decNumberFromInt32 (&number, (int) l);
 
 
  decimal_from_number (&number, dec, len);
  decimal_from_number (&number, dec, len);
  match_endianness (dec, len, to);
  match_endianness (dec, len, to);
}
}
 
 
/* Converts a value of a float type to a decimal float of
/* Converts a value of a float type to a decimal float of
   specified LEN bytes.
   specified LEN bytes.
 
 
   This is an ugly way to do the conversion, but libdecnumber does
   This is an ugly way to do the conversion, but libdecnumber does
   not offer a direct way to do it.  */
   not offer a direct way to do it.  */
void
void
decimal_from_floating (struct value *from, gdb_byte *to, int len)
decimal_from_floating (struct value *from, gdb_byte *to, int len)
{
{
  char *buffer;
  char *buffer;
  int ret;
  int ret;
 
 
  ret = asprintf (&buffer, "%.30" DOUBLEST_PRINT_FORMAT,
  ret = asprintf (&buffer, "%.30" DOUBLEST_PRINT_FORMAT,
                  value_as_double (from));
                  value_as_double (from));
  if (ret < 0)
  if (ret < 0)
    error (_("Error in memory allocation for conversion to decimal float."));
    error (_("Error in memory allocation for conversion to decimal float."));
 
 
  decimal_from_string (to, len, buffer);
  decimal_from_string (to, len, buffer);
 
 
  free (buffer);
  free (buffer);
}
}
 
 
/* Converts a decimal float of LEN bytes to a double value.  */
/* Converts a decimal float of LEN bytes to a double value.  */
DOUBLEST
DOUBLEST
decimal_to_doublest (const gdb_byte *from, int len)
decimal_to_doublest (const gdb_byte *from, int len)
{
{
  char buffer[MAX_DECIMAL_STRING];
  char buffer[MAX_DECIMAL_STRING];
 
 
  /* This is an ugly way to do the conversion, but libdecnumber does
  /* This is an ugly way to do the conversion, but libdecnumber does
     not offer a direct way to do it.  */
     not offer a direct way to do it.  */
  decimal_to_string (from, len, buffer);
  decimal_to_string (from, len, buffer);
  return strtod (buffer, NULL);
  return strtod (buffer, NULL);
}
}
 
 
/* Check if operands have the same size and convert them to the
/* Check if operands have the same size and convert them to the
   biggest of the two if necessary.  */
   biggest of the two if necessary.  */
static int
static int
promote_decimal (gdb_byte *x, int len_x, gdb_byte *y, int len_y)
promote_decimal (gdb_byte *x, int len_x, gdb_byte *y, int len_y)
{
{
  int len_result;
  int len_result;
  decNumber number;
  decNumber number;
 
 
  if (len_x < len_y)
  if (len_x < len_y)
    {
    {
      decimal_to_number (x, len_x, &number);
      decimal_to_number (x, len_x, &number);
      decimal_from_number (&number, x, len_y);
      decimal_from_number (&number, x, len_y);
      len_result = len_y;
      len_result = len_y;
    }
    }
  else if (len_x > len_y)
  else if (len_x > len_y)
    {
    {
      decimal_to_number (y, len_y, &number);
      decimal_to_number (y, len_y, &number);
      decimal_from_number (&number, y, len_x);
      decimal_from_number (&number, y, len_x);
      len_result = len_x;
      len_result = len_x;
    }
    }
  else
  else
    len_result = len_x;
    len_result = len_x;
 
 
  return len_result;
  return len_result;
}
}
 
 
/* Perform operation OP with operands X and Y and store value in RESULT.
/* Perform operation OP with operands X and Y and store value in RESULT.
   If LEN_X and LEN_Y are not equal, RESULT will have the size of the biggest
   If LEN_X and LEN_Y are not equal, RESULT will have the size of the biggest
   of the two, and LEN_RESULT will be set accordingly.  */
   of the two, and LEN_RESULT will be set accordingly.  */
void
void
decimal_binop (enum exp_opcode op, const gdb_byte *x, int len_x,
decimal_binop (enum exp_opcode op, const gdb_byte *x, int len_x,
               const gdb_byte *y, int len_y, gdb_byte *result, int *len_result)
               const gdb_byte *y, int len_y, gdb_byte *result, int *len_result)
{
{
  decContext set;
  decContext set;
  decNumber number1, number2, number3;
  decNumber number1, number2, number3;
  gdb_byte dec1[16], dec2[16], dec3[16];
  gdb_byte dec1[16], dec2[16], dec3[16];
 
 
  match_endianness (x, len_x, dec1);
  match_endianness (x, len_x, dec1);
  match_endianness (y, len_y, dec2);
  match_endianness (y, len_y, dec2);
 
 
  *len_result = promote_decimal (dec1, len_x, dec2, len_y);
  *len_result = promote_decimal (dec1, len_x, dec2, len_y);
 
 
  /* Both operands are of size *len_result from now on.  */
  /* Both operands are of size *len_result from now on.  */
 
 
  decimal_to_number (dec1, *len_result, &number1);
  decimal_to_number (dec1, *len_result, &number1);
  decimal_to_number (dec2, *len_result, &number2);
  decimal_to_number (dec2, *len_result, &number2);
 
 
  set_decnumber_context (&set, *len_result);
  set_decnumber_context (&set, *len_result);
 
 
  switch (op)
  switch (op)
    {
    {
      case BINOP_ADD:
      case BINOP_ADD:
        decNumberAdd (&number3, &number1, &number2, &set);
        decNumberAdd (&number3, &number1, &number2, &set);
        break;
        break;
      case BINOP_SUB:
      case BINOP_SUB:
        decNumberSubtract (&number3, &number1, &number2, &set);
        decNumberSubtract (&number3, &number1, &number2, &set);
        break;
        break;
      case BINOP_MUL:
      case BINOP_MUL:
        decNumberMultiply (&number3, &number1, &number2, &set);
        decNumberMultiply (&number3, &number1, &number2, &set);
        break;
        break;
      case BINOP_DIV:
      case BINOP_DIV:
        decNumberDivide (&number3, &number1, &number2, &set);
        decNumberDivide (&number3, &number1, &number2, &set);
        break;
        break;
      case BINOP_EXP:
      case BINOP_EXP:
        decNumberPower (&number3, &number1, &number2, &set);
        decNumberPower (&number3, &number1, &number2, &set);
        break;
        break;
      default:
      default:
        internal_error (__FILE__, __LINE__,
        internal_error (__FILE__, __LINE__,
                        _("Unknown decimal floating point operation."));
                        _("Unknown decimal floating point operation."));
        break;
        break;
    }
    }
 
 
  /* Check for errors in the DFP operation.  */
  /* Check for errors in the DFP operation.  */
  decimal_check_errors (&set);
  decimal_check_errors (&set);
 
 
  decimal_from_number (&number3, dec3, *len_result);
  decimal_from_number (&number3, dec3, *len_result);
 
 
  match_endianness (dec3, *len_result, result);
  match_endianness (dec3, *len_result, result);
}
}
 
 
/* Returns true if X (which is LEN bytes wide) is the number zero.  */
/* Returns true if X (which is LEN bytes wide) is the number zero.  */
int
int
decimal_is_zero (const gdb_byte *x, int len)
decimal_is_zero (const gdb_byte *x, int len)
{
{
  decNumber number;
  decNumber number;
  gdb_byte dec[16];
  gdb_byte dec[16];
 
 
  match_endianness (x, len, dec);
  match_endianness (x, len, dec);
  decimal_to_number (dec, len, &number);
  decimal_to_number (dec, len, &number);
 
 
  return decNumberIsZero (&number);
  return decNumberIsZero (&number);
}
}
 
 
/* Compares two numbers numerically.  If X is less than Y then the return value
/* Compares two numbers numerically.  If X is less than Y then the return value
   will be -1.  If they are equal, then the return value will be 0.  If X is
   will be -1.  If they are equal, then the return value will be 0.  If X is
   greater than the Y then the return value will be 1.  */
   greater than the Y then the return value will be 1.  */
int
int
decimal_compare (const gdb_byte *x, int len_x, const gdb_byte *y, int len_y)
decimal_compare (const gdb_byte *x, int len_x, const gdb_byte *y, int len_y)
{
{
  decNumber number1, number2, result;
  decNumber number1, number2, result;
  decContext set;
  decContext set;
  gdb_byte dec1[16], dec2[16];
  gdb_byte dec1[16], dec2[16];
  int len_result;
  int len_result;
 
 
  match_endianness (x, len_x, dec1);
  match_endianness (x, len_x, dec1);
  match_endianness (y, len_y, dec2);
  match_endianness (y, len_y, dec2);
 
 
  len_result = promote_decimal (dec1, len_x, dec2, len_y);
  len_result = promote_decimal (dec1, len_x, dec2, len_y);
 
 
  decimal_to_number (dec1, len_result, &number1);
  decimal_to_number (dec1, len_result, &number1);
  decimal_to_number (dec2, len_result, &number2);
  decimal_to_number (dec2, len_result, &number2);
 
 
  set_decnumber_context (&set, len_result);
  set_decnumber_context (&set, len_result);
 
 
  decNumberCompare (&result, &number1, &number2, &set);
  decNumberCompare (&result, &number1, &number2, &set);
 
 
  /* Check for errors in the DFP operation.  */
  /* Check for errors in the DFP operation.  */
  decimal_check_errors (&set);
  decimal_check_errors (&set);
 
 
  if (decNumberIsNaN (&result))
  if (decNumberIsNaN (&result))
    error (_("Comparison with an invalid number (NaN)."));
    error (_("Comparison with an invalid number (NaN)."));
  else if (decNumberIsZero (&result))
  else if (decNumberIsZero (&result))
    return 0;
    return 0;
  else if (decNumberIsNegative (&result))
  else if (decNumberIsNegative (&result))
    return -1;
    return -1;
  else
  else
    return 1;
    return 1;
}
}
 
 
/* Convert a decimal value from a decimal type with LEN_FROM bytes to a
/* Convert a decimal value from a decimal type with LEN_FROM bytes to a
   decimal type with LEN_TO bytes.  */
   decimal type with LEN_TO bytes.  */
void
void
decimal_convert (const gdb_byte *from, int len_from, gdb_byte *to,
decimal_convert (const gdb_byte *from, int len_from, gdb_byte *to,
                 int len_to)
                 int len_to)
{
{
  decNumber number;
  decNumber number;
 
 
  decimal_to_number (from, len_from, &number);
  decimal_to_number (from, len_from, &number);
  decimal_from_number (&number, to, len_to);
  decimal_from_number (&number, to, len_to);
}
}
 
 

powered by: WebSVN 2.1.0

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