]>
Commit | Line | Data |
---|---|---|
252b5132 | 1 | /* atof_tahoe.c - turn a string into a Tahoe floating point number |
f7e42eb4 | 2 | Copyright 1987, 1993, 2000 Free Software Foundation, Inc. |
252b5132 RH |
3 | |
4 | /* This is really a simplified version of atof_vax.c. I glommed it wholesale | |
5 | and then shaved it down. I don't even know how it works. (Don't you find | |
2d484c7f | 6 | my honesty refreshing? Devon E Bowen <[email protected]> |
252b5132 | 7 | |
2d484c7f KH |
8 | I don't allow uppercase letters in the precision descrpitors. |
9 | i.e. 'f' and 'd' are allowed but 'F' and 'D' aren't. */ | |
252b5132 RH |
10 | |
11 | #include "as.h" | |
12 | ||
2d484c7f | 13 | /* Precision in LittleNums. */ |
252b5132 RH |
14 | #define MAX_PRECISION (4) |
15 | #define D_PRECISION (4) | |
16 | #define F_PRECISION (2) | |
17 | ||
2d484c7f | 18 | /* Precision in chars. */ |
252b5132 RH |
19 | #define D_PRECISION_CHARS (8) |
20 | #define F_PRECISION_CHARS (4) | |
21 | ||
2d484c7f | 22 | /* Length in LittleNums of guard bits. */ |
252b5132 RH |
23 | #define GUARD (2) |
24 | ||
25 | static const long int mask[] = | |
26 | { | |
27 | 0x00000000, | |
28 | 0x00000001, | |
29 | 0x00000003, | |
30 | 0x00000007, | |
31 | 0x0000000f, | |
32 | 0x0000001f, | |
33 | 0x0000003f, | |
34 | 0x0000007f, | |
35 | 0x000000ff, | |
36 | 0x000001ff, | |
37 | 0x000003ff, | |
38 | 0x000007ff, | |
39 | 0x00000fff, | |
40 | 0x00001fff, | |
41 | 0x00003fff, | |
42 | 0x00007fff, | |
43 | 0x0000ffff, | |
44 | 0x0001ffff, | |
45 | 0x0003ffff, | |
46 | 0x0007ffff, | |
47 | 0x000fffff, | |
48 | 0x001fffff, | |
49 | 0x003fffff, | |
50 | 0x007fffff, | |
51 | 0x00ffffff, | |
52 | 0x01ffffff, | |
53 | 0x03ffffff, | |
54 | 0x07ffffff, | |
55 | 0x0fffffff, | |
56 | 0x1fffffff, | |
57 | 0x3fffffff, | |
58 | 0x7fffffff, | |
59 | 0xffffffff | |
60 | }; | |
61 | \f | |
2d484c7f | 62 | /* Shared between flonum_gen2tahoe and next_bits. */ |
252b5132 RH |
63 | static int bits_left_in_littlenum; |
64 | static LITTLENUM_TYPE *littlenum_pointer; | |
65 | static LITTLENUM_TYPE *littlenum_end; | |
66 | ||
67 | #if __STDC__ == 1 | |
68 | ||
2d484c7f KH |
69 | int flonum_gen2tahoe (int format_letter, FLONUM_TYPE * f, |
70 | LITTLENUM_TYPE * words); | |
252b5132 | 71 | |
2d484c7f | 72 | #else /* not __STDC__ */ |
252b5132 RH |
73 | |
74 | int flonum_gen2tahoe (); | |
75 | ||
2d484c7f | 76 | #endif /* not __STDC__ */ |
252b5132 RH |
77 | |
78 | static int | |
79 | next_bits (number_of_bits) | |
80 | int number_of_bits; | |
81 | { | |
82 | int return_value; | |
83 | ||
84 | if (littlenum_pointer < littlenum_end) | |
85 | return 0; | |
86 | if (number_of_bits >= bits_left_in_littlenum) | |
87 | { | |
88 | return_value = mask[bits_left_in_littlenum] & *littlenum_pointer; | |
89 | number_of_bits -= bits_left_in_littlenum; | |
90 | return_value <<= number_of_bits; | |
91 | bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS - number_of_bits; | |
92 | littlenum_pointer--; | |
93 | if (littlenum_pointer >= littlenum_end) | |
94 | return_value |= ((*littlenum_pointer) >> (bits_left_in_littlenum)) & | |
95 | mask[number_of_bits]; | |
96 | } | |
97 | else | |
98 | { | |
99 | bits_left_in_littlenum -= number_of_bits; | |
100 | return_value = mask[number_of_bits] & | |
101 | ((*littlenum_pointer) >> bits_left_in_littlenum); | |
102 | } | |
2d484c7f | 103 | return return_value; |
252b5132 RH |
104 | } |
105 | ||
106 | static void | |
107 | make_invalid_floating_point_number (words) | |
108 | LITTLENUM_TYPE *words; | |
109 | { | |
2d484c7f KH |
110 | /* Floating Reserved Operand Code. */ |
111 | *words = 0x8000; | |
252b5132 RH |
112 | } |
113 | \f | |
2d484c7f | 114 | static int /* 0 means letter is OK. */ |
252b5132 | 115 | what_kind_of_float (letter, precisionP, exponent_bitsP) |
2d484c7f KH |
116 | /* In: lowercase please. What kind of float? */ |
117 | char letter; | |
118 | ||
119 | /* Number of 16-bit words in the float. */ | |
120 | int *precisionP; | |
121 | ||
122 | /* Number of exponent bits. */ | |
123 | long int *exponent_bitsP; | |
252b5132 | 124 | { |
2d484c7f | 125 | int retval; /* 0: OK. */ |
252b5132 RH |
126 | |
127 | retval = 0; | |
128 | switch (letter) | |
129 | { | |
130 | case 'f': | |
131 | *precisionP = F_PRECISION; | |
132 | *exponent_bitsP = 8; | |
133 | break; | |
134 | ||
135 | case 'd': | |
136 | *precisionP = D_PRECISION; | |
137 | *exponent_bitsP = 8; | |
138 | break; | |
139 | ||
140 | default: | |
141 | retval = 69; | |
142 | break; | |
143 | } | |
144 | return (retval); | |
145 | } | |
146 | \f | |
2d484c7f KH |
147 | /* Warning: This returns 16-bit LITTLENUMs, because that is what the |
148 | VAX thinks in. It is up to the caller to figure out any alignment | |
149 | problems and to conspire for the bytes/word to be emitted in the | |
150 | right order. Bigendians beware! */ | |
151 | ||
152 | char * /* Return pointer past text consumed. */ | |
252b5132 | 153 | atof_tahoe (str, what_kind, words) |
2d484c7f | 154 | char *str; /* Text to convert to binary. */ |
252b5132 | 155 | char what_kind; /* 'd', 'f', 'g', 'h' */ |
2d484c7f | 156 | LITTLENUM_TYPE *words; /* Build the binary here. */ |
252b5132 RH |
157 | { |
158 | FLONUM_TYPE f; | |
159 | LITTLENUM_TYPE bits[MAX_PRECISION + MAX_PRECISION + GUARD]; | |
2d484c7f KH |
160 | /* Extra bits for zeroed low-order bits. */ |
161 | /* The 1st MAX_PRECISION are zeroed, the last contain flonum bits. */ | |
252b5132 | 162 | char *return_value; |
2d484c7f | 163 | int precision; /* Number of 16-bit words in the format. */ |
252b5132 RH |
164 | long int exponent_bits; |
165 | ||
166 | return_value = str; | |
167 | f.low = bits + MAX_PRECISION; | |
168 | f.high = NULL; | |
169 | f.leader = NULL; | |
170 | f.exponent = NULL; | |
171 | f.sign = '\0'; | |
172 | ||
173 | if (what_kind_of_float (what_kind, &precision, &exponent_bits)) | |
174 | { | |
2d484c7f KH |
175 | /* We lost. */ |
176 | return_value = NULL; | |
252b5132 RH |
177 | make_invalid_floating_point_number (words); |
178 | } | |
179 | if (return_value) | |
180 | { | |
181 | memset (bits, '\0', sizeof (LITTLENUM_TYPE) * MAX_PRECISION); | |
182 | ||
2d484c7f KH |
183 | /* Use more LittleNums than seems necessary: |
184 | the highest flonum may have 15 leading 0 bits, so could be | |
185 | useless. */ | |
252b5132 RH |
186 | f.high = f.low + precision - 1 + GUARD; |
187 | ||
188 | if (atof_generic (&return_value, ".", "eE", &f)) | |
189 | { | |
190 | make_invalid_floating_point_number (words); | |
2d484c7f KH |
191 | /* We lost. */ |
192 | return_value = NULL; | |
252b5132 RH |
193 | } |
194 | else | |
195 | { | |
196 | if (flonum_gen2tahoe (what_kind, &f, words)) | |
2d484c7f | 197 | return_value = NULL; |
252b5132 RH |
198 | } |
199 | } | |
2d484c7f | 200 | return return_value; |
252b5132 RH |
201 | } |
202 | \f | |
2d484c7f KH |
203 | /* In: a flonum, a Tahoe floating point format. |
204 | Out: a Tahoe floating-point bit pattern. */ | |
252b5132 | 205 | |
2d484c7f | 206 | int /* 0: OK. */ |
252b5132 | 207 | flonum_gen2tahoe (format_letter, f, words) |
2d484c7f | 208 | char format_letter; /* One of 'd' 'f'. */ |
252b5132 | 209 | FLONUM_TYPE *f; |
2d484c7f | 210 | LITTLENUM_TYPE *words; /* Deliver answer here. */ |
252b5132 RH |
211 | { |
212 | LITTLENUM_TYPE *lp; | |
213 | int precision; | |
214 | long int exponent_bits; | |
2d484c7f | 215 | int return_value; /* 0 == OK. */ |
252b5132 | 216 | |
2d484c7f KH |
217 | return_value = |
218 | what_kind_of_float (format_letter, &precision, &exponent_bits); | |
252b5132 RH |
219 | if (return_value != 0) |
220 | { | |
221 | make_invalid_floating_point_number (words); | |
222 | } | |
223 | else | |
224 | { | |
225 | if (f->low > f->leader) | |
226 | { | |
2d484c7f | 227 | /* 0.0e0 seen. */ |
252b5132 RH |
228 | memset (words, '\0', sizeof (LITTLENUM_TYPE) * precision); |
229 | } | |
230 | else | |
231 | { | |
232 | long int exponent_1; | |
233 | long int exponent_2; | |
234 | long int exponent_3; | |
235 | long int exponent_4; | |
236 | int exponent_skippage; | |
237 | LITTLENUM_TYPE word1; | |
238 | ||
2d484c7f | 239 | /* JF: Deal with new Nan, +Inf and -Inf codes. */ |
252b5132 RH |
240 | if (f->sign != '-' && f->sign != '+') |
241 | { | |
242 | make_invalid_floating_point_number (words); | |
243 | return return_value; | |
244 | } | |
2d484c7f KH |
245 | /* All tahoe floating_point formats have: |
246 | Bit 15 is sign bit. | |
247 | Bits 14:n are excess-whatever exponent. | |
248 | Bits n-1:0 (if any) are most significant bits of fraction. | |
249 | Bits 15:0 of the next word are the next most significant bits. | |
250 | And so on for each other word. | |
251 | ||
252 | So we need: number of bits of exponent, number of bits of | |
253 | mantissa. */ | |
252b5132 RH |
254 | |
255 | bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS; | |
256 | littlenum_pointer = f->leader; | |
257 | littlenum_end = f->low; | |
2d484c7f KH |
258 | |
259 | /* Seek (and forget) 1st significant bit. */ | |
252b5132 RH |
260 | for (exponent_skippage = 0; |
261 | !next_bits (1); | |
262 | exponent_skippage++) | |
2d484c7f KH |
263 | ; |
264 | ||
252b5132 | 265 | exponent_1 = f->exponent + f->leader + 1 - f->low; |
2d484c7f KH |
266 | |
267 | /* Radix LITTLENUM_RADIX, point just higher than f -> leader. */ | |
252b5132 | 268 | exponent_2 = exponent_1 * LITTLENUM_NUMBER_OF_BITS; |
2d484c7f KH |
269 | |
270 | /* Radix 2. */ | |
252b5132 | 271 | exponent_3 = exponent_2 - exponent_skippage; |
2d484c7f KH |
272 | |
273 | /* Forget leading zeros, forget 1st bit. */ | |
252b5132 | 274 | exponent_4 = exponent_3 + (1 << (exponent_bits - 1)); |
2d484c7f KH |
275 | |
276 | /* Offset exponent. */ | |
252b5132 RH |
277 | |
278 | if (exponent_4 & ~mask[exponent_bits]) | |
279 | { | |
2d484c7f | 280 | /* Exponent overflow. Lose immediately. */ |
252b5132 RH |
281 | |
282 | make_invalid_floating_point_number (words); | |
283 | ||
2d484c7f KH |
284 | /* We leave return_value alone: admit we read the |
285 | number, but return a floating exception because we | |
286 | can't encode the number. */ | |
252b5132 RH |
287 | } |
288 | else | |
289 | { | |
290 | lp = words; | |
291 | ||
2d484c7f KH |
292 | /* Word 1. Sign, exponent and perhaps high bits. */ |
293 | /* Assume 2's complement integers. */ | |
294 | word1 = ((exponent_4 & mask[exponent_bits]) | |
295 | << (15 - exponent_bits)) | |
252b5132 RH |
296 | | ((f->sign == '+') ? 0 : 0x8000) |
297 | | next_bits (15 - exponent_bits); | |
298 | *lp++ = word1; | |
299 | ||
2d484c7f | 300 | /* The rest of the words are just mantissa bits. */ |
252b5132 | 301 | for (; lp < words + precision; lp++) |
2d484c7f | 302 | *lp = next_bits (LITTLENUM_NUMBER_OF_BITS); |
252b5132 RH |
303 | |
304 | if (next_bits (1)) | |
305 | { | |
2d484c7f KH |
306 | /* Since the NEXT bit is a 1, round UP the mantissa. |
307 | The cunning design of these hidden-1 floats permits | |
308 | us to let the mantissa overflow into the exponent, and | |
309 | it 'does the right thing'. However, we lose if the | |
310 | highest-order bit of the lowest-order word flips. | |
311 | Is that clear? */ | |
252b5132 RH |
312 | |
313 | unsigned long int carry; | |
314 | ||
2d484c7f KH |
315 | /* #if (sizeof(carry)) < ((sizeof(bits[0]) * |
316 | BITS_PER_CHAR) + 2) Please allow at least 1 more | |
317 | bit in carry than is in a LITTLENUM. We need | |
318 | that extra bit to hold a carry during a LITTLENUM | |
319 | carry propagation. Another extra bit (kept 0) | |
320 | will assure us that we don't get a sticky sign | |
321 | bit after shifting right, and that permits us to | |
322 | propagate the carry without any masking of bits. | |
323 | #endif */ | |
252b5132 RH |
324 | for (carry = 1, lp--; |
325 | carry && (lp >= words); | |
326 | lp--) | |
327 | { | |
328 | carry = *lp + carry; | |
329 | *lp = carry; | |
330 | carry >>= LITTLENUM_NUMBER_OF_BITS; | |
331 | } | |
332 | ||
2d484c7f KH |
333 | if ((word1 ^ *words) |
334 | & (1 << (LITTLENUM_NUMBER_OF_BITS - 1))) | |
252b5132 RH |
335 | { |
336 | make_invalid_floating_point_number (words); | |
2d484c7f KH |
337 | /* We leave return_value alone: admit we read |
338 | the number, but return a floating exception | |
339 | because we can't encode the number. */ | |
252b5132 | 340 | } |
2d484c7f KH |
341 | } /* if (we needed to round up) */ |
342 | } /* if (exponent overflow) */ | |
343 | } /* if (0.0e0) */ | |
344 | } /* if (float_type was OK) */ | |
345 | return return_value; | |
252b5132 RH |
346 | } |
347 | \f | |
2d484c7f | 348 | /* In: input_line_pointer -> the 1st character of a floating-point |
252b5132 RH |
349 | * number. |
350 | * 1 letter denoting the type of statement that wants a | |
351 | * binary floating point number returned. | |
352 | * Address of where to build floating point literal. | |
353 | * Assumed to be 'big enough'. | |
354 | * Address of where to return size of literal (in chars). | |
355 | * | |
356 | * Out: Input_line_pointer -> of next char after floating number. | |
357 | * Error message, or 0. | |
358 | * Floating point literal. | |
2d484c7f | 359 | * Number of chars we used for the literal. */ |
252b5132 RH |
360 | |
361 | char * | |
362 | md_atof (what_statement_type, literalP, sizeP) | |
363 | char what_statement_type; | |
364 | char *literalP; | |
365 | int *sizeP; | |
366 | { | |
367 | LITTLENUM_TYPE words[MAX_PRECISION]; | |
368 | register char kind_of_float; | |
369 | register int number_of_chars; | |
370 | register LITTLENUM_TYPE *littlenum_pointer; | |
371 | ||
372 | switch (what_statement_type) | |
373 | { | |
2d484c7f KH |
374 | case 'f': /* .ffloat */ |
375 | case 'd': /* .dfloat */ | |
252b5132 RH |
376 | kind_of_float = what_statement_type; |
377 | break; | |
378 | ||
379 | default: | |
380 | kind_of_float = 0; | |
381 | break; | |
2d484c7f | 382 | } |
252b5132 RH |
383 | |
384 | if (kind_of_float) | |
385 | { | |
386 | register LITTLENUM_TYPE *limit; | |
387 | ||
388 | input_line_pointer = atof_tahoe (input_line_pointer, | |
389 | kind_of_float, | |
390 | words); | |
2d484c7f KH |
391 | /* The atof_tahoe() builds up 16-bit numbers. |
392 | Since the assembler may not be running on | |
393 | a different-endian machine, be very careful about | |
394 | converting words to chars. */ | |
252b5132 RH |
395 | number_of_chars = (kind_of_float == 'f' ? F_PRECISION_CHARS : |
396 | (kind_of_float == 'd' ? D_PRECISION_CHARS : 0)); | |
397 | know (number_of_chars <= MAX_PRECISION * sizeof (LITTLENUM_TYPE)); | |
398 | limit = words + (number_of_chars / sizeof (LITTLENUM_TYPE)); | |
399 | for (littlenum_pointer = words; | |
400 | littlenum_pointer < limit; | |
401 | littlenum_pointer++) | |
402 | { | |
403 | md_number_to_chars (literalP, *littlenum_pointer, | |
404 | sizeof (LITTLENUM_TYPE)); | |
405 | literalP += sizeof (LITTLENUM_TYPE); | |
2d484c7f | 406 | } |
252b5132 RH |
407 | } |
408 | else | |
409 | { | |
410 | number_of_chars = 0; | |
2d484c7f | 411 | } |
252b5132 RH |
412 | |
413 | *sizeP = number_of_chars; | |
414 | return kind_of_float ? 0 : _("Bad call to md_atof()"); | |
415 | } |