1 /*
2 * UAE - The Un*x Amiga Emulator
3 *
4 * MC68881/68882/68040/68060 FPU emulation
5 * Softfloat version
6 *
7 * Andreas Grabher and Toni Wilen
8 *
9 */
10 #define __USE_ISOC9X /* We might be able to pick up a NaN */
11
12 #define SOFTFLOAT_FAST_INT64
13
14 #include <math.h>
15 #include <float.h>
16 #include <fenv.h>
17
18 #include "sysconfig.h"
19 #include "sysdeps.h"
20
21 #ifdef WINUAE_FOR_HATARI
22 #include "main.h"
23 #include "hatari-glue.h"
24 #endif
25
26 #include "options_cpu.h"
27 #include "memory.h"
28 #include "newcpu.h"
29 #include "fpp.h"
30 #include "newcpu.h"
31
32 #include "softfloat/softfloat-macros.h"
33 #include "softfloat/softfloat-specialize.h"
34
35 #define FPCR_ROUNDING_MODE 0x00000030
36 #define FPCR_ROUND_NEAR 0x00000000
37 #define FPCR_ROUND_ZERO 0x00000010
38 #define FPCR_ROUND_MINF 0x00000020
39 #define FPCR_ROUND_PINF 0x00000030
40
41 #define FPCR_ROUNDING_PRECISION 0x000000c0
42 #define FPCR_PRECISION_SINGLE 0x00000040
43 #define FPCR_PRECISION_DOUBLE 0x00000080
44 #define FPCR_PRECISION_EXTENDED 0x00000000
45
46 static struct float_status fs;
47
48 /* Functions for setting host/library modes and getting status */
fp_set_mode(uae_u32 mode_control)49 static void fp_set_mode(uae_u32 mode_control)
50 {
51 set_float_detect_tininess(float_tininess_before_rounding, &fs);
52
53 switch(mode_control & FPCR_ROUNDING_PRECISION) {
54 case FPCR_PRECISION_SINGLE: // single
55 set_floatx80_rounding_precision(32, &fs);
56 break;
57 default: // double
58 case FPCR_PRECISION_DOUBLE: // double
59 set_floatx80_rounding_precision(64, &fs);
60 break;
61 case FPCR_PRECISION_EXTENDED: // extended
62 set_floatx80_rounding_precision(80, &fs);
63 break;
64 }
65
66 switch(mode_control & FPCR_ROUNDING_MODE) {
67 case FPCR_ROUND_NEAR: // to neareset
68 set_float_rounding_mode(float_round_nearest_even, &fs);
69 break;
70 case FPCR_ROUND_ZERO: // to zero
71 set_float_rounding_mode(float_round_to_zero, &fs);
72 break;
73 case FPCR_ROUND_MINF: // to minus
74 set_float_rounding_mode(float_round_down, &fs);
75 break;
76 case FPCR_ROUND_PINF: // to plus
77 set_float_rounding_mode(float_round_up, &fs);
78 break;
79 }
80 }
81
fp_get_status(uae_u32 * status)82 static void fp_get_status(uae_u32 *status)
83 {
84 if (fs.float_exception_flags & float_flag_signaling)
85 *status |= FPSR_SNAN;
86 if (fs.float_exception_flags & float_flag_invalid)
87 *status |= FPSR_OPERR;
88 if (fs.float_exception_flags & float_flag_divbyzero)
89 *status |= FPSR_DZ;
90 if (fs.float_exception_flags & float_flag_overflow)
91 *status |= FPSR_OVFL;
92 if (fs.float_exception_flags & float_flag_underflow)
93 *status |= FPSR_UNFL;
94 if (fs.float_exception_flags & float_flag_inexact)
95 *status |= FPSR_INEX2;
96 if (fs.float_exception_flags & float_flag_decimal)
97 *status |= FPSR_INEX1;
98 }
99
fp_clear_status(void)100 STATIC_INLINE void fp_clear_status(void)
101 {
102 fs.float_exception_flags = 0;
103 }
104
fp_get_support_flags(void)105 static uae_u32 fp_get_support_flags(void)
106 {
107 return FPU_FEATURE_EXCEPTIONS | FPU_FEATURE_DENORMALS;
108 }
109
fp_printx80(floatx80 * fx,int mode)110 static const TCHAR *fp_printx80(floatx80 *fx, int mode)
111 {
112 static TCHAR fsout[32];
113 flag n, u, d;
114
115 if (mode < 0) {
116 _stprintf(fsout, _T("%04X-%08X-%08X"), fx->high, (uae_u32)(fx->low >> 32), (uae_u32)fx->low);
117 return fsout;
118 }
119
120 n = floatx80_is_negative(*fx);
121 u = floatx80_is_unnormal(*fx);
122 d = floatx80_is_denormal(*fx);
123
124 if (floatx80_is_infinity(*fx)) {
125 _stprintf(fsout, _T("%c%s"), n ? '-' : '+', _T("inf"));
126 } else if (floatx80_is_signaling_nan(*fx)) {
127 _stprintf(fsout, _T("%c%s"), n ? '-' : '+', _T("snan"));
128 } else if (floatx80_is_nan(*fx)) {
129 _stprintf(fsout, _T("%c%s"), n ? '-' : '+', _T("nan"));
130 } else {
131 int32_t len = 17;
132 int8_t save_exception_flags = fs.float_exception_flags;
133 fs.float_exception_flags = 0;
134 floatx80 x = floatx80_to_floatdecimal(*fx, &len, &fs);
135 _stprintf(fsout, _T("%c%01lld.%016llde%c%04d%s%s"), n ? '-' : '+',
136 x.low / LIT64(10000000000000000), x.low % LIT64(10000000000000000),
137 (x.high & 0x4000) ? '-' : '+', x.high & 0x3FFF, d ? _T("D") : u ? _T("U") : _T(""),
138 (fs.float_exception_flags & float_flag_inexact) ? _T("~") : _T(""));
139 fs.float_exception_flags = save_exception_flags;
140 }
141
142 if (mode == 0 || mode > _tcslen(fsout))
143 return fsout;
144 fsout[mode] = 0;
145 return fsout;
146 }
147
fp_print(fpdata * fpd,int mode)148 static const TCHAR *fp_print(fpdata *fpd, int mode)
149 {
150 return fp_printx80(&fpd->fpx, mode);
151 }
152
153 /* Functions for detecting float type */
fp_is_init(fpdata * fpd)154 static bool fp_is_init(fpdata *fpd)
155 {
156 return false;
157 }
fp_is_snan(fpdata * fpd)158 static bool fp_is_snan(fpdata *fpd)
159 {
160 return floatx80_is_signaling_nan(fpd->fpx) != 0;
161 }
fp_unset_snan(fpdata * fpd)162 static bool fp_unset_snan(fpdata *fpd)
163 {
164 fpd->fpx.low |= LIT64(0x4000000000000000);
165 return false;
166 }
fp_is_nan(fpdata * fpd)167 static bool fp_is_nan(fpdata *fpd)
168 {
169 return floatx80_is_any_nan(fpd->fpx) != 0;
170 }
fp_is_infinity(fpdata * fpd)171 static bool fp_is_infinity(fpdata *fpd)
172 {
173 return floatx80_is_infinity(fpd->fpx) != 0;
174 }
fp_fix_infinity(fpdata * fpd)175 static void fp_fix_infinity(fpdata *fpd)
176 {
177 fpd->fpx.low = 0;
178 }
fp_is_zero(fpdata * fpd)179 static bool fp_is_zero(fpdata *fpd)
180 {
181 return floatx80_is_zero(fpd->fpx) != 0;
182 }
fp_is_neg(fpdata * fpd)183 static bool fp_is_neg(fpdata *fpd)
184 {
185 return floatx80_is_negative(fpd->fpx) != 0;
186 }
fp_is_denormal(fpdata * fpd)187 static bool fp_is_denormal(fpdata *fpd)
188 {
189 return floatx80_is_denormal(fpd->fpx) != 0;
190 }
fp_is_unnormal(fpdata * fpd)191 static bool fp_is_unnormal(fpdata *fpd)
192 {
193 return floatx80_is_unnormal(fpd->fpx) != 0;
194 }
195
196
to_single(fpdata * fpd,uae_u32 wrd1)197 static void to_single(fpdata *fpd, uae_u32 wrd1)
198 {
199 float32 f = wrd1;
200 fpd->fpx = float32_to_floatx80_allowunnormal(f, &fs);
201 }
from_single(fpdata * fpd)202 static uae_u32 from_single(fpdata *fpd)
203 {
204 float32 f = floatx80_to_float32(fpd->fpx, &fs);
205 return f;
206 }
207
to_double(fpdata * fpd,uae_u32 wrd1,uae_u32 wrd2)208 static void to_double(fpdata *fpd, uae_u32 wrd1, uae_u32 wrd2)
209 {
210 float64 f = ((float64)wrd1 << 32) | wrd2;
211 fpd->fpx = float64_to_floatx80_allowunnormal(f, &fs);
212 }
from_double(fpdata * fpd,uae_u32 * wrd1,uae_u32 * wrd2)213 static void from_double(fpdata *fpd, uae_u32 *wrd1, uae_u32 *wrd2)
214 {
215 float64 f = floatx80_to_float64(fpd->fpx, &fs);
216 *wrd1 = f >> 32;
217 *wrd2 = (uae_u32)f;
218 }
219
to_exten(fpdata * fpd,uae_u32 wrd1,uae_u32 wrd2,uae_u32 wrd3)220 static void to_exten(fpdata *fpd, uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3)
221 {
222 fpd->fpx.high = (uae_u16)(wrd1 >> 16);
223 fpd->fpx.low = ((uae_u64)wrd2 << 32) | wrd3;
224 }
from_exten(fpdata * fpd,uae_u32 * wrd1,uae_u32 * wrd2,uae_u32 * wrd3)225 static void from_exten(fpdata *fpd, uae_u32 *wrd1, uae_u32 *wrd2, uae_u32 *wrd3)
226 {
227 floatx80 f = floatx80_to_floatx80(fpd->fpx, &fs);
228 *wrd1 = (uae_u32)(f.high << 16);
229 *wrd2 = f.low >> 32;
230 *wrd3 = (uae_u32)f.low;
231 }
232
to_exten_fmovem(fpdata * fpd,uae_u32 wrd1,uae_u32 wrd2,uae_u32 wrd3)233 static void to_exten_fmovem(fpdata *fpd, uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3)
234 {
235 fpd->fpx.high = (uae_u16)(wrd1 >> 16);
236 fpd->fpx.low = ((uae_u64)wrd2 << 32) | wrd3;
237 }
from_exten_fmovem(fpdata * fpd,uae_u32 * wrd1,uae_u32 * wrd2,uae_u32 * wrd3)238 static void from_exten_fmovem(fpdata *fpd, uae_u32 *wrd1, uae_u32 *wrd2, uae_u32 *wrd3)
239 {
240 *wrd1 = (uae_u32)(fpd->fpx.high << 16);
241 *wrd2 = fpd->fpx.low >> 32;
242 *wrd3 = (uae_u32)fpd->fpx.low;
243 }
244
to_int(fpdata * src,int size)245 static uae_s64 to_int(fpdata *src, int size)
246 {
247 switch (size) {
248 case 0: return floatx80_to_int8(src->fpx, &fs);
249 case 1: return floatx80_to_int16(src->fpx, &fs);
250 case 2: return floatx80_to_int32(src->fpx, &fs);
251 default: return 0;
252 }
253 }
from_int(fpdata * fpd,uae_s32 src)254 static void from_int(fpdata *fpd, uae_s32 src)
255 {
256 fpd->fpx = int32_to_floatx80(src);
257 }
258
259 /* Functions for returning exception state data */
fp_get_internal_overflow(fpdata * fpd)260 static void fp_get_internal_overflow(fpdata *fpd)
261 {
262 fpd->fpx = getFloatInternalOverflow();
263 }
fp_get_internal_underflow(fpdata * fpd)264 static void fp_get_internal_underflow(fpdata *fpd)
265 {
266 fpd->fpx = getFloatInternalUnderflow();
267 }
fp_get_internal_round_all(fpdata * fpd)268 static void fp_get_internal_round_all(fpdata *fpd)
269 {
270 fpd->fpx = getFloatInternalRoundedAll();
271 }
fp_get_internal_round(fpdata * fpd)272 static void fp_get_internal_round(fpdata *fpd)
273 {
274 fpd->fpx = getFloatInternalRoundedSome();
275 }
fp_get_internal_round_exten(fpdata * fpd)276 static void fp_get_internal_round_exten(fpdata *fpd)
277 {
278 fpd->fpx = getFloatInternalFloatx80();
279 }
fp_get_internal(fpdata * fpd)280 static void fp_get_internal(fpdata *fpd)
281 {
282 fpd->fpx = getFloatInternalUnrounded();
283 }
fp_get_internal_grs(void)284 static uae_u32 fp_get_internal_grs(void)
285 {
286 return (uae_u32)getFloatInternalGRS();
287 }
288 /* Function for denormalizing */
fp_denormalize(fpdata * fpd,int esign)289 static void fp_denormalize(fpdata *fpd, int esign)
290 {
291 fpd->fpx = floatx80_denormalize(fpd->fpx, esign);
292 }
293
294 /* Functions for rounding */
295
296 // round to float with extended precision exponent
fp_round32(fpdata * fpd)297 static void fp_round32(fpdata *fpd)
298 {
299 fpd->fpx = floatx80_round32(fpd->fpx, &fs);
300 }
301
302 // round to double with extended precision exponent
fp_round64(fpdata * fpd)303 static void fp_round64(fpdata *fpd)
304 {
305 fpd->fpx = floatx80_round64(fpd->fpx, &fs);
306 }
307
308 // round to float
fp_round_single(fpdata * fpd)309 static void fp_round_single(fpdata *fpd)
310 {
311 fpd->fpx = floatx80_round_to_float32(fpd->fpx, &fs);
312 }
313
314 // round to double
fp_round_double(fpdata * fpd)315 static void fp_round_double(fpdata *fpd)
316 {
317 fpd->fpx = floatx80_round_to_float64(fpd->fpx, &fs);
318 }
319
320 #if 0
321 // round to selected precision
322 static void fp_round(fpdata *a)
323 {
324 switch(fs.floatx80_rounding_precision) {
325 case 32:
326 a->fpx = floatx80_round_to_float32(a->fpx, &fs);
327 break;
328 case 64:
329 a->fpx = floatx80_round_to_float64(a->fpx, &fs);
330 break;
331 default:
332 break;
333 }
334 }
335 #endif
336
337 /* Arithmetic functions */
338
fp_int(fpdata * a,fpdata * b)339 static void fp_int(fpdata *a, fpdata *b)
340 {
341 a->fpx = floatx80_round_to_int(b->fpx, &fs);
342 }
343
fp_intrz(fpdata * a,fpdata * b)344 static void fp_intrz(fpdata *a, fpdata *b)
345 {
346 a->fpx = floatx80_round_to_int_toward_zero(b->fpx, &fs);
347 }
348
fp_getexp(fpdata * a,fpdata * b)349 static void fp_getexp(fpdata *a, fpdata *b)
350 {
351 a->fpx = floatx80_getexp(b->fpx, &fs);
352 }
fp_getman(fpdata * a,fpdata * b)353 static void fp_getman(fpdata *a, fpdata *b)
354 {
355 a->fpx = floatx80_getman(b->fpx, &fs);
356 }
fp_mod(fpdata * a,fpdata * b,uae_u64 * q,uae_u8 * s)357 static void fp_mod(fpdata *a, fpdata *b, uae_u64 *q, uae_u8 *s)
358 {
359 #ifndef WINUAE_FOR_HATARI
360 a->fpx = floatx80_mod(a->fpx, b->fpx, q, s, &fs);
361 #else
362 a->fpx = floatx80_mod(a->fpx, b->fpx, (uint64_t *)q, s, &fs);
363 #endif
364 }
fp_sgldiv(fpdata * a,fpdata * b)365 static void fp_sgldiv(fpdata *a, fpdata *b)
366 {
367 a->fpx = floatx80_sgldiv(a->fpx, b->fpx, &fs);
368 }
fp_sglmul(fpdata * a,fpdata * b)369 static void fp_sglmul(fpdata *a, fpdata *b)
370 {
371 a->fpx = floatx80_sglmul(a->fpx, b->fpx, &fs);
372 }
fp_rem(fpdata * a,fpdata * b,uae_u64 * q,uae_u8 * s)373 static void fp_rem(fpdata *a, fpdata *b, uae_u64 *q, uae_u8 *s)
374 {
375 #ifndef WINUAE_FOR_HATARI
376 a->fpx = floatx80_rem(a->fpx, b->fpx, q, s, &fs);
377 #else
378 a->fpx = floatx80_rem(a->fpx, b->fpx, (uint64_t *)q, s, &fs);
379 #endif
380 }
fp_scale(fpdata * a,fpdata * b)381 static void fp_scale(fpdata *a, fpdata *b)
382 {
383 a->fpx = floatx80_scale(a->fpx, b->fpx, &fs);
384 }
fp_cmp(fpdata * a,fpdata * b)385 static void fp_cmp(fpdata *a, fpdata *b)
386 {
387 a->fpx = floatx80_cmp(a->fpx, b->fpx, &fs);
388 }
fp_tst(fpdata * a,fpdata * b)389 static void fp_tst(fpdata *a, fpdata *b)
390 {
391 a->fpx = floatx80_tst(b->fpx, &fs);
392 }
393
394 static const uint8_t prectable[] = { 0, 32, 64, 80 };
395
396 #define SETPREC \
397 uint8_t oldprec = fs.floatx80_rounding_precision; \
398 if (prec > PREC_NORMAL) \
399 set_floatx80_rounding_precision(prectable[prec], &fs);
400
401 #define RESETPREC \
402 set_floatx80_rounding_precision(oldprec, &fs);
403
404 /* Functions with fixed precision */
fp_move(fpdata * a,fpdata * b,int prec)405 static void fp_move(fpdata *a, fpdata *b, int prec)
406 {
407 SETPREC
408 a->fpx = floatx80_move(b->fpx, &fs);
409 RESETPREC
410 }
fp_abs(fpdata * a,fpdata * b,int prec)411 static void fp_abs(fpdata *a, fpdata *b, int prec)
412 {
413 SETPREC
414 a->fpx = floatx80_abs(b->fpx, &fs);
415 RESETPREC
416 }
fp_neg(fpdata * a,fpdata * b,int prec)417 static void fp_neg(fpdata *a, fpdata *b, int prec)
418 {
419 SETPREC
420 a->fpx = floatx80_neg(b->fpx, &fs);
421 RESETPREC
422 }
fp_add(fpdata * a,fpdata * b,int prec)423 static void fp_add(fpdata *a, fpdata *b, int prec)
424 {
425 SETPREC
426 a->fpx = floatx80_add(a->fpx, b->fpx, &fs);
427 RESETPREC
428 }
fp_sub(fpdata * a,fpdata * b,int prec)429 static void fp_sub(fpdata *a, fpdata *b, int prec)
430 {
431 SETPREC
432 a->fpx = floatx80_sub(a->fpx, b->fpx, &fs);
433 RESETPREC
434 }
fp_mul(fpdata * a,fpdata * b,int prec)435 static void fp_mul(fpdata *a, fpdata *b, int prec)
436 {
437 SETPREC
438 a->fpx = floatx80_mul(a->fpx, b->fpx, &fs);
439 RESETPREC
440 }
fp_div(fpdata * a,fpdata * b,int prec)441 static void fp_div(fpdata *a, fpdata *b, int prec)
442 {
443 SETPREC
444 a->fpx = floatx80_div(a->fpx, b->fpx, &fs);
445 RESETPREC
446 }
fp_sqrt(fpdata * a,fpdata * b,int prec)447 static void fp_sqrt(fpdata *a, fpdata *b, int prec)
448 {
449 SETPREC
450 a->fpx = floatx80_sqrt(b->fpx, &fs);
451 RESETPREC
452 }
453
454
fp_sinh(fpdata * a,fpdata * b)455 static void fp_sinh(fpdata *a, fpdata *b)
456 {
457 a->fpx = floatx80_sinh(b->fpx, &fs);
458 }
fp_lognp1(fpdata * a,fpdata * b)459 static void fp_lognp1(fpdata *a, fpdata *b)
460 {
461 a->fpx = floatx80_lognp1(b->fpx, &fs);
462 }
fp_etoxm1(fpdata * a,fpdata * b)463 static void fp_etoxm1(fpdata *a, fpdata *b)
464 {
465 a->fpx = floatx80_etoxm1(b->fpx, &fs);
466 }
fp_tanh(fpdata * a,fpdata * b)467 static void fp_tanh(fpdata *a, fpdata *b)
468 {
469 a->fpx = floatx80_tanh(b->fpx, &fs);
470 }
fp_atan(fpdata * a,fpdata * b)471 static void fp_atan(fpdata *a, fpdata *b)
472 {
473 a->fpx = floatx80_atan(b->fpx, &fs);
474 }
fp_asin(fpdata * a,fpdata * b)475 static void fp_asin(fpdata *a, fpdata *b)
476 {
477 a->fpx = floatx80_asin(b->fpx, &fs);
478 }
fp_atanh(fpdata * a,fpdata * b)479 static void fp_atanh(fpdata *a, fpdata *b)
480 {
481 a->fpx = floatx80_atanh(b->fpx, &fs);
482 }
fp_sin(fpdata * a,fpdata * b)483 static void fp_sin(fpdata *a, fpdata *b)
484 {
485 a->fpx = floatx80_sin(b->fpx, &fs);
486 }
fp_tan(fpdata * a,fpdata * b)487 static void fp_tan(fpdata *a, fpdata *b)
488 {
489 a->fpx = floatx80_tan(b->fpx, &fs);
490 }
fp_etox(fpdata * a,fpdata * b)491 static void fp_etox(fpdata *a, fpdata *b)
492 {
493 a->fpx = floatx80_etox(b->fpx, &fs);
494 }
fp_twotox(fpdata * a,fpdata * b)495 static void fp_twotox(fpdata *a, fpdata *b)
496 {
497 a->fpx = floatx80_twotox(b->fpx, &fs);
498 }
fp_tentox(fpdata * a,fpdata * b)499 static void fp_tentox(fpdata *a, fpdata *b)
500 {
501 a->fpx = floatx80_tentox(b->fpx, &fs);
502 }
fp_logn(fpdata * a,fpdata * b)503 static void fp_logn(fpdata *a, fpdata *b)
504 {
505 a->fpx = floatx80_logn(b->fpx, &fs);
506 }
fp_log10(fpdata * a,fpdata * b)507 static void fp_log10(fpdata *a, fpdata *b)
508 {
509 a->fpx = floatx80_log10(b->fpx, &fs);
510 }
fp_log2(fpdata * a,fpdata * b)511 static void fp_log2(fpdata *a, fpdata *b)
512 {
513 a->fpx = floatx80_log2(b->fpx, &fs);
514 }
fp_cosh(fpdata * a,fpdata * b)515 static void fp_cosh(fpdata *a, fpdata *b)
516 {
517 a->fpx = floatx80_cosh(b->fpx, &fs);
518 }
fp_acos(fpdata * a,fpdata * b)519 static void fp_acos(fpdata *a, fpdata *b)
520 {
521 a->fpx = floatx80_acos(b->fpx, &fs);
522 }
fp_cos(fpdata * a,fpdata * b)523 static void fp_cos(fpdata *a, fpdata *b)
524 {
525 a->fpx = floatx80_cos(b->fpx, &fs);
526 }
527
528 /* Functions for converting between float formats */
529 static const fptype twoto32 = 4294967296.0;
530
to_native(fptype * fp,fpdata * fpd)531 static void to_native(fptype *fp, fpdata *fpd)
532 {
533 int expon;
534 fptype frac;
535
536 expon = fpd->fpx.high & 0x7fff;
537
538 fp_is_init(fpd);
539 if (fp_is_zero(fpd)) {
540 *fp = fp_is_neg(fpd) ? -0.0 : +0.0;
541 return;
542 }
543 if (fp_is_nan(fpd)) {
544 #ifdef USE_LONG_DOUBLE
545 *fp = sqrtl(-1);
546 #else
547 *fp = sqrt(-1);
548 #endif
549 return;
550 }
551 if (fp_is_infinity(fpd)) {
552 double zero = 0.0;
553 #ifdef USE_LONG_DOUBLE
554 *fp = fp_is_neg(fpd) ? logl(0.0) : (1.0 / zero);
555 #else
556 *fp = fp_is_neg(fpd) ? log(0.0) : (1.0 / zero);
557 #endif
558 return;
559 }
560
561 frac = (fptype)fpd->fpx.low / (fptype)(twoto32 * 2147483648.0);
562 if (fp_is_neg(fpd))
563 frac = -frac;
564 #ifdef USE_LONG_DOUBLE
565 *fp = ldexpl (frac, expon - 16383);
566 #else
567 *fp = ldexp (frac, expon - 16383);
568 #endif
569 }
570
from_native(fptype fp,fpdata * fpd)571 static void from_native(fptype fp, fpdata *fpd)
572 {
573 int expon;
574 fptype frac;
575
576 if (signbit(fp))
577 fpd->fpx.high = 0x8000;
578 else
579 fpd->fpx.high = 0x0000;
580
581 if (isnan(fp)) {
582 fpd->fpx.high |= 0x7fff;
583 fpd->fpx.low = LIT64(0xffffffffffffffff);
584 return;
585 }
586 if (isinf(fp)) {
587 fpd->fpx.high |= 0x7fff;
588 fpd->fpx.low = LIT64(0x0000000000000000);
589 return;
590 }
591 if (fp == 0.0) {
592 fpd->fpx.low = LIT64(0x0000000000000000);
593 return;
594 }
595 if (fp < 0.0)
596 fp = -fp;
597
598 #ifdef USE_LONG_DOUBLE
599 frac = frexpl (fp, &expon);
600 #else
601 frac = frexp (fp, &expon);
602 #endif
603 frac += 0.5 / (twoto32 * twoto32);
604 if (frac >= 1.0) {
605 frac /= 2.0;
606 expon++;
607 }
608 fpd->fpx.high |= (expon + 16383 - 1) & 0x7fff;
609 fpd->fpx.low = (uint64_t)(frac * (fptype)(twoto32 * twoto32));
610
611 while (!(fpd->fpx.low & LIT64( 0x8000000000000000))) {
612 if (fpd->fpx.high == 0) {
613 break;
614 }
615 fpd->fpx.low <<= 1;
616 fpd->fpx.high--;
617 }
618 }
619
fp_normalize(fpdata * a)620 static void fp_normalize(fpdata *a)
621 {
622 a->fpx = floatx80_normalize(a->fpx);
623 }
624
fp_to_pack(fpdata * fp,uae_u32 * wrd,int dummy)625 static void fp_to_pack(fpdata *fp, uae_u32 *wrd, int dummy)
626 {
627 floatx80 f;
628 int i;
629 uae_s32 exp;
630 uae_s64 mant;
631 uae_u32 pack_exp, pack_int, pack_se, pack_sm;
632 uae_u64 pack_frac;
633
634 if (((wrd[0] >> 16) & 0x7fff) == 0x7fff) {
635 // infinity has extended exponent and all 0 packed fraction
636 // nans are copies bit by bit
637 fpp_to_exten(fp, wrd[0], wrd[1], wrd[2]);
638 return;
639 }
640 if (!(wrd[0] & 0xf) && !wrd[1] && !wrd[2]) {
641 // exponent is not cared about, if mantissa is zero
642 wrd[0] &= 0x80000000;
643 fpp_to_exten(fp, wrd[0], wrd[1], wrd[2]);
644 return;
645 }
646
647 pack_exp = (wrd[0] >> 16) & 0xFFF; // packed exponent
648 pack_int = wrd[0] & 0xF; // packed integer part
649 pack_frac = ((uae_u64)wrd[1] << 32) | wrd[2]; // packed fraction
650 pack_se = (wrd[0] >> 30) & 1; // sign of packed exponent
651 pack_sm = (wrd[0] >> 31) & 1; // sign of packed significand
652 exp = 0;
653
654 for (i = 0; i < 3; i++) {
655 exp *= 10;
656 exp += (pack_exp >> (8 - i * 4)) & 0xF;
657 }
658
659 if (pack_se) {
660 exp = -exp;
661 }
662
663 exp -= 16;
664
665 if (exp < 0) {
666 exp = -exp;
667 pack_se = 1;
668 }
669
670 mant = pack_int;
671
672 for (i = 0; i < 16; i++) {
673 mant *= 10;
674 mant += (pack_frac >> (60 - i * 4)) & 0xF;
675 }
676
677 f.high = exp & 0x3FFF;
678 f.high |= pack_se ? 0x4000 : 0;
679 f.high |= pack_sm ? 0x8000 : 0;
680 f.low = mant;
681
682 fp->fpx = floatdecimal_to_floatx80(f, &fs);
683 }
684
685
fp_from_pack(fpdata * fp,uae_u32 * wrd,int kfactor)686 static void fp_from_pack(fpdata *fp, uae_u32 *wrd, int kfactor)
687 {
688 floatx80 f = floatx80_to_floatdecimal(fp->fpx, &kfactor, &fs);
689
690 uae_u32 pack_exp, pack_exp4, pack_int, pack_se, pack_sm;
691 uae_u64 pack_frac;
692
693 uae_u32 exponent;
694 uae_u64 significand;
695
696 uae_s32 len;
697 uae_u64 digit;
698
699 if ((f.high & 0x7FFF) == 0x7FFF) {
700 wrd[0] = (uae_u32)(f.high << 16);
701 wrd[1] = f.low >> 32;
702 wrd[2] = (uae_u32)f.low;
703 } else {
704 exponent = f.high & 0x3FFF;
705 significand = f.low;
706
707 pack_int = 0;
708 pack_frac = 0;
709 len = kfactor; // SoftFloat saved len to kfactor variable
710 while (len > 0) {
711 len--;
712 digit = significand % 10;
713 significand /= 10;
714 if (len == 0) {
715 pack_int = digit;
716 } else {
717 pack_frac |= digit << (64 - len * 4);
718 }
719 }
720
721 pack_exp = 0;
722 pack_exp4 = 0;
723 len = 4;
724 while (len > 0) {
725 len--;
726 digit = exponent % 10;
727 exponent /= 10;
728 if (len == 0) {
729 pack_exp4 = digit;
730 } else {
731 pack_exp |= digit << (12 - len * 4);
732 }
733 }
734
735 pack_se = f.high & 0x4000;
736 pack_sm = f.high & 0x8000;
737
738 wrd[0] = pack_exp << 16;
739 wrd[0] |= pack_exp4 << 12;
740 wrd[0] |= pack_int;
741 wrd[0] |= pack_se ? 0x40000000 : 0;
742 wrd[0] |= pack_sm ? 0x80000000 : 0;
743
744 wrd[1] = pack_frac >> 32;
745 wrd[2] = pack_frac & 0xffffffff;
746 }
747 }
748
fp_init_softfloat(int fpu_model)749 void fp_init_softfloat(int fpu_model)
750 {
751 if (fpu_model == 68040) {
752 set_special_flags(cmp_signed_nan, &fs);
753 } else if (fpu_model == 68060) {
754 set_special_flags(infinity_clear_intbit, &fs);
755 } else {
756 set_special_flags(addsub_swap_inf, &fs);
757 }
758
759 fpp_print = fp_print;
760 fpp_unset_snan = fp_unset_snan;
761
762 fpp_is_init = fp_is_init;
763 fpp_is_snan = fp_is_snan;
764 fpp_is_nan = fp_is_nan;
765 fpp_is_infinity = fp_is_infinity;
766 fpp_is_zero = fp_is_zero;
767 fpp_is_neg = fp_is_neg;
768 fpp_is_denormal = fp_is_denormal;
769 fpp_is_unnormal = fp_is_unnormal;
770 fpp_fix_infinity = fp_fix_infinity;
771
772 fpp_get_status = fp_get_status;
773 fpp_clear_status = fp_clear_status;
774 fpp_set_mode = fp_set_mode;
775 fpp_get_support_flags = fp_get_support_flags;
776
777 fpp_to_int = to_int;
778 fpp_from_int = from_int;
779
780 fpp_to_pack = fp_to_pack;
781 fpp_from_pack = fp_from_pack;
782
783 fpp_to_single = to_single;
784 fpp_from_single = from_single;
785 fpp_to_double = to_double;
786 fpp_from_double = from_double;
787 fpp_to_exten = to_exten;
788 fpp_from_exten = from_exten;
789 fpp_to_exten_fmovem = to_exten_fmovem;
790 fpp_from_exten_fmovem = from_exten_fmovem;
791
792 fpp_round_single = fp_round_single;
793 fpp_round_double = fp_round_double;
794 fpp_round32 = fp_round32;
795 fpp_round64 = fp_round64;
796
797 fpp_normalize = fp_normalize;
798 fpp_denormalize = fp_denormalize;
799 fpp_get_internal_overflow = fp_get_internal_overflow;
800 fpp_get_internal_underflow = fp_get_internal_underflow;
801 fpp_get_internal_round_all = fp_get_internal_round_all;
802 fpp_get_internal_round = fp_get_internal_round;
803 fpp_get_internal_round_exten = fp_get_internal_round_exten;
804 fpp_get_internal = fp_get_internal;
805 fpp_get_internal_grs = fp_get_internal_grs;
806
807 fpp_int = fp_int;
808 fpp_sinh = fp_sinh;
809 fpp_intrz = fp_intrz;
810 fpp_sqrt = fp_sqrt;
811 fpp_lognp1 = fp_lognp1;
812 fpp_etoxm1 = fp_etoxm1;
813 fpp_tanh = fp_tanh;
814 fpp_atan = fp_atan;
815 fpp_atanh = fp_atanh;
816 fpp_sin = fp_sin;
817 fpp_asin = fp_asin;
818 fpp_tan = fp_tan;
819 fpp_etox = fp_etox;
820 fpp_twotox = fp_twotox;
821 fpp_tentox = fp_tentox;
822 fpp_logn = fp_logn;
823 fpp_log10 = fp_log10;
824 fpp_log2 = fp_log2;
825 fpp_abs = fp_abs;
826 fpp_cosh = fp_cosh;
827 fpp_neg = fp_neg;
828 fpp_acos = fp_acos;
829 fpp_cos = fp_cos;
830 fpp_getexp = fp_getexp;
831 fpp_getman = fp_getman;
832 fpp_div = fp_div;
833 fpp_mod = fp_mod;
834 fpp_add = fp_add;
835 fpp_mul = fp_mul;
836 fpp_rem = fp_rem;
837 fpp_scale = fp_scale;
838 fpp_sub = fp_sub;
839 fpp_sgldiv = fp_sgldiv;
840 fpp_sglmul = fp_sglmul;
841 fpp_cmp = fp_cmp;
842 fpp_tst = fp_tst;
843 fpp_move = fp_move;
844 }
845
846