atof-vax.c revision 1.10 1 /* atof_vax.c - turn a Flonum into a VAX floating point number
2 Copyright (C) 1987-2025 Free Software Foundation, Inc.
3
4 This file is part of GAS, the GNU Assembler.
5
6 GAS 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 3, or (at your option)
9 any later version.
10
11 GAS 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 GAS; see the file COPYING. If not, write to the Free
18 Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
19 02110-1301, USA. */
20
21 #include "as.h"
22
23 /* Precision in LittleNums. */
24 #define MAX_PRECISION 8
25 #define H_PRECISION 8
26 #define G_PRECISION 4
27 #define D_PRECISION 4
28 #define F_PRECISION 2
29
30 /* Length in LittleNums of guard bits. */
31 #define GUARD 2
32
33 int flonum_gen2vax (int, FLONUM_TYPE *, LITTLENUM_TYPE *);
34
35 /* Number of chars in flonum type 'letter'. */
36
37 static unsigned int
38 atof_vax_sizeof (int letter)
39 {
40 int return_value;
41
42 /* Permitting uppercase letters is probably a bad idea.
43 Please use only lower-cased letters in case the upper-cased
44 ones become unsupported! */
45 switch (letter)
46 {
47 case 'f':
48 case 'F':
49 return_value = 4;
50 break;
51
52 case 'd':
53 case 'D':
54 case 'g':
55 case 'G':
56 return_value = 8;
57 break;
58
59 case 'h':
60 case 'H':
61 return_value = 16;
62 break;
63
64 default:
65 return_value = 0;
66 break;
67 }
68
69 return return_value;
70 }
71
72 static const long mask[] =
73 {
74 0x00000000,
75 0x00000001,
76 0x00000003,
77 0x00000007,
78 0x0000000f,
79 0x0000001f,
80 0x0000003f,
81 0x0000007f,
82 0x000000ff,
83 0x000001ff,
84 0x000003ff,
85 0x000007ff,
86 0x00000fff,
87 0x00001fff,
88 0x00003fff,
89 0x00007fff,
90 0x0000ffff,
91 0x0001ffff,
92 0x0003ffff,
93 0x0007ffff,
94 0x000fffff,
95 0x001fffff,
96 0x003fffff,
97 0x007fffff,
98 0x00ffffff,
99 0x01ffffff,
100 0x03ffffff,
101 0x07ffffff,
102 0x0fffffff,
103 0x1fffffff,
104 0x3fffffff,
105 0x7fffffff,
106 0xffffffff
107 };
108
109
111 /* Shared between flonum_gen2vax and next_bits. */
112 static int bits_left_in_littlenum;
113 static LITTLENUM_TYPE *littlenum_pointer;
114 static LITTLENUM_TYPE *littlenum_end;
115
116 static int
117 next_bits (int number_of_bits)
118 {
119 int return_value;
120
121 if (littlenum_pointer < littlenum_end)
122 return 0;
123 if (number_of_bits >= bits_left_in_littlenum)
124 {
125 return_value = mask[bits_left_in_littlenum] & *littlenum_pointer;
126 number_of_bits -= bits_left_in_littlenum;
127 return_value <<= number_of_bits;
128 bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS - number_of_bits;
129 littlenum_pointer--;
130 if (littlenum_pointer >= littlenum_end)
131 return_value |= ((*littlenum_pointer) >> (bits_left_in_littlenum)) & mask[number_of_bits];
132 }
133 else
134 {
135 bits_left_in_littlenum -= number_of_bits;
136 return_value = mask[number_of_bits] & ((*littlenum_pointer) >> bits_left_in_littlenum);
137 }
138 return return_value;
139 }
140
141 static void
142 make_invalid_floating_point_number (LITTLENUM_TYPE *words)
143 {
144 *words = 0x8000; /* Floating Reserved Operand Code. */
145 }
146
147
148 static int /* 0 means letter is OK. */
150 what_kind_of_float (int letter, /* In: lowercase please. What kind of float? */
151 int *precisionP, /* Number of 16-bit words in the float. */
152 long *exponent_bitsP) /* Number of exponent bits. */
153 {
154 int retval;
155
156 retval = 0;
157 switch (letter)
158 {
159 case 'f':
160 *precisionP = F_PRECISION;
161 *exponent_bitsP = 8;
162 break;
163
164 case 'd':
165 *precisionP = D_PRECISION;
166 *exponent_bitsP = 8;
167 break;
168
169 case 'g':
170 *precisionP = G_PRECISION;
171 *exponent_bitsP = 11;
172 break;
173
174 case 'h':
175 *precisionP = H_PRECISION;
176 *exponent_bitsP = 15;
177 break;
178
179 default:
180 retval = 69;
181 break;
182 }
183 return retval;
184 }
185
186 /* Warning: this returns 16-bit LITTLENUMs, because that is
188 what the VAX thinks in. It is up to the caller to figure
189 out any alignment problems and to conspire for the bytes/word
190 to be emitted in the right order. Bigendians beware! */
191
192 static char *
193 atof_vax (char *str, /* Text to convert to binary. */
194 int what_kind, /* 'd', 'f', 'g', 'h' */
195 LITTLENUM_TYPE *words) /* Build the binary here. */
196 {
197 FLONUM_TYPE f;
198 LITTLENUM_TYPE bits[MAX_PRECISION + MAX_PRECISION + GUARD];
199 /* Extra bits for zeroed low-order bits.
200 The 1st MAX_PRECISION are zeroed,
201 the last contain flonum bits. */
202 char *return_value;
203 int precision; /* Number of 16-bit words in the format. */
204 long exponent_bits;
205
206 return_value = str;
207 f.low = bits + MAX_PRECISION;
208 f.high = NULL;
209 f.leader = NULL;
210 f.exponent = 0;
211 f.sign = '\0';
212
213 if (what_kind_of_float (what_kind, &precision, &exponent_bits))
214 {
215 return_value = NULL;
216 make_invalid_floating_point_number (words);
217 }
218
219 if (return_value)
220 {
221 memset (bits, '\0', sizeof (LITTLENUM_TYPE) * MAX_PRECISION);
222
223 /* Use more LittleNums than seems
224 necessary: the highest flonum may have
225 15 leading 0 bits, so could be useless. */
226 f.high = f.low + precision - 1 + GUARD;
227
228 if (atof_generic (&return_value, ".", "eE", &f))
229 {
230 make_invalid_floating_point_number (words);
231 return_value = NULL;
232 }
233 else if (flonum_gen2vax (what_kind, &f, words))
234 return_value = NULL;
235 }
236
237 return return_value;
238 }
239
240 /* In: a flonum, a vax floating point format.
242 Out: a vax floating-point bit pattern. */
243
244 int
245 flonum_gen2vax (int format_letter, /* One of 'd' 'f' 'g' 'h'. */
246 FLONUM_TYPE *f,
247 LITTLENUM_TYPE *words) /* Deliver answer here. */
248 {
249 LITTLENUM_TYPE *lp;
250 int precision;
251 long exponent_bits;
252 int return_value; /* 0 == OK. */
253
254 return_value = what_kind_of_float (format_letter, &precision, &exponent_bits);
255
256 if (return_value != 0)
257 make_invalid_floating_point_number (words);
258
259 else
260 {
261 if (f->low > f->leader)
262 /* 0.0e0 seen. */
263 memset (words, '\0', sizeof (LITTLENUM_TYPE) * precision);
264
265 else
266 {
267 long exponent_1;
268 long exponent_2;
269 long exponent_3;
270 long exponent_4;
271 int exponent_skippage;
272 LITTLENUM_TYPE word1;
273
274 if (f->sign != '-' && f->sign != '+')
275 {
276 if (f->sign == 0)
277 {
278 /* All NaNs are 0. */
279 memset (words, 0x00, sizeof (LITTLENUM_TYPE) * precision);
280 }
281 else if (f->sign == 'P')
282 {
283 /* Positive Infinity. */
284 memset (words, 0xff, sizeof (LITTLENUM_TYPE) * precision);
285 words[0] &= 0x7fff;
286 }
287 else if (f->sign == 'N')
288 {
289 /* Negative Infinity. */
290 memset (words, 0x00, sizeof (LITTLENUM_TYPE) * precision);
291 words[0] = 0x0080;
292 }
293 else
294 make_invalid_floating_point_number (words);
295 return return_value;
296 }
297
298 /* All vaxen floating_point formats (so far) have:
299 Bit 15 is sign bit.
300 Bits 14:n are excess-whatever exponent.
301 Bits n-1:0 (if any) are most significant bits of fraction.
302 Bits 15:0 of the next word are the next most significant bits.
303 And so on for each other word.
304
305 All this to be compatible with a KF11?? (Which is still faster
306 than lots of vaxen I can think of, but it also has higher
307 maintenance costs ... sigh).
308
309 So we need: number of bits of exponent, number of bits of
310 mantissa. */
311
312 bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS;
313 littlenum_pointer = f->leader;
314 littlenum_end = f->low;
315 /* Seek (and forget) 1st significant bit. */
316 for (exponent_skippage = 0;
317 !next_bits (1);
318 exponent_skippage++);
319
320 exponent_1 = f->exponent + f->leader + 1 - f->low;
321 /* Radix LITTLENUM_RADIX, point just higher than f->leader. */
322 exponent_2 = exponent_1 * LITTLENUM_NUMBER_OF_BITS;
323 /* Radix 2. */
324 exponent_3 = exponent_2 - exponent_skippage;
325 /* Forget leading zeros, forget 1st bit. */
326 exponent_4 = exponent_3 + (1 << (exponent_bits - 1));
327 /* Offset exponent. */
328
329 if (exponent_4 & ~mask[exponent_bits])
330 {
331 /* Exponent overflow. Lose immediately. */
332 make_invalid_floating_point_number (words);
333
334 /* We leave return_value alone: admit we read the
335 number, but return a floating exception
336 because we can't encode the number. */
337 }
338 else
339 {
340 lp = words;
341
342 /* Word 1. Sign, exponent and perhaps high bits.
343 Assume 2's complement integers. */
344 word1 = (((exponent_4 & mask[exponent_bits]) << (15 - exponent_bits))
345 | ((f->sign == '+') ? 0 : 0x8000)
346 | next_bits (15 - exponent_bits));
347 *lp++ = word1;
348
349 /* The rest of the words are just mantissa bits. */
350 for (; lp < words + precision; lp++)
351 *lp = next_bits (LITTLENUM_NUMBER_OF_BITS);
352
353 if (next_bits (1))
354 {
355 /* Since the NEXT bit is a 1, round UP the mantissa.
356 The cunning design of these hidden-1 floats permits
357 us to let the mantissa overflow into the exponent, and
358 it 'does the right thing'. However, we lose if the
359 highest-order bit of the lowest-order word flips.
360 Is that clear? */
361 unsigned long carry;
362
363 /*
364 #if (sizeof(carry)) < ((sizeof(bits[0]) * BITS_PER_CHAR) + 2)
365 Please allow at least 1 more bit in carry than is in a LITTLENUM.
366 We need that extra bit to hold a carry during a LITTLENUM carry
367 propagation. Another extra bit (kept 0) will assure us that we
368 don't get a sticky sign bit after shifting right, and that
369 permits us to propagate the carry without any masking of bits.
370 #endif */
371 for (carry = 1, lp--;
372 carry && (lp >= words);
373 lp--)
374 {
375 carry = *lp + carry;
376 *lp = carry;
377 carry >>= LITTLENUM_NUMBER_OF_BITS;
378 }
379
380 if ((word1 ^ *words) & (1 << (LITTLENUM_NUMBER_OF_BITS - 1)))
381 {
382 make_invalid_floating_point_number (words);
383 /* We leave return_value alone: admit we read the
384 number, but return a floating exception
385 because we can't encode the number. */
386 }
387 }
388 }
389 }
390 }
391 return return_value;
392 }
393
394 /* JF this used to be in vax.c but this looks like a better place for it. */
395
396 /* In: input_line_pointer->the 1st character of a floating-point
397 number.
398 1 letter denoting the type of statement that wants a
399 binary floating point number returned.
400 Address of where to build floating point literal.
401 Assumed to be 'big enough'.
402 Address of where to return size of literal (in chars).
403
404 Out: Input_line_pointer->of next char after floating number.
405 Error message, or 0.
406 Floating point literal.
407 Number of chars we used for the literal. */
408
409 #define MAXIMUM_NUMBER_OF_LITTLENUMS 8 /* For .hfloats. */
410
411 const char *
412 vax_md_atof (int what_statement_type,
413 char *literalP,
414 int *sizeP)
415 {
416 LITTLENUM_TYPE words[MAXIMUM_NUMBER_OF_LITTLENUMS];
417 char kind_of_float;
418 unsigned int number_of_chars;
419 LITTLENUM_TYPE *littlenumP;
420
421 switch (what_statement_type)
422 {
423 case 'F':
424 case 'f':
425 kind_of_float = 'f';
426 break;
427
428 case 'D':
429 case 'd':
430 kind_of_float = 'd';
431 break;
432
433 case 'g':
434 kind_of_float = 'g';
435 break;
436
437 case 'h':
438 kind_of_float = 'h';
439 break;
440
441 default:
442 kind_of_float = 0;
443 break;
444 };
445
446 if (kind_of_float)
447 {
448 LITTLENUM_TYPE *limit;
449
450 input_line_pointer = atof_vax (input_line_pointer,
451 kind_of_float,
452 words);
453 /* The atof_vax() builds up 16-bit numbers.
454 Since the assembler may not be running on
455 a little-endian machine, be very careful about
456 converting words to chars. */
457 number_of_chars = atof_vax_sizeof (kind_of_float);
458 know (number_of_chars <= MAXIMUM_NUMBER_OF_LITTLENUMS * sizeof (LITTLENUM_TYPE));
459 limit = words + (number_of_chars / sizeof (LITTLENUM_TYPE));
460 for (littlenumP = words; littlenumP < limit; littlenumP++)
461 {
462 md_number_to_chars (literalP, *littlenumP, sizeof (LITTLENUM_TYPE));
463 literalP += sizeof (LITTLENUM_TYPE);
464 };
465 }
466 else
467 number_of_chars = 0;
468
469 *sizeP = number_of_chars;
470 return kind_of_float ? NULL : _("Unrecognized or unsupported floating point constant");
471 }
472