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