www.pudn.com > nasm-0.98.zip > float.c


/* float.c     floating-point constant support for the Netwide Assembler 
 * 
 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and 
 * Julian Hall. All rights reserved. The software is 
 * redistributable under the licence given in the file "Licence" 
 * distributed in the NASM archive. 
 * 
 * initial version 13/ix/96 by Simon Tatham 
 */ 
 
#include  
#include  
#include  
 
#include "nasm.h" 
 
#define TRUE 1 
#define FALSE 0 
 
#define MANT_WORDS 6		       /* 64 bits + 32 for accuracy == 96 */ 
#define MANT_DIGITS 28		       /* 29 digits don't fit in 96 bits */ 
 
/* 
 * guaranteed top bit of from is set 
 * => we only have to worry about _one_ bit shift to the left 
 */ 
 
static int multiply(unsigned short *to, unsigned short *from)  
{ 
    unsigned long temp[MANT_WORDS*2]; 
    int           i, j; 
 
    for (i=0; i> 16; 
	    temp[i+j+1] += n & 0xFFFF; 
	} 
 
    for (i=MANT_WORDS*2; --i ;) { 
	temp[i-1] += temp[i] >> 16; 
	temp[i] &= 0xFFFF; 
    } 
    if (temp[0] & 0x8000) { 
	for (i=0; i= '0' && *string <= '9') { 
	    if (*string == '0' && !started) { 
		if (seendot) 
		    tenpwr--; 
	    } else { 
		started = TRUE; 
		if (p < digits+sizeof(digits)) 
		    *p++ = *string - '0'; 
		if (!seendot) 
		    tenpwr++; 
	    } 
	} else { 
	    error (ERR_NONFATAL, 
		   "floating-point constant: `%c' is invalid character", 
		   *string); 
	    return; 
	} 
	string++; 
    } 
    if (*string) { 
	string++;		       /* eat the E */ 
	tenpwr += atoi(string); 
    } 
 
    /* 
     * At this point, the memory interval [digits,p) contains a 
     * series of decimal digits zzzzzzz such that our number X 
     * satisfies 
     * 
     * X = 0.zzzzzzz * 10^tenpwr 
     */ 
 
    bit = 0x8000; 
    for (m=mant; m q && !p[-1]) 
	    p--; 
	if (p <= q) 
	    break; 
	for (r = p; r-- > q ;) { 
	    int i; 
 
	    i = 2 * *r + carry; 
	    if (i >= 10) 
		carry = 1, i -= 10; 
	    else 
		carry = 0; 
	    *r = i; 
	} 
	if (carry) 
	    *m |= bit, started = TRUE; 
	if (started) { 
	    if (bit == 1) 
		bit = 0x8000, m++; 
	    else 
		bit >>= 1; 
	} else 
	    twopwr--; 
    } 
    twopwr += tenpwr; 
 
    /* 
     * At this point the `mant' array contains the first six 
     * fractional places of a base-2^16 real number, which when 
     * multiplied by 2^twopwr and 5^tenpwr gives X. So now we 
     * really do multiply by 5^tenpwr. 
     */ 
 
    if (tenpwr < 0) { 
	for (m=mult; m 0) { 
	mult[0] = 0xA000; 
	for (m=mult+1; m>= 1; 
    } 
 
    /* 
     * Conversion is done. The elements of `mant' contain the first 
     * fractional places of a base-2^16 real number in [0.5,1) 
     * which we can multiply by 2^twopwr to get X. Or, of course, 
     * it contains zero. 
     */ 
    *exponent = twopwr; 
} 
 
/* 
 * Shift a mantissa to the right by i (i < 16) bits. 
 */ 
static void shr(unsigned short *mant, int i)  
{ 
    unsigned short n = 0, m; 
    int            j; 
 
    for (j=0; j> i) | n; 
	n = m; 
    } 
} 
 
/* 
 * Round a mantissa off after i words. 
 */ 
static int round(unsigned short *mant, int i)  
{ 
    if (mant[i] & 0x8000) { 
	do { 
	    ++mant[--i]; 
	    mant[i] &= 0xFFFF; 
	} while (i > 0 && !mant[i]); 
	return !i && !mant[i]; 
    } 
    return 0; 
} 
 
#define put(a,b) ( (*(a)=(b)), ((a)[1]=(b)>>8) ) 
 
static int to_double(char *str, long sign, unsigned char *result, 
		     efunc error)  
{ 
    unsigned short mant[MANT_WORDS]; 
    long exponent; 
 
    sign = (sign < 0 ? 0x8000L : 0L); 
 
    flconvert (str, mant, &exponent, error); 
    if (mant[0] & 0x8000) { 
	/* 
	 * Non-zero. 
	 */ 
	exponent--; 
	if (exponent >= -1022 && exponent <= 1024) { 
	    /* 
	     * Normalised. 
	     */ 
	    exponent += 1023; 
	    shr(mant, 11); 
	    round(mant, 4); 
	    if (mant[0] & 0x20)	       /* did we scale up by one? */ 
		shr(mant, 1), exponent++; 
	    mant[0] &= 0xF;	       /* remove leading one */ 
	    put(result+6,(exponent << 4) | mant[0] | sign); 
	    put(result+4,mant[1]); 
	    put(result+2,mant[2]); 
	    put(result+0,mant[3]); 
	} else if (exponent < -1022 && exponent >= -1074) { 
	    /* 
	     * Denormal. 
	     */ 
	    int shift = -(exponent+1011); 
	    int sh = shift % 16, wds = shift / 16; 
	    shr(mant, sh); 
	    if (round(mant, 4-wds) || (sh>0 && (mant[0]&(0x8000>>(sh-1))))) { 
		shr(mant, 1); 
		if (sh==0) 
		    mant[0] |= 0x8000; 
		exponent++; 
	    } 
	    put(result+6,(wds == 0 ? mant[0] : 0) | sign); 
	    put(result+4,(wds <= 1 ? mant[1-wds] : 0)); 
	    put(result+2,(wds <= 2 ? mant[2-wds] : 0)); 
	    put(result+0,(wds <= 3 ? mant[3-wds] : 0)); 
	} else { 
	    if (exponent > 0) { 
		error(ERR_NONFATAL, "overflow in floating-point constant"); 
		return 0; 
	    } else 
		memset (result, 0, 8); 
	} 
    } else { 
	/* 
	 * Zero. 
	 */ 
	memset (result, 0, 8); 
    } 
    return 1;			       /* success */ 
} 
 
