xref: /linux/arch/parisc/math-emu/sfdiv.c (revision ca55b2fef3a9373fcfc30f82fd26bc7fccbda732)
1 /*
2  * Linux/PA-RISC Project (http://www.parisc-linux.org/)
3  *
4  * Floating-point emulation code
5  *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
6  *
7  *    This program is free software; you can redistribute it and/or modify
8  *    it under the terms of the GNU General Public License as published by
9  *    the Free Software Foundation; either version 2, or (at your option)
10  *    any later version.
11  *
12  *    This program is distributed in the hope that it will be useful,
13  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *    GNU General Public License for more details.
16  *
17  *    You should have received a copy of the GNU General Public License
18  *    along with this program; if not, write to the Free Software
19  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 /*
22  * BEGIN_DESC
23  *
24  *  File:
25  *	@(#)	pa/spmath/sfdiv.c		$Revision: 1.1 $
26  *
27  *  Purpose:
28  *	Single Precision Floating-point Divide
29  *
30  *  External Interfaces:
31  *	sgl_fdiv(srcptr1,srcptr2,dstptr,status)
32  *
33  *  Internal Interfaces:
34  *
35  *  Theory:
36  *	<<please update with a overview of the operation of this file>>
37  *
38  * END_DESC
39 */
40 
41 
42 #include "float.h"
43 #include "sgl_float.h"
44 
45 /*
46  *  Single Precision Floating-point Divide
47  */
48 
49 int
50 sgl_fdiv (sgl_floating_point * srcptr1, sgl_floating_point * srcptr2,
51 	  sgl_floating_point * dstptr, unsigned int *status)
52 {
53 	register unsigned int opnd1, opnd2, opnd3, result;
54 	register int dest_exponent, count;
55 	register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
56 	boolean is_tiny;
57 
58 	opnd1 = *srcptr1;
59 	opnd2 = *srcptr2;
60 	/*
61 	 * set sign bit of result
62 	 */
63 	if (Sgl_sign(opnd1) ^ Sgl_sign(opnd2)) Sgl_setnegativezero(result);
64 	else Sgl_setzero(result);
65 	/*
66 	 * check first operand for NaN's or infinity
67 	 */
68 	if (Sgl_isinfinity_exponent(opnd1)) {
69 		if (Sgl_iszero_mantissa(opnd1)) {
70 			if (Sgl_isnotnan(opnd2)) {
71 				if (Sgl_isinfinity(opnd2)) {
72 					/*
73 					 * invalid since both operands
74 					 * are infinity
75 					 */
76 					if (Is_invalidtrap_enabled())
77                                 		return(INVALIDEXCEPTION);
78                                 	Set_invalidflag();
79                                 	Sgl_makequietnan(result);
80 					*dstptr = result;
81 					return(NOEXCEPTION);
82 				}
83 				/*
84 			 	 * return infinity
85 			 	 */
86 				Sgl_setinfinity_exponentmantissa(result);
87 				*dstptr = result;
88 				return(NOEXCEPTION);
89 			}
90 		}
91 		else {
92                 	/*
93                  	 * is NaN; signaling or quiet?
94                  	 */
95                 	if (Sgl_isone_signaling(opnd1)) {
96                         	/* trap if INVALIDTRAP enabled */
97                         	if (Is_invalidtrap_enabled())
98                             		return(INVALIDEXCEPTION);
99                         	/* make NaN quiet */
100                         	Set_invalidflag();
101                         	Sgl_set_quiet(opnd1);
102                 	}
103 			/*
104 			 * is second operand a signaling NaN?
105 			 */
106 			else if (Sgl_is_signalingnan(opnd2)) {
107                         	/* trap if INVALIDTRAP enabled */
108                         	if (Is_invalidtrap_enabled())
109                             		return(INVALIDEXCEPTION);
110                         	/* make NaN quiet */
111                         	Set_invalidflag();
112                         	Sgl_set_quiet(opnd2);
113                 		*dstptr = opnd2;
114                 		return(NOEXCEPTION);
115 			}
116                 	/*
117                  	 * return quiet NaN
118                  	 */
119                 	*dstptr = opnd1;
120                 	return(NOEXCEPTION);
121 		}
122 	}
123 	/*
124 	 * check second operand for NaN's or infinity
125 	 */
126 	if (Sgl_isinfinity_exponent(opnd2)) {
127 		if (Sgl_iszero_mantissa(opnd2)) {
128 			/*
129 			 * return zero
130 			 */
131 			Sgl_setzero_exponentmantissa(result);
132 			*dstptr = result;
133 			return(NOEXCEPTION);
134 		}
135                 /*
136                  * is NaN; signaling or quiet?
137                  */
138                 if (Sgl_isone_signaling(opnd2)) {
139                         /* trap if INVALIDTRAP enabled */
140                         if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
141                         /* make NaN quiet */
142                         Set_invalidflag();
143                         Sgl_set_quiet(opnd2);
144                 }
145                 /*
146                  * return quiet NaN
147                  */
148                 *dstptr = opnd2;
149                 return(NOEXCEPTION);
150 	}
151 	/*
152 	 * check for division by zero
153 	 */
154 	if (Sgl_iszero_exponentmantissa(opnd2)) {
155 		if (Sgl_iszero_exponentmantissa(opnd1)) {
156 			/* invalid since both operands are zero */
157 			if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
158                         Set_invalidflag();
159                         Sgl_makequietnan(result);
160 			*dstptr = result;
161 			return(NOEXCEPTION);
162 		}
163 		if (Is_divisionbyzerotrap_enabled())
164                         return(DIVISIONBYZEROEXCEPTION);
165                 Set_divisionbyzeroflag();
166                 Sgl_setinfinity_exponentmantissa(result);
167 		*dstptr = result;
168 		return(NOEXCEPTION);
169 	}
170 	/*
171 	 * Generate exponent
172 	 */
173 	dest_exponent = Sgl_exponent(opnd1) - Sgl_exponent(opnd2) + SGL_BIAS;
174 
175 	/*
176 	 * Generate mantissa
177 	 */
178 	if (Sgl_isnotzero_exponent(opnd1)) {
179 		/* set hidden bit */
180 		Sgl_clear_signexponent_set_hidden(opnd1);
181 	}
182 	else {
183 		/* check for zero */
184 		if (Sgl_iszero_mantissa(opnd1)) {
185 			Sgl_setzero_exponentmantissa(result);
186 			*dstptr = result;
187 			return(NOEXCEPTION);
188 		}
189                 /* is denormalized; want to normalize */
190                 Sgl_clear_signexponent(opnd1);
191                 Sgl_leftshiftby1(opnd1);
192 		Sgl_normalize(opnd1,dest_exponent);
193 	}
194 	/* opnd2 needs to have hidden bit set with msb in hidden bit */
195 	if (Sgl_isnotzero_exponent(opnd2)) {
196 		Sgl_clear_signexponent_set_hidden(opnd2);
197 	}
198 	else {
199                 /* is denormalized; want to normalize */
200                 Sgl_clear_signexponent(opnd2);
201                 Sgl_leftshiftby1(opnd2);
202 		while(Sgl_iszero_hiddenhigh7mantissa(opnd2)) {
203 			Sgl_leftshiftby8(opnd2);
204 			dest_exponent += 8;
205 		}
206 		if(Sgl_iszero_hiddenhigh3mantissa(opnd2)) {
207 			Sgl_leftshiftby4(opnd2);
208 			dest_exponent += 4;
209 		}
210 		while(Sgl_iszero_hidden(opnd2)) {
211 			Sgl_leftshiftby1(opnd2);
212 			dest_exponent += 1;
213 		}
214 	}
215 
216 	/* Divide the source mantissas */
217 
218 	/*
219 	 * A non_restoring divide algorithm is used.
220 	 */
221 	Sgl_subtract(opnd1,opnd2,opnd1);
222 	Sgl_setzero(opnd3);
223 	for (count=1;count<=SGL_P && Sgl_all(opnd1);count++) {
224 		Sgl_leftshiftby1(opnd1);
225 		Sgl_leftshiftby1(opnd3);
226 		if (Sgl_iszero_sign(opnd1)) {
227 			Sgl_setone_lowmantissa(opnd3);
228 			Sgl_subtract(opnd1,opnd2,opnd1);
229 		}
230 		else Sgl_addition(opnd1,opnd2,opnd1);
231 	}
232 	if (count <= SGL_P) {
233 		Sgl_leftshiftby1(opnd3);
234 		Sgl_setone_lowmantissa(opnd3);
235 		Sgl_leftshift(opnd3,SGL_P-count);
236 		if (Sgl_iszero_hidden(opnd3)) {
237 			Sgl_leftshiftby1(opnd3);
238 			dest_exponent--;
239 		}
240 	}
241 	else {
242 		if (Sgl_iszero_hidden(opnd3)) {
243 			/* need to get one more bit of result */
244 			Sgl_leftshiftby1(opnd1);
245 			Sgl_leftshiftby1(opnd3);
246 			if (Sgl_iszero_sign(opnd1)) {
247 				Sgl_setone_lowmantissa(opnd3);
248 				Sgl_subtract(opnd1,opnd2,opnd1);
249 			}
250 			else Sgl_addition(opnd1,opnd2,opnd1);
251 			dest_exponent--;
252 		}
253 		if (Sgl_iszero_sign(opnd1)) guardbit = TRUE;
254 		stickybit = Sgl_all(opnd1);
255 	}
256 	inexact = guardbit | stickybit;
257 
258 	/*
259 	 * round result
260 	 */
261 	if (inexact && (dest_exponent > 0 || Is_underflowtrap_enabled())) {
262 		Sgl_clear_signexponent(opnd3);
263 		switch (Rounding_mode()) {
264 			case ROUNDPLUS:
265 				if (Sgl_iszero_sign(result))
266 					Sgl_increment_mantissa(opnd3);
267 				break;
268 			case ROUNDMINUS:
269 				if (Sgl_isone_sign(result))
270 					Sgl_increment_mantissa(opnd3);
271 				break;
272 			case ROUNDNEAREST:
273 				if (guardbit) {
274 			   	if (stickybit || Sgl_isone_lowmantissa(opnd3))
275 			      	    Sgl_increment_mantissa(opnd3);
276 				}
277 		}
278 		if (Sgl_isone_hidden(opnd3)) dest_exponent++;
279 	}
280 	Sgl_set_mantissa(result,opnd3);
281 
282         /*
283          * Test for overflow
284          */
285 	if (dest_exponent >= SGL_INFINITY_EXPONENT) {
286                 /* trap if OVERFLOWTRAP enabled */
287                 if (Is_overflowtrap_enabled()) {
288                         /*
289                          * Adjust bias of result
290                          */
291                         Sgl_setwrapped_exponent(result,dest_exponent,ovfl);
292                         *dstptr = result;
293                         if (inexact)
294                             if (Is_inexacttrap_enabled())
295                                 return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
296                             else Set_inexactflag();
297                         return(OVERFLOWEXCEPTION);
298                 }
299 		Set_overflowflag();
300                 /* set result to infinity or largest number */
301 		Sgl_setoverflow(result);
302 		inexact = TRUE;
303 	}
304         /*
305          * Test for underflow
306          */
307 	else if (dest_exponent <= 0) {
308                 /* trap if UNDERFLOWTRAP enabled */
309                 if (Is_underflowtrap_enabled()) {
310                         /*
311                          * Adjust bias of result
312                          */
313                         Sgl_setwrapped_exponent(result,dest_exponent,unfl);
314                         *dstptr = result;
315                         if (inexact)
316                             if (Is_inexacttrap_enabled())
317                                 return(UNDERFLOWEXCEPTION | INEXACTEXCEPTION);
318                             else Set_inexactflag();
319                         return(UNDERFLOWEXCEPTION);
320                 }
321 
322 		/* Determine if should set underflow flag */
323 		is_tiny = TRUE;
324 		if (dest_exponent == 0 && inexact) {
325 			switch (Rounding_mode()) {
326 			case ROUNDPLUS:
327 				if (Sgl_iszero_sign(result)) {
328 					Sgl_increment(opnd3);
329 					if (Sgl_isone_hiddenoverflow(opnd3))
330                 			    is_tiny = FALSE;
331 					Sgl_decrement(opnd3);
332 				}
333 				break;
334 			case ROUNDMINUS:
335 				if (Sgl_isone_sign(result)) {
336 					Sgl_increment(opnd3);
337 					if (Sgl_isone_hiddenoverflow(opnd3))
338                 			    is_tiny = FALSE;
339 					Sgl_decrement(opnd3);
340 				}
341 				break;
342 			case ROUNDNEAREST:
343 				if (guardbit && (stickybit ||
344 				    Sgl_isone_lowmantissa(opnd3))) {
345 				      	Sgl_increment(opnd3);
346 					if (Sgl_isone_hiddenoverflow(opnd3))
347                 			    is_tiny = FALSE;
348 					Sgl_decrement(opnd3);
349 				}
350 				break;
351 			}
352 		}
353 
354                 /*
355                  * denormalize result or set to signed zero
356                  */
357 		stickybit = inexact;
358 		Sgl_denormalize(opnd3,dest_exponent,guardbit,stickybit,inexact);
359 
360 		/* return rounded number */
361 		if (inexact) {
362 			switch (Rounding_mode()) {
363 			case ROUNDPLUS:
364 				if (Sgl_iszero_sign(result)) {
365 					Sgl_increment(opnd3);
366 				}
367 				break;
368 			case ROUNDMINUS:
369 				if (Sgl_isone_sign(result))  {
370 					Sgl_increment(opnd3);
371 				}
372 				break;
373 			case ROUNDNEAREST:
374 				if (guardbit && (stickybit ||
375 				    Sgl_isone_lowmantissa(opnd3))) {
376 			      		Sgl_increment(opnd3);
377 				}
378 				break;
379 			}
380                 	if (is_tiny) Set_underflowflag();
381                 }
382 		Sgl_set_exponentmantissa(result,opnd3);
383 	}
384 	else Sgl_set_exponent(result,dest_exponent);
385 	*dstptr = result;
386 	/* check for inexact */
387 	if (inexact) {
388 		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
389 		else  Set_inexactflag();
390 	}
391 	return(NOEXCEPTION);
392 }
393