aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/post/lib_powerpc/fpu
diff options
context:
space:
mode:
authorAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
committerAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
commitaf1a266670d040d2f4083ff309d732d648afba2a (patch)
tree2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/u-boot/post/lib_powerpc/fpu
parente02cda008591317b1625707ff8e115a4841aa889 (diff)
Add submodule dependency filesHEADmaster
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/u-boot/post/lib_powerpc/fpu')
-rw-r--r--roms/u-boot/post/lib_powerpc/fpu/20001122-1.c43
-rw-r--r--roms/u-boot/post/lib_powerpc/fpu/20010114-2.c48
-rw-r--r--roms/u-boot/post/lib_powerpc/fpu/20010226-1.c36
-rw-r--r--roms/u-boot/post/lib_powerpc/fpu/980619-1.c42
-rw-r--r--roms/u-boot/post/lib_powerpc/fpu/Makefile18
-rw-r--r--roms/u-boot/post/lib_powerpc/fpu/acc1.c39
-rw-r--r--roms/u-boot/post/lib_powerpc/fpu/compare-fp-1.c207
-rw-r--r--roms/u-boot/post/lib_powerpc/fpu/darwin-ldouble.c119
-rw-r--r--roms/u-boot/post/lib_powerpc/fpu/fpu.c74
-rw-r--r--roms/u-boot/post/lib_powerpc/fpu/mul-subnormal-single-1.c85
10 files changed, 711 insertions, 0 deletions
diff --git a/roms/u-boot/post/lib_powerpc/fpu/20001122-1.c b/roms/u-boot/post/lib_powerpc/fpu/20001122-1.c
new file mode 100644
index 000000000..4b452dc08
--- /dev/null
+++ b/roms/u-boot/post/lib_powerpc/fpu/20001122-1.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2007
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+/*
+ * This file is originally a part of the GCC testsuite.
+ */
+
+#include <common.h>
+
+#include <post.h>
+
+GNU_FPOST_ATTR
+
+#if CONFIG_POST & CONFIG_SYS_POST_FPU
+
+int fpu_post_test_math1 (void)
+{
+ volatile double a;
+ double c, d;
+ volatile double b;
+
+ d = 1.0;
+
+ do
+ {
+ c = d;
+ d = c * 0.5;
+ b = 1 + d;
+ } while (b != 1.0);
+
+ a = 1.0 + c;
+
+ if (a == 1.0) {
+ post_log ("Error in FPU math1 test\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_POST & CONFIG_SYS_POST_FPU */
diff --git a/roms/u-boot/post/lib_powerpc/fpu/20010114-2.c b/roms/u-boot/post/lib_powerpc/fpu/20010114-2.c
new file mode 100644
index 000000000..4aadd1e04
--- /dev/null
+++ b/roms/u-boot/post/lib_powerpc/fpu/20010114-2.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2007
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+/*
+ * This file is originally a part of the GCC testsuite.
+ */
+
+#include <common.h>
+
+#include <post.h>
+
+GNU_FPOST_ATTR
+
+#if CONFIG_POST & CONFIG_SYS_POST_FPU
+
+static float rintf (float x)
+{
+ volatile float TWO23 = 8388608.0;
+
+ if (__builtin_fabs (x) < TWO23)
+ {
+ if (x > 0.0)
+ {
+ x += TWO23;
+ x -= TWO23;
+ }
+ else if (x < 0.0)
+ {
+ x = TWO23 - x;
+ x = -(x - TWO23);
+ }
+ }
+
+ return x;
+}
+
+int fpu_post_test_math2 (void)
+{
+ if (rintf (-1.5) != -2.0) {
+ post_log ("Error in FPU math2 test\n");
+ return -1;
+ }
+ return 0;
+}
+
+#endif /* CONFIG_POST & CONFIG_SYS_POST_FPU */
diff --git a/roms/u-boot/post/lib_powerpc/fpu/20010226-1.c b/roms/u-boot/post/lib_powerpc/fpu/20010226-1.c
new file mode 100644
index 000000000..b09a25c21
--- /dev/null
+++ b/roms/u-boot/post/lib_powerpc/fpu/20010226-1.c
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2007
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+/*
+ * This file is originally a part of the GCC testsuite.
+ */
+
+#include <common.h>
+
+#include <post.h>
+
+GNU_FPOST_ATTR
+
+#if CONFIG_POST & CONFIG_SYS_POST_FPU
+
+int fpu_post_test_math3 (void)
+{
+ volatile long double dfrom = 1.1;
+ volatile long double m1;
+ volatile long double m2;
+ volatile unsigned long mant_long;
+
+ m1 = dfrom / 2.0;
+ m2 = m1 * 4294967296.0;
+ mant_long = ((unsigned long) m2) & 0xffffffff;
+
+ if (mant_long != 0x8ccccccc) {
+ post_log ("Error in FPU math3 test\n");
+ return -1;
+ }
+ return 0;
+}
+
+#endif /* CONFIG_POST & CONFIG_SYS_POST_FPU */
diff --git a/roms/u-boot/post/lib_powerpc/fpu/980619-1.c b/roms/u-boot/post/lib_powerpc/fpu/980619-1.c
new file mode 100644
index 000000000..2fea70830
--- /dev/null
+++ b/roms/u-boot/post/lib_powerpc/fpu/980619-1.c
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2007
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+/*
+ * This file is originally a part of the GCC testsuite.
+ */
+
+#include <common.h>
+
+#include <post.h>
+
+GNU_FPOST_ATTR
+
+#if CONFIG_POST & CONFIG_SYS_POST_FPU
+
+int fpu_post_test_math4 (void)
+{
+ volatile float reale = 1.0f;
+ volatile float oneplus;
+ int i;
+
+ if (sizeof (float) != 4)
+ return 0;
+
+ for (i = 0; ; i++)
+ {
+ oneplus = 1.0f + reale;
+ if (oneplus == 1.0f)
+ break;
+ reale = reale / 2.0f;
+ }
+ /* Assumes ieee754 accurate arithmetic above. */
+ if (i != 24) {
+ post_log ("Error in FPU math4 test\n");
+ return -1;
+ }
+ return 0;
+}
+
+#endif /* CONFIG_POST & CONFIG_SYS_POST_FPU */
diff --git a/roms/u-boot/post/lib_powerpc/fpu/Makefile b/roms/u-boot/post/lib_powerpc/fpu/Makefile
new file mode 100644
index 000000000..9b2c1fadb
--- /dev/null
+++ b/roms/u-boot/post/lib_powerpc/fpu/Makefile
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2007
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+
+objs-before-objcopy := 20001122-1.o 20010114-2.o 20010226-1.o 980619-1.o \
+ acc1.o compare-fp-1.o fpu.o mul-subnormal-single-1.o darwin-ldouble.o
+targets += $(objs-before-objcopy)
+
+# remove -msoft-float flag
+$(foreach m, $(objs-before-objcopy), $(eval CFLAGS_REMOVE_$m := -msoft-float))
+ccflags-y := -mhard-float -fkeep-inline-functions
+
+obj-y := $(objs-before-objcopy:.o=_.o)
+
+OBJCOPYFLAGS := -R .gnu.attributes
+$(obj)/%_.o: $(obj)/%.o FORCE
+ $(call if_changed,objcopy)
diff --git a/roms/u-boot/post/lib_powerpc/fpu/acc1.c b/roms/u-boot/post/lib_powerpc/fpu/acc1.c
new file mode 100644
index 000000000..9e5783b25
--- /dev/null
+++ b/roms/u-boot/post/lib_powerpc/fpu/acc1.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2007
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+/*
+ * This file is originally a part of the GCC testsuite.
+ */
+
+#include <common.h>
+
+#include <post.h>
+
+GNU_FPOST_ATTR
+
+#if CONFIG_POST & CONFIG_SYS_POST_FPU
+
+static double func (const double *array)
+{
+ double d = *array;
+
+ if (d == 0.0)
+ return d;
+ else
+ return d + func (array + 1);
+}
+
+int fpu_post_test_math5 (void)
+{
+ double values[] = { 0.1e-100, 1.0, -1.0, 0.0 };
+
+ if (func (values) != 0.1e-100) {
+ post_log ("Error in FPU math5 test\n");
+ return -1;
+ }
+ return 0;
+}
+
+#endif /* CONFIG_POST & CONFIG_SYS_POST_FPU */
diff --git a/roms/u-boot/post/lib_powerpc/fpu/compare-fp-1.c b/roms/u-boot/post/lib_powerpc/fpu/compare-fp-1.c
new file mode 100644
index 000000000..d46a13adc
--- /dev/null
+++ b/roms/u-boot/post/lib_powerpc/fpu/compare-fp-1.c
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2007
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+/*
+ * Test for correctness of composite floating-point comparisons.
+ * Written by Paolo Bonzini, 26th May 2004.
+ * This file is originally a part of the GCC testsuite.
+ */
+
+#include <common.h>
+
+#include <post.h>
+
+GNU_FPOST_ATTR
+
+#if CONFIG_POST & CONFIG_SYS_POST_FPU
+
+static int failed;
+
+#define TEST(c) if ((c) != ok) failed++
+#define ORD(a, b) (!__builtin_isunordered ((a), (b)))
+#define UNORD(a, b) (__builtin_isunordered ((a), (b)))
+#define UNEQ(a, b) (__builtin_isunordered ((a), (b)) || ((a) == (b)))
+#define UNLT(a, b) (__builtin_isunordered ((a), (b)) || ((a) < (b)))
+#define UNLE(a, b) (__builtin_isunordered ((a), (b)) || ((a) <= (b)))
+#define UNGT(a, b) (__builtin_isunordered ((a), (b)) || ((a) > (b)))
+#define UNGE(a, b) (__builtin_isunordered ((a), (b)) || ((a) >= (b)))
+#define LTGT(a, b) (__builtin_islessgreater ((a), (b)))
+
+static float pinf;
+static float ninf;
+static float NaN;
+
+static void iuneq (float x, float y, int ok)
+{
+ TEST (UNEQ (x, y));
+ TEST (!LTGT (x, y));
+ TEST (UNLE (x, y) && UNGE (x,y));
+}
+
+static void ieq (float x, float y, int ok)
+{
+ TEST (ORD (x, y) && UNEQ (x, y));
+}
+
+static void iltgt (float x, float y, int ok)
+{
+ TEST (!UNEQ (x, y)); /* Not optimizable. */
+ TEST (LTGT (x, y)); /* Same, __builtin_islessgreater does not trap. */
+ TEST (ORD (x, y) && (UNLT (x, y) || UNGT (x,y)));
+}
+
+static void ine (float x, float y, int ok)
+{
+ TEST (UNLT (x, y) || UNGT (x, y));
+}
+
+static void iunlt (float x, float y, int ok)
+{
+ TEST (UNLT (x, y));
+ TEST (UNORD (x, y) || (x < y));
+}
+
+static void ilt (float x, float y, int ok)
+{
+ TEST (ORD (x, y) && UNLT (x, y)); /* Not optimized */
+ TEST ((x <= y) && (x != y));
+ TEST ((x <= y) && (y != x));
+ TEST ((x != y) && (x <= y)); /* Not optimized */
+ TEST ((y != x) && (x <= y)); /* Not optimized */
+}
+
+static void iunle (float x, float y, int ok)
+{
+ TEST (UNLE (x, y));
+ TEST (UNORD (x, y) || (x <= y));
+}
+
+static void ile (float x, float y, int ok)
+{
+ TEST (ORD (x, y) && UNLE (x, y)); /* Not optimized */
+ TEST ((x < y) || (x == y));
+ TEST ((y > x) || (x == y));
+ TEST ((x == y) || (x < y)); /* Not optimized */
+ TEST ((y == x) || (x < y)); /* Not optimized */
+}
+
+static void iungt (float x, float y, int ok)
+{
+ TEST (UNGT (x, y));
+ TEST (UNORD (x, y) || (x > y));
+}
+
+static void igt (float x, float y, int ok)
+{
+ TEST (ORD (x, y) && UNGT (x, y)); /* Not optimized */
+ TEST ((x >= y) && (x != y));
+ TEST ((x >= y) && (y != x));
+ TEST ((x != y) && (x >= y)); /* Not optimized */
+ TEST ((y != x) && (x >= y)); /* Not optimized */
+}
+
+static void iunge (float x, float y, int ok)
+{
+ TEST (UNGE (x, y));
+ TEST (UNORD (x, y) || (x >= y));
+}
+
+static void ige (float x, float y, int ok)
+{
+ TEST (ORD (x, y) && UNGE (x, y)); /* Not optimized */
+ TEST ((x > y) || (x == y));
+ TEST ((y < x) || (x == y));
+ TEST ((x == y) || (x > y)); /* Not optimized */
+ TEST ((y == x) || (x > y)); /* Not optimized */
+}
+
+int fpu_post_test_math6 (void)
+{
+ pinf = __builtin_inf ();
+ ninf = -__builtin_inf ();
+ NaN = __builtin_nan ("");
+
+ iuneq (ninf, pinf, 0);
+ iuneq (NaN, NaN, 1);
+ iuneq (pinf, ninf, 0);
+ iuneq (1, 4, 0);
+ iuneq (3, 3, 1);
+ iuneq (5, 2, 0);
+
+ ieq (1, 4, 0);
+ ieq (3, 3, 1);
+ ieq (5, 2, 0);
+
+ iltgt (ninf, pinf, 1);
+ iltgt (NaN, NaN, 0);
+ iltgt (pinf, ninf, 1);
+ iltgt (1, 4, 1);
+ iltgt (3, 3, 0);
+ iltgt (5, 2, 1);
+
+ ine (1, 4, 1);
+ ine (3, 3, 0);
+ ine (5, 2, 1);
+
+ iunlt (NaN, ninf, 1);
+ iunlt (pinf, NaN, 1);
+ iunlt (pinf, ninf, 0);
+ iunlt (pinf, pinf, 0);
+ iunlt (ninf, ninf, 0);
+ iunlt (1, 4, 1);
+ iunlt (3, 3, 0);
+ iunlt (5, 2, 0);
+
+ ilt (1, 4, 1);
+ ilt (3, 3, 0);
+ ilt (5, 2, 0);
+
+ iunle (NaN, ninf, 1);
+ iunle (pinf, NaN, 1);
+ iunle (pinf, ninf, 0);
+ iunle (pinf, pinf, 1);
+ iunle (ninf, ninf, 1);
+ iunle (1, 4, 1);
+ iunle (3, 3, 1);
+ iunle (5, 2, 0);
+
+ ile (1, 4, 1);
+ ile (3, 3, 1);
+ ile (5, 2, 0);
+
+ iungt (NaN, ninf, 1);
+ iungt (pinf, NaN, 1);
+ iungt (pinf, ninf, 1);
+ iungt (pinf, pinf, 0);
+ iungt (ninf, ninf, 0);
+ iungt (1, 4, 0);
+ iungt (3, 3, 0);
+ iungt (5, 2, 1);
+
+ igt (1, 4, 0);
+ igt (3, 3, 0);
+ igt (5, 2, 1);
+
+ iunge (NaN, ninf, 1);
+ iunge (pinf, NaN, 1);
+ iunge (ninf, pinf, 0);
+ iunge (pinf, pinf, 1);
+ iunge (ninf, ninf, 1);
+ iunge (1, 4, 0);
+ iunge (3, 3, 1);
+ iunge (5, 2, 1);
+
+ ige (1, 4, 0);
+ ige (3, 3, 1);
+ ige (5, 2, 1);
+
+ if (failed) {
+ post_log ("Error in FPU math6 test\n");
+ return -1;
+ }
+ return 0;
+}
+
+#endif /* CONFIG_POST & CONFIG_SYS_POST_FPU */
diff --git a/roms/u-boot/post/lib_powerpc/fpu/darwin-ldouble.c b/roms/u-boot/post/lib_powerpc/fpu/darwin-ldouble.c
new file mode 100644
index 000000000..16105c837
--- /dev/null
+++ b/roms/u-boot/post/lib_powerpc/fpu/darwin-ldouble.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Borrowed from GCC 4.2.2 (which still was GPL v2+)
+ */
+/* 128-bit long double support routines for Darwin.
+ Copyright (C) 1993, 2003, 2004, 2005, 2006, 2007
+ Free Software Foundation, Inc.
+
+This file is part of GCC.
+ */
+
+/*
+ * Implementations of floating-point long double basic arithmetic
+ * functions called by the IBM C compiler when generating code for
+ * PowerPC platforms. In particular, the following functions are
+ * implemented: __gcc_qadd, __gcc_qsub, __gcc_qmul, and __gcc_qdiv.
+ * Double-double algorithms are based on the paper "Doubled-Precision
+ * IEEE Standard 754 Floating-Point Arithmetic" by W. Kahan, February 26,
+ * 1987. An alternative published reference is "Software for
+ * Doubled-Precision Floating-Point Computations", by Seppo Linnainmaa,
+ * ACM TOMS vol 7 no 3, September 1981, pages 272-283.
+ */
+
+/*
+ * Each long double is made up of two IEEE doubles. The value of the
+ * long double is the sum of the values of the two parts. The most
+ * significant part is required to be the value of the long double
+ * rounded to the nearest double, as specified by IEEE. For Inf
+ * values, the least significant part is required to be one of +0.0 or
+ * -0.0. No other requirements are made; so, for example, 1.0 may be
+ * represented as (1.0, +0.0) or (1.0, -0.0), and the low part of a
+ * NaN is don't-care.
+ *
+ * This code currently assumes big-endian.
+ */
+
+#define fabs(x) __builtin_fabs(x)
+#define isless(x, y) __builtin_isless(x, y)
+#define inf() __builtin_inf()
+#define unlikely(x) __builtin_expect((x), 0)
+#define nonfinite(a) unlikely(!isless(fabs(a), inf()))
+
+typedef union {
+ long double ldval;
+ double dval[2];
+} longDblUnion;
+
+/* Add two 'long double' values and return the result. */
+long double __gcc_qadd(double a, double aa, double c, double cc)
+{
+ longDblUnion x;
+ double z, q, zz, xh;
+
+ z = a + c;
+
+ if (nonfinite(z)) {
+ z = cc + aa + c + a;
+ if (nonfinite(z))
+ return z;
+ x.dval[0] = z; /* Will always be DBL_MAX. */
+ zz = aa + cc;
+ if (fabs(a) > fabs(c))
+ x.dval[1] = a - z + c + zz;
+ else
+ x.dval[1] = c - z + a + zz;
+ } else {
+ q = a - z;
+ zz = q + c + (a - (q + z)) + aa + cc;
+
+ /* Keep -0 result. */
+ if (zz == 0.0)
+ return z;
+
+ xh = z + zz;
+ if (nonfinite(xh))
+ return xh;
+
+ x.dval[0] = xh;
+ x.dval[1] = z - xh + zz;
+ }
+ return x.ldval;
+}
+
+long double __gcc_qsub(double a, double b, double c, double d)
+{
+ return __gcc_qadd(a, b, -c, -d);
+}
+
+long double __gcc_qmul(double a, double b, double c, double d)
+{
+ longDblUnion z;
+ double t, tau, u, v, w;
+
+ t = a * c; /* Highest order double term. */
+
+ if (unlikely(t == 0) /* Preserve -0. */
+ || nonfinite(t))
+ return t;
+
+ /* Sum terms of two highest orders. */
+
+ /* Use fused multiply-add to get low part of a * c. */
+#ifndef __NO_FPRS__
+ asm("fmsub %0,%1,%2,%3" : "=f"(tau) : "f"(a), "f"(c), "f"(t));
+#else
+ tau = fmsub(a, c, t);
+#endif
+ v = a * d;
+ w = b * c;
+ tau += v + w; /* Add in other second-order terms. */
+ u = t + tau;
+
+ /* Construct long double result. */
+ if (nonfinite(u))
+ return u;
+ z.dval[0] = u;
+ z.dval[1] = (t - u) + tau;
+ return z.ldval;
+}
diff --git a/roms/u-boot/post/lib_powerpc/fpu/fpu.c b/roms/u-boot/post/lib_powerpc/fpu/fpu.c
new file mode 100644
index 000000000..0de76ce05
--- /dev/null
+++ b/roms/u-boot/post/lib_powerpc/fpu/fpu.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2007
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Author: Sergei Poselenov <sposelenov@emcraft.com>
+ */
+
+#include <common.h>
+
+/*
+ * FPU test
+ *
+ * This test checks the arithmetic logic unit (ALU) of CPU.
+ * It tests independently various groups of instructions using
+ * run-time modification of the code to reduce the memory footprint.
+ * For more details refer to post/cpu/ *.c files.
+ */
+
+#include <post.h>
+
+GNU_FPOST_ATTR
+
+#if CONFIG_POST & CONFIG_SYS_POST_FPU
+
+#include <watchdog.h>
+
+extern int fpu_status (void);
+extern void fpu_enable (void);
+extern void fpu_disable (void);
+
+extern int fpu_post_test_math1 (void);
+extern int fpu_post_test_math2 (void);
+extern int fpu_post_test_math3 (void);
+extern int fpu_post_test_math4 (void);
+extern int fpu_post_test_math5 (void);
+extern int fpu_post_test_math6 (void);
+extern int fpu_post_test_math7 (void);
+
+int fpu_post_test (int flags)
+{
+ int fpu = fpu_status ();
+
+ int ret = 0;
+
+ WATCHDOG_RESET ();
+
+ if (!fpu)
+ fpu_enable ();
+
+ if (ret == 0)
+ ret = fpu_post_test_math1 ();
+ if (ret == 0)
+ ret = fpu_post_test_math2 ();
+ if (ret == 0)
+ ret = fpu_post_test_math3 ();
+ if (ret == 0)
+ ret = fpu_post_test_math4 ();
+ if (ret == 0)
+ ret = fpu_post_test_math5 ();
+ if (ret == 0)
+ ret = fpu_post_test_math6 ();
+ if (ret == 0)
+ ret = fpu_post_test_math7 ();
+
+ if (!fpu)
+ fpu_disable ();
+
+ WATCHDOG_RESET ();
+
+ return ret;
+}
+
+#endif /* CONFIG_POST & CONFIG_SYS_POST_FPU */
diff --git a/roms/u-boot/post/lib_powerpc/fpu/mul-subnormal-single-1.c b/roms/u-boot/post/lib_powerpc/fpu/mul-subnormal-single-1.c
new file mode 100644
index 000000000..cb61c9114
--- /dev/null
+++ b/roms/u-boot/post/lib_powerpc/fpu/mul-subnormal-single-1.c
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2007
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+/*
+ * This file is originally a part of the GCC testsuite.
+ * Check that certain subnormal numbers (formerly known as denormalized
+ * numbers) are rounded to within 0.5 ulp. PR other/14354.
+ */
+
+#include <common.h>
+
+#include <post.h>
+
+GNU_FPOST_ATTR
+
+#if CONFIG_POST & CONFIG_SYS_POST_FPU
+
+union uf
+{
+ unsigned int u;
+ float f;
+};
+
+static float
+u2f (unsigned int v)
+{
+ union uf u;
+ u.u = v;
+ return u.f;
+}
+
+static unsigned int
+f2u (float v)
+{
+ union uf u;
+ u.f = v;
+ return u.u;
+}
+
+static int ok = 1;
+
+static void
+tstmul (unsigned int ux, unsigned int uy, unsigned int ur)
+{
+ float x = u2f (ux);
+ float y = u2f (uy);
+
+ if (f2u (x * y) != ur)
+ /* Set a variable rather than aborting here, to simplify tracing when
+ several computations are wrong. */
+ ok = 0;
+}
+
+/* We don't want to make this const and static, or else we risk inlining
+ causing the test to fold as constants at compile-time. */
+struct
+{
+ unsigned int p1, p2, res;
+} static volatile expected[] =
+{
+ {0xfff, 0x3f800400, 0xfff},
+ {0xf, 0x3fc88888, 0x17},
+ {0xf, 0x3f844444, 0xf}
+};
+
+int fpu_post_test_math7 (void)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(expected); i++)
+ {
+ tstmul (expected[i].p1, expected[i].p2, expected[i].res);
+ tstmul (expected[i].p2, expected[i].p1, expected[i].res);
+ }
+
+ if (!ok) {
+ post_log ("Error in FPU math7 test\n");
+ return -1;
+ }
+ return 0;
+}
+
+#endif /* CONFIG_POST & CONFIG_SYS_POST_FPU */