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/sfmpy.c		$Revision: 1.1 $
13 *
14 *  Purpose:
15 *	Single Precision Floating-point Multiply
16 *
17 *  External Interfaces:
18 *	sgl_fmpy(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 Multiply
34 */
35
36int
37sgl_fmpy(
38    sgl_floating_point *srcptr1,
39    sgl_floating_point *srcptr2,
40    sgl_floating_point *dstptr,
41    unsigned int *status)
42{
43	register unsigned int opnd1, opnd2, opnd3, result;
44	register int dest_exponent, count;
45	register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
46	boolean is_tiny;
47
48	opnd1 = *srcptr1;
49	opnd2 = *srcptr2;
50	/*
51	 * set sign bit of result
52	 */
53	if (Sgl_sign(opnd1) ^ Sgl_sign(opnd2)) Sgl_setnegativezero(result);
54	else Sgl_setzero(result);
55	/*
56	 * check first operand for NaN's or infinity
57	 */
58	if (Sgl_isinfinity_exponent(opnd1)) {
59		if (Sgl_iszero_mantissa(opnd1)) {
60			if (Sgl_isnotnan(opnd2)) {
61				if (Sgl_iszero_exponentmantissa(opnd2)) {
62					/*
63					 * invalid since operands are infinity
64					 * and zero
65					 */
66					if (Is_invalidtrap_enabled())
67                                		return(INVALIDEXCEPTION);
68                                	Set_invalidflag();
69                                	Sgl_makequietnan(result);
70					*dstptr = result;
71					return(NOEXCEPTION);
72				}
73				/*
74			 	 * return infinity
75			 	 */
76				Sgl_setinfinity_exponentmantissa(result);
77				*dstptr = result;
78				return(NOEXCEPTION);
79			}
80		}
81		else {
82                	/*
83                 	 * is NaN; signaling or quiet?
84                 	 */
85                	if (Sgl_isone_signaling(opnd1)) {
86                        	/* trap if INVALIDTRAP enabled */
87                        	if (Is_invalidtrap_enabled())
88                            		return(INVALIDEXCEPTION);
89                        	/* make NaN quiet */
90                        	Set_invalidflag();
91                        	Sgl_set_quiet(opnd1);
92                	}
93			/*
94			 * is second operand a signaling NaN?
95			 */
96			else if (Sgl_is_signalingnan(opnd2)) {
97                        	/* trap if INVALIDTRAP enabled */
98                        	if (Is_invalidtrap_enabled())
99                            		return(INVALIDEXCEPTION);
100                        	/* make NaN quiet */
101                        	Set_invalidflag();
102                        	Sgl_set_quiet(opnd2);
103                		*dstptr = opnd2;
104                		return(NOEXCEPTION);
105			}
106                	/*
107                 	 * return quiet NaN
108                 	 */
109                	*dstptr = opnd1;
110                	return(NOEXCEPTION);
111		}
112	}
113	/*
114	 * check second operand for NaN's or infinity
115	 */
116	if (Sgl_isinfinity_exponent(opnd2)) {
117		if (Sgl_iszero_mantissa(opnd2)) {
118			if (Sgl_iszero_exponentmantissa(opnd1)) {
119				/* invalid since operands are zero & infinity */
120				if (Is_invalidtrap_enabled())
121                                	return(INVALIDEXCEPTION);
122                                Set_invalidflag();
123                                Sgl_makequietnan(opnd2);
124				*dstptr = opnd2;
125				return(NOEXCEPTION);
126			}
127			/*
128			 * return infinity
129			 */
130			Sgl_setinfinity_exponentmantissa(result);
131			*dstptr = result;
132			return(NOEXCEPTION);
133		}
134                /*
135                 * is NaN; signaling or quiet?
136                 */
137                if (Sgl_isone_signaling(opnd2)) {
138                        /* trap if INVALIDTRAP enabled */
139                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
140
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	 * Generate exponent
153	 */
154	dest_exponent = Sgl_exponent(opnd1) + Sgl_exponent(opnd2) - SGL_BIAS;
155
156	/*
157	 * Generate mantissa
158	 */
159	if (Sgl_isnotzero_exponent(opnd1)) {
160		/* set hidden bit */
161		Sgl_clear_signexponent_set_hidden(opnd1);
162	}
163	else {
164		/* check for zero */
165		if (Sgl_iszero_mantissa(opnd1)) {
166			Sgl_setzero_exponentmantissa(result);
167			*dstptr = result;
168			return(NOEXCEPTION);
169		}
170                /* is denormalized, adjust exponent */
171                Sgl_clear_signexponent(opnd1);
172		Sgl_leftshiftby1(opnd1);
173		Sgl_normalize(opnd1,dest_exponent);
174	}
175	/* opnd2 needs to have hidden bit set with msb in hidden bit */
176	if (Sgl_isnotzero_exponent(opnd2)) {
177		Sgl_clear_signexponent_set_hidden(opnd2);
178	}
179	else {
180		/* check for zero */
181		if (Sgl_iszero_mantissa(opnd2)) {
182			Sgl_setzero_exponentmantissa(result);
183			*dstptr = result;
184			return(NOEXCEPTION);
185		}
186                /* is denormalized; want to normalize */
187                Sgl_clear_signexponent(opnd2);
188                Sgl_leftshiftby1(opnd2);
189		Sgl_normalize(opnd2,dest_exponent);
190	}
191
192	/* Multiply two source mantissas together */
193
194	Sgl_leftshiftby4(opnd2);     /* make room for guard bits */
195	Sgl_setzero(opnd3);
196	/*
197	 * Four bits at a time are inspected in each loop, and a
198	 * simple shift and add multiply algorithm is used.
199	 */
200	for (count=1;count<SGL_P;count+=4) {
201		stickybit |= Slow4(opnd3);
202		Sgl_rightshiftby4(opnd3);
203		if (Sbit28(opnd1)) Sall(opnd3) += (Sall(opnd2) << 3);
204		if (Sbit29(opnd1)) Sall(opnd3) += (Sall(opnd2) << 2);
205		if (Sbit30(opnd1)) Sall(opnd3) += (Sall(opnd2) << 1);
206		if (Sbit31(opnd1)) Sall(opnd3) += Sall(opnd2);
207		Sgl_rightshiftby4(opnd1);
208	}
209	/* make sure result is left-justified */
210	if (Sgl_iszero_sign(opnd3)) {
211		Sgl_leftshiftby1(opnd3);
212	}
213	else {
214		/* result mantissa >= 2. */
215		dest_exponent++;
216	}
217	/* check for denormalized result */
218	while (Sgl_iszero_sign(opnd3)) {
219		Sgl_leftshiftby1(opnd3);
220		dest_exponent--;
221	}
222	/*
223	 * check for guard, sticky and inexact bits
224	 */
225	stickybit |= Sgl_all(opnd3) << (SGL_BITLENGTH - SGL_EXP_LENGTH + 1);
226	guardbit = Sbit24(opnd3);
227	inexact = guardbit | stickybit;
228
229	/* re-align mantissa */
230	Sgl_rightshiftby8(opnd3);
231
232	/*
233	 * round result
234	 */
235	if (inexact && (dest_exponent>0 || Is_underflowtrap_enabled())) {
236		Sgl_clear_signexponent(opnd3);
237		switch (Rounding_mode()) {
238			case ROUNDPLUS:
239				if (Sgl_iszero_sign(result))
240					Sgl_increment(opnd3);
241				break;
242			case ROUNDMINUS:
243				if (Sgl_isone_sign(result))
244					Sgl_increment(opnd3);
245				break;
246			case ROUNDNEAREST:
247				if (guardbit) {
248			   	if (stickybit || Sgl_isone_lowmantissa(opnd3))
249			      	Sgl_increment(opnd3);
250				}
251		}
252		if (Sgl_isone_hidden(opnd3)) dest_exponent++;
253	}
254	Sgl_set_mantissa(result,opnd3);
255
256        /*
257         * Test for overflow
258         */
259	if (dest_exponent >= SGL_INFINITY_EXPONENT) {
260                /* trap if OVERFLOWTRAP enabled */
261                if (Is_overflowtrap_enabled()) {
262                        /*
263                         * Adjust bias of result
264                         */
265			Sgl_setwrapped_exponent(result,dest_exponent,ovfl);
266			*dstptr = result;
267			if (inexact)
268			    if (Is_inexacttrap_enabled())
269				return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
270			    else Set_inexactflag();
271			return(OVERFLOWEXCEPTION);
272                }
273		inexact = TRUE;
274		Set_overflowflag();
275                /* set result to infinity or largest number */
276		Sgl_setoverflow(result);
277	}
278        /*
279         * Test for underflow
280         */
281	else if (dest_exponent <= 0) {
282                /* trap if UNDERFLOWTRAP enabled */
283                if (Is_underflowtrap_enabled()) {
284                        /*
285                         * Adjust bias of result
286                         */
287			Sgl_setwrapped_exponent(result,dest_exponent,unfl);
288			*dstptr = result;
289			if (inexact)
290			    if (Is_inexacttrap_enabled())
291				return(UNDERFLOWEXCEPTION | INEXACTEXCEPTION);
292			    else Set_inexactflag();
293			return(UNDERFLOWEXCEPTION);
294                }
295
296		/* Determine if should set underflow flag */
297		is_tiny = TRUE;
298		if (dest_exponent == 0 && inexact) {
299			switch (Rounding_mode()) {
300			case ROUNDPLUS:
301				if (Sgl_iszero_sign(result)) {
302					Sgl_increment(opnd3);
303					if (Sgl_isone_hiddenoverflow(opnd3))
304                			    is_tiny = FALSE;
305					Sgl_decrement(opnd3);
306				}
307				break;
308			case ROUNDMINUS:
309				if (Sgl_isone_sign(result)) {
310					Sgl_increment(opnd3);
311					if (Sgl_isone_hiddenoverflow(opnd3))
312                			    is_tiny = FALSE;
313					Sgl_decrement(opnd3);
314				}
315				break;
316			case ROUNDNEAREST:
317				if (guardbit && (stickybit ||
318				    Sgl_isone_lowmantissa(opnd3))) {
319				      	Sgl_increment(opnd3);
320					if (Sgl_isone_hiddenoverflow(opnd3))
321                			    is_tiny = FALSE;
322					Sgl_decrement(opnd3);
323				}
324				break;
325			}
326		}
327
328                /*
329                 * denormalize result or set to signed zero
330                 */
331		stickybit = inexact;
332		Sgl_denormalize(opnd3,dest_exponent,guardbit,stickybit,inexact);
333
334		/* return zero or smallest number */
335		if (inexact) {
336			switch (Rounding_mode()) {
337			case ROUNDPLUS:
338				if (Sgl_iszero_sign(result)) {
339					Sgl_increment(opnd3);
340				}
341				break;
342			case ROUNDMINUS:
343				if (Sgl_isone_sign(result)) {
344					Sgl_increment(opnd3);
345				}
346				break;
347			case ROUNDNEAREST:
348				if (guardbit && (stickybit ||
349				    Sgl_isone_lowmantissa(opnd3))) {
350			      		Sgl_increment(opnd3);
351				}
352				break;
353			}
354                if (is_tiny) Set_underflowflag();
355		}
356		Sgl_set_exponentmantissa(result,opnd3);
357	}
358	else Sgl_set_exponent(result,dest_exponent);
359	*dstptr = result;
360
361	/* check for inexact */
362	if (inexact) {
363		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
364		else Set_inexactflag();
365	}
366	return(NOEXCEPTION);
367}
368