]> granicus.if.org Git - yasm/commitdiff
Implement floating point size conversions (with help from BitVector).
authorPeter Johnson <peter@tortall.net>
Thu, 27 Sep 2001 07:55:36 +0000 (07:55 -0000)
committerPeter Johnson <peter@tortall.net>
Thu, 27 Sep 2001 07:55:36 +0000 (07:55 -0000)
Interface changed slightly (only affects symrec.c right now).  Tests committed
to check a single case (pi) with all three size conversion functions.
Still need to write to/from ASCII string functions (the hard part).

svn path=/trunk/yasm/; revision=247

libyasm/floatnum.c
libyasm/floatnum.h
libyasm/symrec.c
libyasm/tests/Makefile.am
libyasm/tests/floatnum_test.c [new file with mode: 0644]
src/floatnum.c
src/floatnum.h
src/symrec.c
src/tests/Makefile.am
src/tests/floatnum_test.c [new file with mode: 0644]

index bef9080e56cbd847843a394a00422fc14cb6c6f3..50656aa645258c170ab960181735603f1c7b5166 100644 (file)
@@ -3,6 +3,8 @@
  *
  *  Copyright (C) 2001  Peter Johnson
  *
+ *  Based on public-domain x86 assembly code by Randall Hyde (8/28/91).
+ *
  *  This file is part of YASM.
  *
  *  YASM is free software; you can redistribute it and/or modify
 
 #ifdef STDC_HEADERS
 # include <stdlib.h>
+# include <string.h>
+#endif
+
+#include <libintl.h>
+#define _(String)      gettext(String)
+#ifdef gettext_noop
+#define N_(String)     gettext_noop(String)
+#else
+#define N_(String)     (String)
 #endif
 
+#include "bitvect.h"
+#include "file.h"
+
 #include "errwarn.h"
 #include "floatnum.h"
 
@@ -42,36 +56,224 @@ floatnum_new(char *str)
     floatnum *flt = malloc(sizeof(floatnum));
     if (!flt)
        Fatal(FATAL_NOMEM);
-    /* TODO */
+
+    flt->mantissa = BitVector_Create(64, TRUE);
+    if (!flt->mantissa)
+       Fatal(FATAL_NOMEM);
+
+    /* check for + or - character and skip */
+    if (*str == '-') {
+       flt->sign = 1;
+       str++;
+    } else if (*str == '+') {
+       flt->sign = 0;
+       str++;
+    } else
+       flt->sign = 0;
+
     return flt;
 }
 
-unsigned long
-floatnum_get_int(floatnum *flt)
+int
+floatnum_get_int(unsigned long *ret_val, const floatnum *flt)
 {
-    return 0;  /* TODO */
+    unsigned char t[4];
+
+    if (floatnum_get_single(t, flt))
+       return 1;
+
+    LOAD_LONG(*ret_val, &t[0]);
+    return 0;
 }
 
-unsigned char *
-floatnum_get_single(unsigned char *ptr, floatnum *flt)
+/* IEEE-754 (Intel) "single precision" format:
+ * 32 bits:
+ * Bit 31    Bit 22              Bit 0
+ * |         |                       |
+ * seeeeeee emmmmmmm mmmmmmmm mmmmmmmm
+ *
+ * e = bias 127 exponent
+ * s = sign bit
+ * m = mantissa bits, bit 23 is an implied one bit.
+ */
+int
+floatnum_get_single(unsigned char *ptr, const floatnum *flt)
 {
-    return ptr;        /* TODO */
+    unsigned long exponent = flt->exponent;
+    unsigned int *output;
+    unsigned char *buf;
+    unsigned int len;
+
+    output = BitVector_Create(32, TRUE);
+    if (!output)
+       Fatal(FATAL_NOMEM);
+
+    /* copy mantissa */
+    BitVector_Interval_Copy(output, flt->mantissa, 0, 40, 23);
+
+    /* round mantissa */
+    BitVector_increment(output);
+
+    if (BitVector_bit_test(output, 23)) {
+       /* overflowed, so divide mantissa by 2 (shift right) */
+       BitVector_shift_right(output, 0);
+       /* and up the exponent (checking for overflow) */
+       if (exponent+1 >= 0x10000) {
+           BitVector_Destroy(output);
+           return 1;       /* exponent too large */
+       }
+       exponent++;
+    }
+
+    /* adjust the exponent to bias 127 */
+    exponent -= 32767-127;
+    if (exponent >= 256) {
+       BitVector_Destroy(output);
+       return 1;           /* exponent too large */
+    }
+
+    /* move exponent into place */
+    BitVector_Chunk_Store(output, 8, 23, exponent);
+
+    /* merge in sign bit */
+    BitVector_Bit_Copy(output, 31, flt->sign);
+
+    /* get little-endian bytes */
+    buf = BitVector_Block_Read(output, &len);
+    if (!buf)
+       Fatal(FATAL_NOMEM);
+    if (len != 4)
+       InternalError(__LINE__, __FILE__,
+                     _("Length of 32-bit BitVector not 4"));
+
+    /* copy to output */
+    memcpy(ptr, buf, 4*sizeof(unsigned char));
+
+    /* free allocated resources */
+    free(buf);
+
+    BitVector_Destroy(output);
+
+    return 0;
 }
 
