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/fcnvuf.c		$Revision: 1.1.1.1 $
26 *
27 *  Purpose:
28 *	Fixed point to Floating-point Converts
29 *
30 *  External Interfaces:
31 *	dbl_to_dbl_fcnvuf(srcptr,nullptr,dstptr,status)
32 *	dbl_to_sgl_fcnvuf(srcptr,nullptr,dstptr,status)
33 *	sgl_to_dbl_fcnvuf(srcptr,nullptr,dstptr,status)
34 *	sgl_to_sgl_fcnvuf(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 *  Fixed point to Floating-point Converts				*
52 ************************************************************************/
53
54/*
55 *  Convert Single Unsigned Fixed to Single Floating-point format
56 */
57
58int
59sgl_to_sgl_fcnvuf(
60			unsigned int *srcptr,
61			unsigned int *nullptr,
62			sgl_floating_point *dstptr,
63			unsigned int *status)
64{
65	register unsigned int src, result = 0;
66	register int dst_exponent;
67
68	src = *srcptr;
69
70	/* Check for zero */
71	if (src == 0) {
72	       	Sgl_setzero(result);
73		*dstptr = result;
74	       	return(NOEXCEPTION);
75	}
76	/*
77	 * Generate exponent and normalized mantissa
78	 */
79	dst_exponent = 16;    /* initialize for normalization */
80	/*
81	 * Check word for most significant bit set.  Returns
82	 * a value in dst_exponent indicating the bit position,
83	 * between -1 and 30.
84	 */
85	Find_ms_one_bit(src,dst_exponent);
86	/*  left justify source, with msb at bit position 0  */
87	src <<= dst_exponent+1;
88	Sgl_set_mantissa(result, src >> SGL_EXP_LENGTH);
89	Sgl_set_exponent(result, 30+SGL_BIAS - dst_exponent);
90
91	/* check for inexact */
92	if (Suint_isinexact_to_sgl(src)) {
93		switch (Rounding_mode()) {
94			case ROUNDPLUS:
95				Sgl_increment(result);
96				break;
97			case ROUNDMINUS: /* never negative */
98				break;
99			case ROUNDNEAREST:
100				Sgl_roundnearest_from_suint(src,result);
101				break;
102		}
103		if (Is_inexacttrap_enabled()) {
104			*dstptr = result;
105			return(INEXACTEXCEPTION);
106		}
107		else Set_inexactflag();
108	}
109	*dstptr = result;
110	return(NOEXCEPTION);
111}
112
113/*
114 *  Single Unsigned Fixed to Double Floating-point
115 */
116
117int
118sgl_to_dbl_fcnvuf(
119			unsigned int *srcptr,
120			unsigned int *nullptr,
121			dbl_floating_point *dstptr,
122			unsigned int *status)
123{
124	register int dst_exponent;
125	register unsigned int src, resultp1 = 0, resultp2 = 0;
126
127	src = *srcptr;
128
129	/* Check for zero */
130	if (src == 0) {
131	       	Dbl_setzero(resultp1,resultp2);
132	       	Dbl_copytoptr(resultp1,resultp2,dstptr);
133	       	return(NOEXCEPTION);
134	}
135	/*
136	 * Generate exponent and normalized mantissa
137	 */
138	dst_exponent = 16;    /* initialize for normalization */
139	/*
140	 * Check word for most significant bit set.  Returns
141	 * a value in dst_exponent indicating the bit position,
142	 * between -1 and 30.
143	 */
144	Find_ms_one_bit(src,dst_exponent);
145	/*  left justify source, with msb at bit position 0  */
146	src <<= dst_exponent+1;
147	Dbl_set_mantissap1(resultp1, src >> DBL_EXP_LENGTH);
148	Dbl_set_mantissap2(resultp2, src << (32-DBL_EXP_LENGTH));
149	Dbl_set_exponent(resultp1, (30+DBL_BIAS) - dst_exponent);
150	Dbl_copytoptr(resultp1,resultp2,dstptr);
151	return(NOEXCEPTION);
152}
153
154/*
155 *  Double Unsigned Fixed to Single Floating-point
156 */
157
158int
159dbl_to_sgl_fcnvuf(
160			dbl_unsigned *srcptr,
161			unsigned int *nullptr,
162			sgl_floating_point *dstptr,
163			unsigned int *status)
164{
165	int dst_exponent;
166	unsigned int srcp1, srcp2, result = 0;
167
168	Duint_copyfromptr(srcptr,srcp1,srcp2);
169
170	/* Check for zero */
171	if (srcp1 == 0 && srcp2 == 0) {
172	       	Sgl_setzero(result);
173	       	*dstptr = result;
174	       	return(NOEXCEPTION);
175	}
176	/*
177	 * Generate exponent and normalized mantissa
178	 */
179	dst_exponent = 16;    /* initialize for normalization */
180	if (srcp1 == 0) {
181		/*
182		 * Check word for most significant bit set.  Returns
183		 * a value in dst_exponent indicating the bit position,
184		 * between -1 and 30.
185		 */
186		Find_ms_one_bit(srcp2,dst_exponent);
187		/*  left justify source, with msb at bit position 0  */
188		srcp1 = srcp2 << dst_exponent+1;
189		srcp2 = 0;
190		/*
191		 *  since msb set is in second word, need to
192		 *  adjust bit position count
193		 */
194		dst_exponent += 32;
195	}
196	else {
197		/*
198		 * Check word for most significant bit set.  Returns
199		 * a value in dst_exponent indicating the bit position,
200		 * between -1 and 30.
201		 *
202		 */
203		Find_ms_one_bit(srcp1,dst_exponent);
204		/*  left justify source, with msb at bit position 0  */
205		if (dst_exponent >= 0) {
206			Variable_shift_double(srcp1,srcp2,(31-dst_exponent),
207			 srcp1);
208			srcp2 <<= dst_exponent+1;
209		}
210	}
211	Sgl_set_mantissa(result, srcp1 >> SGL_EXP_LENGTH);
212	Sgl_set_exponent(result, (62+SGL_BIAS) - dst_exponent);
213
214	/* check for inexact */
215	if (Duint_isinexact_to_sgl(srcp1,srcp2)) {
216		switch (Rounding_mode()) {
217			case ROUNDPLUS:
218				Sgl_increment(result);
219				break;
220			case ROUNDMINUS: /* never negative */
221				break;
222			case ROUNDNEAREST:
223				Sgl_roundnearest_from_duint(srcp1,srcp2,result);
224				break;
225		}
226		if (Is_inexacttrap_enabled()) {
227			*dstptr = result;
228			return(INEXACTEXCEPTION);
229		}
230		else Set_inexactflag();
231	}
232	*dstptr = result;
233	return(NOEXCEPTION);
234}
235
236/*
237 *  Double Unsigned Fixed to Double Floating-point
238 */
239
240int
241dbl_to_dbl_fcnvuf(
242		    dbl_unsigned *srcptr,
243		    unsigned int *nullptr,
244		    dbl_floating_point *dstptr,
245		    unsigned int *status)
246{
247	register int dst_exponent;
248	register unsigned int srcp1, srcp2, resultp1 = 0, resultp2 = 0;
249
250	Duint_copyfromptr(srcptr,srcp1,srcp2);
251
252	/* Check for zero */
253	if (srcp1 == 0 && srcp2 ==0) {
254	       	Dbl_setzero(resultp1,resultp2);
255	       	Dbl_copytoptr(resultp1,resultp2,dstptr);
256	       	return(NOEXCEPTION);
257	}
258	/*
259	 * Generate exponent and normalized mantissa
260	 */
261	dst_exponent = 16;    /* initialize for normalization */
262	if (srcp1 == 0) {
263		/*
264		 * Check word for most significant bit set.  Returns
265		 * a value in dst_exponent indicating the bit position,
266		 * between -1 and 30.
267		 */
268		Find_ms_one_bit(srcp2,dst_exponent);
269		/*  left justify source, with msb at bit position 0  */
270		srcp1 = srcp2 << dst_exponent+1;
271		srcp2 = 0;
272		/*
273		 *  since msb set is in second word, need to
274		 *  adjust bit position count
275		 */
276		dst_exponent += 32;
277	}
278	else {
279		/*
280		 * Check word for most significant bit set.  Returns
281		 * a value in dst_exponent indicating the bit position,
282		 * between -1 and 30.
283		 */
284		Find_ms_one_bit(srcp1,dst_exponent);
285		/*  left justify source, with msb at bit position 0  */
286		if (dst_exponent >= 0) {
287			Variable_shift_double(srcp1,srcp2,(31-dst_exponent),
288			 srcp1);
289			srcp2 <<= dst_exponent+1;
290		}
291	}
292	Dbl_set_mantissap1(resultp1, srcp1 >> DBL_EXP_LENGTH);
293	Shiftdouble(srcp1,srcp2,DBL_EXP_LENGTH,resultp2);
294	Dbl_set_exponent(resultp1, (62+DBL_BIAS) - dst_exponent);
295
296	/* check for inexact */
297	if (Duint_isinexact_to_dbl(srcp2)) {
298		switch (Rounding_mode()) {
299			case ROUNDPLUS:
300				Dbl_increment(resultp1,resultp2);
301				break;
302			case ROUNDMINUS: /* never negative */
303				break;
304			case ROUNDNEAREST:
305				Dbl_roundnearest_from_duint(srcp2,resultp1,
306				resultp2);
307				break;
308		}
309		if (Is_inexacttrap_enabled()) {
310			Dbl_copytoptr(resultp1,resultp2,dstptr);
311			return(INEXACTEXCEPTION);
312		}
313		else Set_inexactflag();
314	}
315	Dbl_copytoptr(resultp1,resultp2,dstptr);
316	return(NOEXCEPTION);
317}
318