xref: /openbsd-src/sys/arch/hppa/spmath/sfdiv.c (revision c2feb25228e11b3c285a2d9400475896f2dd1562)
1*c2feb252Smickey /*	$OpenBSD: sfdiv.c,v 1.5 2002/05/07 22:19:30 mickey Exp $	*/
2*c2feb252Smickey /*
3*c2feb252Smickey   (c) Copyright 1986 HEWLETT-PACKARD COMPANY
4*c2feb252Smickey   To anyone who acknowledges that this file is provided "AS IS"
5*c2feb252Smickey   without any express or implied warranty:
6*c2feb252Smickey       permission to use, copy, modify, and distribute this file
7*c2feb252Smickey   for any purpose is hereby granted without fee, provided that
8*c2feb252Smickey   the above copyright notice and this notice appears in all
9*c2feb252Smickey   copies, and that the name of Hewlett-Packard Company not be
10*c2feb252Smickey   used in advertising or publicity pertaining to distribution
11*c2feb252Smickey   of the software without specific, written prior permission.
12*c2feb252Smickey   Hewlett-Packard Company makes no representations about the
13*c2feb252Smickey   suitability of this software for any purpose.
14*c2feb252Smickey */
15*c2feb252Smickey /* @(#)sfdiv.c: Revision: 2.9.88.1 Date: 93/12/07 15:07:05 */
16b94afd46Smickey 
17*c2feb252Smickey #include "float.h"
18*c2feb252Smickey #include "sgl_float.h"
198a472b3eSmickey 
208a472b3eSmickey /*
218a472b3eSmickey  *  Single Precision Floating-point Divide
228a472b3eSmickey  */
23b94afd46Smickey int
sgl_fdiv(srcptr1,srcptr2,dstptr,status)248a472b3eSmickey sgl_fdiv(srcptr1,srcptr2,dstptr,status)
258a472b3eSmickey 	sgl_floating_point *srcptr1, *srcptr2, *dstptr;
268a472b3eSmickey 	unsigned int *status;
278a472b3eSmickey {
288a472b3eSmickey 	register unsigned int opnd1, opnd2, opnd3, result;
298a472b3eSmickey 	register int dest_exponent, count;
30628bbdd4Smickey 	register int inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
31628bbdd4Smickey 	int is_tiny;
328a472b3eSmickey 
338a472b3eSmickey 	opnd1 = *srcptr1;
348a472b3eSmickey 	opnd2 = *srcptr2;
358a472b3eSmickey 	/*
368a472b3eSmickey 	 * set sign bit of result
378a472b3eSmickey 	 */
388a472b3eSmickey 	if (Sgl_sign(opnd1) ^ Sgl_sign(opnd2)) Sgl_setnegativezero(result);
398a472b3eSmickey 	else Sgl_setzero(result);
408a472b3eSmickey 	/*
418a472b3eSmickey 	 * check first operand for NaN's or infinity
428a472b3eSmickey 	 */
438a472b3eSmickey 	if (Sgl_isinfinity_exponent(opnd1)) {
448a472b3eSmickey 		if (Sgl_iszero_mantissa(opnd1)) {
458a472b3eSmickey 			if (Sgl_isnotnan(opnd2)) {
468a472b3eSmickey 				if (Sgl_isinfinity(opnd2)) {
478a472b3eSmickey 					/*
488a472b3eSmickey 					 * invalid since both operands
498a472b3eSmickey 					 * are infinity
508a472b3eSmickey 					 */
518a472b3eSmickey 					if (Is_invalidtrap_enabled())
528a472b3eSmickey 						return(INVALIDEXCEPTION);
538a472b3eSmickey 					Set_invalidflag();
548a472b3eSmickey 					Sgl_makequietnan(result);
558a472b3eSmickey 					*dstptr = result;
568a472b3eSmickey 					return(NOEXCEPTION);
578a472b3eSmickey 				}
588a472b3eSmickey 				/*
598a472b3eSmickey 				 * return infinity
608a472b3eSmickey 				 */
618a472b3eSmickey 				Sgl_setinfinity_exponentmantissa(result);
628a472b3eSmickey 				*dstptr = result;
638a472b3eSmickey 				return(NOEXCEPTION);
648a472b3eSmickey 			}
658a472b3eSmickey 		}
668a472b3eSmickey 		else {
678a472b3eSmickey 			/*
688a472b3eSmickey 			 * is NaN; signaling or quiet?
698a472b3eSmickey 			 */
708a472b3eSmickey 			if (Sgl_isone_signaling(opnd1)) {
718a472b3eSmickey 				/* trap if INVALIDTRAP enabled */
728a472b3eSmickey 				if (Is_invalidtrap_enabled())
738a472b3eSmickey 					return(INVALIDEXCEPTION);
748a472b3eSmickey 				/* make NaN quiet */
758a472b3eSmickey 				Set_invalidflag();
768a472b3eSmickey 				Sgl_set_quiet(opnd1);
778a472b3eSmickey 			}
788a472b3eSmickey 			/*
798a472b3eSmickey 			 * is second operand a signaling NaN?
808a472b3eSmickey 			 */
818a472b3eSmickey 			else if (Sgl_is_signalingnan(opnd2)) {
828a472b3eSmickey 				/* trap if INVALIDTRAP enabled */
838a472b3eSmickey 				if (Is_invalidtrap_enabled())
848a472b3eSmickey 					return(INVALIDEXCEPTION);
858a472b3eSmickey 				/* make NaN quiet */
868a472b3eSmickey 				Set_invalidflag();
878a472b3eSmickey 				Sgl_set_quiet(opnd2);
888a472b3eSmickey 				*dstptr = opnd2;
898a472b3eSmickey 				return(NOEXCEPTION);
908a472b3eSmickey 			}
918a472b3eSmickey 			/*
928a472b3eSmickey 			 * return quiet NaN
938a472b3eSmickey 			 */
948a472b3eSmickey 			*dstptr = opnd1;
958a472b3eSmickey 			return(NOEXCEPTION);
968a472b3eSmickey 		}
978a472b3eSmickey 	}
988a472b3eSmickey 	/*
998a472b3eSmickey 	 * check second operand for NaN's or infinity
1008a472b3eSmickey 	 */
1018a472b3eSmickey 	if (Sgl_isinfinity_exponent(opnd2)) {
1028a472b3eSmickey 		if (Sgl_iszero_mantissa(opnd2)) {
1038a472b3eSmickey 			/*
1048a472b3eSmickey 			 * return zero
1058a472b3eSmickey 			 */
1068a472b3eSmickey 			Sgl_setzero_exponentmantissa(result);
1078a472b3eSmickey 			*dstptr = result;
1088a472b3eSmickey 			return(NOEXCEPTION);
1098a472b3eSmickey 		}
1108a472b3eSmickey 		/*
1118a472b3eSmickey 		 * is NaN; signaling or quiet?
1128a472b3eSmickey 		 */
1138a472b3eSmickey 		if (Sgl_isone_signaling(opnd2)) {
1148a472b3eSmickey 			/* trap if INVALIDTRAP enabled */
1158a472b3eSmickey 			if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
1168a472b3eSmickey 			/* make NaN quiet */
1178a472b3eSmickey 			Set_invalidflag();
1188a472b3eSmickey 			Sgl_set_quiet(opnd2);
1198a472b3eSmickey 		}
1208a472b3eSmickey 		/*
1218a472b3eSmickey 		 * return quiet NaN
1228a472b3eSmickey 		 */
1238a472b3eSmickey 		*dstptr = opnd2;
1248a472b3eSmickey 		return(NOEXCEPTION);
1258a472b3eSmickey 	}
1268a472b3eSmickey 	/*
1278a472b3eSmickey 	 * check for division by zero
1288a472b3eSmickey 	 */
1298a472b3eSmickey 	if (Sgl_iszero_exponentmantissa(opnd2)) {
1308a472b3eSmickey 		if (Sgl_iszero_exponentmantissa(opnd1)) {
1318a472b3eSmickey 			/* invalid since both operands are zero */
1328a472b3eSmickey 			if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
1338a472b3eSmickey 			Set_invalidflag();
1348a472b3eSmickey 			Sgl_makequietnan(result);
1358a472b3eSmickey 			*dstptr = result;
1368a472b3eSmickey 			return(NOEXCEPTION);
1378a472b3eSmickey 		}
1388a472b3eSmickey 		if (Is_divisionbyzerotrap_enabled())
1398a472b3eSmickey 			return(DIVISIONBYZEROEXCEPTION);
1408a472b3eSmickey 		Set_divisionbyzeroflag();
1418a472b3eSmickey 		Sgl_setinfinity_exponentmantissa(result);
1428a472b3eSmickey 		*dstptr = result;
1438a472b3eSmickey 		return(NOEXCEPTION);
1448a472b3eSmickey 	}
1458a472b3eSmickey 	/*
1468a472b3eSmickey 	 * Generate exponent
1478a472b3eSmickey 	 */
1488a472b3eSmickey 	dest_exponent = Sgl_exponent(opnd1) - Sgl_exponent(opnd2) + SGL_BIAS;
1498a472b3eSmickey 
1508a472b3eSmickey 	/*
1518a472b3eSmickey 	 * Generate mantissa
1528a472b3eSmickey 	 */
1538a472b3eSmickey 	if (Sgl_isnotzero_exponent(opnd1)) {
1548a472b3eSmickey 		/* set hidden bit */
1558a472b3eSmickey 		Sgl_clear_signexponent_set_hidden(opnd1);
1568a472b3eSmickey 	}
1578a472b3eSmickey 	else {
1588a472b3eSmickey 		/* check for zero */
1598a472b3eSmickey 		if (Sgl_iszero_mantissa(opnd1)) {
1608a472b3eSmickey 			Sgl_setzero_exponentmantissa(result);
1618a472b3eSmickey 			*dstptr = result;
1628a472b3eSmickey 			return(NOEXCEPTION);
1638a472b3eSmickey 		}
1648a472b3eSmickey 		/* is denormalized; want to normalize */
1658a472b3eSmickey 		Sgl_clear_signexponent(opnd1);
1668a472b3eSmickey 		Sgl_leftshiftby1(opnd1);
1678a472b3eSmickey 		Sgl_normalize(opnd1,dest_exponent);
1688a472b3eSmickey 	}
1698a472b3eSmickey 	/* opnd2 needs to have hidden bit set with msb in hidden bit */
1708a472b3eSmickey 	if (Sgl_isnotzero_exponent(opnd2)) {
1718a472b3eSmickey 		Sgl_clear_signexponent_set_hidden(opnd2);
1728a472b3eSmickey 	}
1738a472b3eSmickey 	else {
1748a472b3eSmickey 		/* is denormalized; want to normalize */
1758a472b3eSmickey 		Sgl_clear_signexponent(opnd2);
1768a472b3eSmickey 		Sgl_leftshiftby1(opnd2);
1778a472b3eSmickey 		while(Sgl_iszero_hiddenhigh7mantissa(opnd2)) {
1788a472b3eSmickey 			Sgl_leftshiftby8(opnd2);
1798a472b3eSmickey 			dest_exponent += 8;
1808a472b3eSmickey 		}
1818a472b3eSmickey 		if(Sgl_iszero_hiddenhigh3mantissa(opnd2)) {
1828a472b3eSmickey 			Sgl_leftshiftby4(opnd2);
1838a472b3eSmickey 			dest_exponent += 4;
1848a472b3eSmickey 		}
1858a472b3eSmickey 		while(Sgl_iszero_hidden(opnd2)) {
1868a472b3eSmickey 			Sgl_leftshiftby1(opnd2);
1878a472b3eSmickey 			dest_exponent += 1;
1888a472b3eSmickey 		}
1898a472b3eSmickey 	}
1908a472b3eSmickey 
1918a472b3eSmickey 	/* Divide the source mantissas */
1928a472b3eSmickey 
1938a472b3eSmickey 	/*
1948a472b3eSmickey 	 * A non_restoring divide algorithm is used.
1958a472b3eSmickey 	 */
1968a472b3eSmickey 	Sgl_subtract(opnd1,opnd2,opnd1);
1978a472b3eSmickey 	Sgl_setzero(opnd3);
1988a472b3eSmickey 	for (count=1;count<=SGL_P && Sgl_all(opnd1);count++) {
1998a472b3eSmickey 		Sgl_leftshiftby1(opnd1);
2008a472b3eSmickey 		Sgl_leftshiftby1(opnd3);
2018a472b3eSmickey 		if (Sgl_iszero_sign(opnd1)) {
2028a472b3eSmickey 			Sgl_setone_lowmantissa(opnd3);
2038a472b3eSmickey 			Sgl_subtract(opnd1,opnd2,opnd1);
2048a472b3eSmickey 		}
2058a472b3eSmickey 		else Sgl_addition(opnd1,opnd2,opnd1);
2068a472b3eSmickey 	}
2078a472b3eSmickey 	if (count <= SGL_P) {
2088a472b3eSmickey 		Sgl_leftshiftby1(opnd3);
2098a472b3eSmickey 		Sgl_setone_lowmantissa(opnd3);
2108a472b3eSmickey 		Sgl_leftshift(opnd3,SGL_P-count);
2118a472b3eSmickey 		if (Sgl_iszero_hidden(opnd3)) {
2128a472b3eSmickey 			Sgl_leftshiftby1(opnd3);
2138a472b3eSmickey 			dest_exponent--;
2148a472b3eSmickey 		}
2158a472b3eSmickey 	}
2168a472b3eSmickey 	else {
2178a472b3eSmickey 		if (Sgl_iszero_hidden(opnd3)) {
2188a472b3eSmickey 			/* need to get one more bit of result */
2198a472b3eSmickey 			Sgl_leftshiftby1(opnd1);
2208a472b3eSmickey 			Sgl_leftshiftby1(opnd3);
2218a472b3eSmickey 			if (Sgl_iszero_sign(opnd1)) {
2228a472b3eSmickey 				Sgl_setone_lowmantissa(opnd3);
2238a472b3eSmickey 				Sgl_subtract(opnd1,opnd2,opnd1);
2248a472b3eSmickey 			}
2258a472b3eSmickey 			else Sgl_addition(opnd1,opnd2,opnd1);
2268a472b3eSmickey 			dest_exponent--;
2278a472b3eSmickey 		}
2288a472b3eSmickey 		if (Sgl_iszero_sign(opnd1)) guardbit = TRUE;
2298a472b3eSmickey 		stickybit = Sgl_all(opnd1);
2308a472b3eSmickey 	}
2318a472b3eSmickey 	inexact = guardbit | stickybit;
2328a472b3eSmickey 
2338a472b3eSmickey 	/*
2348a472b3eSmickey 	 * round result
2358a472b3eSmickey 	 */
2368a472b3eSmickey 	if (inexact && (dest_exponent > 0 || Is_underflowtrap_enabled())) {
2378a472b3eSmickey 		Sgl_clear_signexponent(opnd3);
2388a472b3eSmickey 		switch (Rounding_mode()) {
2398a472b3eSmickey 			case ROUNDPLUS:
2408a472b3eSmickey 				if (Sgl_iszero_sign(result))
2418a472b3eSmickey 					Sgl_increment_mantissa(opnd3);
2428a472b3eSmickey 				break;
2438a472b3eSmickey 			case ROUNDMINUS:
2448a472b3eSmickey 				if (Sgl_isone_sign(result))
2458a472b3eSmickey 					Sgl_increment_mantissa(opnd3);
2468a472b3eSmickey 				break;
2478a472b3eSmickey 			case ROUNDNEAREST:
248628bbdd4Smickey 				if (guardbit &&
249628bbdd4Smickey 				    (stickybit || Sgl_isone_lowmantissa(opnd3)))
2508a472b3eSmickey 					Sgl_increment_mantissa(opnd3);
2518a472b3eSmickey 		}
2528a472b3eSmickey 		if (Sgl_isone_hidden(opnd3)) dest_exponent++;
2538a472b3eSmickey 	}
2548a472b3eSmickey 	Sgl_set_mantissa(result,opnd3);
2558a472b3eSmickey 
2568a472b3eSmickey 	/*
2578a472b3eSmickey 	 * Test for overflow
2588a472b3eSmickey 	 */
2598a472b3eSmickey 	if (dest_exponent >= SGL_INFINITY_EXPONENT) {
2608a472b3eSmickey 		/* trap if OVERFLOWTRAP enabled */
2618a472b3eSmickey 		if (Is_overflowtrap_enabled()) {
2628a472b3eSmickey 			/*
2638a472b3eSmickey 			 * Adjust bias of result
2648a472b3eSmickey 			 */
2658a472b3eSmickey 			Sgl_setwrapped_exponent(result,dest_exponent,ovfl);
2668a472b3eSmickey 			*dstptr = result;
267b94afd46Smickey 			if (inexact) {
2688a472b3eSmickey 			    if (Is_inexacttrap_enabled())
2698a472b3eSmickey 				return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
2708a472b3eSmickey 			    else Set_inexactflag();
271b94afd46Smickey 			}
2728a472b3eSmickey 			return(OVERFLOWEXCEPTION);
2738a472b3eSmickey 		}
2748a472b3eSmickey 		Set_overflowflag();
2758a472b3eSmickey 		/* set result to infinity or largest number */
2768a472b3eSmickey 		Sgl_setoverflow(result);
2778a472b3eSmickey 		inexact = TRUE;
2788a472b3eSmickey 	}
2798a472b3eSmickey 	/*
2808a472b3eSmickey 	 * Test for underflow
2818a472b3eSmickey 	 */
2828a472b3eSmickey 	else if (dest_exponent <= 0) {
2838a472b3eSmickey 		/* trap if UNDERFLOWTRAP enabled */
2848a472b3eSmickey 		if (Is_underflowtrap_enabled()) {
2858a472b3eSmickey 			/*
2868a472b3eSmickey 			 * Adjust bias of result
2878a472b3eSmickey 			 */
2888a472b3eSmickey 			Sgl_setwrapped_exponent(result,dest_exponent,unfl);
2898a472b3eSmickey 			*dstptr = result;
290b94afd46Smickey 			if (inexact) {
2918a472b3eSmickey 			    if (Is_inexacttrap_enabled())
2928a472b3eSmickey 				return(UNDERFLOWEXCEPTION | INEXACTEXCEPTION);
2938a472b3eSmickey 			    else Set_inexactflag();
294b94afd46Smickey 			}
2958a472b3eSmickey 			return(UNDERFLOWEXCEPTION);
2968a472b3eSmickey 		}
2978a472b3eSmickey 
2988a472b3eSmickey 		/* Determine if should set underflow flag */
2998a472b3eSmickey 		is_tiny = TRUE;
3008a472b3eSmickey 		if (dest_exponent == 0 && inexact) {
3018a472b3eSmickey 			switch (Rounding_mode()) {
3028a472b3eSmickey 			case ROUNDPLUS:
3038a472b3eSmickey 				if (Sgl_iszero_sign(result)) {
3048a472b3eSmickey 					Sgl_increment(opnd3);
3058a472b3eSmickey 					if (Sgl_isone_hiddenoverflow(opnd3))
3068a472b3eSmickey 						is_tiny = FALSE;
3078a472b3eSmickey 					Sgl_decrement(opnd3);
3088a472b3eSmickey 				}
3098a472b3eSmickey 				break;
3108a472b3eSmickey 			case ROUNDMINUS:
3118a472b3eSmickey 				if (Sgl_isone_sign(result)) {
3128a472b3eSmickey 					Sgl_increment(opnd3);
3138a472b3eSmickey 					if (Sgl_isone_hiddenoverflow(opnd3))
3148a472b3eSmickey 						is_tiny = FALSE;
3158a472b3eSmickey 					Sgl_decrement(opnd3);
3168a472b3eSmickey 				}
3178a472b3eSmickey 				break;
3188a472b3eSmickey 			case ROUNDNEAREST:
3198a472b3eSmickey 				if (guardbit && (stickybit ||
3208a472b3eSmickey 				    Sgl_isone_lowmantissa(opnd3))) {
3218a472b3eSmickey 					Sgl_increment(opnd3);
3228a472b3eSmickey 					if (Sgl_isone_hiddenoverflow(opnd3))
3238a472b3eSmickey 						is_tiny = FALSE;
3248a472b3eSmickey 					Sgl_decrement(opnd3);
3258a472b3eSmickey 				}
3268a472b3eSmickey 				break;
3278a472b3eSmickey 			}
3288a472b3eSmickey 		}
3298a472b3eSmickey 
3308a472b3eSmickey 		/*
3318a472b3eSmickey 		 * denormalize result or set to signed zero
3328a472b3eSmickey 		 */
3338a472b3eSmickey 		stickybit = inexact;
3348a472b3eSmickey 		Sgl_denormalize(opnd3,dest_exponent,guardbit,stickybit,inexact);
3358a472b3eSmickey 
3368a472b3eSmickey 		/* return rounded number */
3378a472b3eSmickey 		if (inexact) {
3388a472b3eSmickey 			switch (Rounding_mode()) {
3398a472b3eSmickey 			case ROUNDPLUS:
3408a472b3eSmickey 				if (Sgl_iszero_sign(result)) {
3418a472b3eSmickey 					Sgl_increment(opnd3);
3428a472b3eSmickey 				}
3438a472b3eSmickey 				break;
3448a472b3eSmickey 			case ROUNDMINUS:
3458a472b3eSmickey 				if (Sgl_isone_sign(result))  {
3468a472b3eSmickey 					Sgl_increment(opnd3);
3478a472b3eSmickey 				}
3488a472b3eSmickey 				break;
3498a472b3eSmickey 			case ROUNDNEAREST:
3508a472b3eSmickey 				if (guardbit && (stickybit ||
3518a472b3eSmickey 				    Sgl_isone_lowmantissa(opnd3))) {
3528a472b3eSmickey 					Sgl_increment(opnd3);
3538a472b3eSmickey 				}
3548a472b3eSmickey 				break;
3558a472b3eSmickey 			}
3568a472b3eSmickey 			if (is_tiny) Set_underflowflag();
3578a472b3eSmickey 		}
3588a472b3eSmickey 		Sgl_set_exponentmantissa(result,opnd3);
3598a472b3eSmickey 	}
3608a472b3eSmickey 	else Sgl_set_exponent(result,dest_exponent);
3618a472b3eSmickey 	*dstptr = result;
3628a472b3eSmickey 	/* check for inexact */
3638a472b3eSmickey 	if (inexact) {
3648a472b3eSmickey 		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
3658a472b3eSmickey 		else  Set_inexactflag();
3668a472b3eSmickey 	}
3678a472b3eSmickey 	return(NOEXCEPTION);
3688a472b3eSmickey }
369