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