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*/ |
45 | int |
46 | sgl_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*/ |
166 | int |
167 | sgl_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*/ |
287 | int |
288 | dbl_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*/ |
410 | int |
411 | dbl_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 | |