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