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