* configure: Regenerate with proper autoconf 2.13.
[deliverable/binutils-gdb.git] / gdb / i387-tdep.c
index 0621bdf4a48d1e8718a4046e9cb81fe0e778745f..9b47e5827af9ac18ae95a3e512d1c5ccf019585a 100644 (file)
@@ -1,5 +1,6 @@
 /* Intel 387 floating point stuff.
-   Copyright (C) 1988, 1989, 1991, 1998 Free Software Foundation, Inc.
+   Copyright 1988, 1989, 1991, 1992, 1993, 1994, 1998, 1999, 2000,
+   2001, 2002 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "value.h"
 #include "gdbcore.h"
 #include "floatformat.h"
+#include "regcache.h"
+#include "gdb_assert.h"
+#include "gdb_string.h"
+#include "doublest.h"
 
-void i387_to_double PARAMS ((char *, char *));
-void double_to_i387 PARAMS ((char *, char *));
+#include "i386-tdep.h"
 
-static void print_387_control_bits PARAMS ((unsigned int control));
-static void print_387_status_bits  PARAMS ((unsigned int status));
+/* FIXME: Eliminate the next two functions when we have the time to
+   change all the callers.  */
 
-/* FIXME:  Eliminate these routines when we have the time to change all
-   the callers.  */
+void i387_to_double (char *from, char *to);
+void double_to_i387 (char *from, char *to);
 
 void
-i387_to_double (from, to)
-     char *from;
-     char *to;
+i387_to_double (char *from, char *to)
 {
   floatformat_to_double (&floatformat_i387_ext, from, (double *) to);
 }
 
 void
-double_to_i387 (from, to)
-     char *from;
-     char *to;
+double_to_i387 (char *from, char *to)
 {
   floatformat_from_double (&floatformat_i387_ext, (double *) from, to);
 }
 
+\f
+/* FIXME: The functions on this page are used by the old `info float'
+   implementations that a few of the i386 targets provide.  These
+   functions should be removed if all of these have been converted to
+   use the generic implementation based on the new register file
+   layout.  */
+
+static void print_387_control_bits (unsigned int control);
+static void print_387_status_bits (unsigned int status);
+
 static void
-print_387_control_bits (control)
-     unsigned int control;
+print_387_control_bits (unsigned int control)
 {
   switch ((control >> 8) & 3)
     {
@@ -102,15 +111,14 @@ print_387_control_bits (control)
        puts_unfiltered (" LOS");
       puts_unfiltered (";");
     }
-  printf_unfiltered ("\n");
+
   if (control & 0xe080)
     warning ("\nreserved bits on: %s",
             local_hex_string (control & 0xe080));
 }
 
 void
-print_387_control_word (control)
-     unsigned int control;
+print_387_control_word (unsigned int control)
 {
   printf_filtered ("control %s:", local_hex_string(control & 0xffff));
   print_387_control_bits (control);
@@ -118,8 +126,7 @@ print_387_control_word (control)
 }
 
 static void
