1/*
2 * File:         arch/blackfin/lib/muldi3.c
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description:
8 *
9 * Modified:
10 *               Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs:         Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
28 */
29
30#ifndef SI_TYPE_SIZE
31#define SI_TYPE_SIZE 32
32#endif
33#define __ll_b (1L << (SI_TYPE_SIZE / 2))
34#define __ll_lowpart(t) ((usitype) (t) % __ll_b)
35#define __ll_highpart(t) ((usitype) (t) / __ll_b)
36#define BITS_PER_UNIT 8
37
38#if !defined(umul_ppmm)
39#define umul_ppmm(w1, w0, u, v)						\
40  do {									\
41    usitype __x0, __x1, __x2, __x3;					\
42    usitype __ul, __vl, __uh, __vh;					\
43									\
44    __ul = __ll_lowpart (u);						\
45    __uh = __ll_highpart (u);						\
46    __vl = __ll_lowpart (v);						\
47    __vh = __ll_highpart (v);						\
48									\
49    __x0 = (usitype) __ul * __vl;					\
50    __x1 = (usitype) __ul * __vh;					\
51    __x2 = (usitype) __uh * __vl;					\
52    __x3 = (usitype) __uh * __vh;					\
53									\
54    __x1 += __ll_highpart (__x0);/* this can't give carry */		\
55    __x1 += __x2;		/* but this indeed can */		\
56    if (__x1 < __x2)		/* did we get it? */			\
57      __x3 += __ll_b;		/* yes, add it in the proper pos. */	\
58									\
59    (w1) = __x3 + __ll_highpart (__x1);					\
60    (w0) = __ll_lowpart (__x1) * __ll_b + __ll_lowpart (__x0);		\
61  } while (0)
62#endif
63
64#if !defined(__umulsidi3)
65#define __umulsidi3(u, v) 						\
66  ({diunion __w;                                                        \
67       umul_ppmm (__w.s.high, __w.s.low, u, v);                         \
68           __w.ll; })
69#endif
70
71typedef unsigned int usitype __attribute__ ((mode(SI)));
72typedef int sitype __attribute__ ((mode(SI)));
73typedef int ditype __attribute__ ((mode(DI)));
74typedef int word_type __attribute__ ((mode(__word__)));
75
76struct distruct {
77	sitype low, high;
78};
79typedef union {
80	struct distruct s;
81	ditype ll;
82} diunion;
83
84#ifdef CONFIG_ARITHMETIC_OPS_L1
85ditype __muldi3(ditype u, ditype v)__attribute__((l1_text));
86#endif
87
88ditype __muldi3(ditype u, ditype v)
89{
90	diunion w;
91	diunion uu, vv;
92
93	uu.ll = u, vv.ll = v;
94	w.ll = __umulsidi3(uu.s.low, vv.s.low);
95	w.s.high += ((usitype) uu.s.low * (usitype) vv.s.high
96		     + (usitype) uu.s.high * (usitype) vv.s.low);
97
98	return w.ll;
99}
100