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