
From: Simon Glass <sjg@chromium.org> U-Boot does not normally make use of floating point and it is generally possible and desirable to avoid it within a bootloader. However there are libraries which need it. For example, U-Boot's Truetype font implementation needs floating point and some features such as the Nuklear GUI make use of it also. Enable this to compile in some basic library functions for floating point. Signed-off-by: Simon Glass <sjg@chromium.org> --- include/vsprintf.h | 25 ++++++ lib/Kconfig | 13 +++ lib/Makefile | 1 + lib/strtof.c | 200 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 239 insertions(+) create mode 100644 lib/strtof.c diff --git a/include/vsprintf.h b/include/vsprintf.h index 9da6ce7cc4d..9e86f395331 100644 --- a/include/vsprintf.h +++ b/include/vsprintf.h @@ -364,4 +364,29 @@ int vsscanf(const char *inp, char const *fmt0, va_list ap); */ int sscanf(const char *buf, const char *fmt, ...); +/** + * strtod() - Convert text floating-point number to double + * + * @str: String to convert + * @entptr: If non-NULL, set to point to the character after the last one that + * was part of the floating-point number + * @return double-precision floating-point representation of the characters in + * @str. + */ +double strtod(const char *str, char **endptr); + +/** + * strtod() - Convert text floating-point number to double + * + * @str: decimal ASCII floating-point number, optionally preceded by whitespace. + * Must have form "-I.FE-X", where I is the integer part of the mantissa, F is + * the fractional part of the mantissa, and X is the exponent. Either of the + * signs may be "+", "-", or omitted. Either I or F may be omitted, or both. + * The decimal point isn't necessary unless F is present. The "E" may actually + * be an "e". E and X may both be omitted (but not just one). + * @return double-precision floating-point representation of the characters in + * @str. + */ +double atof(const char *str); + #endif diff --git a/lib/Kconfig b/lib/Kconfig index ed35c1f0b30..b9866619c5d 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -1246,6 +1246,19 @@ config PHANDLE_CHECK_SEQ enable this config option to distinguish them using phandles in fdtdec_get_alias_seq() function. +config FLOAT + bool "Support floating-point functions" + help + U-Boot does not normally make use of floating point and it is + generally possible and desirable to avoid it within a bootloader. + + However there are libraries which need it. For example, U-Boot's + Truetype font implementation needs floating point and some features + such as the Nuklear GUI make use of it also. + + Enable this to compile in some basic library functions for floating + point. + endmenu source "lib/fwu_updates/Kconfig" diff --git a/lib/Makefile b/lib/Makefile index 84b94d78680..b9a5378e8aa 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -155,6 +155,7 @@ obj-y += vsprintf.o strto.o obj-$(CONFIG_SSCANF) += sscanf.o endif obj-$(CONFIG_$(PHASE_)OID_REGISTRY) += oid_registry.o +obj-$(CONFIG_FLOAT) += strtof.o obj-y += abuf.o obj-y += alist.o diff --git a/lib/strtof.c b/lib/strtof.c new file mode 100644 index 00000000000..f26eca5ab79 --- /dev/null +++ b/lib/strtof.c @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 1988-1993 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * Copyright 2020 Google LLC + * Relicensed as GPL-2.0+ for U-Boot + * + * Modified from commit fae05bc at:: + * github.com/embeddedartistry/embedded-resources/tree/master/examples/libc/stdlib + */ + +#include <linux/ctype.h> +#include <stdbool.h> +#include <stddef.h> + +/* + * Largest possible base--10 exponent. Any exponent larger than this will + * already produce underflow or overflow, so there's no need to worry about + * additional digits. + */ +static int maxExponent = 511; + +/* + * Table giving binary powers of 10. Entry is 10^2^i. Used to convert decimal + * exponents into floating-point numbers + */ +static double powersOf10[] = { + 1.0e4, + 1.0e8, + 1.0e16, + 1.0e32, + 1.0e64, + 1.0e128, + 1.0e256 +}; + +/* + * Details on @str: + */ +double strtod(const char *string, char **endptr) +{ + int sign, expsign = false; + double fraction, dblexp, *d; + const char *p; + int c; + int exp = 0; /* Exponent read from "EX" field */ + /* + * Exponent that derives from the fractional part. Under normal + * circumstatnces, it is the negative of the number of digits in F. + * However if I is very long, the last digits of I get dropped + * (otherwise a long I with a large negative exponent could cause an + * unnecessary overflow on I alone). In this case, fracexp is + * incremented one for each dropped digit. + */ + int fracexp = 0; + int mantsize; /* Number of digits in mantissa */ + int decpt; /* Number of mantissa digits BEFORE decimal point */ + /* Temporarily holds location of exponent in string */ + const char *pexp; + + /* Strip off leading blanks and check for a sign */ + p = string; + while (isspace(*p)) + p += 1; + if (*p == '-') { + sign = true; + p += 1; + } else { + if (*p == '+') + p += 1; + sign = false; + } + + /* + * Count the number of digits in the mantissa (including the decimal + * point), and also locate the decimal point. + */ + decpt = -1; + for (mantsize = 0;; mantsize += 1) { + c = *p; + if (!isdigit(c)) { + if (c != '.' || decpt >= 0) + break; + decpt = mantsize; + } + p += 1; + } + + /* + * Now suck up the digits in the mantissa. Use two integers to + * collect 9 digits each (this is faster than using floating-point). + * If the mantissa has more than 18 digits, ignore the extras, since + * they can't affect the value anyway. + */ + pexp = p; + p -= mantsize; + if (decpt < 0) + decpt = mantsize; + else + mantsize -= 1; /* One of the digits was the point */ + if (mantsize > 18) { + fracexp = decpt - 18; + mantsize = 18; + } else { + fracexp = decpt - mantsize; + } + if (!mantsize) { + fraction = 0.0; + p = string; + goto done; + } else { + int frac1, frac2; + + frac1 = 0; + for (; mantsize > 9; mantsize -= 1) { + c = *p; + p += 1; + if (c == '.') { + c = *p; + p += 1; + } + frac1 = 10 * frac1 + (c - '0'); + } + frac2 = 0; + for (; mantsize > 0; mantsize -= 1) { + c = *p; + p += 1; + if (c == '.') { + c = *p; + p += 1; + } + frac2 = 10 * frac2 + (c - '0'); + } + fraction = (1.0e9 * frac1) + frac2; + } + + /* Skim off the exponent */ + p = pexp; + if (*p == 'E' || *p == 'e') { + p += 1; + if (*p == '-') { + expsign = true; + p += 1; + } else { + if (*p == '+') + p += 1; + expsign = false; + } + if (!isdigit(*p)) { + p = pexp; + goto done; + } + while (isdigit(*p)) { + exp = exp * 10 + (*p - '0'); + p += 1; + } + } + if (expsign) + exp = fracexp - exp; + else + exp = fracexp + exp; + + /* + * Generate a floating-point number that represents the exponent. + * Do this by processing the exponent one bit at a time to combine + * many powers of 2 of 10. Then combine the exponent with the + * fraction. + */ + if (exp < 0) { + expsign = true; + exp = -exp; + } else { + expsign = false; + } + if (exp > maxExponent) + exp = maxExponent; /* errno = ERANGE; */ + dblexp = 1.0; + for (d = powersOf10; exp != 0; exp >>= 1, d += 1) { + if (exp & 01) + dblexp *= *d; + } + if (expsign) + fraction /= dblexp; + else + fraction *= dblexp; + +done: + if (endptr) + *endptr = (char *)p; + + if (sign) + return -fraction; + + return fraction; +} + +double atof(const char *str) +{ + return strtod(str, NULL); +} -- 2.43.0