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 |