static int to_float(char *str, long sign, unsigned char *result, 
		    efunc error)  
{ 
    unsigned short mant[MANT_WORDS]; 
    long exponent; 
 
    sign = (sign < 0 ? 0x8000L : 0L); 
 
    flconvert (str, mant, &exponent, error); 
    if (mant[0] & 0x8000) { 
	/* 
	 * Non-zero. 
	 */ 
	exponent--; 
	if (exponent >= -126 && exponent <= 128) { 
	    /* 
	     * Normalised. 
	     */ 
	    exponent += 127; 
	    shr(mant, 8); 
	    round(mant, 2); 
	    if (mant[0] & 0x100)       /* did we scale up by one? */ 
		shr(mant, 1), exponent++; 
	    mant[0] &= 0x7F;	       /* remove leading one */ 
	    put(result+2,(exponent << 7) | mant[0] | sign); 
	    put(result+0,mant[1]); 
	} else if (exponent < -126 && exponent >= -149) { 
	    /* 
	     * Denormal. 
	     */ 
	    int shift = -(exponent+118); 
	    int sh = shift % 16, wds = shift / 16; 
	    shr(mant, sh); 
	    if (round(mant, 2-wds) || (sh>0 && (mant[0]&(0x8000>>(sh-1))))) { 
		shr(mant, 1); 
		if (sh==0) 
		    mant[0] |= 0x8000; 
		exponent++; 
	    } 
	    put(result+2,(wds == 0 ? mant[0] : 0) | sign); 
	    put(result+0,(wds <= 1 ? mant[1-wds] : 0)); 
	} else { 
	    if (exponent > 0) { 
		error(ERR_NONFATAL, "overflow in floating-point constant"); 
		return 0; 
	    } else 
		memset (result, 0, 4); 
	} 
    } else { 
	memset (result, 0, 4); 
    } 
    return 1; 
} 
 
static int to_ldoub(char *str, long sign, unsigned char *result, 
		    efunc error)  
{ 
    unsigned short mant[MANT_WORDS]; 
    long exponent; 
 
    sign = (sign < 0 ? 0x8000L : 0L); 
 
    flconvert (str, mant, &exponent, error); 
    if (mant[0] & 0x8000) { 
	/* 
	 * Non-zero. 
	 */ 
	exponent--; 
	if (exponent >= -16383 && exponent <= 16384) { 
	    /* 
	     * Normalised. 
	     */ 
	    exponent += 16383; 
	    if (round(mant, 4))	       /* did we scale up by one? */ 
		shr(mant, 1), mant[0] |= 0x8000, exponent++; 
	    put(result+8,exponent | sign); 
	    put(result+6,mant[0]); 
	    put(result+4,mant[1]); 
	    put(result+2,mant[2]); 
	    put(result+0,mant[3]); 
	} else if (exponent < -16383 && exponent >= -16446) { 
	    /* 
	     * Denormal. 
	     */ 
	    int shift = -(exponent+16383); 
	    int sh = shift % 16, wds = shift / 16; 
	    shr(mant, sh); 
	    if (round(mant, 4-wds) || (sh>0 && (mant[0]&(0x8000>>(sh-1))))) { 
		shr(mant, 1); 
		if (sh==0) 
		    mant[0] |= 0x8000; 
		exponent++; 
	    } 
	    put(result+8,sign); 
	    put(result+6,(wds == 0 ? mant[0] : 0)); 
	    put(result+4,(wds <= 1 ? mant[1-wds] : 0)); 
	    put(result+2,(wds <= 2 ? mant[2-wds] : 0)); 
	    put(result+0,(wds <= 3 ? mant[3-wds] : 0)); 
	} else { 
	    if (exponent > 0) { 
		error(ERR_NONFATAL, "overflow in floating-point constant"); 
		return 0; 
	    } else 
		memset (result, 0, 10); 
	} 
    } else { 
	/* 
	 * Zero. 
	 */ 
	memset (result, 0, 10); 
    } 
    return 1; 
} 
 
int float_const (char *number, long sign, unsigned char *result, int bytes, 
		 efunc error)  
{ 
    if (bytes == 4) 
	return to_float (number, sign, result, error); 
    else if (bytes == 8) 
	return to_double (number, sign, result, error); 
    else if (bytes == 10) 
	return to_ldoub (number, sign, result, error); 
    else { 
	error(ERR_PANIC, "strange value %d passed to float_const", bytes); 
	return 0; 
    } 
}