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