xref: /netbsd-src/sys/arch/hppa/spmath/fcnvfx.c (revision d72340ff8e2fb5c3ca49ab85c798389cda4408d6)
1 
2 /*	$OpenBSD: fcnvfx.c,v 1.8 2010/07/30 18:05:23 kettenis Exp $	*/
3 
4 /*
5  * Copyright 1996 1995 by Open Software Foundation, Inc.
6  *              All Rights Reserved
7  *
8  * Permission to use, copy, modify, and distribute this software and
9  * its documentation for any purpose and without fee is hereby granted,
10  * provided that the above copyright notice appears in all copies and
11  * that both the copyright notice and this permission notice appear in
12  * supporting documentation.
13  *
14  * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
16  * FOR A PARTICULAR PURPOSE.
17  *
18  * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
19  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
20  * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
21  * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
22  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23  *
24  */
25 /*
26  * pmk1.1
27  */
28 /*
29  * (c) Copyright 1986 HEWLETT-PACKARD COMPANY
30  *
31  * To anyone who acknowledges that this file is provided "AS IS"
32  * without any express or implied warranty:
33  *     permission to use, copy, modify, and distribute this file
34  * for any purpose is hereby granted without fee, provided that
35  * the above copyright notice and this notice appears in all
36  * copies, and that the name of Hewlett-Packard Company not be
37  * used in advertising or publicity pertaining to distribution
38  * of the software without specific, written prior permission.
39  * Hewlett-Packard Company makes no representations about the
40  * suitability of this software for any purpose.
41  */
42 
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: fcnvfx.c,v 1.6 2012/02/04 17:03:09 skrll Exp $");
45 
46 #include "../spmath/float.h"
47 #include "../spmath/sgl_float.h"
48 #include "../spmath/dbl_float.h"
49 #include "../spmath/cnv_float.h"
50 
51 /*
52  *  Single Floating-point to Single Fixed-point
53  */
54 /*ARGSUSED*/
55 int
sgl_to_sgl_fcnvfx(sgl_floating_point * srcptr,int * dstptr,unsigned int * status)56 sgl_to_sgl_fcnvfx(sgl_floating_point *srcptr, int *dstptr,
57     unsigned int *status)
58 {
59 	register unsigned int src, temp;
60 	register int src_exponent, result;
61 	register int inexact = false;
62 
63 	src = *srcptr;
64 	src_exponent = Sgl_exponent(src) - SGL_BIAS;
65 
66 	/*
67 	 * Test for overflow
68 	 */
69 	if (src_exponent > SGL_FX_MAX_EXP) {
70 		/* check for MININT */
71 		if ((src_exponent > SGL_FX_MAX_EXP + 1) ||
72 		Sgl_isnotzero_mantissa(src) || Sgl_iszero_sign(src)) {
73 			if (Sgl_iszero_sign(src)) result = 0x7fffffff;
74 			else result = 0x80000000;
75 
76 			if (Is_invalidtrap_enabled()) {
77 				return(INVALIDEXCEPTION);
78 			}
79 			Set_invalidflag();
80 			*dstptr = result;
81 			return(NOEXCEPTION);
82 		}
83 	}
84 	/*
85 	 * Generate result
86 	 */
87 	if (src_exponent >= 0) {
88 		temp = src;
89 		Sgl_clear_signexponent_set_hidden(temp);
90 		Int_from_sgl_mantissa(temp,src_exponent);
91 		if (Sgl_isone_sign(src))  result = -Sgl_all(temp);
92 		else result = Sgl_all(temp);
93 
94 		/* check for inexact */
95 		if (Sgl_isinexact_to_fix(src,src_exponent)) {
96 			inexact = true;
97 			/*  round result  */
98 			switch (Rounding_mode()) {
99 			case ROUNDPLUS:
100 			     if (Sgl_iszero_sign(src)) result++;
101 			     break;
102 			case ROUNDMINUS:
103 			     if (Sgl_isone_sign(src)) result--;
104 			     break;
105 			case ROUNDNEAREST:
106 			     if (Sgl_isone_roundbit(src,src_exponent)) {
107 				if (Sgl_isone_stickybit(src,src_exponent)
108 				|| (Sgl_isone_lowmantissa(temp))) {
109 				   if (Sgl_iszero_sign(src)) result++;
110 				   else result--;
111 				}
112 			     }
113 			}
114 		}
115 	}
116 	else {
117 		result = 0;
118 
119 		/* check for inexact */
120 		if (Sgl_isnotzero_exponentmantissa(src)) {
121 			inexact = true;
122 			/*  round result  */
123 			switch (Rounding_mode()) {
124 			case ROUNDPLUS:
125 			     if (Sgl_iszero_sign(src)) result++;
126 			     break;
127 			case ROUNDMINUS:
128 			     if (Sgl_isone_sign(src)) result--;
129 			     break;
130 			case ROUNDNEAREST:
131 			     if (src_exponent == -1)
132 				if (Sgl_isnotzero_mantissa(src)) {
133 				   if (Sgl_iszero_sign(src)) result++;
134 				   else result--;
135 				}
136 			}
137 		}
138 	}
139 	*dstptr = result;
140 	if (inexact) {
141 		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
142 		else Set_inexactflag();
143 	}
144 	return(NOEXCEPTION);
145 }
146 
147 /*
148  *  Single Floating-point to Double Fixed-point
149  */
150 /*ARGSUSED*/
151 int
sgl_to_dbl_fcnvfx(sgl_floating_point * srcptr,dbl_integer * dstptr,unsigned int * status)152 sgl_to_dbl_fcnvfx(sgl_floating_point *srcptr, dbl_integer *dstptr,
153     unsigned int *status)
154 {
155 	register int src_exponent, resultp1;
156 	register unsigned int src, temp, resultp2;
157 	register int inexact = false;
158 
159 	src = *srcptr;
160 	src_exponent = Sgl_exponent(src) - SGL_BIAS;
161 
162 	/*
163 	 * Test for overflow
164 	 */
165 	if (src_exponent > DBL_FX_MAX_EXP) {
166 		/* check for MININT */
167 		if ((src_exponent > DBL_FX_MAX_EXP + 1) ||
168 		Sgl_isnotzero_mantissa(src) || Sgl_iszero_sign(src)) {
169 			if (Sgl_iszero_sign(src)) {
170 				resultp1 = 0x7fffffff;
171 				resultp2 = 0xffffffff;
172 			}
173 			else {
174 				resultp1 = 0x80000000;
175 				resultp2 = 0;
176 			}
177 
178 			if (Is_invalidtrap_enabled()) {
179 				return(INVALIDEXCEPTION);
180 			}
181 			Set_invalidflag();
182 			Dint_copytoptr(resultp1,resultp2,dstptr);
183 			return(NOEXCEPTION);
184 		}
185 		Dint_set_minint(resultp1,resultp2);
186 		Dint_copytoptr(resultp1,resultp2,dstptr);
187 		return(NOEXCEPTION);
188 	}
189 	/*
190 	 * Generate result
191 	 */
192 	if (src_exponent >= 0) {
193 		temp = src;
194 		Sgl_clear_signexponent_set_hidden(temp);
195 		Dint_from_sgl_mantissa(temp,src_exponent,resultp1,resultp2);
196 		if (Sgl_isone_sign(src)) {
197 			Dint_setone_sign(resultp1,resultp2);
198 		}
199 
200 		/* check for inexact */
201 		if (Sgl_isinexact_to_fix(src,src_exponent)) {
202 			inexact = true;
203 			/*  round result  */
204 			switch (Rounding_mode()) {
205 			case ROUNDPLUS:
206 			     if (Sgl_iszero_sign(src)) {
207 				Dint_increment(resultp1,resultp2);
208 			     }
209 			     break;
210 			case ROUNDMINUS:
211 			     if (Sgl_isone_sign(src)) {
212 				Dint_decrement(resultp1,resultp2);
213 			     }
214 			     break;
215 			case ROUNDNEAREST:
216 			     if (Sgl_isone_roundbit(src,src_exponent))
217 				if (Sgl_isone_stickybit(src,src_exponent) ||
218 				(Dint_isone_lowp2(resultp2))) {
219 				   if (Sgl_iszero_sign(src)) {
220 				      Dint_increment(resultp1,resultp2);
221 				   }
222 				   else {
223 				      Dint_decrement(resultp1,resultp2);
224 				   }
225 				}
226 			}
227 		}
228 	}
229 	else {
230 		Dint_setzero(resultp1,resultp2);
231 
232 		/* check for inexact */
233 		if (Sgl_isnotzero_exponentmantissa(src)) {
234 			inexact = true;
235 			/*  round result  */
236 			switch (Rounding_mode()) {
237 			case ROUNDPLUS:
238 			     if (Sgl_iszero_sign(src)) {
239 				Dint_increment(resultp1,resultp2);
240 			     }
241 			     break;
242 			case ROUNDMINUS:
243 			     if (Sgl_isone_sign(src)) {
244 				Dint_decrement(resultp1,resultp2);
245 			     }
246 			     break;
247 			case ROUNDNEAREST:
248 			     if (src_exponent == -1)
249 				if (Sgl_isnotzero_mantissa(src)) {
250 				   if (Sgl_iszero_sign(src)) {
251 				      Dint_increment(resultp1,resultp2);
252 				   }
253 				   else {
254 				      Dint_decrement(resultp1,resultp2);
255 				   }
256 				}
257 			}
258 		}
259 	}
260 	Dint_copytoptr(resultp1,resultp2,dstptr);
261 	if (inexact) {
262 		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
263 		else Set_inexactflag();
264 	}
265 	return(NOEXCEPTION);
266 }
267 
268 /*
269  *  Double Floating-point to Single Fixed-point
270  */
271 /*ARGSUSED*/
272 int
dbl_to_sgl_fcnvfx(dbl_floating_point * srcptr,int * dstptr,unsigned int * status)273 dbl_to_sgl_fcnvfx(dbl_floating_point *srcptr, int *dstptr,
274    unsigned int *status)
275 {
276 	register unsigned int srcp1,srcp2, tempp1,tempp2;
277 	register int src_exponent, result;
278 	register int inexact = false;
279 
280 	Dbl_copyfromptr(srcptr,srcp1,srcp2);
281 	src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
282 
283 	/*
284 	 * Test for overflow
285 	 */
286 	if (src_exponent > SGL_FX_MAX_EXP) {
287 		/* check for MININT */
288 		if (Dbl_isoverflow_to_int(src_exponent,srcp1,srcp2)) {
289 			if (Dbl_iszero_sign(srcp1)) result = 0x7fffffff;
290 			else result = 0x80000000;
291 
292 			if (Is_invalidtrap_enabled()) {
293 				return(INVALIDEXCEPTION);
294 			}
295 			Set_invalidflag();
296 			*dstptr = result;
297 			return(NOEXCEPTION);
298 		}
299 	}
300 	/*
301 	 * Generate result
302 	 */
303 	if (src_exponent >= 0) {
304 		tempp1 = srcp1;
305 		tempp2 = srcp2;
306 		Dbl_clear_signexponent_set_hidden(tempp1);
307 		Int_from_dbl_mantissa(tempp1,tempp2,src_exponent);
308 		if (Dbl_isone_sign(srcp1) && (src_exponent <= SGL_FX_MAX_EXP))
309 			result = -Dbl_allp1(tempp1);
310 		else result = Dbl_allp1(tempp1);
311 
312 		/* check for inexact */
313 		if (Dbl_isinexact_to_fix(srcp1,srcp2,src_exponent)) {
314 			inexact = true;
315 			/*  round result  */
316 			switch (Rounding_mode()) {
317 			case ROUNDPLUS:
318 				if (Dbl_iszero_sign(srcp1))
319 					result++;
320 			     break;
321 			case ROUNDMINUS:
322 			     if (Dbl_isone_sign(srcp1)) result--;
323 			     break;
324 			case ROUNDNEAREST:
325 			     if (Dbl_isone_roundbit(srcp1,srcp2,src_exponent))
326 				if (Dbl_isone_stickybit(srcp1,srcp2,src_exponent) ||
327 				(Dbl_isone_lowmantissap1(tempp1))) {
328 				   if (Dbl_iszero_sign(srcp1)) result++;
329 				   else result--;
330 				}
331 			}
332 			/* check for overflow */
333 			if ((Dbl_iszero_sign(srcp1) && result < 0) ||
334 			    (Dbl_isone_sign(srcp1) && result > 0)) {
335 
336 				if (Dbl_iszero_sign(srcp1))
337 					result = 0x7fffffff;
338 				else
339 					result = 0x80000000;
340 
341 			    if (Is_overflowtrap_enabled()) {
342 			    if (Is_inexacttrap_enabled())
343 			      return(OVERFLOWEXCEPTION|INEXACTEXCEPTION);
344 			    else Set_inexactflag();
345 			    return(OVERFLOWEXCEPTION);
346 			    }
347 			  Set_overflowflag();
348 			  *dstptr = result;
349 			  if (Is_inexacttrap_enabled() )
350 				return(INEXACTEXCEPTION);
351 			  else Set_inexactflag();
352 			  return(NOEXCEPTION);
353 			}
354 		}
355 	}
356 	else {
357 		result = 0;
358 
359 		/* check for inexact */
360 		if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
361 			inexact = true;
362 			/*  round result  */
363 			switch (Rounding_mode()) {
364 			case ROUNDPLUS:
365 			     if (Dbl_iszero_sign(srcp1)) result++;
366 			     break;
367 			case ROUNDMINUS:
368 			     if (Dbl_isone_sign(srcp1)) result--;
369 			     break;
370 			case ROUNDNEAREST:
371 			     if (src_exponent == -1)
372 				if (Dbl_isnotzero_mantissa(srcp1,srcp2)) {
373 				   if (Dbl_iszero_sign(srcp1)) result++;
374 				   else result--;
375 				}
376 			}
377 		}
378 	}
379 	*dstptr = result;
380 	if (inexact) {
381 		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
382 		else Set_inexactflag();
383 	}
384 	return(NOEXCEPTION);
385 }
386 
387 /*
388  *  Double Floating-point to Double Fixed-point
389  */
390 /*ARGSUSED*/
391 int
dbl_to_dbl_fcnvfx(dbl_floating_point * srcptr,dbl_integer * dstptr,unsigned int * status)392 dbl_to_dbl_fcnvfx(dbl_floating_point *srcptr, dbl_integer *dstptr,
393     unsigned int *status)
394 {
395 	register int src_exponent, resultp1;
396 	register unsigned int srcp1, srcp2, tempp1, tempp2, resultp2;
397 	register int inexact = false;
398 
399 	Dbl_copyfromptr(srcptr,srcp1,srcp2);
400 	src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
401 
402 	/*
403 	 * Test for overflow
404 	 */
405 	if (src_exponent > DBL_FX_MAX_EXP) {
406 		/* check for MININT */
407 		if ((src_exponent > DBL_FX_MAX_EXP + 1) ||
408 		Dbl_isnotzero_mantissa(srcp1,srcp2) || Dbl_iszero_sign(srcp1)) {
409 			if (Dbl_iszero_sign(srcp1)) {
410 				resultp1 = 0x7fffffff;
411 				resultp2 = 0xffffffff;
412 			}
413 			else {
414 				resultp1 = 0x80000000;
415 				resultp2 = 0;
416 			}
417 
418 			if (Is_invalidtrap_enabled()) {
419 				return(INVALIDEXCEPTION);
420 			}
421 			Set_invalidflag();
422 			Dint_copytoptr(resultp1,resultp2,dstptr);
423 			return(NOEXCEPTION);
424 		}
425 	}
426 
427 	/*
428 	 * Generate result
429 	 */
430 	if (src_exponent >= 0) {
431 		tempp1 = srcp1;
432 		tempp2 = srcp2;
433 		Dbl_clear_signexponent_set_hidden(tempp1);
434 		Dint_from_dbl_mantissa(tempp1,tempp2,src_exponent,
435 				       resultp1, resultp2);
436 		if (Dbl_isone_sign(srcp1)) {
437 			Dint_setone_sign(resultp1,resultp2);
438 		}
439 
440 		/* check for inexact */
441 		if (Dbl_isinexact_to_fix(srcp1,srcp2,src_exponent)) {
442 			inexact = true;
443 			/*  round result  */
444 			switch (Rounding_mode()) {
445 			case ROUNDPLUS:
446 			     if (Dbl_iszero_sign(srcp1)) {
447 				Dint_increment(resultp1,resultp2);
448 			     }
449 			     break;
450 			case ROUNDMINUS:
451 			     if (Dbl_isone_sign(srcp1)) {
452 				Dint_decrement(resultp1,resultp2);
453 			     }
454 			     break;
455 			case ROUNDNEAREST:
456 			     if (Dbl_isone_roundbit(srcp1,srcp2,src_exponent))
457 				if (Dbl_isone_stickybit(srcp1,srcp2,src_exponent) ||
458 				(Dint_isone_lowp2(resultp2))) {
459 				   if (Dbl_iszero_sign(srcp1)) {
460 				      Dint_increment(resultp1,resultp2);
461 				   }
462 				   else {
463 				      Dint_decrement(resultp1,resultp2);
464 				   }
465 				}
466 			}
467 		}
468 	}
469 	else {
470 		Dint_setzero(resultp1,resultp2);
471 
472 		/* check for inexact */
473 		if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
474 			inexact = true;
475 			/*  round result  */
476 			switch (Rounding_mode()) {
477 			case ROUNDPLUS:
478 			     if (Dbl_iszero_sign(srcp1)) {
479 				Dint_increment(resultp1,resultp2);
480 			     }
481 			     break;
482 			case ROUNDMINUS:
483 			     if (Dbl_isone_sign(srcp1)) {
484 				Dint_decrement(resultp1,resultp2);
485 			     }
486 			     break;
487 			case ROUNDNEAREST:
488 			     if (src_exponent == -1)
489 				if (Dbl_isnotzero_mantissa(srcp1,srcp2)) {
490 				   if (Dbl_iszero_sign(srcp1)) {
491 				      Dint_increment(resultp1,resultp2);
492 				   }
493 				   else {
494 				      Dint_decrement(resultp1,resultp2);
495 				   }
496 				}
497 			}
498 		}
499 	}
500 	Dint_copytoptr(resultp1,resultp2,dstptr);
501 	if (inexact) {
502 		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
503 		else Set_inexactflag();
504 	}
505 	return(NOEXCEPTION);
506 }
507