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