From patchwork Mon Aug 25 20:40:14 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 138 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1756154435; bh=lBmag95gO7q1KEy0BoKwgcfvPUmYMSjrIvNAuxwzovA=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=ad208mw0xDqCQB90goypkiutgL2qISiervOWkBHiEpc9c4EKFH/ukNuwKnc3wTbey z5KVQ0ZFUDhJACxa90JxcHlkzmTzh1thjElhjkeAnRrh1xxX/Jl3zMMbWUOx3T0VIU A8s4f8AY03XtMkmhmtJJpJnFA++mf9DlqfHvB7A1AXFGnF1ROmi1VE4GL79QT2YTW3 jSdZQ+KsQDmA4pJ+vXJUDAmuuuyJNNMRhBAEx4J8+kC6iPYrJhSK/vHvEgn6Fvg9Ku 75ojeIaXq2mcSQSYox5EiBghVE6o4MWZIYTYmitOxU53r5GO3kryPVsao6F7XdFn+n Nm+25dxgdOpIA== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id DCDDA6779C for ; Mon, 25 Aug 2025 14:40:35 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id 99NsG-VI-u-j for ; Mon, 25 Aug 2025 14:40:35 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1756154435; bh=lBmag95gO7q1KEy0BoKwgcfvPUmYMSjrIvNAuxwzovA=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=ad208mw0xDqCQB90goypkiutgL2qISiervOWkBHiEpc9c4EKFH/ukNuwKnc3wTbey z5KVQ0ZFUDhJACxa90JxcHlkzmTzh1thjElhjkeAnRrh1xxX/Jl3zMMbWUOx3T0VIU A8s4f8AY03XtMkmhmtJJpJnFA++mf9DlqfHvB7A1AXFGnF1ROmi1VE4GL79QT2YTW3 jSdZQ+KsQDmA4pJ+vXJUDAmuuuyJNNMRhBAEx4J8+kC6iPYrJhSK/vHvEgn6Fvg9Ku 75ojeIaXq2mcSQSYox5EiBghVE6o4MWZIYTYmitOxU53r5GO3kryPVsao6F7XdFn+n Nm+25dxgdOpIA== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id CBDD767795 for ; Mon, 25 Aug 2025 14:40:35 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1756154433; bh=/m7c4rWEbaf9jA6scdItj1hGp+W9mJv1Vqm+NbvXTtE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Cffj/leKGpZC2AK6IVIq/DCXTGqwa/mGXa20mrcAGz18QF7hhKPB1KwaNNn6RIdVx 54QAkO0JX0jScAL5zhERpqKkCseiXcAMFOK/o//ti9a7XKIrKxKs3vcewzb6y6SYTE 0juLyd9GSjGDMnMQCrvOrCCw0gW+tWporkL6wWH5G8UKCFT4FEhB8qX7qJoWCpplOt 8qw/wIKKPAcK0dnSeg3UZmrxzHSKdWjOvwbODaZ4QmS4T45gm5Z3UgFgtmrw7e6VLn SGNZUJCZSGDCYjsfP/2jv+5t7VvdG3MkuPPRP1obSH3IgtnV1XNNwX4rscINvdqUdD zgq77frvKBU1g== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id C99EF67787; Mon, 25 Aug 2025 14:40:33 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id Abc-KtMZAM1X; Mon, 25 Aug 2025 14:40:33 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1756154433; bh=fJrUSo00xRSdyGkVgV2zwXYnWZJEEic5P187pJdj2RI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nTlZInMP19taI5fHs+1vUp5gncVeUTOkPIbOyeBfznq4wmdL5WbdiPz+9vVEwfKrd hJ8CXfUooszenWS+koPqut57RaXHfgv5ml2vGq+fJWdJ0OLokkosnBtvzivyabr57v h98n30z0zsi0e/dv2RZ12Umtq24TX2AR16GtBoYBl1cEMMsNSiccnem5erJvO2p+KS pfqJxGi9KKC6kH6r4Q0tzxcvBvsjoSmDHcJv/58NU6Ebs/MBnvsK0FyMjn2u8kNdho FDczv5ZLMyshToXiIq1K6unmJcrVLn4Ucu/R4wu5K7tt6zH6L1Phrx2q8XYe9w9ybT EaVCIlGXyVycw== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 1C53067709; Mon, 25 Aug 2025 14:40:33 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Mon, 25 Aug 2025 14:40:14 -0600 Message-ID: <20250825204022.3655799-2-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250825204022.3655799-1-sjg@u-boot.org> References: <20250825204022.3655799-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: 2EYJMPM2I6UV2CICHZ4KZGGW4XC3QSKA X-Message-ID-Hash: 2EYJMPM2I6UV2CICHZ4KZGGW4XC3QSKA X-MailFrom: sjg@u-boot.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Heinrich Schuchardt , Simon Glass X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 1/6] Add a few floating-point routines List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass 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 --- 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 +#include +#include + +/* + * 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); +}