blob: d6475bddb507dc95a17f8d8800c535078abf53da [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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*/
57int
58sgl_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*/
154int
155sgl_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*/
275int
276dbl_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*/
386int
387dbl_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}