-print_387_status_bits (status)
-     unsigned int status;
+print_387_status_bits (unsigned int status)
 {
   printf_unfiltered (" flags %d%d%d%d; ",
                     (status & 0x4000) != 0,
@@ -141,191 +148,584 @@ print_387_status_bits (status)
 }
 
 void
-print_387_status_word (status)
-     unsigned int status;
+print_387_status_word (unsigned int status)
 {
   printf_filtered ("status %s:", local_hex_string (status & 0xffff));
   print_387_status_bits (status);
   puts_unfiltered ("\n");
 }
 
-void
-i387_print_register (raw_regs, regnum)
-     char *raw_regs;
-     int regnum;
+\f
+/* Implement the `info float' layout based on the register definitions
+   in `tm-i386.h'.  */
+
+/* Print the floating point number specified by RAW.  */
+static void
+print_i387_value (char *raw, struct ui_file *file)
 {
-  unsigned char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
-  unsigned long val;
-  int j, sign, special;
-  unsigned swd, tags, expon, top, norm, ls, ms;
-  char string[12];
-
-#if (FPREG_RAW_SIZE != 10)
-#error "Bad FPREG_RAW_SIZE"
+  DOUBLEST value;
+
+  /* Using extract_typed_floating here might affect the representation
+     of certain numbers such as NaNs, even if GDB is running natively.
+     This is fine since our caller already detects such special
+     numbers and we print the hexadecimal representation anyway.  */
+  value = extract_typed_floating (raw, builtin_type_i387_ext);
+
+  /* We try to print 19 digits.  The last digit may or may not contain
+     garbage, but we'd better print one too many.  We need enough room
+     to print the value, 1 position for the sign, 1 for the decimal
+     point, 19 for the digits and 6 for the exponent adds up to 27.  */
+#ifdef PRINTF_HAS_LONG_DOUBLE
+  fprintf_filtered (file, " %-+27.19Lg", (long double) value);
+#else
+  fprintf_filtered (file, " %-+27.19g", (double) value);
 #endif
+}
 
-  printf_filtered ("%8.8s: ", REGISTER_NAME (regnum));
-  if (regnum < FPDATA_REGNUM)
+/* Print the classification for the register contents RAW.  */
+static void
+print_i387_ext (unsigned char *raw, struct ui_file *file)
+{
+  int sign;
+  int integer;
+  unsigned int exponent;
+  unsigned long fraction[2];
+
+  sign = raw[9] & 0x80;
+  integer = raw[7] & 0x80;
+  exponent = (((raw[9] & 0x7f) << 8) | raw[8]);
+  fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]);
+  fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16)
+                | (raw[5] << 8) | raw[4]);
+
+  if (exponent == 0x7fff && integer)
     {
-      val = extract_unsigned_integer (raw_regs + REGISTER_BYTE (regnum), 4);
-      if ( (regnum < FPSTART_REGNUM + 3) ||
-          (regnum == FPSTART_REGNUM + 6) )
-       /* Don't print the un-modifiable bytes. */
-       sprintf(string, "0x%04x", val & 0xffff);
+      if (fraction[0] == 0x00000000 && fraction[1] == 0x00000000)
+       /* Infinity.  */
+       fprintf_filtered (file, " %cInf", (sign ? '-' : '+'));
+      else if (sign && fraction[0] == 0x00000000 && fraction[1] == 0x40000000)
+       /* Real Indefinite (QNaN).  */
+       fputs_unfiltered (" Real Indefinite (QNaN)", file);
+      else if (fraction[1] & 0x40000000)
+       /* QNaN.  */
+       fputs_filtered (" QNaN", file);
       else
-       sprintf(string, "0x%08x", val);
-
-      printf_unfiltered ("%10.10s", string);
-
-      if (regnum == FPCONTROL_REGNUM)
-       print_387_control_bits (val);
-      else if (regnum == FPSTATUS_REGNUM)
-       print_387_status_bits (val);
+       /* SNaN.  */
+       fputs_filtered (" SNaN", file);
+    }
+  else if (exponent < 0x7fff && exponent > 0x0000 && integer)
+    /* Normal.  */
+    print_i387_value (raw, file);
+  else if (exponent == 0x0000)
+    {
+      /* Denormal or zero.  */
+      print_i387_value (raw, file);
+      
+      if (integer)
+       /* Pseudo-denormal.  */
+       fputs_filtered (" Pseudo-denormal", file);
+      else if (fraction[0] || fraction[1])
+       /* Denormal.  */
+       fputs_filtered (" Denormal", file);
     }
   else
