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*/ |
44 | int |
45 | sgl_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*/ |
141 | int |
142 | sgl_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*/ |
262 | int |
263 | dbl_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*/ |
373 | int |
374 | dbl_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 | |