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