-unsigned char *
-floatnum_get_double(unsigned char *ptr, floatnum *flt)
+/* IEEE-754 (Intel) "double precision" format:
+ * 64 bits:
+ * bit 63       bit 51                                               bit 0
+ * |            |                                                        |
+ * seeeeeee eeeemmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm
+ *
+ * e = bias 1023 exponent.
+ * s = sign bit.
+ * m = mantissa bits.  Bit 52 is an implied one bit.
+ */
+int
+floatnum_get_double(unsigned char *ptr, const floatnum *flt)
 {
-    return ptr;        /* TODO */
+    unsigned long exponent = flt->exponent;
+    unsigned int *output;
+    unsigned char *buf;
+    unsigned int len;
+
+    output = BitVector_Create(64, TRUE);
+    if (!output)
+       Fatal(FATAL_NOMEM);
+
+    /* copy mantissa */
+    BitVector_Interval_Copy(output, flt->mantissa, 0, 11, 52);
+
+    /* round mantissa */
+    BitVector_increment(output);
+
+    if (BitVector_bit_test(output, 52)) {
+       /* overflowed, so divide mantissa by 2 (shift right) */
+       BitVector_shift_right(output, 0);
+       /* and up the exponent (checking for overflow) */
+       if (exponent+1 >= 0x10000) {
+           BitVector_Destroy(output);
+           return 1;       /* exponent too large */
+       }
+       exponent++;
+    }
+
+    /* adjust the exponent to bias 1023 */
+    exponent -= 32767-1023;
+    if (exponent >= 2048) {
+       BitVector_Destroy(output);
+       return 1;           /* exponent too large */
+    }
+
+    /* move exponent into place */
+    BitVector_Chunk_Store(output, 11, 52, exponent);
+
+    /* merge in sign bit */
+    BitVector_Bit_Copy(output, 63, flt->sign);
+
+    /* get little-endian bytes */
+    buf = BitVector_Block_Read(output, &len);
+    if (!buf)
+       Fatal(FATAL_NOMEM);
+    if (len != 8)
+       InternalError(__LINE__, __FILE__,
+                     _("Length of 64-bit BitVector not 8"));
+
+    /* copy to output */
+    memcpy(ptr, buf, 8*sizeof(unsigned char));
+
+    /* free allocated resources */
+    free(buf);
+
+    BitVector_Destroy(output);
+
+    return 0;
 }
 
-unsigned char *
-floatnum_get_extended(unsigned char *ptr, floatnum *flt)
+/* IEEE-754 (Intel) "extended precision" format:
+ * 80 bits:
+ * bit 79            bit 63                           bit 0
+ * |                 |                                    |
+ * seeeeeee eeeeeeee mmmmmmmm m...m m...m m...m m...m m...m
+ *
+ * e = bias 16384 exponent
+ * m = 64 bit mantissa with NO implied bit!
+ * s = sign (for mantissa)
+ */
+int
+floatnum_get_extended(unsigned char *ptr, const floatnum *flt)
 {
-    return ptr;        /* TODO */
+    unsigned short exponent = flt->exponent;
+    unsigned char *buf;
+    unsigned int len;
+
+    /* Adjust the exponent to bias 16384 */
+    exponent -= 0x4000;
+    if (exponent >= 0x8000)
+       return 1;           /* exponent too large */
+
+    /* get little-endian bytes */
+    buf = BitVector_Block_Read(flt->mantissa, &len);
+    if (!buf)
+       Fatal(FATAL_NOMEM);
+    if (len != 8)
+       InternalError(__LINE__, __FILE__,
+                     _("Length of 64-bit BitVector not 8"));
+
+    /* copy to output */
+    memcpy(ptr, buf, 8*sizeof(unsigned char));
+
+    /* Save exponent and sign in proper location */
+    SAVE_SHORT(&ptr[8], exponent);
+    if (flt->sign)
+       ptr[9] |= 0x80;
+
+    /* free allocated resources */
+    free(buf);
+
+    return 0;
 }
 
 void
