+
+ /* 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
+\f
+
+/* Handle FSAVE and FXSAVE formats. */
+
+/* FIXME: kettenis/20030927: The functions below should accept a
+ `regcache' argument, but I don't want to change the function
+ signature just yet. There's some band-aid in the functions below
+ in the form of the `regcache' local variables. This will ease the
+ transition later on. */
+
+/* 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 * 10, /* %st(0) ... */
+ 28 + 1 * 10,
+ 28 + 2 * 10,
+ 28 + 3 * 10,
+ 28 + 4 * 10,
+ 28 + 5 * 10,
+ 28 + 6 * 10,
+ 28 + 7 * 10, /* ... %st(7). */
+ 0, /* `fctrl' (16 bits). */
+ 4, /* `fstat' (16 bits). */
+ 8, /* `ftag' (16 bits). */
+ 16, /* `fiseg' (16 bits). */
+ 12, /* `fioff'. */
+ 24, /* `foseg' (16 bits). */
+ 20, /* `fooff'. */
+ 18 /* `fop' (bottom 11 bits). */
+};
+
+#define FSAVE_ADDR(fsave, regnum) \
+ (fsave + fsave_offset[regnum - I387_ST0_REGNUM])
+\f
+
+/* Fill register REGNUM in REGCACHE with the appropriate value from
+ *FSAVE. This function masks off any of the reserved bits in
+ *FSAVE. */
+
+void
+i387_supply_fsave (struct regcache *regcache, int regnum, const void *fsave)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
+ const char *regs = fsave;
+ int i;
+
+ gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
+
+ /* Define I387_ST0_REGNUM such that we use the proper definitions
+ for REGCACHE's architecture. */
+#define I387_ST0_REGNUM tdep->st0_regnum
+
+ for (i = I387_ST0_REGNUM; i < I387_XMM0_REGNUM; i++)
+ if (regnum == -1 || regnum == i)
+ {
+ if (fsave == NULL)
+ {
+ regcache_raw_supply (regcache, i, NULL);
+ continue;
+ }
+
+ /* Most of the FPU control registers occupy only 16 bits in the
+ fsave area. Give those a special treatment. */
+ if (i >= I387_FCTRL_REGNUM
+ && i != I387_FIOFF_REGNUM && i != I387_FOOFF_REGNUM)
+ {
+ unsigned char val[4];
+
+ memcpy (val, FSAVE_ADDR (regs, i), 2);
+ val[2] = val[3] = 0;
+ if (i == I387_FOP_REGNUM)
+ val[1] &= ((1 << 3) - 1);
+ regcache_raw_supply (regcache, i, val);
+ }
+ else
+ regcache_raw_supply (regcache, i, FSAVE_ADDR (regs, i));
+ }
+#undef I387_ST0_REGNUM
+}
+
+/* Fill register REGNUM (if it is a floating-point register) in *FSAVE
+ with the value from REGCACHE. If REGNUM is -1, do this for all
+ registers. This function doesn't touch any of the reserved bits in
+ *FSAVE. */
+
+void
+i387_collect_fsave (const struct regcache *regcache, int regnum, void *fsave)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ char *regs = fsave;
+ int i;
+
+ gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
+
+ /* Define I387_ST0_REGNUM such that we use the proper definitions
+ for REGCACHE's architecture. */
+#define I387_ST0_REGNUM tdep->st0_regnum
+
+ for (i = I387_ST0_REGNUM; i < I387_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 >= I387_FCTRL_REGNUM
+ && i != I387_FIOFF_REGNUM && i != I387_FOOFF_REGNUM)
+ {
+ unsigned char buf[4];
+
+ regcache_raw_collect (regcache, i, buf);
+
+ if (i == I387_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 (regs, i))[1] & ~((1 << 3) - 1));
+ }
+ memcpy (FSAVE_ADDR (regs, i), buf, 2);
+ }
+ else
+ regcache_raw_collect (regcache, i, FSAVE_ADDR (regs, i));
+ }
+#undef I387_ST0_REGNUM
+}
+
+/* Fill register REGNUM (if it is a floating-point register) in *FSAVE
+ with the value in GDB's register cache. 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 (void *fsave, int regnum)
+{
+ i387_collect_fsave (current_regcache, regnum, fsave);
+}
+\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. */
+
+static int fxsave_offset[] =
+{
+ 32, /* %st(0) through ... */
+ 48,
+ 64,
+ 80,
+ 96,
+ 112,
+ 128,
+ 144, /* ... %st(7) (80 bits each). */
+ 0, /* `fctrl' (16 bits). */
+ 2, /* `fstat' (16 bits). */
+ 4, /* `ftag' (16 bits). */
+ 12, /* `fiseg' (16 bits). */
+ 8, /* `fioff'. */
+ 20, /* `foseg' (16 bits). */
+ 16, /* `fooff'. */
+ 6, /* `fop' (bottom 11 bits). */
+ 160 + 0 * 16, /* %xmm0 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 (128 bits each). */
+};
+
+#define FXSAVE_ADDR(fxsave, regnum) \
+ (fxsave + fxsave_offset[regnum - I387_ST0_REGNUM])
+
+/* 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 AMD64 a bit involved. Therefore we
+ don't include the offset for %mxcsr here above. */
+
+#define FXSAVE_MXCSR_ADDR(fxsave) (fxsave + 24)
+
+static int i387_tag (const unsigned char *raw);
+\f
+
+/* Fill register REGNUM in REGCACHE with the appropriate
+ floating-point or SSE register value from *FXSAVE. This function
+ masks off any of the reserved bits in *FXSAVE. */
+
+void
+i387_supply_fxsave (struct regcache *regcache, int regnum, const void *fxsave)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
+ const char *regs = fxsave;
+ int i;
+
+ gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
+ gdb_assert (tdep->num_xmm_regs > 0);
+
+ /* Define I387_ST0_REGNUM and I387_NUM_XMM_REGS such that we use the
+ proper definitions for REGCACHE's architecture. */
+
+#define I387_ST0_REGNUM tdep->st0_regnum
+#define I387_NUM_XMM_REGS tdep->num_xmm_regs
+
+ for (i = I387_ST0_REGNUM; i < I387_MXCSR_REGNUM; i++)
+ if (regnum == -1 || regnum == i)
+ {
+ if (regs == NULL)
+ {
+ regcache_raw_supply (regcache, i, NULL);
+ continue;
+ }
+
+ /* Most of the FPU control registers occupy only 16 bits in
+ the fxsave area. Give those a special treatment. */
+ if (i >= I387_FCTRL_REGNUM && i < I387_XMM0_REGNUM
+ && i != I387_FIOFF_REGNUM && i != I387_FOOFF_REGNUM)
+ {
+ unsigned char val[4];
+
+ memcpy (val, FXSAVE_ADDR (regs, i), 2);
+ val[2] = val[3] = 0;
+ if (i == I387_FOP_REGNUM)
+ val[1] &= ((1 << 3) - 1);
+ else if (i== I387_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 (regs, I387_FSTAT_REGNUM))[1] >> 3);
+ top &= 0x7;
+
+ for (fpreg = 7; fpreg >= 0; fpreg--)
+ {
+ int tag;
+
+ if (val[0] & (1 << fpreg))
+ {
+ int regnum = (fpreg + 8 - top) % 8 + I387_ST0_REGNUM;
+ tag = i387_tag (FXSAVE_ADDR (regs, regnum));
+ }
+ else
+ tag = 3; /* Empty */
+
+ ftag |= tag << (2 * fpreg);
+ }
+ val[0] = ftag & 0xff;
+ val[1] = (ftag >> 8) & 0xff;
+ }
+ regcache_raw_supply (regcache, i, val);
+ }
+ else
+ regcache_raw_supply (regcache, i, FXSAVE_ADDR (regs, i));
+ }
+
+ if (regnum == I387_MXCSR_REGNUM || regnum == -1)