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