summaryrefslogtreecommitdiff
path: root/lib_generic/div64.c
diff options
context:
space:
mode:
authorDirk Behme <dirk.behme@googlemail.com>2007-08-02 17:41:14 +0200
committerWolfgang Denk <wd@denx.de>2007-08-10 10:33:34 +0200
commitf7c086e94e8ce9aad7268af97f73aa6884686f27 (patch)
treef6027f3aa957584b779daeb26efba7326630a8e8 /lib_generic/div64.c
parenta22806469a8f2b69c829f4fd5361fdebd0cb01b4 (diff)
downloadu-boot-imx-f7c086e94e8ce9aad7268af97f73aa6884686f27.zip
u-boot-imx-f7c086e94e8ce9aad7268af97f73aa6884686f27.tar.gz
u-boot-imx-f7c086e94e8ce9aad7268af97f73aa6884686f27.tar.bz2
Move 64bit division from avr32 to generic lib
Move the 64bit division from lib_avr32 to lib_generic. With this, all boards can do_div/__div64_32 if needed, not only avr one. Code is put to lib_generic, so no larger memory footprint if not used. No code modifications. Thanks for proposal by HÃ¥vard Skinnemoen. Signed-off-by: Dirk Behme <dirk.behme@gmail.com>
Diffstat (limited to 'lib_generic/div64.c')
-rw-r--r--lib_generic/div64.c52
1 files changed, 52 insertions, 0 deletions
diff --git a/lib_generic/div64.c b/lib_generic/div64.c
new file mode 100644
index 0000000..d9951b5
--- /dev/null
+++ b/lib_generic/div64.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2003 Bernardo Innocenti <bernie@develer.com>
+ *
+ * Based on former do_div() implementation from asm-parisc/div64.h:
+ * Copyright (C) 1999 Hewlett-Packard Co
+ * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ *
+ *
+ * Generic C version of 64bit/32bit division and modulo, with
+ * 64bit result and 32bit remainder.
+ *
+ * The fast case for (n>>32 == 0) is handled inline by do_div().
+ *
+ * Code generated for this function might be very inefficient
+ * for some CPUs. __div64_32() can be overridden by linking arch-specific
+ * assembly versions such as arch/ppc/lib/div64.S and arch/sh/lib/div64.S.
+ */
+
+#include <linux/types.h>
+
+uint32_t __div64_32(uint64_t *n, uint32_t base)
+{
+ uint64_t rem = *n;
+ uint64_t b = base;
+ uint64_t res, d = 1;
+ uint32_t high = rem >> 32;
+
+ /* Reduce the thing a bit first */
+ res = 0;
+ if (high >= base) {
+ high /= base;
+ res = (uint64_t) high << 32;
+ rem -= (uint64_t) (high*base) << 32;
+ }
+
+ while ((int64_t)b > 0 && b < rem) {
+ b = b+b;
+ d = d+d;
+ }
+
+ do {
+ if (rem >= b) {
+ rem -= b;
+ res += d;
+ }
+ b >>= 1;
+ d >>= 1;
+ } while (d);
+
+ *n = res;
+ return rem;
+}