119370Spst/* Intel 387 floating point stuff.
219370Spst
3130803Smarcel   Copyright 1988, 1989, 1991, 1992, 1993, 1994, 1998, 1999, 2000,
4130803Smarcel   2001, 2002, 2003, 2004 Free Software Foundation, Inc.
5130803Smarcel
698944Sobrien   This file is part of GDB.
719370Spst
898944Sobrien   This program is free software; you can redistribute it and/or modify
998944Sobrien   it under the terms of the GNU General Public License as published by
1098944Sobrien   the Free Software Foundation; either version 2 of the License, or
1198944Sobrien   (at your option) any later version.
1219370Spst
1398944Sobrien   This program is distributed in the hope that it will be useful,
1498944Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1598944Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1698944Sobrien   GNU General Public License for more details.
1719370Spst
1898944Sobrien   You should have received a copy of the GNU General Public License
1998944Sobrien   along with this program; if not, write to the Free Software
2098944Sobrien   Foundation, Inc., 59 Temple Place - Suite 330,
2198944Sobrien   Boston, MA 02111-1307, USA.  */
2219370Spst
2319370Spst#include "defs.h"
24130803Smarcel#include "doublest.h"
25130803Smarcel#include "floatformat.h"
2619370Spst#include "frame.h"
27130803Smarcel#include "gdbcore.h"
2819370Spst#include "inferior.h"
2919370Spst#include "language.h"
30130803Smarcel#include "regcache.h"
3198944Sobrien#include "value.h"
32130803Smarcel
3398944Sobrien#include "gdb_assert.h"
34130803Smarcel#include "gdb_string.h"
3519370Spst
3698944Sobrien#include "i386-tdep.h"
37130803Smarcel#include "i387-tdep.h"
3846283Sdfr
3998944Sobrien/* Implement the `info float' layout based on the register definitions
4098944Sobrien   in `tm-i386.h'.  */
4198944Sobrien
4298944Sobrien/* Print the floating point number specified by RAW.  */
43130803Smarcel
4498944Sobrienstatic void
45130803Smarcelprint_i387_value (char *raw, struct ui_file *file)
4698944Sobrien{
4798944Sobrien  DOUBLEST value;
4898944Sobrien
4998944Sobrien  /* Using extract_typed_floating here might affect the representation
5098944Sobrien     of certain numbers such as NaNs, even if GDB is running natively.
5198944Sobrien     This is fine since our caller already detects such special
5298944Sobrien     numbers and we print the hexadecimal representation anyway.  */
5398944Sobrien  value = extract_typed_floating (raw, builtin_type_i387_ext);
5498944Sobrien
5598944Sobrien  /* We try to print 19 digits.  The last digit may or may not contain
5698944Sobrien     garbage, but we'd better print one too many.  We need enough room
5798944Sobrien     to print the value, 1 position for the sign, 1 for the decimal
5898944Sobrien     point, 19 for the digits and 6 for the exponent adds up to 27.  */
5998944Sobrien#ifdef PRINTF_HAS_LONG_DOUBLE
60130803Smarcel  fprintf_filtered (file, " %-+27.19Lg", (long double) value);
6198944Sobrien#else
62130803Smarcel  fprintf_filtered (file, " %-+27.19g", (double) value);
6398944Sobrien#endif
6498944Sobrien}
6598944Sobrien
6698944Sobrien/* Print the classification for the register contents RAW.  */
67130803Smarcel
6898944Sobrienstatic void
69130803Smarcelprint_i387_ext (unsigned char *raw, struct ui_file *file)
7098944Sobrien{
7198944Sobrien  int sign;
7298944Sobrien  int integer;
7398944Sobrien  unsigned int exponent;
7498944Sobrien  unsigned long fraction[2];
7598944Sobrien
7698944Sobrien  sign = raw[9] & 0x80;
7798944Sobrien  integer = raw[7] & 0x80;
7898944Sobrien  exponent = (((raw[9] & 0x7f) << 8) | raw[8]);
7998944Sobrien  fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]);
8098944Sobrien  fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16)
8198944Sobrien		 | (raw[5] << 8) | raw[4]);
8298944Sobrien
8398944Sobrien  if (exponent == 0x7fff && integer)
8498944Sobrien    {
8598944Sobrien      if (fraction[0] == 0x00000000 && fraction[1] == 0x00000000)
8698944Sobrien	/* Infinity.  */
87130803Smarcel	fprintf_filtered (file, " %cInf", (sign ? '-' : '+'));
8898944Sobrien      else if (sign && fraction[0] == 0x00000000 && fraction[1] == 0x40000000)
8998944Sobrien	/* Real Indefinite (QNaN).  */
90130803Smarcel	fputs_unfiltered (" Real Indefinite (QNaN)", file);
9198944Sobrien      else if (fraction[1] & 0x40000000)
9298944Sobrien	/* QNaN.  */
93130803Smarcel	fputs_filtered (" QNaN", file);
9498944Sobrien      else
9598944Sobrien	/* SNaN.  */
96130803Smarcel	fputs_filtered (" SNaN", file);
9798944Sobrien    }
9898944Sobrien  else if (exponent < 0x7fff && exponent > 0x0000 && integer)
9998944Sobrien    /* Normal.  */
100130803Smarcel    print_i387_value (raw, file);
10198944Sobrien  else if (exponent == 0x0000)
10298944Sobrien    {
10398944Sobrien      /* Denormal or zero.  */
104130803Smarcel      print_i387_value (raw, file);
10598944Sobrien
10698944Sobrien      if (integer)
10798944Sobrien	/* Pseudo-denormal.  */
108130803Smarcel	fputs_filtered (" Pseudo-denormal", file);
10998944Sobrien      else if (fraction[0] || fraction[1])
11098944Sobrien	/* Denormal.  */
111130803Smarcel	fputs_filtered (" Denormal", file);
11298944Sobrien    }
11398944Sobrien  else
11498944Sobrien    /* Unsupported.  */
115130803Smarcel    fputs_filtered (" Unsupported", file);
11698944Sobrien}
11798944Sobrien
11898944Sobrien/* Print the status word STATUS.  */
119130803Smarcel
12098944Sobrienstatic void
121130803Smarcelprint_i387_status_word (unsigned int status, struct ui_file *file)
12298944Sobrien{
123130803Smarcel  fprintf_filtered (file, "Status Word:         %s",
12498944Sobrien		   local_hex_string_custom (status, "04"));
125130803Smarcel  fputs_filtered ("  ", file);
126130803Smarcel  fprintf_filtered (file, " %s", (status & 0x0001) ? "IE" : "  ");
127130803Smarcel  fprintf_filtered (file, " %s", (status & 0x0002) ? "DE" : "  ");
128130803Smarcel  fprintf_filtered (file, " %s", (status & 0x0004) ? "ZE" : "  ");
129130803Smarcel  fprintf_filtered (file, " %s", (status & 0x0008) ? "OE" : "  ");
130130803Smarcel  fprintf_filtered (file, " %s", (status & 0x0010) ? "UE" : "  ");
131130803Smarcel  fprintf_filtered (file, " %s", (status & 0x0020) ? "PE" : "  ");
132130803Smarcel  fputs_filtered ("  ", file);
133130803Smarcel  fprintf_filtered (file, " %s", (status & 0x0080) ? "ES" : "  ");
134130803Smarcel  fputs_filtered ("  ", file);
135130803Smarcel  fprintf_filtered (file, " %s", (status & 0x0040) ? "SF" : "  ");
136130803Smarcel  fputs_filtered ("  ", file);
137130803Smarcel  fprintf_filtered (file, " %s", (status & 0x0100) ? "C0" : "  ");
138130803Smarcel  fprintf_filtered (file, " %s", (status & 0x0200) ? "C1" : "  ");
139130803Smarcel  fprintf_filtered (file, " %s", (status & 0x0400) ? "C2" : "  ");
140130803Smarcel  fprintf_filtered (file, " %s", (status & 0x4000) ? "C3" : "  ");
14198944Sobrien
142130803Smarcel  fputs_filtered ("\n", file);
14398944Sobrien
144130803Smarcel  fprintf_filtered (file,
145130803Smarcel		    "                       TOP: %d\n", ((status >> 11) & 7));
14698944Sobrien}
14798944Sobrien
14898944Sobrien/* Print the control word CONTROL.  */
149130803Smarcel
15098944Sobrienstatic void
151130803Smarcelprint_i387_control_word (unsigned int control, struct ui_file *file)
15298944Sobrien{
153130803Smarcel  fprintf_filtered (file, "Control Word:        %s",
15498944Sobrien		   local_hex_string_custom (control, "04"));
155130803Smarcel  fputs_filtered ("  ", file);
156130803Smarcel  fprintf_filtered (file, " %s", (control & 0x0001) ? "IM" : "  ");
157130803Smarcel  fprintf_filtered (file, " %s", (control & 0x0002) ? "DM" : "  ");
158130803Smarcel  fprintf_filtered (file, " %s", (control & 0x0004) ? "ZM" : "  ");
159130803Smarcel  fprintf_filtered (file, " %s", (control & 0x0008) ? "OM" : "  ");
160130803Smarcel  fprintf_filtered (file, " %s", (control & 0x0010) ? "UM" : "  ");
161130803Smarcel  fprintf_filtered (file, " %s", (control & 0x0020) ? "PM" : "  ");
16298944Sobrien
163130803Smarcel  fputs_filtered ("\n", file);
16498944Sobrien
165130803Smarcel  fputs_filtered ("                       PC: ", file);
16698944Sobrien  switch ((control >> 8) & 3)
16798944Sobrien    {
16898944Sobrien    case 0:
169130803Smarcel      fputs_filtered ("Single Precision (24-bits)\n", file);
17098944Sobrien      break;
17198944Sobrien    case 1:
172130803Smarcel      fputs_filtered ("Reserved\n", file);
17398944Sobrien      break;
17498944Sobrien    case 2:
175130803Smarcel      fputs_filtered ("Double Precision (53-bits)\n", file);
17698944Sobrien      break;
17798944Sobrien    case 3:
178130803Smarcel      fputs_filtered ("Extended Precision (64-bits)\n", file);
17998944Sobrien      break;
18098944Sobrien    }
18198944Sobrien
182130803Smarcel  fputs_filtered ("                       RC: ", file);
18398944Sobrien  switch ((control >> 10) & 3)
18498944Sobrien    {
18598944Sobrien    case 0:
186130803Smarcel      fputs_filtered ("Round to nearest\n", file);
18798944Sobrien      break;
18898944Sobrien    case 1:
189130803Smarcel      fputs_filtered ("Round down\n", file);
19098944Sobrien      break;
19198944Sobrien    case 2:
192130803Smarcel      fputs_filtered ("Round up\n", file);
19398944Sobrien      break;
19498944Sobrien    case 3:
195130803Smarcel      fputs_filtered ("Round toward zero\n", file);
19698944Sobrien      break;
19798944Sobrien    }
19898944Sobrien}
19998944Sobrien
200130803Smarcel/* Print out the i387 floating point state.  Note that we ignore FRAME
201130803Smarcel   in the code below.  That's OK since floating-point registers are
202130803Smarcel   never saved on the stack.  */
203130803Smarcel
20498944Sobrienvoid
205130803Smarceli387_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
206130803Smarcel		       struct frame_info *frame, const char *args)
20798944Sobrien{
208130803Smarcel  struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (frame));
209130803Smarcel  char buf[4];
210130803Smarcel  ULONGEST fctrl;
211130803Smarcel  ULONGEST fstat;
212130803Smarcel  ULONGEST ftag;
213130803Smarcel  ULONGEST fiseg;
214130803Smarcel  ULONGEST fioff;
215130803Smarcel  ULONGEST foseg;
216130803Smarcel  ULONGEST fooff;
217130803Smarcel  ULONGEST fop;
21898944Sobrien  int fpreg;
21998944Sobrien  int top;
22098944Sobrien
221130803Smarcel  gdb_assert (gdbarch == get_frame_arch (frame));
222130803Smarcel
223130803Smarcel  /* Define I387_ST0_REGNUM such that we use the proper definitions
224130803Smarcel     for FRAME's architecture.  */
225130803Smarcel#define I387_ST0_REGNUM tdep->st0_regnum
226130803Smarcel
227130803Smarcel  fctrl = get_frame_register_unsigned (frame, I387_FCTRL_REGNUM);
228130803Smarcel  fstat = get_frame_register_unsigned (frame, I387_FSTAT_REGNUM);
229130803Smarcel  ftag = get_frame_register_unsigned (frame, I387_FTAG_REGNUM);
230130803Smarcel  fiseg = get_frame_register_unsigned (frame, I387_FISEG_REGNUM);
231130803Smarcel  fioff = get_frame_register_unsigned (frame, I387_FIOFF_REGNUM);
232130803Smarcel  foseg = get_frame_register_unsigned (frame, I387_FOSEG_REGNUM);
233130803Smarcel  fooff = get_frame_register_unsigned (frame, I387_FOOFF_REGNUM);
234130803Smarcel  fop = get_frame_register_unsigned (frame, I387_FOP_REGNUM);
235130803Smarcel
23698944Sobrien  top = ((fstat >> 11) & 7);
23798944Sobrien
23898944Sobrien  for (fpreg = 7; fpreg >= 0; fpreg--)
23998944Sobrien    {
240130803Smarcel      unsigned char raw[I386_MAX_REGISTER_SIZE];
24198944Sobrien      int tag = (ftag >> (fpreg * 2)) & 3;
24298944Sobrien      int i;
24398944Sobrien
244130803Smarcel      fprintf_filtered (file, "%sR%d: ", fpreg == top ? "=>" : "  ", fpreg);
24598944Sobrien
24698944Sobrien      switch (tag)
24798944Sobrien	{
24898944Sobrien	case 0:
249130803Smarcel	  fputs_filtered ("Valid   ", file);
25098944Sobrien	  break;
25198944Sobrien	case 1:
252130803Smarcel	  fputs_filtered ("Zero    ", file);
25398944Sobrien	  break;
25498944Sobrien	case 2:
255130803Smarcel	  fputs_filtered ("Special ", file);
25698944Sobrien	  break;
25798944Sobrien	case 3:
258130803Smarcel	  fputs_filtered ("Empty   ", file);
25998944Sobrien	  break;
26098944Sobrien	}
26198944Sobrien
262130803Smarcel      get_frame_register (frame, (fpreg + 8 - top) % 8 + I387_ST0_REGNUM, raw);
26398944Sobrien
264130803Smarcel      fputs_filtered ("0x", file);
26598944Sobrien      for (i = 9; i >= 0; i--)
266130803Smarcel	fprintf_filtered (file, "%02x", raw[i]);
26798944Sobrien
26898944Sobrien      if (tag != 3)
269130803Smarcel	print_i387_ext (raw, file);
27098944Sobrien
271130803Smarcel      fputs_filtered ("\n", file);
27298944Sobrien    }
27398944Sobrien
274130803Smarcel  fputs_filtered ("\n", file);
27598944Sobrien
276130803Smarcel  print_i387_status_word (fstat, file);
277130803Smarcel  print_i387_control_word (fctrl, file);
278130803Smarcel  fprintf_filtered (file, "Tag Word:            %s\n",
279130803Smarcel		    local_hex_string_custom (ftag, "04"));
280130803Smarcel  fprintf_filtered (file, "Instruction Pointer: %s:",
281130803Smarcel		    local_hex_string_custom (fiseg, "02"));
282130803Smarcel  fprintf_filtered (file, "%s\n", local_hex_string_custom (fioff, "08"));
283130803Smarcel  fprintf_filtered (file, "Operand Pointer:     %s:",
284130803Smarcel		    local_hex_string_custom (foseg, "02"));
285130803Smarcel  fprintf_filtered (file, "%s\n", local_hex_string_custom (fooff, "08"));
286130803Smarcel  fprintf_filtered (file, "Opcode:              %s\n",
287130803Smarcel		    local_hex_string_custom (fop ? (fop | 0xd800) : 0, "04"));
288130803Smarcel
289130803Smarcel#undef I387_ST0_REGNUM
29098944Sobrien}
291130803Smarcel
292130803Smarcel
293130803Smarcel/* Read a value of type TYPE from register REGNUM in frame FRAME, and
294130803Smarcel   return its contents in TO.  */
295130803Smarcel
296130803Smarcelvoid
297130803Smarceli387_register_to_value (struct frame_info *frame, int regnum,
298130803Smarcel			struct type *type, void *to)
299130803Smarcel{
300130803Smarcel  char from[I386_MAX_REGISTER_SIZE];
301130803Smarcel
302130803Smarcel  gdb_assert (i386_fp_regnum_p (regnum));
303130803Smarcel
304130803Smarcel  /* We only support floating-point values.  */
305130803Smarcel  if (TYPE_CODE (type) != TYPE_CODE_FLT)
306130803Smarcel    {
307130803Smarcel      warning ("Cannot convert floating-point register value "
308130803Smarcel	       "to non-floating-point type.");
309130803Smarcel      return;
310130803Smarcel    }
311130803Smarcel
312130803Smarcel  /* Convert to TYPE.  This should be a no-op if TYPE is equivalent to
313130803Smarcel     the extended floating-point format used by the FPU.  */
314130803Smarcel  get_frame_register (frame, regnum, from);
315130803Smarcel  convert_typed_floating (from, builtin_type_i387_ext, to, type);
316130803Smarcel}
317130803Smarcel
318130803Smarcel/* Write the contents FROM of a value of type TYPE into register
319130803Smarcel   REGNUM in frame FRAME.  */
320130803Smarcel
321130803Smarcelvoid
322130803Smarceli387_value_to_register (struct frame_info *frame, int regnum,
323130803Smarcel			struct type *type, const void *from)
324130803Smarcel{
325130803Smarcel  char to[I386_MAX_REGISTER_SIZE];
326130803Smarcel
327130803Smarcel  gdb_assert (i386_fp_regnum_p (regnum));
328130803Smarcel
329130803Smarcel  /* We only support floating-point values.  */
330130803Smarcel  if (TYPE_CODE (type) != TYPE_CODE_FLT)
331130803Smarcel    {
332130803Smarcel      warning ("Cannot convert non-floating-point type "
333130803Smarcel	       "to floating-point register value.");
334130803Smarcel      return;
335130803Smarcel    }
336130803Smarcel
337130803Smarcel  /* Convert from TYPE.  This should be a no-op if TYPE is equivalent
338130803Smarcel     to the extended floating-point format used by the FPU.  */
339130803Smarcel  convert_typed_floating (from, type, to, builtin_type_i387_ext);
340130803Smarcel  put_frame_register (frame, regnum, to);
341130803Smarcel}
342130803Smarcel
343130803Smarcel
344130803Smarcel
345130803Smarcel/* Handle FSAVE and FXSAVE formats.  */
346130803Smarcel
347130803Smarcel/* FIXME: kettenis/20030927: The functions below should accept a
348130803Smarcel   `regcache' argument, but I don't want to change the function
349130803Smarcel   signature just yet.  There's some band-aid in the functions below
350130803Smarcel   in the form of the `regcache' local variables.  This will ease the
351130803Smarcel   transition later on.  */
352130803Smarcel
353130803Smarcel/* At fsave_offset[REGNUM] you'll find the offset to the location in
354130803Smarcel   the data structure used by the "fsave" instruction where GDB
355130803Smarcel   register REGNUM is stored.  */
356130803Smarcel
357130803Smarcelstatic int fsave_offset[] =
358130803Smarcel{
359130803Smarcel  28 + 0 * 10,			/* %st(0) ...  */
360130803Smarcel  28 + 1 * 10,
361130803Smarcel  28 + 2 * 10,
362130803Smarcel  28 + 3 * 10,
363130803Smarcel  28 + 4 * 10,
364130803Smarcel  28 + 5 * 10,
365130803Smarcel  28 + 6 * 10,
366130803Smarcel  28 + 7 * 10,			/* ... %st(7).  */
367130803Smarcel  0,				/* `fctrl' (16 bits).  */
368130803Smarcel  4,				/* `fstat' (16 bits).  */
369130803Smarcel  8,				/* `ftag' (16 bits).  */
370130803Smarcel  16,				/* `fiseg' (16 bits).  */
371130803Smarcel  12,				/* `fioff'.  */
372130803Smarcel  24,				/* `foseg' (16 bits).  */
373130803Smarcel  20,				/* `fooff'.  */
374130803Smarcel  18				/* `fop' (bottom 11 bits).  */
375130803Smarcel};
376130803Smarcel
377130803Smarcel#define FSAVE_ADDR(fsave, regnum) \
378130803Smarcel  (fsave + fsave_offset[regnum - I387_ST0_REGNUM])
379130803Smarcel
380130803Smarcel
381130803Smarcel/* Fill register REGNUM in REGCACHE with the appropriate value from
382130803Smarcel   *FSAVE.  This function masks off any of the reserved bits in
383130803Smarcel   *FSAVE.  */
384130803Smarcel
385130803Smarcelvoid
386130803Smarceli387_supply_fsave (struct regcache *regcache, int regnum, const void *fsave)
387130803Smarcel{
388130803Smarcel  struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
389130803Smarcel  const char *regs = fsave;
390130803Smarcel  int i;
391130803Smarcel
392130803Smarcel  gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
393130803Smarcel
394130803Smarcel  /* Define I387_ST0_REGNUM such that we use the proper definitions
395130803Smarcel     for REGCACHE's architecture.  */
396130803Smarcel#define I387_ST0_REGNUM tdep->st0_regnum
397130803Smarcel
398130803Smarcel  for (i = I387_ST0_REGNUM; i < I387_XMM0_REGNUM; i++)
399130803Smarcel    if (regnum == -1 || regnum == i)
400130803Smarcel      {
401130803Smarcel	if (fsave == NULL)
402130803Smarcel	  {
403130803Smarcel	    regcache_raw_supply (regcache, i, NULL);
404130803Smarcel	    continue;
405130803Smarcel	  }
406130803Smarcel
407130803Smarcel	/* Most of the FPU control registers occupy only 16 bits in the
408130803Smarcel	   fsave area.  Give those a special treatment.  */
409130803Smarcel	if (i >= I387_FCTRL_REGNUM
410130803Smarcel	    && i != I387_FIOFF_REGNUM && i != I387_FOOFF_REGNUM)
411130803Smarcel	  {
412130803Smarcel	    unsigned char val[4];
413130803Smarcel
414130803Smarcel	    memcpy (val, FSAVE_ADDR (regs, i), 2);
415130803Smarcel	    val[2] = val[3] = 0;
416130803Smarcel	    if (i == I387_FOP_REGNUM)
417130803Smarcel	      val[1] &= ((1 << 3) - 1);
418130803Smarcel	    regcache_raw_supply (regcache, i, val);
419130803Smarcel	  }
420130803Smarcel	else
421130803Smarcel	  regcache_raw_supply (regcache, i, FSAVE_ADDR (regs, i));
422130803Smarcel      }
423130803Smarcel#undef I387_ST0_REGNUM
424130803Smarcel}
425130803Smarcel
426130803Smarcel/* Fill register REGNUM (if it is a floating-point register) in *FSAVE
427130803Smarcel   with the value in GDB's register cache.  If REGNUM is -1, do this
428130803Smarcel   for all registers.  This function doesn't touch any of the reserved
429130803Smarcel   bits in *FSAVE.  */
430130803Smarcel
431130803Smarcelvoid
432130803Smarceli387_fill_fsave (void *fsave, int regnum)
433130803Smarcel{
434130803Smarcel  struct regcache *regcache = current_regcache;
435130803Smarcel  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
436130803Smarcel  char *regs = fsave;
437130803Smarcel  int i;
438130803Smarcel
439130803Smarcel  gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
440130803Smarcel
441130803Smarcel  /* Define I387_ST0_REGNUM such that we use the proper definitions
442130803Smarcel     for REGCACHE's architecture.  */
443130803Smarcel#define I387_ST0_REGNUM tdep->st0_regnum
444130803Smarcel
445130803Smarcel  for (i = I387_ST0_REGNUM; i < I387_XMM0_REGNUM; i++)
446130803Smarcel    if (regnum == -1 || regnum == i)
447130803Smarcel      {
448130803Smarcel	/* Most of the FPU control registers occupy only 16 bits in
449130803Smarcel           the fsave area.  Give those a special treatment.  */
450130803Smarcel	if (i >= I387_FCTRL_REGNUM
451130803Smarcel	    && i != I387_FIOFF_REGNUM && i != I387_FOOFF_REGNUM)
452130803Smarcel	  {
453130803Smarcel	    unsigned char buf[4];
454130803Smarcel
455130803Smarcel	    regcache_raw_collect (regcache, i, buf);
456130803Smarcel
457130803Smarcel	    if (i == I387_FOP_REGNUM)
458130803Smarcel	      {
459130803Smarcel		/* The opcode occupies only 11 bits.  Make sure we
460130803Smarcel                   don't touch the other bits.  */
461130803Smarcel		buf[1] &= ((1 << 3) - 1);
462130803Smarcel		buf[1] |= ((FSAVE_ADDR (regs, i))[1] & ~((1 << 3) - 1));
463130803Smarcel	      }
464130803Smarcel	    memcpy (FSAVE_ADDR (regs, i), buf, 2);
465130803Smarcel	  }
466130803Smarcel	else
467130803Smarcel	  regcache_raw_collect (regcache, i, FSAVE_ADDR (regs, i));
468130803Smarcel      }
469130803Smarcel#undef I387_ST0_REGNUM
470130803Smarcel}
471130803Smarcel
472130803Smarcel
473130803Smarcel/* At fxsave_offset[REGNUM] you'll find the offset to the location in
474130803Smarcel   the data structure used by the "fxsave" instruction where GDB
475130803Smarcel   register REGNUM is stored.  */
476130803Smarcel
477130803Smarcelstatic int fxsave_offset[] =
478130803Smarcel{
479130803Smarcel  32,				/* %st(0) through ...  */
480130803Smarcel  48,
481130803Smarcel  64,
482130803Smarcel  80,
483130803Smarcel  96,
484130803Smarcel  112,
485130803Smarcel  128,
486130803Smarcel  144,				/* ... %st(7) (80 bits each).  */
487130803Smarcel  0,				/* `fctrl' (16 bits).  */
488130803Smarcel  2,				/* `fstat' (16 bits).  */
489130803Smarcel  4,				/* `ftag' (16 bits).  */
490130803Smarcel  12,				/* `fiseg' (16 bits).  */
491130803Smarcel  8,				/* `fioff'.  */
492130803Smarcel  20,				/* `foseg' (16 bits).  */
493130803Smarcel  16,				/* `fooff'.  */
494130803Smarcel  6,				/* `fop' (bottom 11 bits).  */
495130803Smarcel  160 + 0 * 16,			/* %xmm0 through ...  */
496130803Smarcel  160 + 1 * 16,
497130803Smarcel  160 + 2 * 16,
498130803Smarcel  160 + 3 * 16,
499130803Smarcel  160 + 4 * 16,
500130803Smarcel  160 + 5 * 16,
501130803Smarcel  160 + 6 * 16,
502130803Smarcel  160 + 7 * 16,
503130803Smarcel  160 + 8 * 16,
504130803Smarcel  160 + 9 * 16,
505130803Smarcel  160 + 10 * 16,
506130803Smarcel  160 + 11 * 16,
507130803Smarcel  160 + 12 * 16,
508130803Smarcel  160 + 13 * 16,
509130803Smarcel  160 + 14 * 16,
510130803Smarcel  160 + 15 * 16,		/* ... %xmm15 (128 bits each).  */
511130803Smarcel};
512130803Smarcel
513130803Smarcel#define FXSAVE_ADDR(fxsave, regnum) \
514130803Smarcel  (fxsave + fxsave_offset[regnum - I387_ST0_REGNUM])
515130803Smarcel
516130803Smarcel/* We made an unfortunate choice in putting %mxcsr after the SSE
517130803Smarcel   registers %xmm0-%xmm7 instead of before, since it makes supporting
518130803Smarcel   the registers %xmm8-%xmm15 on AMD64 a bit involved.  Therefore we
519130803Smarcel   don't include the offset for %mxcsr here above.  */
520130803Smarcel
521130803Smarcel#define FXSAVE_MXCSR_ADDR(fxsave) (fxsave + 24)
522130803Smarcel
523130803Smarcelstatic int i387_tag (const unsigned char *raw);
524130803Smarcel
525130803Smarcel
526130803Smarcel/* Fill register REGNUM in REGCACHE with the appropriate
527130803Smarcel   floating-point or SSE register value from *FXSAVE.  This function
528130803Smarcel   masks off any of the reserved bits in *FXSAVE.  */
529130803Smarcel
530130803Smarcelvoid
531130803Smarceli387_supply_fxsave (struct regcache *regcache, int regnum, const void *fxsave)
532130803Smarcel{
533130803Smarcel  struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
534130803Smarcel  const char *regs = fxsave;
535130803Smarcel  int i;
536130803Smarcel
537130803Smarcel  gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
538130803Smarcel  gdb_assert (tdep->num_xmm_regs > 0);
539130803Smarcel
540130803Smarcel  /* Define I387_ST0_REGNUM and I387_NUM_XMM_REGS such that we use the
541130803Smarcel     proper definitions for REGCACHE's architecture.  */
542130803Smarcel
543130803Smarcel#define I387_ST0_REGNUM	tdep->st0_regnum
544130803Smarcel#define I387_NUM_XMM_REGS tdep->num_xmm_regs
545130803Smarcel
546130803Smarcel  for (i = I387_ST0_REGNUM; i < I387_MXCSR_REGNUM; i++)
547130803Smarcel    if (regnum == -1 || regnum == i)
548130803Smarcel      {
549130803Smarcel	if (regs == NULL)
550130803Smarcel	  {
551130803Smarcel	    regcache_raw_supply (regcache, i, NULL);
552130803Smarcel	    continue;
553130803Smarcel	  }
554130803Smarcel
555130803Smarcel	/* Most of the FPU control registers occupy only 16 bits in
556130803Smarcel	   the fxsave area.  Give those a special treatment.  */
557130803Smarcel	if (i >= I387_FCTRL_REGNUM && i < I387_XMM0_REGNUM
558130803Smarcel	    && i != I387_FIOFF_REGNUM && i != I387_FOOFF_REGNUM)
559130803Smarcel	  {
560130803Smarcel	    unsigned char val[4];
561130803Smarcel
562130803Smarcel	    memcpy (val, FXSAVE_ADDR (regs, i), 2);
563130803Smarcel	    val[2] = val[3] = 0;
564130803Smarcel	    if (i == I387_FOP_REGNUM)
565130803Smarcel	      val[1] &= ((1 << 3) - 1);
566130803Smarcel	    else if (i== I387_FTAG_REGNUM)
567130803Smarcel	      {
568130803Smarcel		/* The fxsave area contains a simplified version of
569130803Smarcel		   the tag word.  We have to look at the actual 80-bit
570130803Smarcel		   FP data to recreate the traditional i387 tag word.  */
571130803Smarcel
572130803Smarcel		unsigned long ftag = 0;
573130803Smarcel		int fpreg;
574130803Smarcel		int top;
575130803Smarcel
576130803Smarcel		top = ((FXSAVE_ADDR (regs, I387_FSTAT_REGNUM))[1] >> 3);
577130803Smarcel		top &= 0x7;
578130803Smarcel
579130803Smarcel		for (fpreg = 7; fpreg >= 0; fpreg--)
580130803Smarcel		  {
581130803Smarcel		    int tag;
582130803Smarcel
583130803Smarcel		    if (val[0] & (1 << fpreg))
584130803Smarcel		      {
585130803Smarcel			int regnum = (fpreg + 8 - top) % 8 + I387_ST0_REGNUM;
586130803Smarcel			tag = i387_tag (FXSAVE_ADDR (regs, regnum));
587130803Smarcel		      }
588130803Smarcel		    else
589130803Smarcel		      tag = 3;		/* Empty */
590130803Smarcel
591130803Smarcel		    ftag |= tag << (2 * fpreg);
592130803Smarcel		  }
593130803Smarcel		val[0] = ftag & 0xff;
594130803Smarcel		val[1] = (ftag >> 8) & 0xff;
595130803Smarcel	      }
596130803Smarcel	    regcache_raw_supply (regcache, i, val);
597130803Smarcel	  }
598130803Smarcel	else
599130803Smarcel	  regcache_raw_supply (regcache, i, FXSAVE_ADDR (regs, i));
600130803Smarcel      }
601130803Smarcel
602130803Smarcel  if (regnum == I387_MXCSR_REGNUM || regnum == -1)
603130803Smarcel    {
604130803Smarcel      if (regs == NULL)
605130803Smarcel	regcache_raw_supply (regcache, I387_MXCSR_REGNUM, NULL);
606130803Smarcel      else
607130803Smarcel	regcache_raw_supply (regcache, I387_MXCSR_REGNUM,
608130803Smarcel			     FXSAVE_MXCSR_ADDR (regs));
609130803Smarcel    }
610130803Smarcel
611130803Smarcel#undef I387_ST0_REGNUM
612130803Smarcel#undef I387_NUM_XMM_REGS
613130803Smarcel}
614130803Smarcel
615130803Smarcel/* Fill register REGNUM (if it is a floating-point or SSE register) in
616130803Smarcel   *FXSAVE with the value from REGCACHE.  If REGNUM is -1, do this for
617130803Smarcel   all registers.  This function doesn't touch any of the reserved
618130803Smarcel   bits in *FXSAVE.  */
619130803Smarcel
620130803Smarcelvoid
621130803Smarceli387_collect_fxsave (const struct regcache *regcache, int regnum, void *fxsave)
622130803Smarcel{
623130803Smarcel  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
624130803Smarcel  char *regs = fxsave;
625130803Smarcel  int i;
626130803Smarcel
627130803Smarcel  gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
628130803Smarcel  gdb_assert (tdep->num_xmm_regs > 0);
629130803Smarcel
630130803Smarcel  /* Define I387_ST0_REGNUM and I387_NUM_XMM_REGS such that we use the
631130803Smarcel     proper definitions for REGCACHE's architecture.  */
632130803Smarcel
633130803Smarcel#define I387_ST0_REGNUM	tdep->st0_regnum
634130803Smarcel#define I387_NUM_XMM_REGS tdep->num_xmm_regs
635130803Smarcel
636130803Smarcel  for (i = I387_ST0_REGNUM; i < I387_MXCSR_REGNUM; i++)
637130803Smarcel    if (regnum == -1 || regnum == i)
638130803Smarcel      {
639130803Smarcel	/* Most of the FPU control registers occupy only 16 bits in
640130803Smarcel           the fxsave area.  Give those a special treatment.  */
641130803Smarcel	if (i >= I387_FCTRL_REGNUM && i < I387_XMM0_REGNUM
642130803Smarcel	    && i != I387_FIOFF_REGNUM && i != I387_FOOFF_REGNUM)
643130803Smarcel	  {
644130803Smarcel	    unsigned char buf[4];
645130803Smarcel
646130803Smarcel	    regcache_raw_collect (regcache, i, buf);
647130803Smarcel
648130803Smarcel	    if (i == I387_FOP_REGNUM)
649130803Smarcel	      {
650130803Smarcel		/* The opcode occupies only 11 bits.  Make sure we
651130803Smarcel                   don't touch the other bits.  */
652130803Smarcel		buf[1] &= ((1 << 3) - 1);
653130803Smarcel		buf[1] |= ((FXSAVE_ADDR (regs, i))[1] & ~((1 << 3) - 1));
654130803Smarcel	      }
655130803Smarcel	    else if (i == I387_FTAG_REGNUM)
656130803Smarcel	      {
657130803Smarcel		/* Converting back is much easier.  */
658130803Smarcel
659130803Smarcel		unsigned short ftag;
660130803Smarcel		int fpreg;
661130803Smarcel
662130803Smarcel		ftag = (buf[1] << 8) | buf[0];
663130803Smarcel		buf[0] = 0;
664130803Smarcel		buf[1] = 0;
665130803Smarcel
666130803Smarcel		for (fpreg = 7; fpreg >= 0; fpreg--)
667130803Smarcel		  {
668130803Smarcel		    int tag = (ftag >> (fpreg * 2)) & 3;
669130803Smarcel
670130803Smarcel		    if (tag != 3)
671130803Smarcel		      buf[0] |= (1 << fpreg);
672130803Smarcel		  }
673130803Smarcel	      }
674130803Smarcel	    memcpy (FXSAVE_ADDR (regs, i), buf, 2);
675130803Smarcel	  }
676130803Smarcel	else
677130803Smarcel	  regcache_raw_collect (regcache, i, FXSAVE_ADDR (regs, i));
678130803Smarcel      }
679130803Smarcel
680130803Smarcel  if (regnum == I387_MXCSR_REGNUM || regnum == -1)
681130803Smarcel    regcache_raw_collect (regcache, I387_MXCSR_REGNUM,
682130803Smarcel			  FXSAVE_MXCSR_ADDR (regs));
683130803Smarcel
684130803Smarcel#undef I387_ST0_REGNUM
685130803Smarcel#undef I387_NUM_XMM_REGS
686130803Smarcel}
687130803Smarcel
688130803Smarcel/* Fill register REGNUM (if it is a floating-point or SSE register) in
689130803Smarcel   *FXSAVE with the value in GDB's register cache.  If REGNUM is -1, do
690130803Smarcel   this for all registers.  This function doesn't touch any of the
691130803Smarcel   reserved bits in *FXSAVE.  */
692130803Smarcel
693130803Smarcelvoid
694130803Smarceli387_fill_fxsave (void *fxsave, int regnum)
695130803Smarcel{
696130803Smarcel  i387_collect_fxsave (current_regcache, regnum, fxsave);
697130803Smarcel}
698130803Smarcel
699130803Smarcel/* Recreate the FTW (tag word) valid bits from the 80-bit FP data in
700130803Smarcel   *RAW.  */
701130803Smarcel
702130803Smarcelstatic int
703130803Smarceli387_tag (const unsigned char *raw)
704130803Smarcel{
705130803Smarcel  int integer;
706130803Smarcel  unsigned int exponent;
707130803Smarcel  unsigned long fraction[2];
708130803Smarcel
709130803Smarcel  integer = raw[7] & 0x80;
710130803Smarcel  exponent = (((raw[9] & 0x7f) << 8) | raw[8]);
711130803Smarcel  fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]);
712130803Smarcel  fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16)
713130803Smarcel		 | (raw[5] << 8) | raw[4]);
714130803Smarcel
715130803Smarcel  if (exponent == 0x7fff)
716130803Smarcel    {
717130803Smarcel      /* Special.  */
718130803Smarcel      return (2);
719130803Smarcel    }
720130803Smarcel  else if (exponent == 0x0000)
721130803Smarcel    {
722130803Smarcel      if (fraction[0] == 0x0000 && fraction[1] == 0x0000 && !integer)
723130803Smarcel	{
724130803Smarcel	  /* Zero.  */
725130803Smarcel	  return (1);
726130803Smarcel	}
727130803Smarcel      else
728130803Smarcel	{
729130803Smarcel	  /* Special.  */
730130803Smarcel	  return (2);
731130803Smarcel	}
732130803Smarcel    }
733130803Smarcel  else
734130803Smarcel    {
735130803Smarcel      if (integer)
736130803Smarcel	{
737130803Smarcel	  /* Valid.  */
738130803Smarcel	  return (0);
739130803Smarcel	}
740130803Smarcel      else
741130803Smarcel	{
742130803Smarcel	  /* Special.  */
743130803Smarcel	  return (2);
744130803Smarcel	}
745130803Smarcel    }
746130803Smarcel}
747130803Smarcel
748130803Smarcel/* Prepare the FPU stack in REGCACHE for a function return.  */
749130803Smarcel
750130803Smarcelvoid
751130803Smarceli387_return_value (struct gdbarch *gdbarch, struct regcache *regcache)
752130803Smarcel{
753130803Smarcel  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
754130803Smarcel  ULONGEST fstat;
755130803Smarcel
756130803Smarcel  /* Define I387_ST0_REGNUM such that we use the proper
757130803Smarcel     definitions for the architecture.  */
758130803Smarcel#define I387_ST0_REGNUM tdep->st0_regnum
759130803Smarcel
760130803Smarcel  /* Set the top of the floating-point register stack to 7.  The
761130803Smarcel     actual value doesn't really matter, but 7 is what a normal
762130803Smarcel     function return would end up with if the program started out with
763130803Smarcel     a freshly initialized FPU.  */
764130803Smarcel  regcache_raw_read_unsigned (regcache, I387_FSTAT_REGNUM, &fstat);
765130803Smarcel  fstat |= (7 << 11);
766130803Smarcel  regcache_raw_write_unsigned (regcache, I387_FSTAT_REGNUM, fstat);
767130803Smarcel
768130803Smarcel  /* Mark %st(1) through %st(7) as empty.  Since we set the top of the
769130803Smarcel     floating-point register stack to 7, the appropriate value for the
770130803Smarcel     tag word is 0x3fff.  */
771130803Smarcel  regcache_raw_write_unsigned (regcache, I387_FTAG_REGNUM, 0x3fff);
772130803Smarcel
773130803Smarcel#undef I387_ST0_REGNUM
774130803Smarcel}
775