ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/mon/src/disass/floatformat.c
Revision: 1.1
Committed: 2000-09-25T12:44:37Z (24 years, 1 month ago) by cebix
Content type: text/plain
Branch: MAIN
CVS Tags: release_3-1, release_3-2, HEAD
Log Message:
- replaced 680x0 and 80x86 disassemblers with the ones from GNU binutils
- 680x0 disassembler shows symbolic MacOS low memory globals

File Contents

# User Rev Content
1 cebix 1.1 /* IEEE floating point support routines, for GDB, the GNU Debugger.
2     Copyright (C) 1991, 1994 Free Software Foundation, Inc.
3    
4     This file is part of GDB.
5    
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10    
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     GNU General Public License for more details.
15    
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
19    
20     #include "floatformat.h"
21     #include <math.h> /* ldexp */
22     #ifdef __STDC__
23     #include <stddef.h>
24     extern void *memcpy (void *s1, const void *s2, size_t n);
25     extern void *memset (void *s, int c, size_t n);
26     #else
27     extern char *memcpy ();
28     extern char *memset ();
29     #endif
30    
31     /* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not
32     going to bother with trying to muck around with whether it is defined in
33     a system header, what we do if not, etc. */
34     #define FLOATFORMAT_CHAR_BIT 8
35    
36     /* floatformats for IEEE single and double, big and little endian. */
37     const struct floatformat floatformat_ieee_single_big =
38     {
39     floatformat_big, 32, 0, 1, 8, 127, 255, 9, 23, floatformat_intbit_no
40     };
41     const struct floatformat floatformat_ieee_single_little =
42     {
43     floatformat_little, 32, 0, 1, 8, 127, 255, 9, 23, floatformat_intbit_no
44     };
45     const struct floatformat floatformat_ieee_double_big =
46     {
47     floatformat_big, 64, 0, 1, 11, 1023, 2047, 12, 52, floatformat_intbit_no
48     };
49     const struct floatformat floatformat_ieee_double_little =
50     {
51     floatformat_little, 64, 0, 1, 11, 1023, 2047, 12, 52, floatformat_intbit_no
52     };
53    
54     /* floatformat for IEEE double, little endian byte order, with big endian word
55     ordering, as on the ARM. */
56    
57     const struct floatformat floatformat_ieee_double_littlebyte_bigword =
58     {
59     floatformat_littlebyte_bigword, 64, 0, 1, 11, 1023, 2047, 12, 52, floatformat_intbit_no
60     };
61    
62     const struct floatformat floatformat_i387_ext =
63     {
64     floatformat_little, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
65     floatformat_intbit_yes
66     };
67     const struct floatformat floatformat_m68881_ext =
68     {
69     /* Note that the bits from 16 to 31 are unused. */
70     floatformat_big, 96, 0, 1, 15, 0x3fff, 0x7fff, 32, 64, floatformat_intbit_yes
71     };
72     const struct floatformat floatformat_i960_ext =
73     {
74     /* Note that the bits from 0 to 15 are unused. */
75     floatformat_little, 96, 16, 17, 15, 0x3fff, 0x7fff, 32, 64,
76     floatformat_intbit_yes
77     };
78     const struct floatformat floatformat_m88110_ext =
79     {
80     #ifdef HARRIS_FLOAT_FORMAT
81     /* Harris uses raw format 128 bytes long, but the number is just an ieee
82     double, and the last 64 bits are wasted. */
83     floatformat_big,128, 0, 1, 11, 0x3ff, 0x7ff, 12, 52,
84     floatformat_intbit_no
85     #else
86     floatformat_big, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
87     floatformat_intbit_yes
88     #endif /* HARRIS_FLOAT_FORMAT */
89     };
90     const struct floatformat floatformat_arm_ext =
91     {
92     /* Bits 1 to 16 are unused. */
93     floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
94     floatformat_intbit_yes
95     };
96    
97     static unsigned long get_field PARAMS ((unsigned char *,
98     enum floatformat_byteorders,
99     unsigned int,
100     unsigned int,
101     unsigned int));
102    
103     /* Extract a field which starts at START and is LEN bytes long. DATA and
104     TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */
105     static unsigned long
106     get_field (data, order, total_len, start, len)
107     unsigned char *data;
108     enum floatformat_byteorders order;
109     unsigned int total_len;
110     unsigned int start;
111     unsigned int len;
112     {
113     unsigned long result;
114     unsigned int cur_byte;
115     int cur_bitshift;
116    
117     /* Start at the least significant part of the field. */
118     cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
119     if (order == floatformat_little)
120     cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1;
121     cur_bitshift =
122     ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
123     result = *(data + cur_byte) >> (-cur_bitshift);
124     cur_bitshift += FLOATFORMAT_CHAR_BIT;
125     if (order == floatformat_little)
126     ++cur_byte;
127     else
128     --cur_byte;
129    
130     /* Move towards the most significant part of the field. */
131     while (cur_bitshift < len)
132     {
133     if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT)
134     /* This is the last byte; zero out the bits which are not part of
135     this field. */
136     result |=
137     (*(data + cur_byte) & ((1 << (len - cur_bitshift)) - 1))
138     << cur_bitshift;
139     else
140     result |= *(data + cur_byte) << cur_bitshift;
141     cur_bitshift += FLOATFORMAT_CHAR_BIT;
142     if (order == floatformat_little)
143     ++cur_byte;
144     else
145     --cur_byte;
146     }
147     return result;
148     }
149    
150     #ifndef min
151     #define min(a, b) ((a) < (b) ? (a) : (b))
152     #endif
153    
154     /* Convert from FMT to a double.
155     FROM is the address of the extended float.
156     Store the double in *TO. */
157    
158     void
159     floatformat_to_double (fmt, from, to)
160     const struct floatformat *fmt;
161     char *from;
162     double *to;
163     {
164     unsigned char *ufrom = (unsigned char *)from;
165     double dto;
166     long exponent;
167     unsigned long mant;
168     unsigned int mant_bits, mant_off;
169     int mant_bits_left;
170     int special_exponent; /* It's a NaN, denorm or zero */
171    
172     exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
173     fmt->exp_start, fmt->exp_len);
174     /* Note that if exponent indicates a NaN, we can't really do anything useful
175     (not knowing if the host has NaN's, or how to build one). So it will
176     end up as an infinity or something close; that is OK. */
177    
178     mant_bits_left = fmt->man_len;
179     mant_off = fmt->man_start;
180     dto = 0.0;
181    
182     special_exponent = exponent == 0 || exponent == fmt->exp_nan;
183    
184     /* Don't bias zero's, denorms or NaNs. */
185     if (!special_exponent)
186     exponent -= fmt->exp_bias;
187    
188     /* Build the result algebraically. Might go infinite, underflow, etc;
189     who cares. */
190    
191     /* If this format uses a hidden bit, explicitly add it in now. Otherwise,
192     increment the exponent by one to account for the integer bit. */
193    
194     if (!special_exponent)
195     if (fmt->intbit == floatformat_intbit_no)
196     dto = ldexp (1.0, exponent);
197     else
198     exponent++;
199    
200     while (mant_bits_left > 0)
201     {
202     mant_bits = min (mant_bits_left, 32);
203    
204     mant = get_field (ufrom, fmt->byteorder, fmt->totalsize,
205     mant_off, mant_bits);
206    
207     dto += ldexp ((double)mant, exponent - mant_bits);
208     exponent -= mant_bits;
209     mant_off += mant_bits;
210     mant_bits_left -= mant_bits;
211     }
212    
213     /* Negate it if negative. */
214     if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
215     dto = -dto;
216     *to = dto;
217     }
218    
219     static void put_field PARAMS ((unsigned char *, enum floatformat_byteorders,
220     unsigned int,
221     unsigned int,
222     unsigned int,
223     unsigned long));
224    
225     /* Set a field which starts at START and is LEN bytes long. DATA and
226     TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */
227     static void
228     put_field (data, order, total_len, start, len, stuff_to_put)
229     unsigned char *data;
230     enum floatformat_byteorders order;
231     unsigned int total_len;
232     unsigned int start;
233     unsigned int len;
234     unsigned long stuff_to_put;
235     {
236     unsigned int cur_byte;
237     int cur_bitshift;
238    
239     /* Start at the least significant part of the field. */
240     cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
241     if (order == floatformat_little)
242     cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1;
243     cur_bitshift =
244     ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
245     *(data + cur_byte) &=
246     ~(((1 << ((start + len) % FLOATFORMAT_CHAR_BIT)) - 1) << (-cur_bitshift));
247     *(data + cur_byte) |=
248     (stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift);
249     cur_bitshift += FLOATFORMAT_CHAR_BIT;
250     if (order == floatformat_little)
251     ++cur_byte;
252     else
253     --cur_byte;
254    
255     /* Move towards the most significant part of the field. */
256     while (cur_bitshift < len)
257     {
258     if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT)
259     {
260     /* This is the last byte. */
261     *(data + cur_byte) &=
262     ~((1 << (len - cur_bitshift)) - 1);
263     *(data + cur_byte) |= (stuff_to_put >> cur_bitshift);
264     }
265     else
266     *(data + cur_byte) = ((stuff_to_put >> cur_bitshift)
267     & ((1 << FLOATFORMAT_CHAR_BIT) - 1));
268     cur_bitshift += FLOATFORMAT_CHAR_BIT;
269     if (order == floatformat_little)
270     ++cur_byte;
271     else
272     --cur_byte;
273     }
274     }
275    
276     /* The converse: convert the double *FROM to an extended float
277     and store where TO points. Neither FROM nor TO have any alignment
278     restrictions. */
279    
280     void
281     floatformat_from_double (fmt, from, to)
282     CONST struct floatformat *fmt;
283     double *from;
284     char *to;
285     {
286     double dfrom;
287     int exponent;
288     double mant;
289     unsigned int mant_bits, mant_off;
290     int mant_bits_left;
291     unsigned char *uto = (unsigned char *)to;
292    
293     memcpy (&dfrom, from, sizeof (dfrom));
294     memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT);
295     if (dfrom == 0)
296     return; /* Result is zero */
297     if (dfrom != dfrom)
298     {
299     /* From is NaN */
300     put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
301     fmt->exp_len, fmt->exp_nan);
302     /* Be sure it's not infinity, but NaN value is irrel */
303     put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start,
304     32, 1);
305     return;
306     }
307    
308     /* If negative, set the sign bit. */
309     if (dfrom < 0)
310     {
311     put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1);
312     dfrom = -dfrom;
313     }
314    
315     /* How to tell an infinity from an ordinary number? FIXME-someday */
316    
317     mant = frexp (dfrom, &exponent);
318     put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, fmt->exp_len,
319     exponent + fmt->exp_bias - 1);
320    
321     mant_bits_left = fmt->man_len;
322     mant_off = fmt->man_start;
323     while (mant_bits_left > 0)
324     {
325     unsigned long mant_long;
326     mant_bits = mant_bits_left < 32 ? mant_bits_left : 32;
327    
328     mant *= 4294967296.0;
329     mant_long = (unsigned long)mant;
330     mant -= mant_long;
331    
332     /* If the integer bit is implicit, then we need to discard it.
333     If we are discarding a zero, we should be (but are not) creating
334     a denormalized number which means adjusting the exponent
335     (I think). */
336     if (mant_bits_left == fmt->man_len
337     && fmt->intbit == floatformat_intbit_no)
338     {
339     mant_long &= 0x7fffffff;
340     mant_bits -= 1;
341     }
342     else if (mant_bits < 32)
343     {
344     /* The bits we want are in the most significant MANT_BITS bits of
345     mant_long. Move them to the least significant. */
346     mant_long >>= 32 - mant_bits;
347     }
348    
349     put_field (uto, fmt->byteorder, fmt->totalsize,
350     mant_off, mant_bits, mant_long);
351     mant_off += mant_bits;
352     mant_bits_left -= mant_bits;
353     }
354     }
355    
356    
357     #ifdef IEEE_DEBUG
358    
359     /* This is to be run on a host which uses IEEE floating point. */
360    
361     void
362     ieee_test (n)
363     double n;
364     {
365     double result;
366     char exten[16];
367    
368     floatformat_to_double (&floatformat_ieee_double_big, &n, &result);
369     if (n != result)
370     printf ("Differ(to): %.20g -> %.20g\n", n, result);
371     floatformat_from_double (&floatformat_ieee_double_big, &n, &result);
372     if (n != result)
373     printf ("Differ(from): %.20g -> %.20g\n", n, result);
374    
375     floatformat_from_double (&floatformat_m68881_ext, &n, exten);
376     floatformat_to_double (&floatformat_m68881_ext, exten, &result);
377     if (n != result)
378     printf ("Differ(to+from): %.20g -> %.20g\n", n, result);
379    
380     #if IEEE_DEBUG > 1
381     /* This is to be run on a host which uses 68881 format. */
382     {
383     long double ex = *(long double *)exten;
384     if (ex != n)
385     printf ("Differ(from vs. extended): %.20g\n", n);
386     }
387     #endif
388     }
389    
390     int
391     main ()
392     {
393     ieee_test (0.5);
394     ieee_test (256.0);
395     ieee_test (0.12345);
396     ieee_test (234235.78907234);
397     ieee_test (-512.0);
398     ieee_test (-0.004321);
399     return 0;
400     }
401     #endif