+    /* Unsupported.  */
+    fputs_filtered (" Unsupported", file);
+}
+
+/* Print the status word STATUS.  */
+static void
+print_i387_status_word (unsigned int status, struct ui_file *file)
+{
+  fprintf_filtered (file, "Status Word:         %s",
+                  local_hex_string_custom (status, "04"));
+  fputs_filtered ("  ", file);
+  fprintf_filtered (file, " %s", (status & 0x0001) ? "IE" : "  ");
+  fprintf_filtered (file, " %s", (status & 0x0002) ? "DE" : "  ");
+  fprintf_filtered (file, " %s", (status & 0x0004) ? "ZE" : "  ");
+  fprintf_filtered (file, " %s", (status & 0x0008) ? "OE" : "  ");
+  fprintf_filtered (file, " %s", (status & 0x0010) ? "UE" : "  ");
+  fprintf_filtered (file, " %s", (status & 0x0020) ? "PE" : "  ");
+  fputs_filtered ("  ", file);
+  fprintf_filtered (file, " %s", (status & 0x0080) ? "ES" : "  ");
+  fputs_filtered ("  ", file);
+  fprintf_filtered (file, " %s", (status & 0x0040) ? "SF" : "  ");
+  fputs_filtered ("  ", file);
+  fprintf_filtered (file, " %s", (status & 0x0100) ? "C0" : "  ");
+  fprintf_filtered (file, " %s", (status & 0x0200) ? "C1" : "  ");
+  fprintf_filtered (file, " %s", (status & 0x0400) ? "C2" : "  ");
+  fprintf_filtered (file, " %s", (status & 0x4000) ? "C3" : "  ");
+
+  fputs_filtered ("\n", file);
+
+  fprintf_filtered (file,
+                   "                       TOP: %d\n", ((status >> 11) & 7));
+}
+
+/* Print the control word CONTROL.  */
+static void
+print_i387_control_word (unsigned int control, struct ui_file *file)
+{
+  fprintf_filtered (file, "Control Word:        %s",
+                  local_hex_string_custom (control, "04"));
+  fputs_filtered ("  ", file);
+  fprintf_filtered (file, " %s", (control & 0x0001) ? "IM" : "  ");
+  fprintf_filtered (file, " %s", (control & 0x0002) ? "DM" : "  ");
+  fprintf_filtered (file, " %s", (control & 0x0004) ? "ZM" : "  ");
+  fprintf_filtered (file, " %s", (control & 0x0008) ? "OM" : "  ");
+  fprintf_filtered (file, " %s", (control & 0x0010) ? "UM" : "  ");
+  fprintf_filtered (file, " %s", (control & 0x0020) ? "PM" : "  ");
+
+  fputs_filtered ("\n", file);
+
+  fputs_filtered ("                       PC: ", file);
+  switch ((control >> 8) & 3)
     {
-      /* An FPU stack register. */
-      if ( REGISTER_RAW_SIZE (regnum) != FPREG_RAW_SIZE )
-       error ("GDB bug: i387-tdep.c (i387_print_register): wrong size for FPU stack register");
-
-      /* Put the data in the buffer.  No conversions are ever necessary. */
-      memcpy (virtual_buffer, raw_regs + REGISTER_BYTE (regnum),
-             FPREG_RAW_SIZE);
-
-      swd = extract_signed_integer (raw_regs + REGISTER_BYTE (FPSTATUS_REGNUM),
-                                   4);
-      top = (swd >> 11) & 7;
-      tags = extract_signed_integer (raw_regs + REGISTER_BYTE (FPTAG_REGNUM),
-                                    4);
-
-      puts_unfiltered ("0x");
-      for (j = 0; j < FPREG_RAW_SIZE; j++)
-       printf_unfiltered ("%02x",
-                          (unsigned char)raw_regs[REGISTER_BYTE (regnum)
-                                                 + FPREG_RAW_SIZE - 1 - j]);
+    case 0:
+      fputs_filtered ("Single Precision (24-bits)\n", file);
+      break;
+    case 1:
+      fputs_filtered ("Reserved\n", file);
+      break;
+    case 2:
+      fputs_filtered ("Double Precision (53-bits)\n", file);
+      break;
+    case 3:
+      fputs_filtered ("Extended Precision (64-bits)\n", file);
+      break;
+    }
       
-      puts_unfiltered ("  ");
-      special = 0;
-      switch ((tags >> (((regnum - FPDATA_REGNUM + top) & 7) * 2)) & 3) 
+  fputs_filtered ("                       RC: ", file);
+  switch ((control >> 10) & 3)
+    {
+    case 0:
+      fputs_filtered ("Round to nearest\n", file);
+      break;
+    case 1:
+      fputs_filtered ("Round down\n", file);
+      break;
+    case 2:
+      fputs_filtered ("Round up\n", file);
+      break;
+    case 3:
+      fputs_filtered ("Round toward zero\n", file);
+      break;
+    }
+}
+
+/* Print out the i387 floating point state.  Note that we ignore FRAME
+   in the code below.  That's OK since floating-point registers are
+   never saved on the stack.  */
+
+void
+i387_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
+                      struct frame_info *frame, const char *args)
+{
+  char buf[4];
+  ULONGEST fctrl;
+  ULONGEST fstat;
+  ULONGEST ftag;
+  ULONGEST fiseg;
+  ULONGEST fioff;
+  ULONGEST foseg;
+  ULONGEST fooff;
+  ULONGEST fop;
+  int fpreg;
+  int top;
+
+  frame_register_read (frame, FCTRL_REGNUM, buf);
+  fctrl = extract_unsigned_integer (buf, 4);
+  frame_register_read (frame, FSTAT_REGNUM, buf);
+  fstat = extract_unsigned_integer (buf, 4);
+  frame_register_read (frame, FTAG_REGNUM, buf);
+  ftag = extract_unsigned_integer (buf, 4);
+  frame_register_read (frame, FISEG_REGNUM, buf);
+  fiseg = extract_unsigned_integer (buf, 4);
+  frame_register_read (frame, FIOFF_REGNUM, buf);
+  fioff = extract_unsigned_integer (buf, 4);
+  frame_register_read (frame, FOSEG_REGNUM, buf);
+  foseg = extract_unsigned_integer (buf, 4);
+  frame_register_read (frame, FOOFF_REGNUM, buf);
+  fooff = extract_unsigned_integer (buf, 4);
+  frame_register_read (frame, FOP_REGNUM, buf);
+  fop = extract_unsigned_integer (buf, 4);
+
+  top = ((fstat >> 11) & 7);
+
+  for (fpreg = 7; fpreg >= 0; fpreg--)
+    {
+      unsigned char raw[FPU_REG_RAW_SIZE];
+      int tag = (ftag >> (fpreg * 2)) & 3;
+      int i;
+
+      fprintf_filtered (file, "%sR%d: ", fpreg == top ? "=>" : "  ", fpreg);
+
+      switch (tag)
        {
-       case 0: puts_unfiltered ("Valid "); break;
-       case 1: puts_unfiltered ("Zero  "); break;
-       case 2: puts_unfiltered ("Spec  ");
-         special = 1;
+       case 0:
+         fputs_filtered ("Valid   ", file);
+         break;
+       case 1:
+         fputs_filtered ("Zero    ", file);
+         break;
+       case 2:
+         fputs_filtered ("Special ", file);
+         break;
+       case 3:
+         fputs_filtered ("Empty   ", file);
          break;
-       case 3: puts_unfiltered ("Empty "); break;
        }
 
-      expon = extract_unsigned_integer (raw_regs + REGISTER_BYTE (regnum)
-                                       + FPREG_RAW_SIZE - 2, 2);
-      sign = expon & 0x8000;
-      expon &= 0x7fff;
-      ms = extract_unsigned_integer (raw_regs + REGISTER_BYTE (regnum) + 4, 4);
-      ls = extract_signed_integer (raw_regs + REGISTER_BYTE (regnum), 4);
-      norm = ms & 0x80000000;
+      frame_register_read (frame, (fpreg + 8 - top) % 8 + FP0_REGNUM, raw);
 
-      if ( expon == 0 )
-       {
-         if ( ms | ls )
-           {
-             /* Denormal or Pseudodenormal. */
-             if ( norm )
-               puts_unfiltered ("Pseudo ");
-             else
-               puts_unfiltered ("Denorm ");
-           }
-         else
-           {
-             /* Zero. */
-             puts_unfiltered ("Zero   ");
-           }
-       }
-      else if ( expon == 0x7fff )
-       {
-         /* Infinity, NaN or unsupported. */
-         if ( (ms == 0x80000000) &&
-              (ls == 0) )
-           {
-              puts_unfiltered ("Infty  ");
-           }
-         else if ( norm )
-           {
-             if ( ms & 0x40000000 )
-               puts_unfiltered ("QNaN   ");
-             else
-               puts_unfiltered ("SNaN   ");
-           }
-         else
-           {
-              puts_unfiltered ("Unsupp ");
-           }
-       }
-      else
-       {
-         /* Normal or unsupported. */
-         if ( norm )
-           puts_unfiltered ("Normal ");
-         else
-           puts_unfiltered ("Unsupp ");
-       }
+      fputs_filtered ("0x", file);
+      for (i = 9; i >= 0; i--)
+       fprintf_filtered (file, "%02x", raw[i]);
 
-      val_print (REGISTER_VIRTUAL_TYPE (regnum), virtual_buffer, 0, 0,
-                gdb_stdout, 0,
-                1, 0, Val_pretty_default);
+      if (tag != 3)
+       print_i387_ext (raw, file);
+
+      fputs_filtered ("\n", file);
     }
-  puts_filtered ("\n");
+
+  fputs_filtered ("\n", file);
+
+  print_i387_status_word (fstat, file);
+  print_i387_control_word (fctrl, file);
+  fprintf_filtered (file, "Tag Word:            %s\n",
+                   local_hex_string_custom (ftag, "04"));
+  fprintf_filtered (file, "Instruction Pointer: %s:",
+                   local_hex_string_custom (fiseg, "02"));
+  fprintf_filtered (file, "%s\n", local_hex_string_custom (fioff, "08"));
+  fprintf_filtered (file, "Operand Pointer:     %s:",
+                   local_hex_string_custom (foseg, "02"));
+  fprintf_filtered (file, "%s\n", local_hex_string_custom (fooff, "08"));
+  fprintf_filtered (file, "Opcode:              %s\n",
+                   local_hex_string_custom (fop ? (fop | 0xd800) : 0, "04"));
 }
 