-floatnum_print(floatnum *flt)
+floatnum_print(const floatnum *flt)
 {
     /* TODO */
 }
index bbea9755e3c884150d60644e80622af0dc276e68..8ac8bf6f551453ac3c556debd84a26783cee2f11 100644 (file)
@@ -3,6 +3,8 @@
  *
  *  Copyright (C) 2001  Peter Johnson
  *
+ *  Based on public-domain x86 assembly code by Randall Hyde (8/28/91).
+ *
  *  This file is part of YASM.
  *
  *  YASM is free software; you can redistribute it and/or modify
 #ifndef YASM_FLOATNUM_H
 #define YASM_FLOATNUM_H
 
+/* 88-bit internal floating point format:
+ * xxxxxxxs eeeeeeee eeeeeeee m..m m..m m..m m..m m..m m..m m..m m..m
+ * Sign          exponent                   mantissa (64 bits)
+ *                            | 7  | 6  | 5  | 4  | 3  | 2  | 1  | 0|
+ *                            63   55   47   39   31   23   15   7  0
+ *
+ * Only L.O. bit of Sign byte is significant.  The rest is garbage.
+ * Exponent is bias 32767 exponent.
+ * Mantissa does NOT have an implied one bit (it's explicit).
+ */
 typedef struct floatnum_s {
-    unsigned char extval[10];      /* float stored in extended precision */
+    unsigned int *mantissa;    /* Allocated to 64 bits */
+    unsigned short exponent;
+    unsigned char sign;
 } floatnum;
 
 floatnum *floatnum_new(char *str);
-unsigned long floatnum_get_int(floatnum *flt);
-unsigned char *floatnum_get_single(unsigned char *ptr, floatnum *flt);
-unsigned char *floatnum_get_double(unsigned char *ptr, floatnum *flt);
-unsigned char *floatnum_get_extended(unsigned char *ptr, floatnum *flt);
 
-void floatnum_print(floatnum *flt);
+/* The get functions return nonzero if flt can't fit into that size format. */
+
+/* Essentially a convert to single-precision and return as 32-bit value.
+ * The 32-bit value is a "standard" C value (eg, of unknown endian).
+ */
+int floatnum_get_int(unsigned long *ret_val, const floatnum *flt);
+
+/* ptr will point to the Intel-format little-endian byte string after a
+ * successful call (eg, [0] should be the first byte output to the file).
+ */
+int floatnum_get_single(unsigned char *ptr, const floatnum *flt);
+int floatnum_get_double(unsigned char *ptr, const floatnum *flt);
+int floatnum_get_extended(unsigned char *ptr, const floatnum *flt);
+
+void floatnum_print(const floatnum *flt);
 
 #endif
