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