-void i387_float_info(void)
+/* FIXME: kettenis/2000-05-21: Right now more than a few i386 targets
+   define their own routines to manage the floating-point registers in
+   GDB's register array.  Most (if not all) of these targets use the
+   format used by the "fsave" instruction in their communication with
+   the OS.  They should all be converted to use the routines below.  */
+
+/* At fsave_offset[REGNUM] you'll find the offset to the location in
+   the data structure used by the "fsave" instruction where GDB
+   register REGNUM is stored.  */
+
+static int fsave_offset[] =
+{
+  28 + 0 * FPU_REG_RAW_SIZE,   /* FP0_REGNUM through ...  */
+  28 + 1 * FPU_REG_RAW_SIZE,  
+  28 + 2 * FPU_REG_RAW_SIZE,  
+  28 + 3 * FPU_REG_RAW_SIZE,  
+  28 + 4 * FPU_REG_RAW_SIZE,  
+  28 + 5 * FPU_REG_RAW_SIZE,  
+  28 + 6 * FPU_REG_RAW_SIZE,  
+  28 + 7 * FPU_REG_RAW_SIZE,   /* ... FP7_REGNUM.  */
+  0,                           /* FCTRL_REGNUM (16 bits).  */
+  4,                           /* FSTAT_REGNUM (16 bits).  */
+  8,                           /* FTAG_REGNUM (16 bits).  */
+  16,                          /* FISEG_REGNUM (16 bits).  */
+  12,                          /* FIOFF_REGNUM.  */
+  24,                          /* FOSEG_REGNUM.  */
+  20,                          /* FOOFF_REGNUM.  */
+  18                           /* FOP_REGNUM (bottom 11 bits).  */
+};
+
+#define FSAVE_ADDR(fsave, regnum) (fsave + fsave_offset[regnum - FP0_REGNUM])
+\f
+
+/* Fill register REGNUM in GDB's register array with the appropriate
+   value from *FSAVE.  This function masks off any of the reserved
+   bits in *FSAVE.  */
+
+void
+i387_supply_register (int regnum, char *fsave)
+{
+  if (fsave == NULL)
+    {
+      supply_register (regnum, NULL);
+      return;
+    }
+
+  /* Most of the FPU control registers occupy only 16 bits in
+     the fsave area.  Give those a special treatment.  */
+  if (regnum >= FPC_REGNUM
+      && regnum != FIOFF_REGNUM && regnum != FOOFF_REGNUM)
+    {
+      unsigned char val[4];
+
+      memcpy (val, FSAVE_ADDR (fsave, regnum), 2);
+      val[2] = val[3] = 0;
+      if (regnum == FOP_REGNUM)
+       val[1] &= ((1 << 3) - 1);
+      supply_register (regnum, val);
+    }
+  else
+    supply_register (regnum, FSAVE_ADDR (fsave, regnum));
+}
+
+/* Fill GDB's register array with the floating-point register values
+   in *FSAVE.  This function masks off any of the reserved
+   bits in *FSAVE.  */
+
+void
+i387_supply_fsave (char *fsave)
 {
-  char raw_regs [REGISTER_BYTES];
   int i;
 
-  for (i = FPSTART_REGNUM; i <= FPEND_REGNUM; i++)
-    read_relative_register_raw_bytes (i, raw_regs + REGISTER_BYTE (i));
+  for (i = FP0_REGNUM; i < XMM0_REGNUM; i++)
+    i387_supply_register (i, fsave);
+}
+
+/* Fill register REGNUM (if it is a floating-point register) in *FSAVE
+   with the value in GDB's register array.  If REGNUM is -1, do this
+   for all registers.  This function doesn't touch any of the reserved
+   bits in *FSAVE.  */
+
+void
+i387_fill_fsave (char *fsave, int regnum)
+{
+  int i;
 
-  for (i = FPSTART_REGNUM; i <= FPEND_REGNUM; i++)
-    i387_print_register (raw_regs, i);
+  for (i = FP0_REGNUM; i < XMM0_REGNUM; i++)
+    if (regnum == -1 || regnum == i)
+      {
+       /* Most of the FPU control registers occupy only 16 bits in
+           the fsave area.  Give those a special treatment.  */
+       if (i >= FPC_REGNUM
+           && i != FIOFF_REGNUM && i != FOOFF_REGNUM)
+         {
+           unsigned char buf[4];
+
+           regcache_collect (i, buf);
+
+           if (i == FOP_REGNUM)
+             {
+               /* The opcode occupies only 11 bits.  Make sure we
+                   don't touch the other bits.  */
+               buf[1] &= ((1 << 3) - 1);
+               buf[1] |= ((FSAVE_ADDR (fsave, i))[1] & ~((1 << 3) - 1));
+             }
+           memcpy (FSAVE_ADDR (fsave, i), buf, 2);
+         }
+       else
+         regcache_collect (i, FSAVE_ADDR (fsave, i));
+      }
 }