index 2c7947cd498281be1116e503ea21a0d6f9503426..5d545632395a09f43f104e1db66dba4102bcc4fd 100644 (file)
@@ -173,7 +173,9 @@ symrec_get_int_value(const symrec *sym, unsigned long *ret_val,
                *ret_val = sym->value.int_val;
                break;
            case SYM_CONSTANT_FLOAT:
-               *ret_val = floatnum_get_int(sym->value.flt);
+               /* FIXME: Line number on this error will be incorrect. */
+               if (floatnum_get_int(ret_val, sym->value.flt))
+                   Error(_("Floating point value cannot fit in 32-bit single precision"));
                break;
            case SYM_LABEL:
                if (!bytecode_get_offset(sym->value.label.sect,
index 9938959cf303e0a7d647a5588b8ab30da7a2477f..a5430acbf871caf51d99603cb6e48e1318b7d118 100644 (file)
@@ -4,10 +4,12 @@ CFLAGS = @ANSI_CFLAGS@
 
 if CHECK
 TESTS = \
-       bytecode_test
+       bytecode_test   \
+       floatnum_test
 
 noinst_PROGRAMS = \
-       bytecode_test
+       bytecode_test   \
+       floatnum_test
 else
 TESTS =
 noinst_PROGRAMS =
@@ -16,6 +18,9 @@ endif
 bytecode_test_SOURCES = \
        bytecode_test.c
 
+floatnum_test_SOURCES = \
+       floatnum_test.c
+
 INCLUDES= -I$(top_srcdir) -I$(top_srcdir)/src -I$(top_srcdir)/check
 LDADD = \
        $(top_builddir)/check/libcheck.a                        \
diff --git a/libyasm/tests/floatnum_test.c b/libyasm/tests/floatnum_test.c
new file mode 100644 (file)
index 0000000..cc09363
--- /dev/null
@@ -0,0 +1,122 @@
+/* $IdPath$
+ *
+ */
+#include <stdlib.h>
+#include "check.h"
+
+#include "bitvect.h"
+
+#include "floatnum.h"
+
+floatnum *flt;
+void get_family_setup(void)
+{
+
+    flt = malloc(sizeof(floatnum));
+    flt->mantissa = BitVector_Create(64, TRUE);
+}
+
+void get_family_teardown(void)
+{
+    BitVector_Destroy(flt->mantissa);
+    free(flt);
+}
+
+void pi_setup(void)
+{
+    /* test value: 3.141592653589793 */
+    /* 80-bit little endian hex: E9 BD 68 21 A2 DA 0F C9 00 40 */
+    unsigned char val[] = {0xE9, 0xBD, 0x68, 0x21, 0xA2, 0xDA, 0x0F, 0xC9};
+    unsigned char sign = 0;
+    unsigned short exp = 32767 + 1;
+
+    BitVector_Block_Store(flt->mantissa, val, 8);
+    flt->sign = sign;
+    flt->exponent = exp;
+}
+
+START_TEST(test_get_single_pi)
+{
+    unsigned char outval[] = {0x00, 0x00, 0x00, 0x00};
+    unsigned char correct[] = {0xDB, 0x0F, 0x49, 0x40};
+    int i;
+
+    pi_setup();
+
+    fail_unless(floatnum_get_single(outval, flt) == 0,
+               "Should not fail on this value");
+
+    /* Compare result with what we should get. */
+    for (i=0;i<4;i++)
+       fail_unless(outval[i] == correct[i], "Invalid result generated");
+}
+END_TEST
+
+START_TEST(test_get_double_pi)
+{
+    unsigned char outval[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+    unsigned char correct[] = {0x18, 0x2D, 0x44, 0x54, 0xFB, 0x21, 0x09, 0x40};
+    int i;
+
+    pi_setup();
+
+    fail_unless(floatnum_get_double(outval, flt) == 0,
+               "Should not fail on this value");
+
+    /* Compare result with what we should get. */
+    for (i=0;i<8;i++)
+       fail_unless(outval[i] == correct[i], "Invalid result generated");
+}
+END_TEST
+
+START_TEST(test_get_extended_pi)
+{
+    unsigned char outval[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+    unsigned char correct[] = {0xE9, 0xBD, 0x68, 0x21, 0xA2, 0xDA, 0x0F, 0xC9, 0x00, 0x40};
+    int i;
+
+    pi_setup();
+
+    fail_unless(floatnum_get_extended(outval, flt) == 0,
+               "Should not fail on this value");
+
+    /* Compare result with what we should get. */
+    for (i=0;i<10;i++)
+       fail_unless(outval[i] == correct[i], "Invalid result generated");
+}
+END_TEST
+
+Suite *bytecode_suite(void)
+{
+    Suite *s = suite_create("floatnum");
+    TCase *tc_get_single = tcase_create("get_single");
+    TCase *tc_get_double = tcase_create("get_double");
+    TCase *tc_get_extended = tcase_create("get_extended");
+
+    suite_add_tcase(s, tc_get_single);
+    tcase_add_test(tc_get_single, test_get_single_pi);
+    tcase_set_fixture(tc_get_single, get_family_setup, get_family_teardown);
+
+    suite_add_tcase(s, tc_get_double);
+    tcase_add_test(tc_get_double, test_get_double_pi);
+    tcase_set_fixture(tc_get_double, get_family_setup, get_family_teardown);
+
+    suite_add_tcase(s, tc_get_extended);
+    tcase_add_test(tc_get_extended, test_get_extended_pi);
+    tcase_set_fixture(tc_get_extended, get_family_setup, get_family_teardown);
+
+    return s;
+}
+
+int main(void)
+{
+    int nf;
+    Suite *s = bytecode_suite();
+    SRunner *sr = srunner_create(s);
+    BitVector_Boot();
+    srunner_run_all(sr, CRNORMAL);
+    nf = srunner_ntests_failed(sr);
+    srunner_free(sr);
+    suite_free(s);
+    return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
index bef9080e56cbd847843a394a00422fc14cb6c6f3..50656aa645258c170ab960181735603f1c7b5166 100644 (file)
@@ -3,6 +3,8 @@
  *
  *  Copyright (C) 2001  Peter Johnson
  *
+ *  Based on public-domain x86 assembly code by Randall Hyde (8/28/91).
+ *
  *  This file is part of YASM.
  *
  *  YASM is free software; you can redistribute it and/or modify
 
 #ifdef STDC_HEADERS
 # include <stdlib.h>
+# include <string.h>
+#endif
+
+#include <libintl.h>
+#define _(String)      gettext(String)
+#ifdef gettext_noop
+#define N_(String)     gettext_noop(String)
+#else
+#define N_(String)     (String)
 #endif
 
+#include "bitvect.h"
+#include "file.h"
+
 #include "errwarn.h"
 #include "floatnum.h"
 
@@ -42,36 +56,224 @@ floatnum_new(char *str)
     floatnum *flt = malloc(sizeof(floatnum));
     if (!flt)
        Fatal(FATAL_NOMEM);
-    /* TODO */
+
+    flt->mantissa = BitVector_Create(64, TRUE);
+    if (!flt->mantissa)
+       Fatal(FATAL_NOMEM);
+
+    /* check for + or - character and skip */
+    if (*str == '-') {
+       flt->sign = 1;
+       str++;
+    } else if (*str == '+') {
+       flt->sign = 0;
+       str++;
+    } else
+       flt->sign = 0;
+
     return flt;
 }
 
-unsigned long
-floatnum_get_int(floatnum *flt)
+int
+floatnum_get_int(unsigned long *ret_val, const floatnum *flt)
 {
-    return 0;  /* TODO */
+    unsigned char t[4];
+
+    if (floatnum_get_single(t, flt))
+       return 1;
+
+    LOAD_LONG(*ret_val, &t[0]);
+    return 0;
 }
 
-unsigned char *
-floatnum_get_single(unsigned char *ptr, floatnum *flt)
+/* IEEE-754 (Intel) "single precision" format:
+ * 32 bits:
+ * Bit 31    Bit 22              Bit 0
+ * |         |                       |
+ * seeeeeee emmmmmmm mmmmmmmm mmmmmmmm
+ *
+ * e = bias 127 exponent
+ * s = sign bit
+ * m = mantissa bits, bit 23 is an implied one bit.
+ */
+int
+floatnum_get_single(unsigned char *ptr, const floatnum *flt)
 {
-    return ptr;        /* TODO */
+    unsigned long exponent = flt->exponent;
+    unsigned int *output;
+    unsigned char *buf;
+    unsigned int len;
+
+    output = BitVector_Create(32, TRUE);
+    if (!output)
+       Fatal(FATAL_NOMEM);
+
+    /* copy mantissa */
+    BitVector_Interval_Copy(output, flt->mantissa, 0, 40, 23);
+
+    /* round mantissa */
+    BitVector_increment(output);
+
+    if (BitVector_bit_test(output, 23)) {
+       /* overflowed, so divide mantissa by 2 (shift right) */
+       BitVector_shift_right(output, 0);
+       /* and up the exponent (checking for overflow) */
+       if (exponent+1 >= 0x10000) {
+           BitVector_Destroy(output);
+           return 1;       /* exponent too large */
+       }
+       exponent++;
+    }
+
+    /* adjust the exponent to bias 127 */
+    exponent -= 32767-127;
+    if (exponent >= 256) {
+       BitVector_Destroy(output);
+       return 1;           /* exponent too large */
+    }
+
+    /* move exponent into place */
+    BitVector_Chunk_Store(output, 8, 23, exponent);
+
+    /* merge in sign bit */
+    BitVector_Bit_Copy(output, 31, flt->sign);
+
+    /* get little-endian bytes */
+    buf = BitVector_Block_Read(output, &len);
+    if (!buf)
+       Fatal(FATAL_NOMEM);
+    if (len != 4)
+       InternalError(__LINE__, __FILE__,
+                     _("Length of 32-bit BitVector not 4"));
+
+    /* copy to output */
+    memcpy(ptr, buf, 4*sizeof(unsigned char));
+
+    /* free allocated resources */
+    free(buf);
+
+    BitVector_Destroy(output);
+
+    return 0;
 }
 
-unsigned char *
-floatnum_get_double(unsigned char *ptr, floatnum *flt)
+/* IEEE-754 (Intel) "double precision" format:
+ * 64 bits:
+ * bit 63       bit 51                                               bit 0
+ * |            |                                                        |
+ * seeeeeee eeeemmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm
+ *
+ * e = bias 1023 exponent.
+ * s = sign bit.
+ * m = mantissa bits.  Bit 52 is an implied one bit.
+ */
+int
+floatnum_get_double(unsigned char *ptr, const floatnum *flt)
 {
-    return ptr;        /* TODO */
+    unsigned long exponent = flt->exponent;
+    unsigned int *output;
+    unsigned char *buf;
+    unsigned int len;
+
+    output = BitVector_Create(64, TRUE);
+    if (!output)
+       Fatal(FATAL_NOMEM);
+
+    /* copy mantissa */
+    BitVector_Interval_Copy(output, flt->mantissa, 0, 11, 52);
+
+    /* round mantissa */
+    BitVector_increment(output);
+
+    if (BitVector_bit_test(output, 52)) {
+       /* overflowed, so divide mantissa by 2 (shift right) */
+       BitVector_shift_right(output, 0);
+       /* and up the exponent (checking for overflow) */
+       if (exponent+1 >= 0x10000) {
+           BitVector_Destroy(output);
+           return 1;       /* exponent too large */
+       }
+       exponent++;
+    }
+
+    /* adjust the exponent to bias 1023 */
+    exponent -= 32767-1023;
+    if (exponent >= 2048) {
+       BitVector_Destroy(output);
+       return 1;           /* exponent too large */
+    }
+
+    /* move exponent into place */
+    BitVector_Chunk_Store(output, 11, 52, exponent);
+
+    /* merge in sign bit */
+    BitVector_Bit_Copy(output, 63, flt->sign);
+
+    /* get little-endian bytes */
+    buf = BitVector_Block_Read(output, &len);
+    if (!buf)
+       Fatal(FATAL_NOMEM);
+    if (len != 8)
+       InternalError(__LINE__, __FILE__,
+                     _("Length of 64-bit BitVector not 8"));
+
+    /* copy to output */
+    memcpy(ptr, buf, 8*sizeof(unsigned char));
+
+    /* free allocated resources */
+    free(buf);
+
+    BitVector_Destroy(output);
+
+    return 0;
 }
 
-unsigned char *
-floatnum_get_extended(unsigned char *ptr, floatnum *flt)
+/* IEEE-754 (Intel) "extended precision" format:
+ * 80 bits:
+ * bit 79            bit 63                           bit 0
+ * |                 |                                    |
+ * seeeeeee eeeeeeee mmmmmmmm m...m m...m m...m m...m m...m
+ *
+ * e = bias 16384 exponent
+ * m = 64 bit mantissa with NO implied bit!
+ * s = sign (for mantissa)
+ */
+int
+floatnum_get_extended(unsigned char *ptr, const floatnum *flt)
 {
-    return ptr;        /* TODO */
+    unsigned short exponent = flt->exponent;
+    unsigned char *buf;
+    unsigned int len;
+
+    /* Adjust the exponent to bias 16384 */
+    exponent -= 0x4000;
+    if (exponent >= 0x8000)
+       return 1;           /* exponent too large */
+
+    /* get little-endian bytes */
+    buf = BitVector_Block_Read(flt->mantissa, &len);
+    if (!buf)
+       Fatal(FATAL_NOMEM);
+    if (len != 8)
+       InternalError(__LINE__, __FILE__,
+                     _("Length of 64-bit BitVector not 8"));
+
+    /* copy to output */
+    memcpy(ptr, buf, 8*sizeof(unsigned char));
+
+    /* Save exponent and sign in proper location */
+    SAVE_SHORT(&ptr[8], exponent);
+    if (flt->sign)
+       ptr[9] |= 0x80;
+
+    /* free allocated resources */
+    free(buf);
+
+    return 0;
 }
 
 void
-floatnum_print(floatnum *flt)
+floatnum_print(const floatnum *flt)
 {
     /* TODO */
 }
index bbea9755e3c884150d60644e80622af0dc276e68..8ac8bf6f551453ac3c556debd84a26783cee2f11 100644 (file)
@@ -3,6 +3,8 @@
  *
  *  Copyright (C) 2001  Peter Johnson
  *
+ *  Based on public-domain x86 assembly code by Randall Hyde (8/28/91).
+ *
  *  This file is part of YASM.
  *
  *  YASM is free software; you can redistribute it and/or modify
 #ifndef YASM_FLOATNUM_H
 #define YASM_FLOATNUM_H
 
+/* 88-bit internal floating point format:
+ * xxxxxxxs eeeeeeee eeeeeeee m..m m..m m..m m..m m..m m..m m..m m..m
+ * Sign          exponent                   mantissa (64 bits)
+ *                            | 7  | 6  | 5  | 4  | 3  | 2  | 1  | 0|
+ *                            63   55   47   39   31   23   15   7  0
+ *
+ * Only L.O. bit of Sign byte is significant.  The rest is garbage.
+ * Exponent is bias 32767 exponent.
+ * Mantissa does NOT have an implied one bit (it's explicit).
+ */
 typedef struct floatnum_s {
-    unsigned char extval[10];      /* float stored in extended precision */
+    unsigned int *mantissa;    /* Allocated to 64 bits */
+    unsigned short exponent;
+    unsigned char sign;
 } floatnum;
 
 floatnum *floatnum_new(char *str);
-unsigned long floatnum_get_int(floatnum *flt);
-unsigned char *floatnum_get_single(unsigned char *ptr, floatnum *flt);
-unsigned char *floatnum_get_double(unsigned char *ptr, floatnum *flt);
-unsigned char *floatnum_get_extended(unsigned char *ptr, floatnum *flt);
 
-void floatnum_print(floatnum *flt);
+/* The get functions return nonzero if flt can't fit into that size format. */
+
+/* Essentially a convert to single-precision and return as 32-bit value.
+ * The 32-bit value is a "standard" C value (eg, of unknown endian).
+ */
+int floatnum_get_int(unsigned long *ret_val, const floatnum *flt);
+
+/* ptr will point to the Intel-format little-endian byte string after a
+ * successful call (eg, [0] should be the first byte output to the file).
+ */
+int floatnum_get_single(unsigned char *ptr, const floatnum *flt);
+int floatnum_get_double(unsigned char *ptr, const floatnum *flt);
+int floatnum_get_extended(unsigned char *ptr, const floatnum *flt);
+
+void floatnum_print(const floatnum *flt);
 
 #endif
index 2c7947cd498281be1116e503ea21a0d6f9503426..5d545632395a09f43f104e1db66dba4102bcc4fd 100644 (file)
@@ -173,7 +173,9 @@ symrec_get_int_value(const symrec *sym, unsigned long *ret_val,
                *ret_val = sym->value.int_val;
                break;
            case SYM_CONSTANT_FLOAT:
-               *ret_val = floatnum_get_int(sym->value.flt);
+               /* FIXME: Line number on this error will be incorrect. */
+               if (floatnum_get_int(ret_val, sym->value.flt))
+                   Error(_("Floating point value cannot fit in 32-bit single precision"));
                break;
            case SYM_LABEL:
                if (!bytecode_get_offset(sym->value.label.sect,
index 9938959cf303e0a7d647a5588b8ab30da7a2477f..a5430acbf871caf51d99603cb6e48e1318b7d118 100644 (file)
@@ -4,10 +4,12 @@ CFLAGS = @ANSI_CFLAGS@
 
 if CHECK
 TESTS = \
-       bytecode_test
+       bytecode_test   \
+       floatnum_test
 
 noinst_PROGRAMS = \
-       bytecode_test
+       bytecode_test   \
+       floatnum_test
 else
 TESTS =
 noinst_PROGRAMS =
@@ -16,6 +18,9 @@ endif
 bytecode_test_SOURCES = \
        bytecode_test.c
 
+floatnum_test_SOURCES = \
+       floatnum_test.c
+
 INCLUDES= -I$(top_srcdir) -I$(top_srcdir)/src -I$(top_srcdir)/check
 LDADD = \
        $(top_builddir)/check/libcheck.a                        \
diff --git a/src/tests/floatnum_test.c b/src/tests/floatnum_test.c
new file mode 100644 (file)
index 0000000..cc09363
--- /dev/null
@@ -0,0 +1,122 @@
+/* $IdPath$
+ *
+ */
+#include <stdlib.h>
+#include "check.h"
+
+#include "bitvect.h"
+
+#include "floatnum.h"
+
+floatnum *flt;
+void get_family_setup(void)
+{
+
+    flt = malloc(sizeof(floatnum));
+    flt->mantissa = BitVector_Create(64, TRUE);
+}
+
+void get_family_teardown(void)
+{
+    BitVector_Destroy(flt->mantissa);
+    free(flt);
+}
+
+void pi_setup(void)
+{
+    /* test value: 3.141592653589793 */
+    /* 80-bit little endian hex: E9 BD 68 21 A2 DA 0F C9 00 40 */
+    unsigned char val[] = {0xE9, 0xBD, 0x68, 0x21, 0xA2, 0xDA, 0x0F, 0xC9};
+    unsigned char sign = 0;
+    unsigned short exp = 32767 + 1;
+
+    BitVector_Block_Store(flt->mantissa, val, 8);
+    flt->sign = sign;
+    flt->exponent = exp;
+}
+
+START_TEST(test_get_single_pi)
+{
+    unsigned char outval[] = {0x00, 0x00, 0x00, 0x00};
+    unsigned char correct[] = {0xDB, 0x0F, 0x49, 0x40};
+    int i;
+
+    pi_setup();
+
+    fail_unless(floatnum_get_single(outval, flt) == 0,
+               "Should not fail on this value");
+
+    /* Compare result with what we should get. */
+    for (i=0;i<4;i++)
+       fail_unless(outval[i] == correct[i], "Invalid result generated");
+}
+END_TEST
+
+START_TEST(test_get_double_pi)
+{
+    unsigned char outval[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+    unsigned char correct[] = {0x18, 0x2D, 0x44, 0x54, 0xFB, 0x21, 0x09, 0x40};
+    int i;
+
+    pi_setup();
+
+    fail_unless(floatnum_get_double(outval, flt) == 0,
+               "Should not fail on this value");
+
+    /* Compare result with what we should get. */
+    for (i=0;i<8;i++)
+       fail_unless(outval[i] == correct[i], "Invalid result generated");
+}
+END_TEST
+
+START_TEST(test_get_extended_pi)
+{
+    unsigned char outval[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+    unsigned char correct[] = {0xE9, 0xBD, 0x68, 0x21, 0xA2, 0xDA, 0x0F, 0xC9, 0x00, 0x40};
+    int i;
+
+    pi_setup();
+
+    fail_unless(floatnum_get_extended(outval, flt) == 0,
+               "Should not fail on this value");
+
+    /* Compare result with what we should get. */
+    for (i=0;i<10;i++)
+       fail_unless(outval[i] == correct[i], "Invalid result generated");
+}
+END_TEST
+
+Suite *bytecode_suite(void)
+{
+    Suite *s = suite_create("floatnum");
+    TCase *tc_get_single = tcase_create("get_single");
+    TCase *tc_get_double = tcase_create("get_double");
+    TCase *tc_get_extended = tcase_create("get_extended");
+
+    suite_add_tcase(s, tc_get_single);
+    tcase_add_test(tc_get_single, test_get_single_pi);
+    tcase_set_fixture(tc_get_single, get_family_setup, get_family_teardown);
+
+    suite_add_tcase(s, tc_get_double);
+    tcase_add_test(tc_get_double, test_get_double_pi);
+    tcase_set_fixture(tc_get_double, get_family_setup, get_family_teardown);
+
+    suite_add_tcase(s, tc_get_extended);
+    tcase_add_test(tc_get_extended, test_get_extended_pi);
+    tcase_set_fixture(tc_get_extended, get_family_setup, get_family_teardown);
+
+    return s;
+}
+
+int main(void)
+{
+    int nf;
+    Suite *s = bytecode_suite();
+    SRunner *sr = srunner_create(s);
+    BitVector_Boot();
+    srunner_run_all(sr, CRNORMAL);
+    nf = srunner_ntests_failed(sr);
+    srunner_free(sr);
+    suite_free(s);
+    return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}