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
36int
37sgl_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