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