+\f
+
+/* At fxsave_offset[REGNUM] you'll find the offset to the location in
+   the data structure used by the "fxsave" instruction where GDB
+   register REGNUM is stored.  */
 
-#ifdef LD_I387
-int
-i387_extract_floating (PTR addr, int len, DOUBLEST *dretptr)
+static int fxsave_offset[] =
 {
-  if (len == TARGET_LONG_DOUBLE_BIT / 8)
+  32,                          /* FP0_REGNUM through ...  */
+  48,
+  64,
+  80,
+  96,
+  112,
+  128,
+  144,                         /* ... FP7_REGNUM (80 bits each).  */
+  0,                           /* FCTRL_REGNUM (16 bits).  */
+  2,                           /* FSTAT_REGNUM (16 bits).  */
+  4,                           /* FTAG_REGNUM (16 bits).  */
+  12,                          /* FISEG_REGNUM (16 bits).  */
+  8,                           /* FIOFF_REGNUM.  */
+  20,                          /* FOSEG_REGNUM (16 bits).  */
+  16,                          /* FOOFF_REGNUM.  */
+  6,                           /* FOP_REGNUM (bottom 11 bits).  */
+  160,                         /* XMM0_REGNUM through ...  */
+  176,
+  192,
+  208,
+  224,
+  240,
+  256,
+  272,                         /* ... XMM7_REGNUM (128 bits each).  */
+  24,                          /* MXCSR_REGNUM.  */
+};
+
+#define FXSAVE_ADDR(fxsave, regnum) \
+  (fxsave + fxsave_offset[regnum - FP0_REGNUM])
+
+static int i387_tag (unsigned char *raw);
+\f
+
+/* Fill GDB's register array with the floating-point and SSE register
+   values in *FXSAVE.  This function masks off any of the reserved
+   bits in *FXSAVE.  */
+
+void
+i387_supply_fxsave (char *fxsave)
+{
+  int i, last_regnum = MXCSR_REGNUM;
+
+  if (gdbarch_tdep (current_gdbarch)->num_xmm_regs == 0)
+    last_regnum = FOP_REGNUM;
+
+  for (i = FP0_REGNUM; i <= last_regnum; i++)
     {
-      if (HOST_LONG_DOUBLE_FORMAT == TARGET_LONG_DOUBLE_FORMAT)
+      if (fxsave == NULL)
+       {
+         supply_register (i, NULL);
+         continue;
+       }
+
+      /* Most of the FPU control registers occupy only 16 bits in
+        the fxsave area.  Give those a special treatment.  */
+      if (i >= FPC_REGNUM && i < XMM0_REGNUM
+         && i != FIOFF_REGNUM && i != FOOFF_REGNUM)
        {
-         DOUBLEST retval;
+         unsigned char val[4];
 
-         memcpy (dretptr, addr, sizeof (retval));
+         memcpy (val, FXSAVE_ADDR (fxsave, i), 2);
+         val[2] = val[3] = 0;
+         if (i == FOP_REGNUM)
+           val[1] &= ((1 << 3) - 1);
+         else if (i== FTAG_REGNUM)
+           {
+             /* The fxsave area contains a simplified version of the
+                 tag word.  We have to look at the actual 80-bit FP
+                 data to recreate the traditional i387 tag word.  */
+
+             unsigned long ftag = 0;
+             int fpreg;
+             int top;
+
+             top = (((FXSAVE_ADDR (fxsave, FSTAT_REGNUM))[1] >> 3) & 0x7);
+
+             for (fpreg = 7; fpreg >= 0; fpreg--)
+               {
+                 int tag;
+
+                 if (val[0] & (1 << fpreg))
+                   {
+                     int regnum = (fpreg + 8 - top) % 8 + FP0_REGNUM;
+                     tag = i387_tag (FXSAVE_ADDR (fxsave, regnum));
+                   }
+                 else
+                   tag = 3;            /* Empty */
+
+                 ftag |= tag << (2 * fpreg);
+               }
+             val[0] = ftag & 0xff;
+             val[1] = (ftag >> 8) & 0xff;
+           }
+         supply_register (i, val);
        }
       else
-       floatformat_to_doublest (TARGET_LONG_DOUBLE_FORMAT, addr, dretptr);
-
-      return 1;
+       supply_register (i, FXSAVE_ADDR (fxsave, i));
     }
-  else
-    return 0;
 }
 
