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: 1.1.1.1 $
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*/
57int
58sgl_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*/
154int
155sgl_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*/
275int
276dbl_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*/
386int
387dbl_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