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