* regcache.c (register_buffer): Consitify first argument.
[deliverable/binutils-gdb.git] / gdb / i387-tdep.c
CommitLineData
c906108c 1/* Intel 387 floating point stuff.
38edeab8 2
dff95cc7 3 Copyright 1988, 1989, 1991, 1992, 1993, 1994, 1998, 1999, 2000,
38edeab8 4 2001, 2002, 2003 Free Software Foundation, Inc.
c906108c 5
c5aa993b 6 This file is part of GDB.
c906108c 7
c5aa993b
JM
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
c906108c 12
c5aa993b
JM
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
c906108c 17
c5aa993b
JM
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA. */
c906108c
SS
22
23#include "defs.h"
786a90bb
MK
24#include "doublest.h"
25#include "floatformat.h"
c906108c 26#include "frame.h"
786a90bb 27#include "gdbcore.h"
c906108c
SS
28#include "inferior.h"
29#include "language.h"
4e052eda 30#include "regcache.h"
786a90bb
MK
31#include "value.h"
32
d0df8472 33#include "gdb_assert.h"
309367d4 34#include "gdb_string.h"
c906108c 35
9a82579f 36#include "i386-tdep.h"
42c466d7 37#include "i387-tdep.h"
c906108c 38
de57eccd
JM
39/* Implement the `info float' layout based on the register definitions
40 in `tm-i386.h'. */
41
42/* Print the floating point number specified by RAW. */
786a90bb 43
de57eccd 44static void
61113f8b 45print_i387_value (char *raw, struct ui_file *file)
de57eccd
JM
46{
47 DOUBLEST value;
4583280c
MK
48
49 /* Using extract_typed_floating here might affect the representation
50 of certain numbers such as NaNs, even if GDB is running natively.
51 This is fine since our caller already detects such special
52 numbers and we print the hexadecimal representation anyway. */
53 value = extract_typed_floating (raw, builtin_type_i387_ext);
de57eccd
JM
54
55 /* We try to print 19 digits. The last digit may or may not contain
56 garbage, but we'd better print one too many. We need enough room
57 to print the value, 1 position for the sign, 1 for the decimal
58 point, 19 for the digits and 6 for the exponent adds up to 27. */
59#ifdef PRINTF_HAS_LONG_DOUBLE
61113f8b 60 fprintf_filtered (file, " %-+27.19Lg", (long double) value);
de57eccd 61#else
61113f8b 62 fprintf_filtered (file, " %-+27.19g", (double) value);
de57eccd
JM
63#endif
64}
65
66/* Print the classification for the register contents RAW. */
786a90bb 67
de57eccd 68static void
61113f8b 69print_i387_ext (unsigned char *raw, struct ui_file *file)
de57eccd
JM
70{
71 int sign;
72 int integer;
73 unsigned int exponent;
74 unsigned long fraction[2];
75
76 sign = raw[9] & 0x80;
77 integer = raw[7] & 0x80;
78 exponent = (((raw[9] & 0x7f) << 8) | raw[8]);
79 fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]);
80 fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16)
81 | (raw[5] << 8) | raw[4]);
82
83 if (exponent == 0x7fff && integer)
84 {
85 if (fraction[0] == 0x00000000 && fraction[1] == 0x00000000)
86 /* Infinity. */
61113f8b 87 fprintf_filtered (file, " %cInf", (sign ? '-' : '+'));
de57eccd
JM
88 else if (sign && fraction[0] == 0x00000000 && fraction[1] == 0x40000000)
89 /* Real Indefinite (QNaN). */
61113f8b 90 fputs_unfiltered (" Real Indefinite (QNaN)", file);
de57eccd
JM
91 else if (fraction[1] & 0x40000000)
92 /* QNaN. */
61113f8b 93 fputs_filtered (" QNaN", file);
de57eccd
JM
94 else
95 /* SNaN. */
61113f8b 96 fputs_filtered (" SNaN", file);
de57eccd
JM
97 }
98 else if (exponent < 0x7fff && exponent > 0x0000 && integer)
99 /* Normal. */
61113f8b 100 print_i387_value (raw, file);
de57eccd
JM
101 else if (exponent == 0x0000)
102 {
103 /* Denormal or zero. */
61113f8b 104 print_i387_value (raw, file);
de57eccd
JM
105
106 if (integer)
107 /* Pseudo-denormal. */
61113f8b 108 fputs_filtered (" Pseudo-denormal", file);
de57eccd
JM
109 else if (fraction[0] || fraction[1])
110 /* Denormal. */
61113f8b 111 fputs_filtered (" Denormal", file);
de57eccd
JM
112 }
113 else
114 /* Unsupported. */
61113f8b 115 fputs_filtered (" Unsupported", file);
de57eccd
JM
116}
117
118/* Print the status word STATUS. */
786a90bb 119
de57eccd 120static void
61113f8b 121print_i387_status_word (unsigned int status, struct ui_file *file)
de57eccd 122{
61113f8b 123 fprintf_filtered (file, "Status Word: %s",
de57eccd 124 local_hex_string_custom (status, "04"));
61113f8b
MK
125 fputs_filtered (" ", file);
126 fprintf_filtered (file, " %s", (status & 0x0001) ? "IE" : " ");
127 fprintf_filtered (file, " %s", (status & 0x0002) ? "DE" : " ");
128 fprintf_filtered (file, " %s", (status & 0x0004) ? "ZE" : " ");
129 fprintf_filtered (file, " %s", (status & 0x0008) ? "OE" : " ");
130 fprintf_filtered (file, " %s", (status & 0x0010) ? "UE" : " ");
131 fprintf_filtered (file, " %s", (status & 0x0020) ? "PE" : " ");
132 fputs_filtered (" ", file);
133 fprintf_filtered (file, " %s", (status & 0x0080) ? "ES" : " ");
134 fputs_filtered (" ", file);
135 fprintf_filtered (file, " %s", (status & 0x0040) ? "SF" : " ");
136 fputs_filtered (" ", file);
137 fprintf_filtered (file, " %s", (status & 0x0100) ? "C0" : " ");
138 fprintf_filtered (file, " %s", (status & 0x0200) ? "C1" : " ");
139 fprintf_filtered (file, " %s", (status & 0x0400) ? "C2" : " ");
140 fprintf_filtered (file, " %s", (status & 0x4000) ? "C3" : " ");
141
142 fputs_filtered ("\n", file);
143
144 fprintf_filtered (file,
145 " TOP: %d\n", ((status >> 11) & 7));
de57eccd
JM
146}
147
148/* Print the control word CONTROL. */
786a90bb 149
de57eccd 150static void
61113f8b 151print_i387_control_word (unsigned int control, struct ui_file *file)
de57eccd 152{
61113f8b 153 fprintf_filtered (file, "Control Word: %s",
de57eccd 154 local_hex_string_custom (control, "04"));
61113f8b
MK
155 fputs_filtered (" ", file);
156 fprintf_filtered (file, " %s", (control & 0x0001) ? "IM" : " ");
157 fprintf_filtered (file, " %s", (control & 0x0002) ? "DM" : " ");
158 fprintf_filtered (file, " %s", (control & 0x0004) ? "ZM" : " ");
159 fprintf_filtered (file, " %s", (control & 0x0008) ? "OM" : " ");
160 fprintf_filtered (file, " %s", (control & 0x0010) ? "UM" : " ");
161 fprintf_filtered (file, " %s", (control & 0x0020) ? "PM" : " ");
de57eccd 162
61113f8b 163 fputs_filtered ("\n", file);
de57eccd 164
61113f8b 165 fputs_filtered (" PC: ", file);
de57eccd
JM
166 switch ((control >> 8) & 3)
167 {
168 case 0:
61113f8b 169 fputs_filtered ("Single Precision (24-bits)\n", file);
de57eccd
JM
170 break;
171 case 1:
61113f8b 172 fputs_filtered ("Reserved\n", file);
de57eccd
JM
173 break;
174 case 2:
61113f8b 175 fputs_filtered ("Double Precision (53-bits)\n", file);
de57eccd
JM
176 break;
177 case 3:
61113f8b 178 fputs_filtered ("Extended Precision (64-bits)\n", file);
de57eccd
JM
179 break;
180 }
181
61113f8b 182 fputs_filtered (" RC: ", file);
de57eccd
JM
183 switch ((control >> 10) & 3)
184 {
185 case 0:
61113f8b 186 fputs_filtered ("Round to nearest\n", file);
de57eccd
JM
187 break;
188 case 1:
61113f8b 189 fputs_filtered ("Round down\n", file);
de57eccd
JM
190 break;
191 case 2:
61113f8b 192 fputs_filtered ("Round up\n", file);
de57eccd
JM
193 break;
194 case 3:
61113f8b 195 fputs_filtered ("Round toward zero\n", file);
de57eccd
JM
196 break;
197 }
198}
199
9b949a49 200/* Print out the i387 floating point state. Note that we ignore FRAME
7d8d2918
MK
201 in the code below. That's OK since floating-point registers are
202 never saved on the stack. */
203
de57eccd 204void
61113f8b 205i387_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
8e186fd6 206 struct frame_info *frame, const char *args)
de57eccd 207{
1d70089a
MK
208 char buf[4];
209 ULONGEST fctrl;
210 ULONGEST fstat;
211 ULONGEST ftag;
212 ULONGEST fiseg;
213 ULONGEST fioff;
214 ULONGEST foseg;
215 ULONGEST fooff;
216 ULONGEST fop;
de57eccd
JM
217 int fpreg;
218 int top;
219
192285c6
MK
220 fctrl = get_frame_register_unsigned (frame, FCTRL_REGNUM);
221 fstat = get_frame_register_unsigned (frame, FSTAT_REGNUM);
222 ftag = get_frame_register_unsigned (frame, FTAG_REGNUM);
223 fiseg = get_frame_register_unsigned (frame, FISEG_REGNUM);
224 fioff = get_frame_register_unsigned (frame, FIOFF_REGNUM);
225 foseg = get_frame_register_unsigned (frame, FOSEG_REGNUM);
226 fooff = get_frame_register_unsigned (frame, FOOFF_REGNUM);
227 fop = get_frame_register_unsigned (frame, FOP_REGNUM);
1d70089a 228
de57eccd
JM
229 top = ((fstat >> 11) & 7);
230
231 for (fpreg = 7; fpreg >= 0; fpreg--)
232 {
233 unsigned char raw[FPU_REG_RAW_SIZE];
234 int tag = (ftag >> (fpreg * 2)) & 3;
235 int i;
236
61113f8b 237 fprintf_filtered (file, "%sR%d: ", fpreg == top ? "=>" : " ", fpreg);
de57eccd
JM
238
239 switch (tag)
240 {
241 case 0:
61113f8b 242 fputs_filtered ("Valid ", file);
de57eccd
JM
243 break;
244 case 1:
61113f8b 245 fputs_filtered ("Zero ", file);
de57eccd
JM
246 break;
247 case 2:
61113f8b 248 fputs_filtered ("Special ", file);
de57eccd
JM
249 break;
250 case 3:
61113f8b 251 fputs_filtered ("Empty ", file);
de57eccd
JM
252 break;
253 }
254
192285c6 255 get_frame_register (frame, (fpreg + 8 - top) % 8 + FP0_REGNUM, raw);
de57eccd 256
61113f8b 257 fputs_filtered ("0x", file);
de57eccd 258 for (i = 9; i >= 0; i--)
61113f8b 259 fprintf_filtered (file, "%02x", raw[i]);
de57eccd
JM
260
261 if (tag != 3)
61113f8b 262 print_i387_ext (raw, file);
de57eccd 263
61113f8b 264 fputs_filtered ("\n", file);
de57eccd
JM
265 }
266
f16a25ae 267 fputs_filtered ("\n", file);
de57eccd 268
61113f8b
MK
269 print_i387_status_word (fstat, file);
270 print_i387_control_word (fctrl, file);
271 fprintf_filtered (file, "Tag Word: %s\n",
272 local_hex_string_custom (ftag, "04"));
273 fprintf_filtered (file, "Instruction Pointer: %s:",
274 local_hex_string_custom (fiseg, "02"));
275 fprintf_filtered (file, "%s\n", local_hex_string_custom (fioff, "08"));
276 fprintf_filtered (file, "Operand Pointer: %s:",
277 local_hex_string_custom (foseg, "02"));
278 fprintf_filtered (file, "%s\n", local_hex_string_custom (fooff, "08"));
279 fprintf_filtered (file, "Opcode: %s\n",
280 local_hex_string_custom (fop ? (fop | 0xd800) : 0, "04"));
de57eccd 281}
d532c08f
MK
282\f
283
284/* Read a value of type TYPE from register REGNUM in frame FRAME, and
285 return its contents in TO. */
286
287void
288i387_register_to_value (struct frame_info *frame, int regnum,
289 struct type *type, void *to)
290{
291 char from[I386_MAX_REGISTER_SIZE];
292
293 gdb_assert (i386_fp_regnum_p (regnum));
294
295 /* We only support floating-point values. */
296 if (TYPE_CODE (type) != TYPE_CODE_FLT)
297 {
298 warning ("Cannot convert floating-point register value "
299 "to non-floating-point type.");
300 return;
301 }
302
303 /* Convert to TYPE. This should be a no-op if TYPE is equivalent to
304 the extended floating-point format used by the FPU. */
192285c6 305 get_frame_register (frame, regnum, from);
d532c08f
MK
306 convert_typed_floating (from, builtin_type_i387_ext, to, type);
307}
308
309/* Write the contents FROM of a value of type TYPE into register
310 REGNUM in frame FRAME. */
311
312void
313i387_value_to_register (struct frame_info *frame, int regnum,
314 struct type *type, const void *from)
315{
316 char to[I386_MAX_REGISTER_SIZE];
317
318 gdb_assert (i386_fp_regnum_p (regnum));
319
320 /* We only support floating-point values. */
321 if (TYPE_CODE (type) != TYPE_CODE_FLT)
322 {
323 warning ("Cannot convert non-floating-point type "
324 "to floating-point register value.");
325 return;
326 }
327
328 /* Convert from TYPE. This should be a no-op if TYPE is equivalent
329 to the extended floating-point format used by the FPU. */
330 convert_typed_floating (from, type, to, builtin_type_i387_ext);
331 put_frame_register (frame, regnum, to);
332}
333\f
e750d25e 334
786a90bb 335/* Handle FSAVE and FXSAVE formats. */
e750d25e
JT
336
337/* At fsave_offset[REGNUM] you'll find the offset to the location in
338 the data structure used by the "fsave" instruction where GDB
339 register REGNUM is stored. */
340
341static int fsave_offset[] =
342{
343 28 + 0 * FPU_REG_RAW_SIZE, /* FP0_REGNUM through ... */
344 28 + 1 * FPU_REG_RAW_SIZE,
345 28 + 2 * FPU_REG_RAW_SIZE,
346 28 + 3 * FPU_REG_RAW_SIZE,
347 28 + 4 * FPU_REG_RAW_SIZE,
348 28 + 5 * FPU_REG_RAW_SIZE,
349 28 + 6 * FPU_REG_RAW_SIZE,
350 28 + 7 * FPU_REG_RAW_SIZE, /* ... FP7_REGNUM. */
351 0, /* FCTRL_REGNUM (16 bits). */
352 4, /* FSTAT_REGNUM (16 bits). */
353 8, /* FTAG_REGNUM (16 bits). */
354 16, /* FISEG_REGNUM (16 bits). */
355 12, /* FIOFF_REGNUM. */
356 24, /* FOSEG_REGNUM. */
357 20, /* FOOFF_REGNUM. */
358 18 /* FOP_REGNUM (bottom 11 bits). */
359};
360
361#define FSAVE_ADDR(fsave, regnum) (fsave + fsave_offset[regnum - FP0_REGNUM])
362\f
363
ed504bdf 364/* Fill register REGNUM in GDB's register cache with the appropriate
e750d25e
JT
365 value from *FSAVE. This function masks off any of the reserved
366 bits in *FSAVE. */
367
368void
ed504bdf 369i387_supply_fsave (const char *fsave, int regnum)
e750d25e
JT
370{
371 int i;
372
373 for (i = FP0_REGNUM; i < XMM0_REGNUM; i++)
ed504bdf
MK
374 if (regnum == -1 || regnum == i)
375 {
376 if (fsave == NULL)
377 {
378 supply_register (i, NULL);
379 return;
380 }
381
382 /* Most of the FPU control registers occupy only 16 bits in the
383 fsave area. Give those a special treatment. */
384 if (i >= FPC_REGNUM
385 && i != FIOFF_REGNUM && i != FOOFF_REGNUM)
386 {
387 unsigned char val[4];
388
389 memcpy (val, FSAVE_ADDR (fsave, i), 2);
390 val[2] = val[3] = 0;
391 if (i == FOP_REGNUM)
392 val[1] &= ((1 << 3) - 1);
393 supply_register (i, val);
394 }
395 else
396 supply_register (i, FSAVE_ADDR (fsave, i));
397 }
e750d25e
JT
398}
399
400/* Fill register REGNUM (if it is a floating-point register) in *FSAVE
ed504bdf 401 with the value in GDB's register cache. If REGNUM is -1, do this
e750d25e
JT
402 for all registers. This function doesn't touch any of the reserved
403 bits in *FSAVE. */
404
405void
406i387_fill_fsave (char *fsave, int regnum)
407{
408 int i;
409
410 for (i = FP0_REGNUM; i < XMM0_REGNUM; i++)
411 if (regnum == -1 || regnum == i)
412 {
413 /* Most of the FPU control registers occupy only 16 bits in
414 the fsave area. Give those a special treatment. */
415 if (i >= FPC_REGNUM
416 && i != FIOFF_REGNUM && i != FOOFF_REGNUM)
417 {
418 unsigned char buf[4];
419
420 regcache_collect (i, buf);
421
422 if (i == FOP_REGNUM)
423 {
424 /* The opcode occupies only 11 bits. Make sure we
425 don't touch the other bits. */
426 buf[1] &= ((1 << 3) - 1);
427 buf[1] |= ((FSAVE_ADDR (fsave, i))[1] & ~((1 << 3) - 1));
428 }
429 memcpy (FSAVE_ADDR (fsave, i), buf, 2);
430 }
431 else
432 regcache_collect (i, FSAVE_ADDR (fsave, i));
433 }
434}
435\f
436
437/* At fxsave_offset[REGNUM] you'll find the offset to the location in
438 the data structure used by the "fxsave" instruction where GDB
439 register REGNUM is stored. */
440
441static int fxsave_offset[] =
442{
443 32, /* FP0_REGNUM through ... */
444 48,
445 64,
446 80,
447 96,
448 112,
449 128,
450 144, /* ... FP7_REGNUM (80 bits each). */
451 0, /* FCTRL_REGNUM (16 bits). */
452 2, /* FSTAT_REGNUM (16 bits). */
453 4, /* FTAG_REGNUM (16 bits). */
454 12, /* FISEG_REGNUM (16 bits). */
455 8, /* FIOFF_REGNUM. */
456 20, /* FOSEG_REGNUM (16 bits). */
457 16, /* FOOFF_REGNUM. */
458 6, /* FOP_REGNUM (bottom 11 bits). */
04c8243f
MK
459 160 + 0 * 16, /* XMM0_REGNUM through ... */
460 160 + 1 * 16,
461 160 + 2 * 16,
462 160 + 3 * 16,
463 160 + 4 * 16,
464 160 + 5 * 16,
465 160 + 6 * 16,
466 160 + 7 * 16,
467 160 + 8 * 16,
468 160 + 9 * 16,
469 160 + 10 * 16,
470 160 + 11 * 16,
471 160 + 12 * 16,
472 160 + 13 * 16,
473 160 + 14 * 16,
474 160 + 15 * 16, /* ... XMM15_REGNUM (128 bits each). */
475 24 /* MXCSR_REGNUM. */
e750d25e
JT
476};
477
04c8243f
MK
478/* FIXME: kettenis/20030430: We made an unfortunate choice in putting
479 %mxcsr after the SSE registers %xmm0-%xmm7 instead of before, since
480 it makes supporting the registers %xmm8-%xmm15 on x86-64 a bit
481 involved. Hack around it by explicitly overriding the offset for
482 %mxcsr here. */
483
e750d25e 484#define FXSAVE_ADDR(fxsave, regnum) \
04c8243f
MK
485 ((regnum == MXCSR_REGNUM) ? (fxsave + 24) : \
486 (fxsave + fxsave_offset[regnum - FP0_REGNUM]))
e750d25e 487
ed504bdf 488static int i387_tag (const unsigned char *raw);
e750d25e
JT
489\f
490
ed504bdf
MK
491/* Fill register REGNUM in GDB's register cache with the appropriate
492 floating-point or SSE register value from *FXSAVE. This function
493 masks off any of the reserved bits in *FXSAVE. */
e750d25e
JT
494
495void
ed504bdf 496i387_supply_fxsave (const char *fxsave, int regnum)
e750d25e 497{
dff95cc7
MK
498 int i, last_regnum = MXCSR_REGNUM;
499
500 if (gdbarch_tdep (current_gdbarch)->num_xmm_regs == 0)
501 last_regnum = FOP_REGNUM;
e750d25e 502
dff95cc7 503 for (i = FP0_REGNUM; i <= last_regnum; i++)
ed504bdf
MK
504 if (regnum == -1 || regnum == i)
505 {
506 if (fxsave == NULL)
507 {
508 supply_register (i, NULL);
509 continue;
510 }
932bb524 511
ed504bdf
MK
512 /* Most of the FPU control registers occupy only 16 bits in
513 the fxsave area. Give those a special treatment. */
514 if (i >= FPC_REGNUM && i < XMM0_REGNUM
515 && i != FIOFF_REGNUM && i != FOOFF_REGNUM)
516 {
517 unsigned char val[4];
518
519 memcpy (val, FXSAVE_ADDR (fxsave, i), 2);
520 val[2] = val[3] = 0;
521 if (i == FOP_REGNUM)
522 val[1] &= ((1 << 3) - 1);
523 else if (i== FTAG_REGNUM)
524 {
525 /* The fxsave area contains a simplified version of
526 the tag word. We have to look at the actual 80-bit
527 FP data to recreate the traditional i387 tag word. */
528
529 unsigned long ftag = 0;
530 int fpreg;
531 int top;
532
533 top = (((FXSAVE_ADDR (fxsave, FSTAT_REGNUM))[1] >> 3) & 0x7);
534
535 for (fpreg = 7; fpreg >= 0; fpreg--)
536 {
537 int tag;
538
539 if (val[0] & (1 << fpreg))
540 {
541 int regnum = (fpreg + 8 - top) % 8 + FP0_REGNUM;
542 tag = i387_tag (FXSAVE_ADDR (fxsave, regnum));
543 }
544 else
545 tag = 3; /* Empty */
546
547 ftag |= tag << (2 * fpreg);
548 }
549 val[0] = ftag & 0xff;
550 val[1] = (ftag >> 8) & 0xff;
551 }
552 supply_register (i, val);
553 }
554 else
555 supply_register (i, FXSAVE_ADDR (fxsave, i));
556 }
e750d25e
JT
557}
558
559/* Fill register REGNUM (if it is a floating-point or SSE register) in
ed504bdf 560 *FXSAVE with the value in GDB's register cache. If REGNUM is -1, do
e750d25e
JT
561 this for all registers. This function doesn't touch any of the
562 reserved bits in *FXSAVE. */
563
564void
565i387_fill_fxsave (char *fxsave, int regnum)
566{
dff95cc7
MK
567 int i, last_regnum = MXCSR_REGNUM;
568
569 if (gdbarch_tdep (current_gdbarch)->num_xmm_regs == 0)
570 last_regnum = FOP_REGNUM;
e750d25e 571
dff95cc7 572 for (i = FP0_REGNUM; i <= last_regnum; i++)
e750d25e
JT
573 if (regnum == -1 || regnum == i)
574 {
575 /* Most of the FPU control registers occupy only 16 bits in
576 the fxsave area. Give those a special treatment. */
577 if (i >= FPC_REGNUM && i < XMM0_REGNUM
19e33363 578 && i != FIOFF_REGNUM && i != FOOFF_REGNUM)
e750d25e
JT
579 {
580 unsigned char buf[4];
581
582 regcache_collect (i, buf);
583
584 if (i == FOP_REGNUM)
585 {
586 /* The opcode occupies only 11 bits. Make sure we
587 don't touch the other bits. */
588 buf[1] &= ((1 << 3) - 1);
589 buf[1] |= ((FXSAVE_ADDR (fxsave, i))[1] & ~((1 << 3) - 1));
590 }
591 else if (i == FTAG_REGNUM)
592 {
593 /* Converting back is much easier. */
594
595 unsigned short ftag;
596 int fpreg;
597
598 ftag = (buf[1] << 8) | buf[0];
599 buf[0] = 0;
600 buf[1] = 0;
601
602 for (fpreg = 7; fpreg >= 0; fpreg--)
603 {
604 int tag = (ftag >> (fpreg * 2)) & 3;
605
606 if (tag != 3)
607 buf[0] |= (1 << fpreg);
608 }
609 }
610 memcpy (FXSAVE_ADDR (fxsave, i), buf, 2);
611 }
612 else
613 regcache_collect (i, FXSAVE_ADDR (fxsave, i));
614 }
615}
616
617/* Recreate the FTW (tag word) valid bits from the 80-bit FP data in
618 *RAW. */
619
620static int
ed504bdf 621i387_tag (const unsigned char *raw)
e750d25e
JT
622{
623 int integer;
624 unsigned int exponent;
625 unsigned long fraction[2];
626
627 integer = raw[7] & 0x80;
628 exponent = (((raw[9] & 0x7f) << 8) | raw[8]);
629 fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]);
630 fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16)
631 | (raw[5] << 8) | raw[4]);
632
633 if (exponent == 0x7fff)
634 {
635 /* Special. */
636 return (2);
637 }
638 else if (exponent == 0x0000)
639 {
640 if (fraction[0] == 0x0000 && fraction[1] == 0x0000 && !integer)
641 {
642 /* Zero. */
643 return (1);
644 }
645 else
646 {
647 /* Special. */
648 return (2);
649 }
650 }
651 else
652 {
653 if (integer)
654 {
655 /* Valid. */
656 return (0);
657 }
658 else
659 {
660 /* Special. */
661 return (2);
662 }
663 }
664}
This page took 0.66804 seconds and 4 git commands to generate.