-int
-i387_store_floating (PTR addr, int len, DOUBLEST val)
+/* Fill register REGNUM (if it is a floating-point or SSE register) in
+   *FXSAVE with the value in GDB's register array.  If REGNUM is -1, do
+   this for all registers.  This function doesn't touch any of the
+   reserved bits in *FXSAVE.  */
+
+void
+i387_fill_fxsave (char *fxsave, int regnum)
+{
+  int i, last_regnum = MXCSR_REGNUM;
+
+  if (gdbarch_tdep (current_gdbarch)->num_xmm_regs == 0)
+    last_regnum = FOP_REGNUM;
+
+  for (i = FP0_REGNUM; i <= last_regnum; i++)
+    if (regnum == -1 || regnum == i)
+      {
+       /* Most of the FPU control registers occupy only 16 bits in
+           the fxsave area.  Give those a special treatment.  */
+       if (i >= FPC_REGNUM && i < XMM0_REGNUM
+           && i != FIOFF_REGNUM && i != FOOFF_REGNUM)
+         {
+           unsigned char buf[4];
+
+           regcache_collect (i, buf);
+
+           if (i == FOP_REGNUM)
+             {
+               /* The opcode occupies only 11 bits.  Make sure we
+                   don't touch the other bits.  */
+               buf[1] &= ((1 << 3) - 1);
+               buf[1] |= ((FXSAVE_ADDR (fxsave, i))[1] & ~((1 << 3) - 1));
+             }
+           else if (i == FTAG_REGNUM)
+             {
+               /* Converting back is much easier.  */
+
+               unsigned short ftag;
+               int fpreg;
+
+               ftag = (buf[1] << 8) | buf[0];
+               buf[0] = 0;
+               buf[1] = 0;
+
+               for (fpreg = 7; fpreg >= 0; fpreg--)
+                 {
+                   int tag = (ftag >> (fpreg * 2)) & 3;
+
+                   if (tag != 3)
+                     buf[0] |= (1 << fpreg);
+                 }
+             }
+           memcpy (FXSAVE_ADDR (fxsave, i), buf, 2);
+         }
+       else
+         regcache_collect (i, FXSAVE_ADDR (fxsave, i));
+      }
+}
+
+/* Recreate the FTW (tag word) valid bits from the 80-bit FP data in
+   *RAW.  */
+
+static int
+i387_tag (unsigned char *raw)
 {
-  if (len == TARGET_LONG_DOUBLE_BIT / 8)
+  int integer;
+  unsigned int exponent;
+  unsigned long fraction[2];
+
+  integer = raw[7] & 0x80;
+  exponent = (((raw[9] & 0x7f) << 8) | raw[8]);
+  fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]);
+  fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16)
+                | (raw[5] << 8) | raw[4]);
+
+  if (exponent == 0x7fff)
+    {
+      /* Special.  */
+      return (2);
+    }
+  else if (exponent == 0x0000)
     {
-      /* This `if' may be totally stupid.  I just put it in here to be
-        absolutely sure I'm preserving the semantics of the code I'm
-        frobbing, while I try to maintain portability boundaries; I
-        don't actually know exactly what it's doing.  -JimB, May 1999 */
-      if (HOST_LONG_DOUBLE_FORMAT == TARGET_LONG_DOUBLE_FORMAT)
-       memcpy (addr, &val, sizeof (val));
+      if (fraction[0] == 0x0000 && fraction[1] == 0x0000 && !integer)
+       {
+         /* Zero.  */
+         return (1);
+       }
       else
-       floatformat_from_doublest (TARGET_LONG_DOUBLE_FORMAT, &val, addr);
-
-      return 1;
+       {
+         /* Special.  */
+         return (2);
+       }
     }
   else
-    return 0;
+    {
+      if (integer)
+       {
+         /* Valid.  */
+         return (0);
+       }
+      else
+       {
+         /* Special.  */
+         return (2);
+       }
+    }
 }
-#endif /* LD_I387 */
This page took 0.044782 seconds and 4 git commands to generate.