xref: /openbmc/u-boot/arch/nios2/lib/longlong.h (revision 83d290c56fab2d38cd1ab4c4cc7099559c1d5046)
1*83d290c5STom Rini /* SPDX-License-Identifier: GPL-2.0+ */
28d52ea6dSThomas Chou /* longlong.h -- definitions for mixed size 32/64 bit arithmetic.
38d52ea6dSThomas Chou    Copyright (C) 1991, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2004,
48d52ea6dSThomas Chou    2005  Free Software Foundation, Inc.
51a05b5f9SThomas Chou  */
68d52ea6dSThomas Chou 
78d52ea6dSThomas Chou /* You have to define the following before including this file:
88d52ea6dSThomas Chou 
98d52ea6dSThomas Chou    UWtype -- An unsigned type, default type for operations (typically a "word")
108d52ea6dSThomas Chou    UHWtype -- An unsigned type, at least half the size of UWtype.
118d52ea6dSThomas Chou    UDWtype -- An unsigned type, at least twice as large a UWtype
128d52ea6dSThomas Chou    W_TYPE_SIZE -- size in bits of UWtype
138d52ea6dSThomas Chou 
148d52ea6dSThomas Chou    UQItype -- Unsigned 8 bit type.
158d52ea6dSThomas Chou    SItype, USItype -- Signed and unsigned 32 bit types.
168d52ea6dSThomas Chou    DItype, UDItype -- Signed and unsigned 64 bit types.
178d52ea6dSThomas Chou 
188d52ea6dSThomas Chou    On a 32 bit machine UWtype should typically be USItype;
198d52ea6dSThomas Chou    on a 64 bit machine, UWtype should typically be UDItype.  */
208d52ea6dSThomas Chou 
218d52ea6dSThomas Chou #define __BITS4 (W_TYPE_SIZE / 4)
228d52ea6dSThomas Chou #define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2))
238d52ea6dSThomas Chou #define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1))
248d52ea6dSThomas Chou #define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2))
258d52ea6dSThomas Chou 
268d52ea6dSThomas Chou #ifndef W_TYPE_SIZE
278d52ea6dSThomas Chou #define W_TYPE_SIZE	32
288d52ea6dSThomas Chou #define UWtype		USItype
298d52ea6dSThomas Chou #define UHWtype		USItype
308d52ea6dSThomas Chou #define UDWtype		UDItype
318d52ea6dSThomas Chou #endif
328d52ea6dSThomas Chou 
338d52ea6dSThomas Chou extern const UQItype __clz_tab[256];
348d52ea6dSThomas Chou 
358d52ea6dSThomas Chou /* Define auxiliary asm macros.
368d52ea6dSThomas Chou 
378d52ea6dSThomas Chou    1) umul_ppmm(high_prod, low_prod, multiplier, multiplicand) multiplies two
388d52ea6dSThomas Chou    UWtype integers MULTIPLIER and MULTIPLICAND, and generates a two UWtype
398d52ea6dSThomas Chou    word product in HIGH_PROD and LOW_PROD.
408d52ea6dSThomas Chou 
418d52ea6dSThomas Chou    2) __umulsidi3(a,b) multiplies two UWtype integers A and B, and returns a
428d52ea6dSThomas Chou    UDWtype product.  This is just a variant of umul_ppmm.
438d52ea6dSThomas Chou 
448d52ea6dSThomas Chou    3) udiv_qrnnd(quotient, remainder, high_numerator, low_numerator,
458d52ea6dSThomas Chou    denominator) divides a UDWtype, composed by the UWtype integers
468d52ea6dSThomas Chou    HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and places the quotient
478d52ea6dSThomas Chou    in QUOTIENT and the remainder in REMAINDER.  HIGH_NUMERATOR must be less
488d52ea6dSThomas Chou    than DENOMINATOR for correct operation.  If, in addition, the most
498d52ea6dSThomas Chou    significant bit of DENOMINATOR must be 1, then the pre-processor symbol
508d52ea6dSThomas Chou    UDIV_NEEDS_NORMALIZATION is defined to 1.
518d52ea6dSThomas Chou 
528d52ea6dSThomas Chou    4) sdiv_qrnnd(quotient, remainder, high_numerator, low_numerator,
538d52ea6dSThomas Chou    denominator).  Like udiv_qrnnd but the numbers are signed.  The quotient
548d52ea6dSThomas Chou    is rounded towards 0.
558d52ea6dSThomas Chou 
568d52ea6dSThomas Chou    5) count_leading_zeros(count, x) counts the number of zero-bits from the
578d52ea6dSThomas Chou    msb to the first nonzero bit in the UWtype X.  This is the number of
588d52ea6dSThomas Chou    steps X needs to be shifted left to set the msb.  Undefined for X == 0,
598d52ea6dSThomas Chou    unless the symbol COUNT_LEADING_ZEROS_0 is defined to some value.
608d52ea6dSThomas Chou 
618d52ea6dSThomas Chou    6) count_trailing_zeros(count, x) like count_leading_zeros, but counts
628d52ea6dSThomas Chou    from the least significant end.
638d52ea6dSThomas Chou 
648d52ea6dSThomas Chou    7) add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1,
658d52ea6dSThomas Chou    high_addend_2, low_addend_2) adds two UWtype integers, composed by
668d52ea6dSThomas Chou    HIGH_ADDEND_1 and LOW_ADDEND_1, and HIGH_ADDEND_2 and LOW_ADDEND_2
678d52ea6dSThomas Chou    respectively.  The result is placed in HIGH_SUM and LOW_SUM.  Overflow
688d52ea6dSThomas Chou    (i.e. carry out) is not stored anywhere, and is lost.
698d52ea6dSThomas Chou 
708d52ea6dSThomas Chou    8) sub_ddmmss(high_difference, low_difference, high_minuend, low_minuend,
718d52ea6dSThomas Chou    high_subtrahend, low_subtrahend) subtracts two two-word UWtype integers,
728d52ea6dSThomas Chou    composed by HIGH_MINUEND_1 and LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and
738d52ea6dSThomas Chou    LOW_SUBTRAHEND_2 respectively.  The result is placed in HIGH_DIFFERENCE
748d52ea6dSThomas Chou    and LOW_DIFFERENCE.  Overflow (i.e. carry out) is not stored anywhere,
758d52ea6dSThomas Chou    and is lost.
768d52ea6dSThomas Chou 
778d52ea6dSThomas Chou    If any of these macros are left undefined for a particular CPU,
788d52ea6dSThomas Chou    C macros are used.  */
798d52ea6dSThomas Chou 
808d52ea6dSThomas Chou /* The CPUs come in alphabetical order below.
818d52ea6dSThomas Chou 
828d52ea6dSThomas Chou    Please add support for more CPUs here, or improve the current support
838d52ea6dSThomas Chou    for the CPUs below!
848d52ea6dSThomas Chou    (E.g. WE32100, IBM360.)  */
858d52ea6dSThomas Chou 
868d52ea6dSThomas Chou /* Snipped per CPU support */
878d52ea6dSThomas Chou 
888d52ea6dSThomas Chou /* If this machine has no inline assembler, use C macros.  */
898d52ea6dSThomas Chou 
908d52ea6dSThomas Chou #if !defined (add_ssaaaa)
918d52ea6dSThomas Chou #define add_ssaaaa(sh, sl, ah, al, bh, bl) \
928d52ea6dSThomas Chou   do {									\
938d52ea6dSThomas Chou     UWtype __x;								\
948d52ea6dSThomas Chou     __x = (al) + (bl);							\
958d52ea6dSThomas Chou     (sh) = (ah) + (bh) + (__x < (al));					\
968d52ea6dSThomas Chou     (sl) = __x;								\
978d52ea6dSThomas Chou   } while (0)
988d52ea6dSThomas Chou #endif
998d52ea6dSThomas Chou 
1008d52ea6dSThomas Chou #if !defined (sub_ddmmss)
1018d52ea6dSThomas Chou #define sub_ddmmss(sh, sl, ah, al, bh, bl) \
1028d52ea6dSThomas Chou   do {									\
1038d52ea6dSThomas Chou     UWtype __x;								\
1048d52ea6dSThomas Chou     __x = (al) - (bl);							\
1058d52ea6dSThomas Chou     (sh) = (ah) - (bh) - (__x > (al));					\
1068d52ea6dSThomas Chou     (sl) = __x;								\
1078d52ea6dSThomas Chou   } while (0)
1088d52ea6dSThomas Chou #endif
1098d52ea6dSThomas Chou 
1108d52ea6dSThomas Chou /* If we lack umul_ppmm but have smul_ppmm, define umul_ppmm in terms of
1118d52ea6dSThomas Chou    smul_ppmm.  */
1128d52ea6dSThomas Chou #if !defined (umul_ppmm) && defined (smul_ppmm)
1138d52ea6dSThomas Chou #define umul_ppmm(w1, w0, u, v)						\
1148d52ea6dSThomas Chou   do {									\
1158d52ea6dSThomas Chou     UWtype __w1;							\
1168d52ea6dSThomas Chou     UWtype __xm0 = (u), __xm1 = (v);					\
1178d52ea6dSThomas Chou     smul_ppmm (__w1, w0, __xm0, __xm1);					\
1188d52ea6dSThomas Chou     (w1) = __w1 + (-(__xm0 >> (W_TYPE_SIZE - 1)) & __xm1)		\
1198d52ea6dSThomas Chou 		+ (-(__xm1 >> (W_TYPE_SIZE - 1)) & __xm0);		\
1208d52ea6dSThomas Chou   } while (0)
1218d52ea6dSThomas Chou #endif
1228d52ea6dSThomas Chou 
1238d52ea6dSThomas Chou /* If we still don't have umul_ppmm, define it using plain C.  */
1248d52ea6dSThomas Chou #if !defined (umul_ppmm)
1258d52ea6dSThomas Chou #define umul_ppmm(w1, w0, u, v)						\
1268d52ea6dSThomas Chou   do {									\
1278d52ea6dSThomas Chou     UWtype __x0, __x1, __x2, __x3;					\
1288d52ea6dSThomas Chou     UHWtype __ul, __vl, __uh, __vh;					\
1298d52ea6dSThomas Chou 									\
1308d52ea6dSThomas Chou     __ul = __ll_lowpart (u);						\
1318d52ea6dSThomas Chou     __uh = __ll_highpart (u);						\
1328d52ea6dSThomas Chou     __vl = __ll_lowpart (v);						\
1338d52ea6dSThomas Chou     __vh = __ll_highpart (v);						\
1348d52ea6dSThomas Chou 									\
1358d52ea6dSThomas Chou     __x0 = (UWtype) __ul * __vl;					\
1368d52ea6dSThomas Chou     __x1 = (UWtype) __ul * __vh;					\
1378d52ea6dSThomas Chou     __x2 = (UWtype) __uh * __vl;					\
1388d52ea6dSThomas Chou     __x3 = (UWtype) __uh * __vh;					\
1398d52ea6dSThomas Chou 									\
1408d52ea6dSThomas Chou     __x1 += __ll_highpart (__x0);/* this can't give carry */		\
1418d52ea6dSThomas Chou     __x1 += __x2;		/* but this indeed can */		\
1428d52ea6dSThomas Chou     if (__x1 < __x2)		/* did we get it? */			\
1438d52ea6dSThomas Chou       __x3 += __ll_B;		/* yes, add it in the proper pos.  */	\
1448d52ea6dSThomas Chou 									\
1458d52ea6dSThomas Chou     (w1) = __x3 + __ll_highpart (__x1);					\
1468d52ea6dSThomas Chou     (w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0);		\
1478d52ea6dSThomas Chou   } while (0)
1488d52ea6dSThomas Chou #endif
1498d52ea6dSThomas Chou 
1508d52ea6dSThomas Chou #if !defined (__umulsidi3)
1518d52ea6dSThomas Chou #define __umulsidi3(u, v) \
1528d52ea6dSThomas Chou   ({DWunion __w;							\
1538d52ea6dSThomas Chou     umul_ppmm (__w.s.high, __w.s.low, u, v);				\
1548d52ea6dSThomas Chou     __w.ll; })
1558d52ea6dSThomas Chou #endif
1568d52ea6dSThomas Chou 
1578d52ea6dSThomas Chou /* Define this unconditionally, so it can be used for debugging.  */
1588d52ea6dSThomas Chou #define __udiv_qrnnd_c(q, r, n1, n0, d) \
1598d52ea6dSThomas Chou   do {									\
1608d52ea6dSThomas Chou     UWtype __d1, __d0, __q1, __q0;					\
1618d52ea6dSThomas Chou     UWtype __r1, __r0, __m;						\
1628d52ea6dSThomas Chou     __d1 = __ll_highpart (d);						\
1638d52ea6dSThomas Chou     __d0 = __ll_lowpart (d);						\
1648d52ea6dSThomas Chou 									\
1658d52ea6dSThomas Chou     __r1 = (n1) % __d1;							\
1668d52ea6dSThomas Chou     __q1 = (n1) / __d1;							\
1678d52ea6dSThomas Chou     __m = (UWtype) __q1 * __d0;						\
1688d52ea6dSThomas Chou     __r1 = __r1 * __ll_B | __ll_highpart (n0);				\
1698d52ea6dSThomas Chou     if (__r1 < __m)							\
1708d52ea6dSThomas Chou       {									\
1718d52ea6dSThomas Chou 	__q1--, __r1 += (d);						\
1728d52ea6dSThomas Chou 	if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\
1738d52ea6dSThomas Chou 	  if (__r1 < __m)						\
1748d52ea6dSThomas Chou 	    __q1--, __r1 += (d);					\
1758d52ea6dSThomas Chou       }									\
1768d52ea6dSThomas Chou     __r1 -= __m;							\
1778d52ea6dSThomas Chou 									\
1788d52ea6dSThomas Chou     __r0 = __r1 % __d1;							\
1798d52ea6dSThomas Chou     __q0 = __r1 / __d1;							\
1808d52ea6dSThomas Chou     __m = (UWtype) __q0 * __d0;						\
1818d52ea6dSThomas Chou     __r0 = __r0 * __ll_B | __ll_lowpart (n0);				\
1828d52ea6dSThomas Chou     if (__r0 < __m)							\
1838d52ea6dSThomas Chou       {									\
1848d52ea6dSThomas Chou 	__q0--, __r0 += (d);						\
1858d52ea6dSThomas Chou 	if (__r0 >= (d))						\
1868d52ea6dSThomas Chou 	  if (__r0 < __m)						\
1878d52ea6dSThomas Chou 	    __q0--, __r0 += (d);					\
1888d52ea6dSThomas Chou       }									\
1898d52ea6dSThomas Chou     __r0 -= __m;							\
1908d52ea6dSThomas Chou 									\
1918d52ea6dSThomas Chou     (q) = (UWtype) __q1 * __ll_B | __q0;				\
1928d52ea6dSThomas Chou     (r) = __r0;								\
1938d52ea6dSThomas Chou   } while (0)
1948d52ea6dSThomas Chou 
1958d52ea6dSThomas Chou /* If the processor has no udiv_qrnnd but sdiv_qrnnd, go through
1968d52ea6dSThomas Chou    __udiv_w_sdiv (defined in libgcc or elsewhere).  */
1978d52ea6dSThomas Chou #if !defined (udiv_qrnnd) && defined (sdiv_qrnnd)
1988d52ea6dSThomas Chou #define udiv_qrnnd(q, r, nh, nl, d) \
1998d52ea6dSThomas Chou   do {									\
2008d52ea6dSThomas Chou     USItype __r;							\
2018d52ea6dSThomas Chou     (q) = __udiv_w_sdiv (&__r, nh, nl, d);				\
2028d52ea6dSThomas Chou     (r) = __r;								\
2038d52ea6dSThomas Chou   } while (0)
2048d52ea6dSThomas Chou #endif
2058d52ea6dSThomas Chou 
2068d52ea6dSThomas Chou /* If udiv_qrnnd was not defined for this processor, use __udiv_qrnnd_c.  */
2078d52ea6dSThomas Chou #if !defined (udiv_qrnnd)
2088d52ea6dSThomas Chou #define UDIV_NEEDS_NORMALIZATION 1
2098d52ea6dSThomas Chou #define udiv_qrnnd __udiv_qrnnd_c
2108d52ea6dSThomas Chou #endif
2118d52ea6dSThomas Chou 
2128d52ea6dSThomas Chou #if !defined (count_leading_zeros)
2138d52ea6dSThomas Chou #define count_leading_zeros(count, x) \
2148d52ea6dSThomas Chou   do {									\
2158d52ea6dSThomas Chou     UWtype __xr = (x);							\
2168d52ea6dSThomas Chou     UWtype __a;								\
2178d52ea6dSThomas Chou 									\
2188d52ea6dSThomas Chou     if (W_TYPE_SIZE <= 32)						\
2198d52ea6dSThomas Chou       {									\
2208d52ea6dSThomas Chou 	__a = __xr < ((UWtype)1<<2*__BITS4)				\
2218d52ea6dSThomas Chou 	  ? (__xr < ((UWtype)1<<__BITS4) ? 0 : __BITS4)			\
2228d52ea6dSThomas Chou 	  : (__xr < ((UWtype)1<<3*__BITS4) ?  2*__BITS4 : 3*__BITS4);	\
2238d52ea6dSThomas Chou       }									\
2248d52ea6dSThomas Chou     else								\
2258d52ea6dSThomas Chou       {									\
2268d52ea6dSThomas Chou 	for (__a = W_TYPE_SIZE - 8; __a > 0; __a -= 8)			\
2278d52ea6dSThomas Chou 	  if (((__xr >> __a) & 0xff) != 0)				\
2288d52ea6dSThomas Chou 	    break;							\
2298d52ea6dSThomas Chou       }									\
2308d52ea6dSThomas Chou 									\
2318d52ea6dSThomas Chou     (count) = W_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a);		\
2328d52ea6dSThomas Chou   } while (0)
2338d52ea6dSThomas Chou #define COUNT_LEADING_ZEROS_0 W_TYPE_SIZE
2348d52ea6dSThomas Chou #endif
2358d52ea6dSThomas Chou 
2368d52ea6dSThomas Chou #if !defined (count_trailing_zeros)
2378d52ea6dSThomas Chou /* Define count_trailing_zeros using count_leading_zeros.  The latter might be
2388d52ea6dSThomas Chou    defined in asm, but if it is not, the C version above is good enough.  */
2398d52ea6dSThomas Chou #define count_trailing_zeros(count, x) \
2408d52ea6dSThomas Chou   do {									\
2418d52ea6dSThomas Chou     UWtype __ctz_x = (x);						\
2428d52ea6dSThomas Chou     UWtype __ctz_c;							\
2438d52ea6dSThomas Chou     count_leading_zeros (__ctz_c, __ctz_x & -__ctz_x);			\
2448d52ea6dSThomas Chou     (count) = W_TYPE_SIZE - 1 - __ctz_c;				\
2458d52ea6dSThomas Chou   } while (0)
2468d52ea6dSThomas Chou #endif
2478d52ea6dSThomas Chou 
2488d52ea6dSThomas Chou #ifndef UDIV_NEEDS_NORMALIZATION
2498d52ea6dSThomas Chou #define UDIV_NEEDS_NORMALIZATION 0
2508d52ea6dSThomas Chou #endif
251