]> git.saurik.com Git - apple/boot.git/blame - i386/nasm/float.c
boot-83.2.tar.gz
[apple/boot.git] / i386 / nasm / float.c
CommitLineData
14c7c974
A
1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24/* float.c floating-point constant support for the Netwide Assembler
25 *
26 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
27 * Julian Hall. All rights reserved. The software is
28 * redistributable under the licence given in the file "Licence"
29 * distributed in the NASM archive.
30 *
31 * initial version 13/ix/96 by Simon Tatham
32 */
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37
38#include "nasm.h"
39
40#define TRUE 1
41#define FALSE 0
42
43#define MANT_WORDS 6 /* 64 bits + 32 for accuracy == 96 */
44#define MANT_DIGITS 28 /* 29 digits don't fit in 96 bits */
45
46/*
47 * guaranteed top bit of from is set
48 * => we only have to worry about _one_ bit shift to the left
49 */
50
51static int multiply(unsigned short *to, unsigned short *from) {
52 unsigned long temp[MANT_WORDS*2];
53 int i, j;
54
55 for (i=0; i<MANT_WORDS*2; i++)
56 temp[i] = 0;
57
58 for (i=0; i<MANT_WORDS; i++)
59 for (j=0; j<MANT_WORDS; j++) {
60 unsigned long n;
61 n = (unsigned long)to[i] * (unsigned long)from[j];
62 temp[i+j] += n >> 16;
63 temp[i+j+1] += n & 0xFFFF;
64 }
65
66 for (i=MANT_WORDS*2; --i ;) {
67 temp[i-1] += temp[i] >> 16;
68 temp[i] &= 0xFFFF;
69 }
70 if (temp[0] & 0x8000) {
71 for (i=0; i<MANT_WORDS; i++)
72 to[i] = temp[i] & 0xFFFF;
73 return 0;
74 } else {
75 for (i=0; i<MANT_WORDS; i++)
76 to[i] = (temp[i] << 1) + !!(temp[i+1] & 0x8000);
77 return -1;
78 }
79}
80
81static void flconvert(char *string, unsigned short *mant, long *exponent,
82 efunc error) {
83 char digits[MANT_DIGITS], *p, *q, *r;
84 unsigned short mult[MANT_WORDS], *m, bit;
85 long tenpwr, twopwr;
86 int extratwos, started, seendot;
87
88 p = digits;
89 tenpwr = 0;
90 started = seendot = FALSE;
91 while (*string && *string != 'E' && *string != 'e') {
92 if (*string == '.') {
93 if (!seendot)
94 seendot = TRUE;
95 else {
96 error (ERR_NONFATAL,
97 "too many periods in floating-point constant");
98 return;
99 }
100 } else if (*string >= '0' && *string <= '9') {
101 if (*string == '0' && !started) {
102 if (seendot)
103 tenpwr--;
104 } else {
105 started = TRUE;
106 if (p < digits+sizeof(digits))
107 *p++ = *string - '0';
108 if (!seendot)
109 tenpwr++;
110 }
111 } else {
112 error (ERR_NONFATAL,
113 "floating-point constant: `%c' is invalid character",
114 *string);
115 return;
116 }
117 string++;
118 }
119 if (*string) {
120 string++; /* eat the E */
121 tenpwr += atoi(string);
122 }
123
124 /*
125 * At this point, the memory interval [digits,p) contains a
126 * series of decimal digits zzzzzzz such that our number X
127 * satisfies
128 *
129 * X = 0.zzzzzzz * 10^tenpwr
130 */
131
132 bit = 0x8000;
133 for (m=mant; m<mant+MANT_WORDS; m++)
134 *m = 0;
135 m = mant;
136 q = digits;
137 started = FALSE;
138 twopwr = 0;
139 while (m < mant+MANT_WORDS) {
140 unsigned short carry = 0;
141 while (p > q && !p[-1])
142 p--;
143 if (p <= q)
144 break;
145 for (r = p; r-- > q ;) {
146 int i;
147
148 i = 2 * *r + carry;
149 if (i >= 10)
150 carry = 1, i -= 10;
151 else
152 carry = 0;
153 *r = i;
154 }
155 if (carry)
156 *m |= bit, started = TRUE;
157 if (started) {
158 if (bit == 1)
159 bit = 0x8000, m++;
160 else
161 bit >>= 1;
162 } else
163 twopwr--;
164 }
165 twopwr += tenpwr;
166
167 /*
168 * At this point the `mant' array contains the first six
169 * fractional places of a base-2^16 real number, which when
170 * multiplied by 2^twopwr and 5^tenpwr gives X. So now we
171 * really do multiply by 5^tenpwr.
172 */
173
174 if (tenpwr < 0) {
175 for (m=mult; m<mult+MANT_WORDS; m++)
176 *m = 0xCCCC;
177 extratwos = -2;
178 tenpwr = -tenpwr;
179 } else if (tenpwr > 0) {
180 mult[0] = 0xA000;
181 for (m=mult+1; m<mult+MANT_WORDS; m++)
182 *m = 0;
183 extratwos = 3;
184 } else
185 extratwos = 0;
186 while (tenpwr) {
187 if (tenpwr & 1)
188 twopwr += extratwos + multiply (mant, mult);
189 extratwos = extratwos * 2 + multiply (mult, mult);
190 tenpwr >>= 1;
191 }
192
193 /*
194 * Conversion is done. The elements of `mant' contain the first
195 * fractional places of a base-2^16 real number in [0.5,1)
196 * which we can multiply by 2^twopwr to get X. Or, of course,
197 * it contains zero.
198 */
199 *exponent = twopwr;
200}
201
202/*
203 * Shift a mantissa to the right by i (i < 16) bits.
204 */
205static void shr(unsigned short *mant, int i) {
206 unsigned short n = 0, m;
207 int j;
208
209 for (j=0; j<MANT_WORDS; j++) {
210 m = (mant[j] << (16-i)) & 0xFFFF;
211 mant[j] = (mant[j] >> i) | n;
212 n = m;
213 }
214}
215
216/*
217 * Round a mantissa off after i words.
218 */
219static int round(unsigned short *mant, int i) {
220 if (mant[i] & 0x8000) {
221 do {
222 ++mant[--i];
223 mant[i] &= 0xFFFF;
224 } while (i > 0 && !mant[i]);
225 return !i && !mant[i];
226 }
227 return 0;
228}
229
230#define put(a,b) ( (*(a)=(b)), ((a)[1]=(b)>>8) )
231
232static int to_double(char *str, long sign, unsigned char *result,
233 efunc error) {
234 unsigned short mant[MANT_WORDS];
235 long exponent;
236
237 sign = (sign < 0 ? 0x8000L : 0L);
238
239 flconvert (str, mant, &exponent, error);
240 if (mant[0] & 0x8000) {
241 /*
242 * Non-zero.
243 */
244 exponent--;
245 if (exponent >= -1022 && exponent <= 1024) {
246 /*
247 * Normalised.
248 */
249 exponent += 1023;
250 shr(mant, 11);
251 round(mant, 4);
252 if (mant[0] & 0x20) /* did we scale up by one? */
253 shr(mant, 1), exponent++;
254 mant[0] &= 0xF; /* remove leading one */
255 put(result+6,(exponent << 4) | mant[0] | sign);
256 put(result+4,mant[1]);
257 put(result+2,mant[2]);
258 put(result+0,mant[3]);
259 } else if (exponent < -1022 && exponent >= -1074) {
260 /*
261 * Denormal.
262 */
263 int shift = -(exponent+1011);
264 int sh = shift % 16, wds = shift / 16;
265 shr(mant, sh);
266 if (round(mant, 4-wds) || (sh>0 && (mant[0]&(0x8000>>(sh-1))))) {
267 shr(mant, 1);
268 if (sh==0)
269 mant[0] |= 0x8000;
270 exponent++;
271 }
272 put(result+6,(wds == 0 ? mant[0] : 0) | sign);
273 put(result+4,(wds <= 1 ? mant[1-wds] : 0));
274 put(result+2,(wds <= 2 ? mant[2-wds] : 0));
275 put(result+0,(wds <= 3 ? mant[3-wds] : 0));
276 } else {
277 if (exponent > 0) {
278 error(ERR_NONFATAL, "overflow in floating-point constant");
279 return 0;
280 } else
281 memset (result, 0, 8);
282 }
283 } else {
284 /*
285 * Zero.
286 */
287 memset (result, 0, 8);
288 }
289 return 1; /* success */
290}
291
292static int to_float(char *str, long sign, unsigned char *result,
293 efunc error) {
294 unsigned short mant[MANT_WORDS];
295 long exponent;
296
297 sign = (sign < 0 ? 0x8000L : 0L);
298
299 flconvert (str, mant, &exponent, error);
300 if (mant[0] & 0x8000) {
301 /*
302 * Non-zero.
303 */
304 exponent--;
305 if (exponent >= -126 && exponent <= 128) {
306 /*
307 * Normalised.
308 */
309 exponent += 127;
310 shr(mant, 8);
311 round(mant, 2);
312 if (mant[0] & 0x100) /* did we scale up by one? */
313 shr(mant, 1), exponent++;
314 mant[0] &= 0x7F; /* remove leading one */
315 put(result+2,(exponent << 7) | mant[0] | sign);
316 put(result+0,mant[1]);
317 } else if (exponent < -126 && exponent >= -149) {
318 /*
319 * Denormal.
320 */
321 int shift = -(exponent+118);
322 int sh = shift % 16, wds = shift / 16;
323 shr(mant, sh);
324 if (round(mant, 2-wds) || (sh>0 && (mant[0]&(0x8000>>(sh-1))))) {
325 shr(mant, 1);
326 if (sh==0)
327 mant[0] |= 0x8000;
328 exponent++;
329 }
330 put(result+2,(wds == 0 ? mant[0] : 0) | sign);
331 put(result+0,(wds <= 1 ? mant[1-wds] : 0));
332 } else {
333 if (exponent > 0) {
334 error(ERR_NONFATAL, "overflow in floating-point constant");
335 return 0;
336 } else
337 memset (result, 0, 4);
338 }
339 } else {
340 memset (result, 0, 4);
341 }
342 return 1;
343}
344
345static int to_ldoub(char *str, long sign, unsigned char *result,
346 efunc error) {
347 unsigned short mant[MANT_WORDS];
348 long exponent;
349
350 sign = (sign < 0 ? 0x8000L : 0L);
351
352 flconvert (str, mant, &exponent, error);
353 if (mant[0] & 0x8000) {
354 /*
355 * Non-zero.
356 */
357 exponent--;
358 if (exponent >= -16383 && exponent <= 16384) {
359 /*
360 * Normalised.
361 */
362 exponent += 16383;
363 if (round(mant, 4)) /* did we scale up by one? */
364 shr(mant, 1), mant[0] |= 0x8000, exponent++;
365 put(result+8,exponent | sign);
366 put(result+6,mant[0]);
367 put(result+4,mant[1]);
368 put(result+2,mant[2]);
369 put(result+0,mant[3]);
370 } else if (exponent < -16383 && exponent >= -16446) {
371 /*
372 * Denormal.
373 */
374 int shift = -(exponent+16383);
375 int sh = shift % 16, wds = shift / 16;
376 shr(mant, sh);
377 if (round(mant, 4-wds) || (sh>0 && (mant[0]&(0x8000>>(sh-1))))) {
378 shr(mant, 1);
379 if (sh==0)
380 mant[0] |= 0x8000;
381 exponent++;
382 }
383 put(result+8,sign);
384 put(result+6,(wds == 0 ? mant[0] : 0));
385 put(result+4,(wds <= 1 ? mant[1-wds] : 0));
386 put(result+2,(wds <= 2 ? mant[2-wds] : 0));
387 put(result+0,(wds <= 3 ? mant[3-wds] : 0));
388 } else {
389 if (exponent > 0) {
390 error(ERR_NONFATAL, "overflow in floating-point constant");
391 return 0;
392 } else
393 memset (result, 0, 10);
394 }
395 } else {
396 /*
397 * Zero.
398 */
399 memset (result, 0, 10);
400 }
401 return 1;
402}
403
404int float_const (char *number, long sign, unsigned char *result, int bytes,
405 efunc error) {
406 if (bytes == 4)
407 return to_float (number, sign, result, error);
408 else if (bytes == 8)
409 return to_double (number, sign, result, error);
410 else if (bytes == 10)
411 return to_ldoub (number, sign, result, error);
412 else {
413 error(ERR_PANIC, "strange value %d passed to float_const", bytes);
414 return 0;
415 }
416}