/* Intel 387 floating point stuff.
+
Copyright 1988, 1989, 1991, 1992, 1993, 1994, 1998, 1999, 2000,
- 2001, 2002 Free Software Foundation, Inc.
+ 2001, 2002, 2003 Free Software Foundation, Inc.
This file is part of GDB.
Boston, MA 02111-1307, USA. */
#include "defs.h"
+#include "doublest.h"
+#include "floatformat.h"
#include "frame.h"
+#include "gdbcore.h"
#include "inferior.h"
#include "language.h"
-#include "value.h"
-#include "gdbcore.h"
-#include "floatformat.h"
#include "regcache.h"
+#include "value.h"
+
#include "gdb_assert.h"
#include "gdb_string.h"
-#include "doublest.h"
#include "i386-tdep.h"
+#include "i387-tdep.h"
-/* FIXME: Eliminate the next two functions 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 (char *from, char *to)
-{
- floatformat_to_double (&floatformat_i387_ext, from, (double *) to);
-}
-
-void
-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 (unsigned int control)
-{
- switch ((control >> 8) & 3)
- {
- case 0:
- puts_unfiltered (" 24 bit; ");
- break;
- case 1:
- puts_unfiltered (" (bad); ");
- break;
- case 2:
- puts_unfiltered (" 53 bit; ");
- break;
- case 3:
- puts_unfiltered (" 64 bit; ");
- break;
- }
- switch ((control >> 10) & 3)
- {
- case 0:
- puts_unfiltered ("NEAR; ");
- break;
- case 1:
- puts_unfiltered ("DOWN; ");
- break;
- case 2:
- puts_unfiltered ("UP; ");
- break;
- case 3:
- puts_unfiltered ("CHOP; ");
- break;
- }
- if (control & 0x3f)
- {
- puts_unfiltered ("mask");
- if (control & 0x0001)
- puts_unfiltered (" INVAL");
- if (control & 0x0002)
- puts_unfiltered (" DENOR");
- if (control & 0x0004)
- puts_unfiltered (" DIVZ");
- if (control & 0x0008)
- puts_unfiltered (" OVERF");
- if (control & 0x0010)
- puts_unfiltered (" UNDER");
- if (control & 0x0020)
- puts_unfiltered (" LOS");
- puts_unfiltered (";");
- }
-
- if (control & 0xe080)
- warning ("\nreserved bits on: %s",
- local_hex_string (control & 0xe080));
-}
-
-void
-print_387_control_word (unsigned int control)
-{
- printf_filtered ("control %s:", local_hex_string(control & 0xffff));
- print_387_control_bits (control);
- puts_unfiltered ("\n");
-}
-
-static void
-print_387_status_bits (unsigned int status)
-{
- printf_unfiltered (" flags %d%d%d%d; ",
- (status & 0x4000) != 0,
- (status & 0x0400) != 0,
- (status & 0x0200) != 0,
- (status & 0x0100) != 0);
- printf_unfiltered ("top %d; ", (status >> 11) & 7);
- if (status & 0xff)
- {
- puts_unfiltered ("excep");
- if (status & 0x0001) puts_unfiltered (" INVAL");
- if (status & 0x0002) puts_unfiltered (" DENOR");
- if (status & 0x0004) puts_unfiltered (" DIVZ");
- if (status & 0x0008) puts_unfiltered (" OVERF");
- if (status & 0x0010) puts_unfiltered (" UNDER");
- if (status & 0x0020) puts_unfiltered (" LOS");
- if (status & 0x0040) puts_unfiltered (" STACK");
- }
-}
-
-void
-print_387_status_word (unsigned int status)
-{
- printf_filtered ("status %s:", local_hex_string (status & 0xffff));
- print_387_status_bits (status);
- puts_unfiltered ("\n");
-}
-
-\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)
{
}
/* Print the classification for the register contents RAW. */
+
static void
print_i387_ext (unsigned char *raw, struct ui_file *file)
{
}
/* Print the status word STATUS. */
+
static void
print_i387_status_word (unsigned int status, struct ui_file *file)
{
}
/* Print the control word CONTROL. */
+
static void
print_i387_control_word (unsigned int control, struct ui_file *file)
{
i387_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
struct frame_info *frame, const char *args)
{
- unsigned int fctrl;
- unsigned int fstat;
- unsigned int ftag;
- unsigned int fiseg;
- unsigned int fioff;
- unsigned int foseg;
- unsigned int fooff;
- unsigned int fop;
+ char buf[4];
+ ULONGEST fctrl;
+ ULONGEST fstat;
+ ULONGEST ftag;
+ ULONGEST fiseg;
+ ULONGEST fioff;
+ ULONGEST foseg;
+ ULONGEST fooff;
+ ULONGEST fop;
int fpreg;
int top;
- fctrl = read_register (FCTRL_REGNUM);
- fstat = read_register (FSTAT_REGNUM);
- ftag = read_register (FTAG_REGNUM);
- fiseg = read_register (FCS_REGNUM);
- fioff = read_register (FCOFF_REGNUM);
- foseg = read_register (FDS_REGNUM);
- fooff = read_register (FDOFF_REGNUM);
- fop = read_register (FOP_REGNUM);
-
+ 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--)
break;
}
- read_register_gen ((fpreg + 8 - top) % 8 + FP0_REGNUM, raw);
+ frame_register_read (frame, (fpreg + 8 - top) % 8 + FP0_REGNUM, raw);
fputs_filtered ("0x", file);
for (i = 9; i >= 0; i--)
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, "Opcode: %s\n",
local_hex_string_custom (fop ? (fop | 0xd800) : 0, "04"));
}
+\f
+
+/* Read a value of type TYPE from register REGNUM in frame FRAME, and
+ return its contents in TO. */
+
+void
+i387_register_to_value (struct frame_info *frame, int regnum,
+ struct type *type, void *to)
+{
+ char from[I386_MAX_REGISTER_SIZE];
-/* 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. */
+ gdb_assert (i386_fp_regnum_p (regnum));
+
+ /* We only support floating-point values. */
+ if (TYPE_CODE (type) != TYPE_CODE_FLT)
+ {
+ warning ("Cannot convert floating-point register value "
+ "to non-floating-point type.");
+ return;
+ }
+
+ /* Convert to TYPE. This should be a no-op if TYPE is equivalent to
+ the extended floating-point format used by the FPU. */
+ frame_read_register (frame, regnum, from);
+ convert_typed_floating (from, builtin_type_i387_ext, to, type);
+}
+
+/* Write the contents FROM of a value of type TYPE into register
+ REGNUM in frame FRAME. */
+
+void
+i387_value_to_register (struct frame_info *frame, int regnum,
+ struct type *type, const void *from)
+{
+ char to[I386_MAX_REGISTER_SIZE];
+
+ gdb_assert (i386_fp_regnum_p (regnum));
+
+ /* We only support floating-point values. */
+ if (TYPE_CODE (type) != TYPE_CODE_FLT)
+ {
+ warning ("Cannot convert non-floating-point type "
+ "to floating-point register value.");
+ return;
+ }
+
+ /* Convert from TYPE. This should be a no-op if TYPE is equivalent
+ to the extended floating-point format used by the FPU. */
+ convert_typed_floating (from, type, to, builtin_type_i387_ext);
+ put_frame_register (frame, regnum, to);
+}
+\f
+
+/* Handle FSAVE and FXSAVE formats. */
/* At fsave_offset[REGNUM] you'll find the offset to the location in
the data structure used by the "fsave" instruction where GDB
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
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. */
+ 160 + 0 * 16, /* XMM0_REGNUM through ... */
+ 160 + 1 * 16,
+ 160 + 2 * 16,
+ 160 + 3 * 16,
+ 160 + 4 * 16,
+ 160 + 5 * 16,
+ 160 + 6 * 16,
+ 160 + 7 * 16,
+ 160 + 8 * 16,
+ 160 + 9 * 16,
+ 160 + 10 * 16,
+ 160 + 11 * 16,
+ 160 + 12 * 16,
+ 160 + 13 * 16,
+ 160 + 14 * 16,
+ 160 + 15 * 16, /* ... XMM15_REGNUM (128 bits each). */
+ 24 /* MXCSR_REGNUM. */
};
+/* FIXME: kettenis/20030430: We made an unfortunate choice in putting
+ %mxcsr after the SSE registers %xmm0-%xmm7 instead of before, since
+ it makes supporting the registers %xmm8-%xmm15 on x86-64 a bit
+ involved. Hack around it by explicitly overriding the offset for
+ %mxcsr here. */
+
#define FXSAVE_ADDR(fxsave, regnum) \
- (fxsave + fxsave_offset[regnum - FP0_REGNUM])
+ ((regnum == MXCSR_REGNUM) ? (fxsave + 24) : \
+ (fxsave + fxsave_offset[regnum - FP0_REGNUM]))
static int i387_tag (unsigned char *raw);
\f
for (i = FP0_REGNUM; i <= last_regnum; i++)
{
+ 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
/* 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 != FDOFF_REGNUM)
+ && i != FIOFF_REGNUM && i != FOOFF_REGNUM)
{
unsigned char buf[4];