xref: /linux/arch/parisc/math-emu/fcnvfx.c (revision 0526b56cbc3c489642bd6a5fe4b718dea7ef0ee8)
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/fcnvfx.c		$Revision: 1.1 $
13  *
14  *  Purpose:
15  *	Single Floating-point to Single Fixed-point
16  *	Single Floating-point to Double Fixed-point
17  *	Double Floating-point to Single Fixed-point
18  *	Double Floating-point to Double Fixed-point
19  *
20  *  External Interfaces:
21  *	dbl_to_dbl_fcnvfx(srcptr,nullptr,dstptr,status)
22  *	dbl_to_sgl_fcnvfx(srcptr,nullptr,dstptr,status)
23  *	sgl_to_dbl_fcnvfx(srcptr,nullptr,dstptr,status)
24  *	sgl_to_sgl_fcnvfx(srcptr,nullptr,dstptr,status)
25  *
26  *  Internal Interfaces:
27  *
28  *  Theory:
29  *	<<please update with a overview of the operation of this file>>
30  *
31  * END_DESC
32 */
33 
34 
35 #include "float.h"
36 #include "sgl_float.h"
37 #include "dbl_float.h"
38 #include "cnv_float.h"
39 
40 /*
41  *  Single Floating-point to Single Fixed-point
42  */
43 /*ARGSUSED*/
44 int
45 sgl_to_sgl_fcnvfx(
46 		    sgl_floating_point *srcptr,
47 		    sgl_floating_point *nullptr,
48 		    int *dstptr,
49 		    sgl_floating_point *status)
50 {
51 	register unsigned int src, temp;
52 	register int src_exponent, result;
53 	register boolean inexact = FALSE;
54 
55 	src = *srcptr;
56 	src_exponent = Sgl_exponent(src) - SGL_BIAS;
57 
58 	/*
59 	 * Test for overflow
60 	 */
61 	if (src_exponent > SGL_FX_MAX_EXP) {
62 		/* check for MININT */
63 		if ((src_exponent > SGL_FX_MAX_EXP + 1) ||
64 		Sgl_isnotzero_mantissa(src) || Sgl_iszero_sign(src)) {
65                         if (Sgl_iszero_sign(src)) result = 0x7fffffff;
66                         else result = 0x80000000;
67 
68 	                if (Is_invalidtrap_enabled()) {
69                             return(INVALIDEXCEPTION);
70                         }
71                         Set_invalidflag();
72 			*dstptr = result;
73 			return(NOEXCEPTION);
74        		}
75 	}
76 	/*
77 	 * Generate result
78 	 */
79 	if (src_exponent >= 0) {
80 		temp = src;
81 		Sgl_clear_signexponent_set_hidden(temp);
82 		Int_from_sgl_mantissa(temp,src_exponent);
83 		if (Sgl_isone_sign(src))  result = -Sgl_all(temp);
84 		else result = Sgl_all(temp);
85 
86 		/* check for inexact */
87 		if (Sgl_isinexact_to_fix(src,src_exponent)) {
88 			inexact = TRUE;
89 			/*  round result  */
90 			switch (Rounding_mode()) {
91 			case ROUNDPLUS:
92 			     if (Sgl_iszero_sign(src)) result++;
93 			     break;
94 			case ROUNDMINUS:
95 			     if (Sgl_isone_sign(src)) result--;
96 			     break;
97 			case ROUNDNEAREST:
98 			     if (Sgl_isone_roundbit(src,src_exponent)) {
99 			        if (Sgl_isone_stickybit(src,src_exponent)
100 				|| (Sgl_isone_lowmantissa(temp)))
101 			           if (Sgl_iszero_sign(src)) result++;
102 			           else result--;
103 			     }
104 			}
105 		}
106 	}
107 	else {
108 		result = 0;
109 
110 		/* check for inexact */
111 		if (Sgl_isnotzero_exponentmantissa(src)) {
112 			inexact = TRUE;
113 			/*  round result  */
114 			switch (Rounding_mode()) {
115 			case ROUNDPLUS:
116 			     if (Sgl_iszero_sign(src)) result++;
117 			     break;
118 			case ROUNDMINUS:
119 			     if (Sgl_isone_sign(src)) result--;
120 			     break;
121 			case ROUNDNEAREST:
122 			     if (src_exponent == -1)
123 			        if (Sgl_isnotzero_mantissa(src))
124 			           if (Sgl_iszero_sign(src)) result++;
125 			           else result--;
126 			}
127 		}
128 	}
129 	*dstptr = result;
130 	if (inexact) {
131 		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
132 		else Set_inexactflag();
133 	}
134 	return(NOEXCEPTION);
135 }
136 
137 /*
138  *  Single Floating-point to Double Fixed-point
139  */
140 /*ARGSUSED*/
141 int
142 sgl_to_dbl_fcnvfx(
143 		sgl_floating_point *srcptr,
144 		unsigned int *nullptr,
145 		dbl_integer *dstptr,
146 		unsigned int *status)
147 {
148 	register int src_exponent, resultp1;
149 	register unsigned int src, temp, resultp2;
150 	register boolean inexact = FALSE;
151 
152 	src = *srcptr;
153 	src_exponent = Sgl_exponent(src) - SGL_BIAS;
154 
155 	/*
156 	 * Test for overflow
157 	 */
158 	if (src_exponent > DBL_FX_MAX_EXP) {
159 		/* check for MININT */
160 		if ((src_exponent > DBL_FX_MAX_EXP + 1) ||
161 		Sgl_isnotzero_mantissa(src) || Sgl_iszero_sign(src)) {
162                         if (Sgl_iszero_sign(src)) {
163                               resultp1 = 0x7fffffff;
164 			      resultp2 = 0xffffffff;
165 			}
166                         else {
167 			    resultp1 = 0x80000000;
168 			    resultp2 = 0;
169 			}
170 	                if (Is_invalidtrap_enabled()) {
171                             return(INVALIDEXCEPTION);
172                         }
173                         Set_invalidflag();
174     		        Dint_copytoptr(resultp1,resultp2,dstptr);
175 			return(NOEXCEPTION);
176 		}
177 		Dint_set_minint(resultp1,resultp2);
178 		Dint_copytoptr(resultp1,resultp2,dstptr);
179 		return(NOEXCEPTION);
180 	}
181 	/*
182 	 * Generate result
183 	 */
184 	if (src_exponent >= 0) {
185 		temp = src;
186 		Sgl_clear_signexponent_set_hidden(temp);
187 		Dint_from_sgl_mantissa(temp,src_exponent,resultp1,resultp2);
188 		if (Sgl_isone_sign(src)) {
189 			Dint_setone_sign(resultp1,resultp2);
190 		}
191 
192 		/* check for inexact */
193 		if (Sgl_isinexact_to_fix(src,src_exponent)) {
194 			inexact = TRUE;
195                         /*  round result  */
196                         switch (Rounding_mode()) {
197                         case ROUNDPLUS:
198                              if (Sgl_iszero_sign(src)) {
199 				Dint_increment(resultp1,resultp2);
200 			     }
201                              break;
202                         case ROUNDMINUS:
203                              if (Sgl_isone_sign(src)) {
204 				Dint_decrement(resultp1,resultp2);
205 			     }
206                              break;
207                         case ROUNDNEAREST:
208                              if (Sgl_isone_roundbit(src,src_exponent))
209                                 if (Sgl_isone_stickybit(src,src_exponent) ||
210 				(Dint_isone_lowp2(resultp2)))
211 				   if (Sgl_iszero_sign(src)) {
212 				      Dint_increment(resultp1,resultp2);
213 				   }
214                                    else {
215 				      Dint_decrement(resultp1,resultp2);
216 				   }
217                         }
218                 }
219         }
220 	else {
221 		Dint_setzero(resultp1,resultp2);
222 
223 		/* check for inexact */
224 		if (Sgl_isnotzero_exponentmantissa(src)) {
225 			inexact = TRUE;
226                         /*  round result  */
227                         switch (Rounding_mode()) {
228                         case ROUNDPLUS:
229                              if (Sgl_iszero_sign(src)) {
230 				Dint_increment(resultp1,resultp2);
231 			     }
232                              break;
233                         case ROUNDMINUS:
234                              if (Sgl_isone_sign(src)) {
235 				Dint_decrement(resultp1,resultp2);
236 			     }
237                              break;
238                         case ROUNDNEAREST:
239                              if (src_exponent == -1)
240                                 if (Sgl_isnotzero_mantissa(src))
241                                    if (Sgl_iszero_sign(src)) {
242 				      Dint_increment(resultp1,resultp2);
243 				   }
244                                    else {
245 				      Dint_decrement(resultp1,resultp2);
246 				   }
247 			}
248 		}
249 	}
250 	Dint_copytoptr(resultp1,resultp2,dstptr);
251 	if (inexact) {
252 		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
253 		else Set_inexactflag();
254 	}
255 	return(NOEXCEPTION);
256 }
257 
258 /*
259  *  Double Floating-point to Single Fixed-point
260  */
261 /*ARGSUSED*/
262 int
263 dbl_to_sgl_fcnvfx(
264 		    dbl_floating_point *srcptr,
265 		    unsigned int *nullptr,
266 		    int *dstptr,
267 		    unsigned int *status)
268 {
269 	register unsigned int srcp1,srcp2, tempp1,tempp2;
270 	register int src_exponent, result;
271 	register boolean inexact = FALSE;
272 
273 	Dbl_copyfromptr(srcptr,srcp1,srcp2);
274 	src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
275 
276 	/*
277 	 * Test for overflow
278 	 */
279 	if (src_exponent > SGL_FX_MAX_EXP) {
280 		/* check for MININT */
281 		if (Dbl_isoverflow_to_int(src_exponent,srcp1,srcp2)) {
282                         if (Dbl_iszero_sign(srcp1)) result = 0x7fffffff;
283                         else result = 0x80000000;
284 
285 	                if (Is_invalidtrap_enabled()) {
286                             return(INVALIDEXCEPTION);
287                         }
288                         Set_invalidflag();
289 			*dstptr = result;
290 			return(NOEXCEPTION);
291 		}
292 	}
293 	/*
294 	 * Generate result
295 	 */
296 	if (src_exponent >= 0) {
297 		tempp1 = srcp1;
298 		tempp2 = srcp2;
299 		Dbl_clear_signexponent_set_hidden(tempp1);
300 		Int_from_dbl_mantissa(tempp1,tempp2,src_exponent);
301 		if (Dbl_isone_sign(srcp1) && (src_exponent <= SGL_FX_MAX_EXP))
302 			result = -Dbl_allp1(tempp1);
303 		else result = Dbl_allp1(tempp1);
304 
305 		/* check for inexact */
306 		if (Dbl_isinexact_to_fix(srcp1,srcp2,src_exponent)) {
307                         inexact = TRUE;
308                         /*  round result  */
309                         switch (Rounding_mode()) {
310                         case ROUNDPLUS:
311                              if (Dbl_iszero_sign(srcp1)) result++;
312                              break;
313                         case ROUNDMINUS:
314                              if (Dbl_isone_sign(srcp1)) result--;
315                              break;
316                         case ROUNDNEAREST:
317                              if (Dbl_isone_roundbit(srcp1,srcp2,src_exponent))
318                                 if (Dbl_isone_stickybit(srcp1,srcp2,src_exponent) ||
319 				(Dbl_isone_lowmantissap1(tempp1)))
320                                    if (Dbl_iszero_sign(srcp1)) result++;
321                                    else result--;
322                         }
323 			/* check for overflow */
324 			if ((Dbl_iszero_sign(srcp1) && result < 0) ||
325 			    (Dbl_isone_sign(srcp1) && result > 0)) {
326 
327                           if (Dbl_iszero_sign(srcp1)) result = 0x7fffffff;
328                           else result = 0x80000000;
329 
330 	                  if (Is_invalidtrap_enabled()) {
331                             return(INVALIDEXCEPTION);
332                           }
333                           Set_invalidflag();
334 			  *dstptr = result;
335 			  return(NOEXCEPTION);
336 			}
337                 }
338 	}
339 	else {
340 		result = 0;
341 
342 		/* check for inexact */
343 		if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
344                         inexact = TRUE;
345                         /*  round result  */
346                         switch (Rounding_mode()) {
347                         case ROUNDPLUS:
348                              if (Dbl_iszero_sign(srcp1)) result++;
349                              break;
350                         case ROUNDMINUS:
351                              if (Dbl_isone_sign(srcp1)) result--;
352                              break;
353                         case ROUNDNEAREST:
354                              if (src_exponent == -1)
355                                 if (Dbl_isnotzero_mantissa(srcp1,srcp2))
356                                    if (Dbl_iszero_sign(srcp1)) result++;
357                                    else result--;
358 			}
359                 }
360 	}
361 	*dstptr = result;
362         if (inexact) {
363                 if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
364 		else Set_inexactflag();
365         }
366 	return(NOEXCEPTION);
367 }
368 
369 /*
370  *  Double Floating-point to Double Fixed-point
371  */
372 /*ARGSUSED*/
373 int
374 dbl_to_dbl_fcnvfx(
375 		    dbl_floating_point *srcptr,
376 		    unsigned int *nullptr,
377 		    dbl_integer *dstptr,
378 		    unsigned int *status)
379 {
380 	register int src_exponent, resultp1;
381 	register unsigned int srcp1, srcp2, tempp1, tempp2, resultp2;
382 	register boolean inexact = FALSE;
383 
384 	Dbl_copyfromptr(srcptr,srcp1,srcp2);
385 	src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
386 
387 	/*
388 	 * Test for overflow
389 	 */
390 	if (src_exponent > DBL_FX_MAX_EXP) {
391 		/* check for MININT */
392 		if ((src_exponent > DBL_FX_MAX_EXP + 1) ||
393 		Dbl_isnotzero_mantissa(srcp1,srcp2) || Dbl_iszero_sign(srcp1)) {
394                         if (Dbl_iszero_sign(srcp1)) {
395                               resultp1 = 0x7fffffff;
396 			      resultp2 = 0xffffffff;
397 			}
398                         else {
399 			    resultp1 = 0x80000000;
400 			    resultp2 = 0;
401 			}
402 	                if (Is_invalidtrap_enabled()) {
403                             return(INVALIDEXCEPTION);
404                         }
405                         Set_invalidflag();
406     		        Dint_copytoptr(resultp1,resultp2,dstptr);
407 			return(NOEXCEPTION);
408 		}
409 	}
410 
411 	/*
412 	 * Generate result
413 	 */
414 	if (src_exponent >= 0) {
415 		tempp1 = srcp1;
416 		tempp2 = srcp2;
417 		Dbl_clear_signexponent_set_hidden(tempp1);
418 		Dint_from_dbl_mantissa(tempp1,tempp2,src_exponent,resultp1,
419 		resultp2);
420 		if (Dbl_isone_sign(srcp1)) {
421 			Dint_setone_sign(resultp1,resultp2);
422 		}
423 
424 		/* check for inexact */
425 		if (Dbl_isinexact_to_fix(srcp1,srcp2,src_exponent)) {
426                         inexact = TRUE;
427                         /*  round result  */
428                         switch (Rounding_mode()) {
429                         case ROUNDPLUS:
430                              if (Dbl_iszero_sign(srcp1)) {
431 				Dint_increment(resultp1,resultp2);
432 			     }
433                              break;
434                         case ROUNDMINUS:
435                              if (Dbl_isone_sign(srcp1)) {
436 				Dint_decrement(resultp1,resultp2);
437 			     }
438                              break;
439                         case ROUNDNEAREST:
440                              if (Dbl_isone_roundbit(srcp1,srcp2,src_exponent))
441                                 if (Dbl_isone_stickybit(srcp1,srcp2,src_exponent) ||
442 				(Dint_isone_lowp2(resultp2)))
443                                    if (Dbl_iszero_sign(srcp1)) {
444 				      Dint_increment(resultp1,resultp2);
445 				   }
446                                    else {
447 				      Dint_decrement(resultp1,resultp2);
448 				   }
449                         }
450                 }
451 	}
452 	else {
453 		Dint_setzero(resultp1,resultp2);
454 
455 		/* check for inexact */
456 		if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
457                         inexact = TRUE;
458                         /*  round result  */
459                         switch (Rounding_mode()) {
460                         case ROUNDPLUS:
461                              if (Dbl_iszero_sign(srcp1)) {
462 				Dint_increment(resultp1,resultp2);
463 			     }
464                              break;
465                         case ROUNDMINUS:
466                              if (Dbl_isone_sign(srcp1)) {
467 				Dint_decrement(resultp1,resultp2);
468 			     }
469                              break;
470                         case ROUNDNEAREST:
471                              if (src_exponent == -1)
472                                 if (Dbl_isnotzero_mantissa(srcp1,srcp2))
473                                    if (Dbl_iszero_sign(srcp1)) {
474 				      Dint_increment(resultp1,resultp2);
475 				   }
476                                    else {
477 				      Dint_decrement(resultp1,resultp2);
478 				   }
479 			}
480                 }
481 	}
482 	Dint_copytoptr(resultp1,resultp2,dstptr);
483         if (inexact) {
484                 if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
485         	else Set_inexactflag();
486         }
487 	return(NOEXCEPTION);
488 }
489