xref: /openbsd-src/gnu/usr.bin/binutils/gdb/i387-tdep.c (revision 63addd46c1e40ca0f49488ddcdc4ab598023b0c1)
1e93f7393Sniklas /* Intel 387 floating point stuff.
2b725ae77Skettenis 
3b725ae77Skettenis    Copyright 1988, 1989, 1991, 1992, 1993, 1994, 1998, 1999, 2000,
4b725ae77Skettenis    2001, 2002, 2003, 2004 Free Software Foundation, Inc.
5e93f7393Sniklas 
6e93f7393Sniklas    This file is part of GDB.
7e93f7393Sniklas 
8e93f7393Sniklas    This program is free software; you can redistribute it and/or modify
9e93f7393Sniklas    it under the terms of the GNU General Public License as published by
10e93f7393Sniklas    the Free Software Foundation; either version 2 of the License, or
11e93f7393Sniklas    (at your option) any later version.
12e93f7393Sniklas 
13e93f7393Sniklas    This program is distributed in the hope that it will be useful,
14e93f7393Sniklas    but WITHOUT ANY WARRANTY; without even the implied warranty of
15e93f7393Sniklas    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16e93f7393Sniklas    GNU General Public License for more details.
17e93f7393Sniklas 
18e93f7393Sniklas    You should have received a copy of the GNU General Public License
19e93f7393Sniklas    along with this program; if not, write to the Free Software
20b725ae77Skettenis    Foundation, Inc., 59 Temple Place - Suite 330,
21b725ae77Skettenis    Boston, MA 02111-1307, USA.  */
22e93f7393Sniklas 
23e93f7393Sniklas #include "defs.h"
24b725ae77Skettenis #include "doublest.h"
25b725ae77Skettenis #include "floatformat.h"
26e93f7393Sniklas #include "frame.h"
27b725ae77Skettenis #include "gdbcore.h"
28e93f7393Sniklas #include "inferior.h"
29e93f7393Sniklas #include "language.h"
30b725ae77Skettenis #include "regcache.h"
31b725ae77Skettenis #include "value.h"
32e93f7393Sniklas 
33b725ae77Skettenis #include "gdb_assert.h"
34b725ae77Skettenis #include "gdb_string.h"
35e93f7393Sniklas 
36b725ae77Skettenis #include "i386-tdep.h"
37b725ae77Skettenis #include "i387-tdep.h"
38b725ae77Skettenis 
39b725ae77Skettenis /* Implement the `info float' layout based on the register definitions
40b725ae77Skettenis    in `tm-i386.h'.  */
41b725ae77Skettenis 
42b725ae77Skettenis /* Print the floating point number specified by RAW.  */
43b725ae77Skettenis 
44b725ae77Skettenis static void
print_i387_value(char * raw,struct ui_file * file)45b725ae77Skettenis print_i387_value (char *raw, struct ui_file *file)
46e93f7393Sniklas {
47b725ae77Skettenis   DOUBLEST value;
48b725ae77Skettenis 
49b725ae77Skettenis   /* Using extract_typed_floating here might affect the representation
50b725ae77Skettenis      of certain numbers such as NaNs, even if GDB is running natively.
51b725ae77Skettenis      This is fine since our caller already detects such special
52b725ae77Skettenis      numbers and we print the hexadecimal representation anyway.  */
53b725ae77Skettenis   value = extract_typed_floating (raw, builtin_type_i387_ext);
54b725ae77Skettenis 
55b725ae77Skettenis   /* We try to print 19 digits.  The last digit may or may not contain
56b725ae77Skettenis      garbage, but we'd better print one too many.  We need enough room
57b725ae77Skettenis      to print the value, 1 position for the sign, 1 for the decimal
58b725ae77Skettenis      point, 19 for the digits and 6 for the exponent adds up to 27.  */
59b725ae77Skettenis #ifdef PRINTF_HAS_LONG_DOUBLE
60b725ae77Skettenis   fprintf_filtered (file, " %-+27.19Lg", (long double) value);
61b725ae77Skettenis #else
62b725ae77Skettenis   fprintf_filtered (file, " %-+27.19g", (double) value);
63b725ae77Skettenis #endif
64e93f7393Sniklas }
65e93f7393Sniklas 
66b725ae77Skettenis /* Print the classification for the register contents RAW.  */
67b725ae77Skettenis 
68b725ae77Skettenis static void
print_i387_ext(unsigned char * raw,struct ui_file * file)69b725ae77Skettenis print_i387_ext (unsigned char *raw, struct ui_file *file)
70e93f7393Sniklas {
71b725ae77Skettenis   int sign;
72b725ae77Skettenis   int integer;
73b725ae77Skettenis   unsigned int exponent;
74b725ae77Skettenis   unsigned long fraction[2];
75b725ae77Skettenis 
76b725ae77Skettenis   sign = raw[9] & 0x80;
77b725ae77Skettenis   integer = raw[7] & 0x80;
78b725ae77Skettenis   exponent = (((raw[9] & 0x7f) << 8) | raw[8]);
79b725ae77Skettenis   fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]);
80b725ae77Skettenis   fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16)
81b725ae77Skettenis 		 | (raw[5] << 8) | raw[4]);
82b725ae77Skettenis 
83b725ae77Skettenis   if (exponent == 0x7fff && integer)
84b725ae77Skettenis     {
85b725ae77Skettenis       if (fraction[0] == 0x00000000 && fraction[1] == 0x00000000)
86b725ae77Skettenis 	/* Infinity.  */
87b725ae77Skettenis 	fprintf_filtered (file, " %cInf", (sign ? '-' : '+'));
88b725ae77Skettenis       else if (sign && fraction[0] == 0x00000000 && fraction[1] == 0x40000000)
89b725ae77Skettenis 	/* Real Indefinite (QNaN).  */
90b725ae77Skettenis 	fputs_unfiltered (" Real Indefinite (QNaN)", file);
91b725ae77Skettenis       else if (fraction[1] & 0x40000000)
92b725ae77Skettenis 	/* QNaN.  */
93b725ae77Skettenis 	fputs_filtered (" QNaN", file);
94b725ae77Skettenis       else
95b725ae77Skettenis 	/* SNaN.  */
96b725ae77Skettenis 	fputs_filtered (" SNaN", file);
97b725ae77Skettenis     }
98b725ae77Skettenis   else if (exponent < 0x7fff && exponent > 0x0000 && integer)
99b725ae77Skettenis     /* Normal.  */
100b725ae77Skettenis     print_i387_value (raw, file);
101b725ae77Skettenis   else if (exponent == 0x0000)
102b725ae77Skettenis     {
103b725ae77Skettenis       /* Denormal or zero.  */
104b725ae77Skettenis       print_i387_value (raw, file);
105b725ae77Skettenis 
106b725ae77Skettenis       if (integer)
107b725ae77Skettenis 	/* Pseudo-denormal.  */
108b725ae77Skettenis 	fputs_filtered (" Pseudo-denormal", file);
109b725ae77Skettenis       else if (fraction[0] || fraction[1])
110b725ae77Skettenis 	/* Denormal.  */
111b725ae77Skettenis 	fputs_filtered (" Denormal", file);
112b725ae77Skettenis     }
113b725ae77Skettenis   else
114b725ae77Skettenis     /* Unsupported.  */
115b725ae77Skettenis     fputs_filtered (" Unsupported", file);
116e93f7393Sniklas }
117e93f7393Sniklas 
118b725ae77Skettenis /* Print the status word STATUS.  */
119b725ae77Skettenis 
120b725ae77Skettenis static void
print_i387_status_word(unsigned int status,struct ui_file * file)121b725ae77Skettenis print_i387_status_word (unsigned int status, struct ui_file *file)
122e93f7393Sniklas {
123b725ae77Skettenis   fprintf_filtered (file, "Status Word:         %s",
124*63addd46Skettenis 		    hex_string_custom (status, 4));
125b725ae77Skettenis   fputs_filtered ("  ", file);
126b725ae77Skettenis   fprintf_filtered (file, " %s", (status & 0x0001) ? "IE" : "  ");
127b725ae77Skettenis   fprintf_filtered (file, " %s", (status & 0x0002) ? "DE" : "  ");
128b725ae77Skettenis   fprintf_filtered (file, " %s", (status & 0x0004) ? "ZE" : "  ");
129b725ae77Skettenis   fprintf_filtered (file, " %s", (status & 0x0008) ? "OE" : "  ");
130b725ae77Skettenis   fprintf_filtered (file, " %s", (status & 0x0010) ? "UE" : "  ");
131b725ae77Skettenis   fprintf_filtered (file, " %s", (status & 0x0020) ? "PE" : "  ");
132b725ae77Skettenis   fputs_filtered ("  ", file);
133b725ae77Skettenis   fprintf_filtered (file, " %s", (status & 0x0080) ? "ES" : "  ");
134b725ae77Skettenis   fputs_filtered ("  ", file);
135b725ae77Skettenis   fprintf_filtered (file, " %s", (status & 0x0040) ? "SF" : "  ");
136b725ae77Skettenis   fputs_filtered ("  ", file);
137b725ae77Skettenis   fprintf_filtered (file, " %s", (status & 0x0100) ? "C0" : "  ");
138b725ae77Skettenis   fprintf_filtered (file, " %s", (status & 0x0200) ? "C1" : "  ");
139b725ae77Skettenis   fprintf_filtered (file, " %s", (status & 0x0400) ? "C2" : "  ");
140b725ae77Skettenis   fprintf_filtered (file, " %s", (status & 0x4000) ? "C3" : "  ");
141b725ae77Skettenis 
142b725ae77Skettenis   fputs_filtered ("\n", file);
143b725ae77Skettenis 
144b725ae77Skettenis   fprintf_filtered (file,
145b725ae77Skettenis 		    "                       TOP: %d\n", ((status >> 11) & 7));
146b725ae77Skettenis }
147b725ae77Skettenis 
148b725ae77Skettenis /* Print the control word CONTROL.  */
149b725ae77Skettenis 
150b725ae77Skettenis static void
print_i387_control_word(unsigned int control,struct ui_file * file)151b725ae77Skettenis print_i387_control_word (unsigned int control, struct ui_file *file)
152b725ae77Skettenis {
153b725ae77Skettenis   fprintf_filtered (file, "Control Word:        %s",
154*63addd46Skettenis 		    hex_string_custom (control, 4));
155b725ae77Skettenis   fputs_filtered ("  ", file);
156b725ae77Skettenis   fprintf_filtered (file, " %s", (control & 0x0001) ? "IM" : "  ");
157b725ae77Skettenis   fprintf_filtered (file, " %s", (control & 0x0002) ? "DM" : "  ");
158b725ae77Skettenis   fprintf_filtered (file, " %s", (control & 0x0004) ? "ZM" : "  ");
159b725ae77Skettenis   fprintf_filtered (file, " %s", (control & 0x0008) ? "OM" : "  ");
160b725ae77Skettenis   fprintf_filtered (file, " %s", (control & 0x0010) ? "UM" : "  ");
161b725ae77Skettenis   fprintf_filtered (file, " %s", (control & 0x0020) ? "PM" : "  ");
162b725ae77Skettenis 
163b725ae77Skettenis   fputs_filtered ("\n", file);
164b725ae77Skettenis 
165b725ae77Skettenis   fputs_filtered ("                       PC: ", file);
166e93f7393Sniklas   switch ((control >> 8) & 3)
167e93f7393Sniklas     {
168b725ae77Skettenis     case 0:
169b725ae77Skettenis       fputs_filtered ("Single Precision (24-bits)\n", file);
170b725ae77Skettenis       break;
171b725ae77Skettenis     case 1:
172b725ae77Skettenis       fputs_filtered ("Reserved\n", file);
173b725ae77Skettenis       break;
174b725ae77Skettenis     case 2:
175b725ae77Skettenis       fputs_filtered ("Double Precision (53-bits)\n", file);
176b725ae77Skettenis       break;
177b725ae77Skettenis     case 3:
178b725ae77Skettenis       fputs_filtered ("Extended Precision (64-bits)\n", file);
179b725ae77Skettenis       break;
180e93f7393Sniklas     }
181b725ae77Skettenis 
182b725ae77Skettenis   fputs_filtered ("                       RC: ", file);
183e93f7393Sniklas   switch ((control >> 10) & 3)
184e93f7393Sniklas     {
185b725ae77Skettenis     case 0:
186b725ae77Skettenis       fputs_filtered ("Round to nearest\n", file);
187b725ae77Skettenis       break;
188b725ae77Skettenis     case 1:
189b725ae77Skettenis       fputs_filtered ("Round down\n", file);
190b725ae77Skettenis       break;
191b725ae77Skettenis     case 2:
192b725ae77Skettenis       fputs_filtered ("Round up\n", file);
193b725ae77Skettenis       break;
194b725ae77Skettenis     case 3:
195b725ae77Skettenis       fputs_filtered ("Round toward zero\n", file);
196b725ae77Skettenis       break;
197e93f7393Sniklas     }
198e93f7393Sniklas }
199b725ae77Skettenis 
200b725ae77Skettenis /* Print out the i387 floating point state.  Note that we ignore FRAME
201b725ae77Skettenis    in the code below.  That's OK since floating-point registers are
202b725ae77Skettenis    never saved on the stack.  */
203e93f7393Sniklas 
204e93f7393Sniklas void
i387_print_float_info(struct gdbarch * gdbarch,struct ui_file * file,struct frame_info * frame,const char * args)205b725ae77Skettenis i387_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
206b725ae77Skettenis 		       struct frame_info *frame, const char *args)
207e93f7393Sniklas {
208b725ae77Skettenis   struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (frame));
209b725ae77Skettenis   char buf[4];
210b725ae77Skettenis   ULONGEST fctrl;
211b725ae77Skettenis   ULONGEST fstat;
212b725ae77Skettenis   ULONGEST ftag;
213b725ae77Skettenis   ULONGEST fiseg;
214b725ae77Skettenis   ULONGEST fioff;
215b725ae77Skettenis   ULONGEST foseg;
216b725ae77Skettenis   ULONGEST fooff;
217b725ae77Skettenis   ULONGEST fop;
218b725ae77Skettenis   int fpreg;
219b725ae77Skettenis   int top;
220e93f7393Sniklas 
221b725ae77Skettenis   gdb_assert (gdbarch == get_frame_arch (frame));
222b725ae77Skettenis 
223b725ae77Skettenis   /* Define I387_ST0_REGNUM such that we use the proper definitions
224b725ae77Skettenis      for FRAME's architecture.  */
225b725ae77Skettenis #define I387_ST0_REGNUM tdep->st0_regnum
226b725ae77Skettenis 
227b725ae77Skettenis   fctrl = get_frame_register_unsigned (frame, I387_FCTRL_REGNUM);
228b725ae77Skettenis   fstat = get_frame_register_unsigned (frame, I387_FSTAT_REGNUM);
229b725ae77Skettenis   ftag = get_frame_register_unsigned (frame, I387_FTAG_REGNUM);
230b725ae77Skettenis   fiseg = get_frame_register_unsigned (frame, I387_FISEG_REGNUM);
231b725ae77Skettenis   fioff = get_frame_register_unsigned (frame, I387_FIOFF_REGNUM);
232b725ae77Skettenis   foseg = get_frame_register_unsigned (frame, I387_FOSEG_REGNUM);
233b725ae77Skettenis   fooff = get_frame_register_unsigned (frame, I387_FOOFF_REGNUM);
234b725ae77Skettenis   fop = get_frame_register_unsigned (frame, I387_FOP_REGNUM);
235b725ae77Skettenis 
236b725ae77Skettenis   top = ((fstat >> 11) & 7);
237b725ae77Skettenis 
238b725ae77Skettenis   for (fpreg = 7; fpreg >= 0; fpreg--)
239b725ae77Skettenis     {
240b725ae77Skettenis       unsigned char raw[I386_MAX_REGISTER_SIZE];
241b725ae77Skettenis       int tag = (ftag >> (fpreg * 2)) & 3;
242b725ae77Skettenis       int i;
243b725ae77Skettenis 
244b725ae77Skettenis       fprintf_filtered (file, "%sR%d: ", fpreg == top ? "=>" : "  ", fpreg);
245b725ae77Skettenis 
246b725ae77Skettenis       switch (tag)
247b725ae77Skettenis 	{
248b725ae77Skettenis 	case 0:
249b725ae77Skettenis 	  fputs_filtered ("Valid   ", file);
250b725ae77Skettenis 	  break;
251b725ae77Skettenis 	case 1:
252b725ae77Skettenis 	  fputs_filtered ("Zero    ", file);
253b725ae77Skettenis 	  break;
254b725ae77Skettenis 	case 2:
255b725ae77Skettenis 	  fputs_filtered ("Special ", file);
256b725ae77Skettenis 	  break;
257b725ae77Skettenis 	case 3:
258b725ae77Skettenis 	  fputs_filtered ("Empty   ", file);
259b725ae77Skettenis 	  break;
260b725ae77Skettenis 	}
261b725ae77Skettenis 
262b725ae77Skettenis       get_frame_register (frame, (fpreg + 8 - top) % 8 + I387_ST0_REGNUM, raw);
263b725ae77Skettenis 
264b725ae77Skettenis       fputs_filtered ("0x", file);
265b725ae77Skettenis       for (i = 9; i >= 0; i--)
266b725ae77Skettenis 	fprintf_filtered (file, "%02x", raw[i]);
267b725ae77Skettenis 
268b725ae77Skettenis       if (tag != 3)
269b725ae77Skettenis 	print_i387_ext (raw, file);
270b725ae77Skettenis 
271b725ae77Skettenis       fputs_filtered ("\n", file);
272b725ae77Skettenis     }
273b725ae77Skettenis 
274b725ae77Skettenis   fputs_filtered ("\n", file);
275b725ae77Skettenis 
276b725ae77Skettenis   print_i387_status_word (fstat, file);
277b725ae77Skettenis   print_i387_control_word (fctrl, file);
278b725ae77Skettenis   fprintf_filtered (file, "Tag Word:            %s\n",
279*63addd46Skettenis 		    hex_string_custom (ftag, 4));
280b725ae77Skettenis   fprintf_filtered (file, "Instruction Pointer: %s:",
281*63addd46Skettenis 		    hex_string_custom (fiseg, 2));
282*63addd46Skettenis   fprintf_filtered (file, "%s\n", hex_string_custom (fioff, 8));
283b725ae77Skettenis   fprintf_filtered (file, "Operand Pointer:     %s:",
284*63addd46Skettenis 		    hex_string_custom (foseg, 2));
285*63addd46Skettenis   fprintf_filtered (file, "%s\n", hex_string_custom (fooff, 8));
286b725ae77Skettenis   fprintf_filtered (file, "Opcode:              %s\n",
287*63addd46Skettenis 		    hex_string_custom (fop ? (fop | 0xd800) : 0, 4));
288b725ae77Skettenis 
289b725ae77Skettenis #undef I387_ST0_REGNUM
290b725ae77Skettenis }
291b725ae77Skettenis 
292b725ae77Skettenis 
293b725ae77Skettenis /* Read a value of type TYPE from register REGNUM in frame FRAME, and
294b725ae77Skettenis    return its contents in TO.  */
295b725ae77Skettenis 
296b725ae77Skettenis void
i387_register_to_value(struct frame_info * frame,int regnum,struct type * type,void * to)297b725ae77Skettenis i387_register_to_value (struct frame_info *frame, int regnum,
298b725ae77Skettenis 			struct type *type, void *to)
299b725ae77Skettenis {
300b725ae77Skettenis   char from[I386_MAX_REGISTER_SIZE];
301b725ae77Skettenis 
302b725ae77Skettenis   gdb_assert (i386_fp_regnum_p (regnum));
303b725ae77Skettenis 
304b725ae77Skettenis   /* We only support floating-point values.  */
305b725ae77Skettenis   if (TYPE_CODE (type) != TYPE_CODE_FLT)
306b725ae77Skettenis     {
307b725ae77Skettenis       warning ("Cannot convert floating-point register value "
308b725ae77Skettenis 	       "to non-floating-point type.");
309b725ae77Skettenis       return;
310b725ae77Skettenis     }
311b725ae77Skettenis 
312b725ae77Skettenis   /* Convert to TYPE.  This should be a no-op if TYPE is equivalent to
313b725ae77Skettenis      the extended floating-point format used by the FPU.  */
314b725ae77Skettenis   get_frame_register (frame, regnum, from);
315b725ae77Skettenis   convert_typed_floating (from, builtin_type_i387_ext, to, type);
316b725ae77Skettenis }
317b725ae77Skettenis 
318b725ae77Skettenis /* Write the contents FROM of a value of type TYPE into register
319b725ae77Skettenis    REGNUM in frame FRAME.  */
320b725ae77Skettenis 
321b725ae77Skettenis void
i387_value_to_register(struct frame_info * frame,int regnum,struct type * type,const void * from)322b725ae77Skettenis i387_value_to_register (struct frame_info *frame, int regnum,
323b725ae77Skettenis 			struct type *type, const void *from)
324b725ae77Skettenis {
325b725ae77Skettenis   char to[I386_MAX_REGISTER_SIZE];
326b725ae77Skettenis 
327b725ae77Skettenis   gdb_assert (i386_fp_regnum_p (regnum));
328b725ae77Skettenis 
329b725ae77Skettenis   /* We only support floating-point values.  */
330b725ae77Skettenis   if (TYPE_CODE (type) != TYPE_CODE_FLT)
331b725ae77Skettenis     {
332b725ae77Skettenis       warning ("Cannot convert non-floating-point type "
333b725ae77Skettenis 	       "to floating-point register value.");
334b725ae77Skettenis       return;
335b725ae77Skettenis     }
336b725ae77Skettenis 
337b725ae77Skettenis   /* Convert from TYPE.  This should be a no-op if TYPE is equivalent
338b725ae77Skettenis      to the extended floating-point format used by the FPU.  */
339b725ae77Skettenis   convert_typed_floating (from, type, to, builtin_type_i387_ext);
340b725ae77Skettenis   put_frame_register (frame, regnum, to);
341b725ae77Skettenis }
342b725ae77Skettenis 
343b725ae77Skettenis 
344b725ae77Skettenis /* Handle FSAVE and FXSAVE formats.  */
345b725ae77Skettenis 
346b725ae77Skettenis /* FIXME: kettenis/20030927: The functions below should accept a
347b725ae77Skettenis    `regcache' argument, but I don't want to change the function
348b725ae77Skettenis    signature just yet.  There's some band-aid in the functions below
349b725ae77Skettenis    in the form of the `regcache' local variables.  This will ease the
350b725ae77Skettenis    transition later on.  */
351b725ae77Skettenis 
352b725ae77Skettenis /* At fsave_offset[REGNUM] you'll find the offset to the location in
353b725ae77Skettenis    the data structure used by the "fsave" instruction where GDB
354b725ae77Skettenis    register REGNUM is stored.  */
355b725ae77Skettenis 
356b725ae77Skettenis static int fsave_offset[] =
357b725ae77Skettenis {
358b725ae77Skettenis   28 + 0 * 10,			/* %st(0) ...  */
359b725ae77Skettenis   28 + 1 * 10,
360b725ae77Skettenis   28 + 2 * 10,
361b725ae77Skettenis   28 + 3 * 10,
362b725ae77Skettenis   28 + 4 * 10,
363b725ae77Skettenis   28 + 5 * 10,
364b725ae77Skettenis   28 + 6 * 10,
365b725ae77Skettenis   28 + 7 * 10,			/* ... %st(7).  */
366b725ae77Skettenis   0,				/* `fctrl' (16 bits).  */
367b725ae77Skettenis   4,				/* `fstat' (16 bits).  */
368b725ae77Skettenis   8,				/* `ftag' (16 bits).  */
369b725ae77Skettenis   16,				/* `fiseg' (16 bits).  */
370b725ae77Skettenis   12,				/* `fioff'.  */
371b725ae77Skettenis   24,				/* `foseg' (16 bits).  */
372b725ae77Skettenis   20,				/* `fooff'.  */
373b725ae77Skettenis   18				/* `fop' (bottom 11 bits).  */
374b725ae77Skettenis };
375b725ae77Skettenis 
376b725ae77Skettenis #define FSAVE_ADDR(fsave, regnum) \
377b725ae77Skettenis   (fsave + fsave_offset[regnum - I387_ST0_REGNUM])
378b725ae77Skettenis 
379b725ae77Skettenis 
380b725ae77Skettenis /* Fill register REGNUM in REGCACHE with the appropriate value from
381b725ae77Skettenis    *FSAVE.  This function masks off any of the reserved bits in
382b725ae77Skettenis    *FSAVE.  */
383b725ae77Skettenis 
384b725ae77Skettenis void
i387_supply_fsave(struct regcache * regcache,int regnum,const void * fsave)385b725ae77Skettenis i387_supply_fsave (struct regcache *regcache, int regnum, const void *fsave)
386b725ae77Skettenis {
387b725ae77Skettenis   struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
388b725ae77Skettenis   const char *regs = fsave;
389b725ae77Skettenis   int i;
390b725ae77Skettenis 
391b725ae77Skettenis   gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
392b725ae77Skettenis 
393*63addd46Skettenis   /* Define I387_ST0_REGNUM and I387_NUM_XMM_REGS such that we use the
394*63addd46Skettenis      proper definitions for REGCACHE's architecture.  */
395*63addd46Skettenis 
396b725ae77Skettenis #define I387_ST0_REGNUM tdep->st0_regnum
397*63addd46Skettenis #define I387_NUM_XMM_REGS tdep->num_xmm_regs
398b725ae77Skettenis 
399b725ae77Skettenis   for (i = I387_ST0_REGNUM; i < I387_XMM0_REGNUM; i++)
400b725ae77Skettenis     if (regnum == -1 || regnum == i)
401b725ae77Skettenis       {
402b725ae77Skettenis 	if (fsave == NULL)
403b725ae77Skettenis 	  {
404b725ae77Skettenis 	    regcache_raw_supply (regcache, i, NULL);
405b725ae77Skettenis 	    continue;
406b725ae77Skettenis 	  }
407b725ae77Skettenis 
408b725ae77Skettenis 	/* Most of the FPU control registers occupy only 16 bits in the
409b725ae77Skettenis 	   fsave area.  Give those a special treatment.  */
410b725ae77Skettenis 	if (i >= I387_FCTRL_REGNUM
411b725ae77Skettenis 	    && i != I387_FIOFF_REGNUM && i != I387_FOOFF_REGNUM)
412b725ae77Skettenis 	  {
413b725ae77Skettenis 	    unsigned char val[4];
414b725ae77Skettenis 
415b725ae77Skettenis 	    memcpy (val, FSAVE_ADDR (regs, i), 2);
416b725ae77Skettenis 	    val[2] = val[3] = 0;
417b725ae77Skettenis 	    if (i == I387_FOP_REGNUM)
418b725ae77Skettenis 	      val[1] &= ((1 << 3) - 1);
419b725ae77Skettenis 	    regcache_raw_supply (regcache, i, val);
420b725ae77Skettenis 	  }
421b725ae77Skettenis 	else
422b725ae77Skettenis 	  regcache_raw_supply (regcache, i, FSAVE_ADDR (regs, i));
423b725ae77Skettenis       }
424*63addd46Skettenis 
425*63addd46Skettenis   /* Provide dummy values for the SSE registers.  */
426*63addd46Skettenis   for (i = I387_XMM0_REGNUM; i < I387_MXCSR_REGNUM; i++)
427*63addd46Skettenis     if (regnum == -1 || regnum == i)
428*63addd46Skettenis       regcache_raw_supply (regcache, i, NULL);
429*63addd46Skettenis   if (regnum == -1 || regnum == I387_MXCSR_REGNUM)
430*63addd46Skettenis     {
431*63addd46Skettenis       char buf[4];
432*63addd46Skettenis 
433*63addd46Skettenis       store_unsigned_integer (buf, 4, 0x1f80);
434*63addd46Skettenis       regcache_raw_supply (regcache, I387_MXCSR_REGNUM, buf);
435*63addd46Skettenis     }
436*63addd46Skettenis 
437b725ae77Skettenis #undef I387_ST0_REGNUM
438*63addd46Skettenis #undef I387_NUM_XMM_REGS
439b725ae77Skettenis }
440b725ae77Skettenis 
441b725ae77Skettenis /* Fill register REGNUM (if it is a floating-point register) in *FSAVE
442*63addd46Skettenis    with the value from REGCACHE.  If REGNUM is -1, do this for all
443*63addd46Skettenis    registers.  This function doesn't touch any of the reserved bits in
444*63addd46Skettenis    *FSAVE.  */
445b725ae77Skettenis 
446b725ae77Skettenis void
i387_collect_fsave(const struct regcache * regcache,int regnum,void * fsave)447*63addd46Skettenis i387_collect_fsave (const struct regcache *regcache, int regnum, void *fsave)
448b725ae77Skettenis {
449b725ae77Skettenis   struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
450b725ae77Skettenis   char *regs = fsave;
451b725ae77Skettenis   int i;
452b725ae77Skettenis 
453b725ae77Skettenis   gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
454b725ae77Skettenis 
455b725ae77Skettenis   /* Define I387_ST0_REGNUM such that we use the proper definitions
456b725ae77Skettenis      for REGCACHE's architecture.  */
457b725ae77Skettenis #define I387_ST0_REGNUM tdep->st0_regnum
458b725ae77Skettenis 
459b725ae77Skettenis   for (i = I387_ST0_REGNUM; i < I387_XMM0_REGNUM; i++)
460b725ae77Skettenis     if (regnum == -1 || regnum == i)
461b725ae77Skettenis       {
462b725ae77Skettenis 	/* Most of the FPU control registers occupy only 16 bits in
463b725ae77Skettenis            the fsave area.  Give those a special treatment.  */
464b725ae77Skettenis 	if (i >= I387_FCTRL_REGNUM
465b725ae77Skettenis 	    && i != I387_FIOFF_REGNUM && i != I387_FOOFF_REGNUM)
466b725ae77Skettenis 	  {
467b725ae77Skettenis 	    unsigned char buf[4];
468b725ae77Skettenis 
469b725ae77Skettenis 	    regcache_raw_collect (regcache, i, buf);
470b725ae77Skettenis 
471b725ae77Skettenis 	    if (i == I387_FOP_REGNUM)
472b725ae77Skettenis 	      {
473b725ae77Skettenis 		/* The opcode occupies only 11 bits.  Make sure we
474b725ae77Skettenis                    don't touch the other bits.  */
475b725ae77Skettenis 		buf[1] &= ((1 << 3) - 1);
476b725ae77Skettenis 		buf[1] |= ((FSAVE_ADDR (regs, i))[1] & ~((1 << 3) - 1));
477b725ae77Skettenis 	      }
478b725ae77Skettenis 	    memcpy (FSAVE_ADDR (regs, i), buf, 2);
479b725ae77Skettenis 	  }
480b725ae77Skettenis 	else
481b725ae77Skettenis 	  regcache_raw_collect (regcache, i, FSAVE_ADDR (regs, i));
482b725ae77Skettenis       }
483b725ae77Skettenis #undef I387_ST0_REGNUM
484b725ae77Skettenis }
485*63addd46Skettenis 
486*63addd46Skettenis /* Fill register REGNUM (if it is a floating-point register) in *FSAVE
487*63addd46Skettenis    with the value in GDB's register cache.  If REGNUM is -1, do this
488*63addd46Skettenis    for all registers.  This function doesn't touch any of the reserved
489*63addd46Skettenis    bits in *FSAVE.  */
490*63addd46Skettenis 
491*63addd46Skettenis void
i387_fill_fsave(void * fsave,int regnum)492*63addd46Skettenis i387_fill_fsave (void *fsave, int regnum)
493*63addd46Skettenis {
494*63addd46Skettenis   i387_collect_fsave (current_regcache, regnum, fsave);
495*63addd46Skettenis }
496b725ae77Skettenis 
497b725ae77Skettenis 
498b725ae77Skettenis /* At fxsave_offset[REGNUM] you'll find the offset to the location in
499b725ae77Skettenis    the data structure used by the "fxsave" instruction where GDB
500b725ae77Skettenis    register REGNUM is stored.  */
501b725ae77Skettenis 
502b725ae77Skettenis static int fxsave_offset[] =
503b725ae77Skettenis {
504b725ae77Skettenis   32,				/* %st(0) through ...  */
505b725ae77Skettenis   48,
506b725ae77Skettenis   64,
507b725ae77Skettenis   80,
508b725ae77Skettenis   96,
509b725ae77Skettenis   112,
510b725ae77Skettenis   128,
511b725ae77Skettenis   144,				/* ... %st(7) (80 bits each).  */
512b725ae77Skettenis   0,				/* `fctrl' (16 bits).  */
513b725ae77Skettenis   2,				/* `fstat' (16 bits).  */
514b725ae77Skettenis   4,				/* `ftag' (16 bits).  */
515b725ae77Skettenis   12,				/* `fiseg' (16 bits).  */
516b725ae77Skettenis   8,				/* `fioff'.  */
517b725ae77Skettenis   20,				/* `foseg' (16 bits).  */
518b725ae77Skettenis   16,				/* `fooff'.  */
519b725ae77Skettenis   6,				/* `fop' (bottom 11 bits).  */
520b725ae77Skettenis   160 + 0 * 16,			/* %xmm0 through ...  */
521b725ae77Skettenis   160 + 1 * 16,
522b725ae77Skettenis   160 + 2 * 16,
523b725ae77Skettenis   160 + 3 * 16,
524b725ae77Skettenis   160 + 4 * 16,
525b725ae77Skettenis   160 + 5 * 16,
526b725ae77Skettenis   160 + 6 * 16,
527b725ae77Skettenis   160 + 7 * 16,
528b725ae77Skettenis   160 + 8 * 16,
529b725ae77Skettenis   160 + 9 * 16,
530b725ae77Skettenis   160 + 10 * 16,
531b725ae77Skettenis   160 + 11 * 16,
532b725ae77Skettenis   160 + 12 * 16,
533b725ae77Skettenis   160 + 13 * 16,
534b725ae77Skettenis   160 + 14 * 16,
535b725ae77Skettenis   160 + 15 * 16,		/* ... %xmm15 (128 bits each).  */
536b725ae77Skettenis };
537b725ae77Skettenis 
538b725ae77Skettenis #define FXSAVE_ADDR(fxsave, regnum) \
539b725ae77Skettenis   (fxsave + fxsave_offset[regnum - I387_ST0_REGNUM])
540b725ae77Skettenis 
541b725ae77Skettenis /* We made an unfortunate choice in putting %mxcsr after the SSE
542b725ae77Skettenis    registers %xmm0-%xmm7 instead of before, since it makes supporting
543b725ae77Skettenis    the registers %xmm8-%xmm15 on AMD64 a bit involved.  Therefore we
544b725ae77Skettenis    don't include the offset for %mxcsr here above.  */
545b725ae77Skettenis 
546b725ae77Skettenis #define FXSAVE_MXCSR_ADDR(fxsave) (fxsave + 24)
547b725ae77Skettenis 
548b725ae77Skettenis static int i387_tag (const unsigned char *raw);
549b725ae77Skettenis 
550b725ae77Skettenis 
551b725ae77Skettenis /* Fill register REGNUM in REGCACHE with the appropriate
552b725ae77Skettenis    floating-point or SSE register value from *FXSAVE.  This function
553b725ae77Skettenis    masks off any of the reserved bits in *FXSAVE.  */
554b725ae77Skettenis 
555b725ae77Skettenis void
i387_supply_fxsave(struct regcache * regcache,int regnum,const void * fxsave)556b725ae77Skettenis i387_supply_fxsave (struct regcache *regcache, int regnum, const void *fxsave)
557b725ae77Skettenis {
558b725ae77Skettenis   struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
559b725ae77Skettenis   const char *regs = fxsave;
560b725ae77Skettenis   int i;
561b725ae77Skettenis 
562b725ae77Skettenis   gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
563b725ae77Skettenis   gdb_assert (tdep->num_xmm_regs > 0);
564b725ae77Skettenis 
565b725ae77Skettenis   /* Define I387_ST0_REGNUM and I387_NUM_XMM_REGS such that we use the
566b725ae77Skettenis      proper definitions for REGCACHE's architecture.  */
567b725ae77Skettenis 
568b725ae77Skettenis #define I387_ST0_REGNUM	tdep->st0_regnum
569b725ae77Skettenis #define I387_NUM_XMM_REGS tdep->num_xmm_regs
570b725ae77Skettenis 
571b725ae77Skettenis   for (i = I387_ST0_REGNUM; i < I387_MXCSR_REGNUM; i++)
572b725ae77Skettenis     if (regnum == -1 || regnum == i)
573b725ae77Skettenis       {
574b725ae77Skettenis 	if (regs == NULL)
575b725ae77Skettenis 	  {
576b725ae77Skettenis 	    regcache_raw_supply (regcache, i, NULL);
577b725ae77Skettenis 	    continue;
578b725ae77Skettenis 	  }
579b725ae77Skettenis 
580b725ae77Skettenis 	/* Most of the FPU control registers occupy only 16 bits in
581b725ae77Skettenis 	   the fxsave area.  Give those a special treatment.  */
582b725ae77Skettenis 	if (i >= I387_FCTRL_REGNUM && i < I387_XMM0_REGNUM
583b725ae77Skettenis 	    && i != I387_FIOFF_REGNUM && i != I387_FOOFF_REGNUM)
584b725ae77Skettenis 	  {
585b725ae77Skettenis 	    unsigned char val[4];
586b725ae77Skettenis 
587b725ae77Skettenis 	    memcpy (val, FXSAVE_ADDR (regs, i), 2);
588b725ae77Skettenis 	    val[2] = val[3] = 0;
589b725ae77Skettenis 	    if (i == I387_FOP_REGNUM)
590b725ae77Skettenis 	      val[1] &= ((1 << 3) - 1);
591b725ae77Skettenis 	    else if (i== I387_FTAG_REGNUM)
592b725ae77Skettenis 	      {
593b725ae77Skettenis 		/* The fxsave area contains a simplified version of
594b725ae77Skettenis 		   the tag word.  We have to look at the actual 80-bit
595b725ae77Skettenis 		   FP data to recreate the traditional i387 tag word.  */
596b725ae77Skettenis 
597b725ae77Skettenis 		unsigned long ftag = 0;
598b725ae77Skettenis 		int fpreg;
599b725ae77Skettenis 		int top;
600b725ae77Skettenis 
601b725ae77Skettenis 		top = ((FXSAVE_ADDR (regs, I387_FSTAT_REGNUM))[1] >> 3);
602b725ae77Skettenis 		top &= 0x7;
603b725ae77Skettenis 
604b725ae77Skettenis 		for (fpreg = 7; fpreg >= 0; fpreg--)
605b725ae77Skettenis 		  {
606b725ae77Skettenis 		    int tag;
607b725ae77Skettenis 
608b725ae77Skettenis 		    if (val[0] & (1 << fpreg))
609b725ae77Skettenis 		      {
610b725ae77Skettenis 			int regnum = (fpreg + 8 - top) % 8 + I387_ST0_REGNUM;
611b725ae77Skettenis 			tag = i387_tag (FXSAVE_ADDR (regs, regnum));
612b725ae77Skettenis 		      }
613b725ae77Skettenis 		    else
614b725ae77Skettenis 		      tag = 3;		/* Empty */
615b725ae77Skettenis 
616b725ae77Skettenis 		    ftag |= tag << (2 * fpreg);
617b725ae77Skettenis 		  }
618b725ae77Skettenis 		val[0] = ftag & 0xff;
619b725ae77Skettenis 		val[1] = (ftag >> 8) & 0xff;
620b725ae77Skettenis 	      }
621b725ae77Skettenis 	    regcache_raw_supply (regcache, i, val);
622b725ae77Skettenis 	  }
623b725ae77Skettenis 	else
624b725ae77Skettenis 	  regcache_raw_supply (regcache, i, FXSAVE_ADDR (regs, i));
625b725ae77Skettenis       }
626b725ae77Skettenis 
627b725ae77Skettenis   if (regnum == I387_MXCSR_REGNUM || regnum == -1)
628b725ae77Skettenis     {
629b725ae77Skettenis       if (regs == NULL)
630b725ae77Skettenis 	regcache_raw_supply (regcache, I387_MXCSR_REGNUM, NULL);
631b725ae77Skettenis       else
632b725ae77Skettenis 	regcache_raw_supply (regcache, I387_MXCSR_REGNUM,
633b725ae77Skettenis 			     FXSAVE_MXCSR_ADDR (regs));
634b725ae77Skettenis     }
635b725ae77Skettenis 
636b725ae77Skettenis #undef I387_ST0_REGNUM
637b725ae77Skettenis #undef I387_NUM_XMM_REGS
638b725ae77Skettenis }
639b725ae77Skettenis 
640b725ae77Skettenis /* Fill register REGNUM (if it is a floating-point or SSE register) in
641b725ae77Skettenis    *FXSAVE with the value from REGCACHE.  If REGNUM is -1, do this for
642b725ae77Skettenis    all registers.  This function doesn't touch any of the reserved
643b725ae77Skettenis    bits in *FXSAVE.  */
644b725ae77Skettenis 
645b725ae77Skettenis void
i387_collect_fxsave(const struct regcache * regcache,int regnum,void * fxsave)646b725ae77Skettenis i387_collect_fxsave (const struct regcache *regcache, int regnum, void *fxsave)
647b725ae77Skettenis {
648b725ae77Skettenis   struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
649b725ae77Skettenis   char *regs = fxsave;
650b725ae77Skettenis   int i;
651b725ae77Skettenis 
652b725ae77Skettenis   gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
653b725ae77Skettenis   gdb_assert (tdep->num_xmm_regs > 0);
654b725ae77Skettenis 
655b725ae77Skettenis   /* Define I387_ST0_REGNUM and I387_NUM_XMM_REGS such that we use the
656b725ae77Skettenis      proper definitions for REGCACHE's architecture.  */
657b725ae77Skettenis 
658b725ae77Skettenis #define I387_ST0_REGNUM	tdep->st0_regnum
659b725ae77Skettenis #define I387_NUM_XMM_REGS tdep->num_xmm_regs
660b725ae77Skettenis 
661b725ae77Skettenis   for (i = I387_ST0_REGNUM; i < I387_MXCSR_REGNUM; i++)
662b725ae77Skettenis     if (regnum == -1 || regnum == i)
663b725ae77Skettenis       {
664b725ae77Skettenis 	/* Most of the FPU control registers occupy only 16 bits in
665b725ae77Skettenis            the fxsave area.  Give those a special treatment.  */
666b725ae77Skettenis 	if (i >= I387_FCTRL_REGNUM && i < I387_XMM0_REGNUM
667b725ae77Skettenis 	    && i != I387_FIOFF_REGNUM && i != I387_FOOFF_REGNUM)
668b725ae77Skettenis 	  {
669b725ae77Skettenis 	    unsigned char buf[4];
670b725ae77Skettenis 
671b725ae77Skettenis 	    regcache_raw_collect (regcache, i, buf);
672b725ae77Skettenis 
673b725ae77Skettenis 	    if (i == I387_FOP_REGNUM)
674b725ae77Skettenis 	      {
675b725ae77Skettenis 		/* The opcode occupies only 11 bits.  Make sure we
676b725ae77Skettenis                    don't touch the other bits.  */
677b725ae77Skettenis 		buf[1] &= ((1 << 3) - 1);
678b725ae77Skettenis 		buf[1] |= ((FXSAVE_ADDR (regs, i))[1] & ~((1 << 3) - 1));
679b725ae77Skettenis 	      }
680b725ae77Skettenis 	    else if (i == I387_FTAG_REGNUM)
681b725ae77Skettenis 	      {
682b725ae77Skettenis 		/* Converting back is much easier.  */
683b725ae77Skettenis 
684b725ae77Skettenis 		unsigned short ftag;
685b725ae77Skettenis 		int fpreg;
686b725ae77Skettenis 
687b725ae77Skettenis 		ftag = (buf[1] << 8) | buf[0];
688b725ae77Skettenis 		buf[0] = 0;
689b725ae77Skettenis 		buf[1] = 0;
690b725ae77Skettenis 
691b725ae77Skettenis 		for (fpreg = 7; fpreg >= 0; fpreg--)
692b725ae77Skettenis 		  {
693b725ae77Skettenis 		    int tag = (ftag >> (fpreg * 2)) & 3;
694b725ae77Skettenis 
695b725ae77Skettenis 		    if (tag != 3)
696b725ae77Skettenis 		      buf[0] |= (1 << fpreg);
697b725ae77Skettenis 		  }
698b725ae77Skettenis 	      }
699b725ae77Skettenis 	    memcpy (FXSAVE_ADDR (regs, i), buf, 2);
700b725ae77Skettenis 	  }
701b725ae77Skettenis 	else
702b725ae77Skettenis 	  regcache_raw_collect (regcache, i, FXSAVE_ADDR (regs, i));
703b725ae77Skettenis       }
704b725ae77Skettenis 
705b725ae77Skettenis   if (regnum == I387_MXCSR_REGNUM || regnum == -1)
706b725ae77Skettenis     regcache_raw_collect (regcache, I387_MXCSR_REGNUM,
707b725ae77Skettenis 			  FXSAVE_MXCSR_ADDR (regs));
708b725ae77Skettenis 
709b725ae77Skettenis #undef I387_ST0_REGNUM
710b725ae77Skettenis #undef I387_NUM_XMM_REGS
711b725ae77Skettenis }
712b725ae77Skettenis 
713b725ae77Skettenis /* Fill register REGNUM (if it is a floating-point or SSE register) in
714b725ae77Skettenis    *FXSAVE with the value in GDB's register cache.  If REGNUM is -1, do
715b725ae77Skettenis    this for all registers.  This function doesn't touch any of the
716b725ae77Skettenis    reserved bits in *FXSAVE.  */
717b725ae77Skettenis 
718b725ae77Skettenis void
i387_fill_fxsave(void * fxsave,int regnum)719b725ae77Skettenis i387_fill_fxsave (void *fxsave, int regnum)
720b725ae77Skettenis {
721b725ae77Skettenis   i387_collect_fxsave (current_regcache, regnum, fxsave);
722b725ae77Skettenis }
723b725ae77Skettenis 
724b725ae77Skettenis /* Recreate the FTW (tag word) valid bits from the 80-bit FP data in
725b725ae77Skettenis    *RAW.  */
726b725ae77Skettenis 
727b725ae77Skettenis static int
i387_tag(const unsigned char * raw)728b725ae77Skettenis i387_tag (const unsigned char *raw)
729b725ae77Skettenis {
730b725ae77Skettenis   int integer;
731b725ae77Skettenis   unsigned int exponent;
732b725ae77Skettenis   unsigned long fraction[2];
733b725ae77Skettenis 
734b725ae77Skettenis   integer = raw[7] & 0x80;
735b725ae77Skettenis   exponent = (((raw[9] & 0x7f) << 8) | raw[8]);
736b725ae77Skettenis   fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]);
737b725ae77Skettenis   fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16)
738b725ae77Skettenis 		 | (raw[5] << 8) | raw[4]);
739b725ae77Skettenis 
740b725ae77Skettenis   if (exponent == 0x7fff)
741b725ae77Skettenis     {
742b725ae77Skettenis       /* Special.  */
743b725ae77Skettenis       return (2);
744b725ae77Skettenis     }
745b725ae77Skettenis   else if (exponent == 0x0000)
746b725ae77Skettenis     {
747b725ae77Skettenis       if (fraction[0] == 0x0000 && fraction[1] == 0x0000 && !integer)
748b725ae77Skettenis 	{
749b725ae77Skettenis 	  /* Zero.  */
750b725ae77Skettenis 	  return (1);
751b725ae77Skettenis 	}
752b725ae77Skettenis       else
753b725ae77Skettenis 	{
754b725ae77Skettenis 	  /* Special.  */
755b725ae77Skettenis 	  return (2);
756b725ae77Skettenis 	}
757b725ae77Skettenis     }
758b725ae77Skettenis   else
759b725ae77Skettenis     {
760b725ae77Skettenis       if (integer)
761b725ae77Skettenis 	{
762b725ae77Skettenis 	  /* Valid.  */
763b725ae77Skettenis 	  return (0);
764b725ae77Skettenis 	}
765b725ae77Skettenis       else
766b725ae77Skettenis 	{
767b725ae77Skettenis 	  /* Special.  */
768b725ae77Skettenis 	  return (2);
769b725ae77Skettenis 	}
770b725ae77Skettenis     }
771b725ae77Skettenis }
772b725ae77Skettenis 
773b725ae77Skettenis /* Prepare the FPU stack in REGCACHE for a function return.  */
774b725ae77Skettenis 
775b725ae77Skettenis void
i387_return_value(struct gdbarch * gdbarch,struct regcache * regcache)776b725ae77Skettenis i387_return_value (struct gdbarch *gdbarch, struct regcache *regcache)
777b725ae77Skettenis {
778b725ae77Skettenis   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
779b725ae77Skettenis   ULONGEST fstat;
780b725ae77Skettenis 
781b725ae77Skettenis   /* Define I387_ST0_REGNUM such that we use the proper
782b725ae77Skettenis      definitions for the architecture.  */
783b725ae77Skettenis #define I387_ST0_REGNUM tdep->st0_regnum
784b725ae77Skettenis 
785b725ae77Skettenis   /* Set the top of the floating-point register stack to 7.  The
786b725ae77Skettenis      actual value doesn't really matter, but 7 is what a normal
787b725ae77Skettenis      function return would end up with if the program started out with
788b725ae77Skettenis      a freshly initialized FPU.  */
789b725ae77Skettenis   regcache_raw_read_unsigned (regcache, I387_FSTAT_REGNUM, &fstat);
790b725ae77Skettenis   fstat |= (7 << 11);
791b725ae77Skettenis   regcache_raw_write_unsigned (regcache, I387_FSTAT_REGNUM, fstat);
792b725ae77Skettenis 
793b725ae77Skettenis   /* Mark %st(1) through %st(7) as empty.  Since we set the top of the
794b725ae77Skettenis      floating-point register stack to 7, the appropriate value for the
795b725ae77Skettenis      tag word is 0x3fff.  */
796b725ae77Skettenis   regcache_raw_write_unsigned (regcache, I387_FTAG_REGNUM, 0x3fff);
797b725ae77Skettenis 
798b725ae77Skettenis #undef I387_ST0_REGNUM
799e93f7393Sniklas }
800