Pull throttle into release branch
[linux-2.6] / arch / parisc / math-emu / fcnvfx.c
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/fcnvfx.c              $Revision: 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*/
57 int
58 sgl_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*/
154 int
155 sgl_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*/
275 int
276 dbl_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*/
386 int
387 dbl_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 }