1 /* fpu.c --- FPU emulator for stand-alone RX simulator.
3 Copyright (C) 2008-2024 Free Software Foundation, Inc.
4 Contributed by Red Hat, Inc.
6 This file is part of the GNU simulators.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 /* This must come before any other includes. */
30 /* FPU encodings are as follows:
33 1 12345678 12345678901234567890123
35 0 00000000 00000000000000000000000 +0
36 1 00000000 00000000000000000000000 -0
38 X 00000000 00000000000000000000001 Denormals
39 X 00000000 11111111111111111111111
41 X 00000001 XXXXXXXXXXXXXXXXXXXXXXX Normals
42 X 11111110 XXXXXXXXXXXXXXXXXXXXXXX
44 0 11111111 00000000000000000000000 +Inf
45 1 11111111 00000000000000000000000 -Inf
47 X 11111111 0XXXXXXXXXXXXXXXXXXXXXX SNaN (X != 0)
48 X 11111111 1XXXXXXXXXXXXXXXXXXXXXX QNaN (X != 0)
53 #define tprintf if (trace) printf
55 /* Some magic numbers. */
56 #define PLUS_MAX 0x7f7fffffUL
57 #define MINUS_MAX 0xff7fffffUL
58 #define PLUS_INF 0x7f800000UL
59 #define MINUS_INF 0xff800000UL
60 #define PLUS_ZERO 0x00000000UL
61 #define MINUS_ZERO 0x80000000UL
63 #define FP_RAISE(e) fp_raise(FPSWBITS_C##e)
68 if (mask
!= FPSWBITS_CE
)
70 if (regs
.r_fpsw
& (mask
<< FPSW_CESH
))
71 regs
.r_fpsw
|= (mask
<< FPSW_CFSH
);
72 if (regs
.r_fpsw
& FPSWBITS_FMASK
)
73 regs
.r_fpsw
|= FPSWBITS_FSUM
;
75 regs
.r_fpsw
&= ~FPSWBITS_FSUM
;
79 /* We classify all numbers as one of these. They correspond to the
80 rows/colums in the exception tables. */
93 static const char *fpt_names
[] = {
94 "Normal", "+0", "-0", "+Inf", "-Inf", "Denormal", "QNaN", "SNaN"
102 #define MANT_BIAS 0x00080000UL
106 unsigned int mant
; /* 24 bits */
113 fp_explode (fp_t f
, FP_Parts
*p
)
117 exp
= ((f
& 0x7f800000UL
) >> 23);
118 mant
= f
& 0x007fffffUL
;
119 sign
= f
& 0x80000000UL
;
120 /*printf("explode: %08x %x %2x %6x\n", f, sign, exp, mant);*/
122 p
->sign
= sign
? -1 : 1;
123 p
->exp
= exp
- EXP_BIAS
;
125 p
->mant
= mant
| 0x00800000UL
;
127 if (p
->exp
== EXP_ZERO
)
129 if (regs
.r_fpsw
& FPSWBITS_DN
)
132 p
->type
= FP_DENORMAL
;
136 p
->type
= sign
? FP_NZERO
: FP_PZERO
;
139 else if (p
->exp
== EXP_INF
)
142 p
->type
= sign
? FP_NINFINITY
: FP_PINFINITY
;
143 else if (mant
& 0x00400000UL
)
153 fp_implode (FP_Parts
*p
)
157 exp
= p
->exp
+ EXP_BIAS
;
159 /*printf("implode: exp %d mant 0x%x\n", exp, mant);*/
160 if (p
->type
== FP_NORMAL
)
164 && mant
< 0x00800000UL
)
169 while (mant
> 0x00ffffffUL
)
189 mant
&= 0x007fffffUL
;
193 mant
|= 0x80000000UL
;
199 unsigned long long ll
;
203 static int checked_format
= 0;
205 /* We assume a double format like this:
210 fp_to_double (FP_Parts
*p
)
217 if (u
.ll
!= 0x3ff8000000000000ULL
)
220 if (u
.ll
!= 0xc06c200000000000ULL
)
223 if (u
.ll
!= 0x4024333333333333ULL
)
230 u
.ll
|= (1ULL << 63);
231 /* Make sure a zero encoding stays a zero. */
232 if (p
->exp
!= -EXP_BIAS
)
233 u
.ll
|= ((unsigned long long)p
->exp
+ 1023ULL) << 52;
234 u
.ll
|= (unsigned long long) (p
->mant
& 0x007fffffUL
) << (52 - 23);
239 double_to_fp (double d
, FP_Parts
*p
)
247 sign
= (u
.ll
& 0x8000000000000000ULL
) ? 1 : 0;
253 /* A generated denormal should show up as an underflow, not
256 fp_explode (MINUS_ZERO
, p
);
258 fp_explode (PLUS_ZERO
, p
);
263 if ((exp
+ EXP_BIAS
) > 254)
266 switch (regs
.r_fpsw
& FPSWBITS_RM
)
270 fp_explode (MINUS_INF
, p
);
272 fp_explode (PLUS_INF
, p
);
276 fp_explode (MINUS_MAX
, p
);
278 fp_explode (PLUS_MAX
, p
);
282 fp_explode (MINUS_MAX
, p
);
284 fp_explode (PLUS_INF
, p
);
288 fp_explode (MINUS_INF
, p
);
290 fp_explode (PLUS_MAX
, p
);
295 if ((exp
+ EXP_BIAS
) < 1)
298 fp_explode (MINUS_ZERO
, p
);
300 fp_explode (PLUS_ZERO
, p
);
304 p
->sign
= sign
? -1 : 1;
306 p
->mant
= u
.ll
>> (52-23) & 0x007fffffUL
;
307 p
->mant
|= 0x00800000UL
;
310 if (u
.ll
& 0x1fffffffULL
)
312 switch (regs
.r_fpsw
& FPSWBITS_RM
)
315 if (u
.ll
& 0x10000000ULL
)
335 eNR
, /* Use the normal result. */
336 ePZ
, eNZ
, /* +- zero */
337 eSZ
, /* signed zero - XOR signs of ops together. */
338 eRZ
, /* +- zero depending on rounding mode. */
339 ePI
, eNI
, /* +- Infinity */
340 eSI
, /* signed infinity - XOR signs of ops together. */
341 eQN
, eSN
, /* Quiet/Signalling NANs */
343 eUn
, /* Unimplemented. */
344 eDZ
, /* Divide-by-zero. */
346 eGT
, /* greater than */
351 static const char *ex_names
[] = {
352 "NR", "PZ", "NZ", "SZ", "RZ", "PI", "NI", "SI", "QN", "SN", "IN", "Un", "DZ", "LT", "GT", "EQ"
356 /* This checks for all exceptional cases (not all FP exceptions) and
357 returns TRUE if it is providing the result in *c. If it returns
358 FALSE, the caller should do the "normal" operation. */
360 check_exceptions (FP_Parts
*a
, FP_Parts
*b
, fp_t
*c
,
361 FP_ExceptionCases ex_tab
[5][5],
362 FP_ExceptionCases
*case_ret
)
364 FP_ExceptionCases fpec
;
366 if (a
->type
== FP_SNAN
367 || b
->type
== FP_SNAN
)
369 else if (a
->type
== FP_QNAN
370 || b
->type
== FP_QNAN
)
372 else if (a
->type
== FP_DENORMAL
373 || b
->type
== FP_DENORMAL
)
376 fpec
= ex_tab
[(int)(a
->type
)][(int)(b
->type
)];
378 /*printf("%s %s -> %s\n", fpt_names[(int)(a->type)], fpt_names[(int)(b->type)], ex_names[(int)(fpec)]);*/
385 case eNR
: /* Use the normal result. */
388 case ePZ
: /* + zero */
392 case eNZ
: /* - zero */
396 case eSZ
: /* signed zero */
397 *c
= (a
->sign
== b
->sign
) ? PLUS_ZERO
: MINUS_ZERO
;
400 case eRZ
: /* +- zero depending on rounding mode. */
401 if ((regs
.r_fpsw
& FPSWBITS_RM
) == FPRM_NINF
)
407 case ePI
: /* + Infinity */
411 case eNI
: /* - Infinity */
415 case eSI
: /* sign Infinity */
416 *c
= (a
->sign
== b
->sign
) ? PLUS_INF
: MINUS_INF
;
419 case eQN
: /* Quiet NANs */
420 if (a
->type
== FP_QNAN
)
426 case eSN
: /* Signalling NANs */
427 if (a
->type
== FP_SNAN
)
434 case eIn
: /* Invalid. */
436 if (a
->type
== FP_SNAN
)
437 *c
= a
->orig_value
| 0x00400000;
438 else if (b
->type
== FP_SNAN
)
439 *c
= b
->orig_value
| 0x00400000;
444 case eUn
: /* Unimplemented. */
448 case eDZ
: /* Division-by-zero. */
449 *c
= (a
->sign
== b
->sign
) ? PLUS_INF
: MINUS_INF
;
458 #define CHECK_EXCEPTIONS(FPPa, FPPb, fpc, ex_tab) \
459 if (check_exceptions (&FPPa, &FPPb, &fpc, ex_tab, 0)) \
462 /* For each operation, we have two tables of how nonnormal cases are
463 handled. The DN=0 case is first, followed by the DN=1 case, with
464 each table using the following layout: */
466 static FP_ExceptionCases ex_add_tab
[5][5] = {
467 /* N +0 -0 +In -In */
468 { eNR
, eNR
, eNR
, ePI
, eNI
}, /* Normal */
469 { eNR
, ePZ
, eRZ
, ePI
, eNI
}, /* +0 */
470 { eNR
, eRZ
, eNZ
, ePI
, eNI
}, /* -0 */
471 { ePI
, ePI
, ePI
, ePI
, eIn
}, /* +Inf */
472 { eNI
, eNI
, eNI
, eIn
, eNI
}, /* -Inf */
476 rxfp_add (fp_t fa
, fp_t fb
)
484 CHECK_EXCEPTIONS (a
, b
, rv
, ex_add_tab
);
486 da
= fp_to_double (&a
);
487 db
= fp_to_double (&b
);
488 tprintf("%g + %g = %g\n", da
, db
, da
+db
);
490 double_to_fp (da
+db
, &c
);
491 rv
= fp_implode (&c
);
495 static FP_ExceptionCases ex_sub_tab
[5][5] = {
496 /* N +0 -0 +In -In */
497 { eNR
, eNR
, eNR
, eNI
, ePI
}, /* Normal */
498 { eNR
, eRZ
, ePZ
, eNI
, ePI
}, /* +0 */
499 { eNR
, eNZ
, eRZ
, eNI
, ePI
}, /* -0 */
500 { ePI
, ePI
, ePI
, eIn
, ePI
}, /* +Inf */
501 { eNI
, eNI
, eNI
, eNI
, eIn
}, /* -Inf */
505 rxfp_sub (fp_t fa
, fp_t fb
)
513 CHECK_EXCEPTIONS (a
, b
, rv
, ex_sub_tab
);
515 da
= fp_to_double (&a
);
516 db
= fp_to_double (&b
);
517 tprintf("%g - %g = %g\n", da
, db
, da
-db
);
519 double_to_fp (da
-db
, &c
);
520 rv
= fp_implode (&c
);
525 static FP_ExceptionCases ex_mul_tab
[5][5] = {
526 /* N +0 -0 +In -In */
527 { eNR
, eNR
, eNR
, eSI
, eSI
}, /* Normal */
528 { eNR
, ePZ
, eNZ
, eIn
, eIn
}, /* +0 */
529 { eNR
, eNZ
, ePZ
, eIn
, eIn
}, /* -0 */
530 { eSI
, eIn
, eIn
, ePI
, eNI
}, /* +Inf */
531 { eSI
, eIn
, eIn
, eNI
, ePI
}, /* -Inf */
535 rxfp_mul (fp_t fa
, fp_t fb
)
543 CHECK_EXCEPTIONS (a
, b
, rv
, ex_mul_tab
);
545 da
= fp_to_double (&a
);
546 db
= fp_to_double (&b
);
547 tprintf("%g x %g = %g\n", da
, db
, da
*db
);
549 double_to_fp (da
*db
, &c
);
550 rv
= fp_implode (&c
);
555 static FP_ExceptionCases ex_div_tab
[5][5] = {
556 /* N +0 -0 +In -In */
557 { eNR
, eDZ
, eDZ
, eSZ
, eSZ
}, /* Normal */
558 { eSZ
, eIn
, eIn
, ePZ
, eNZ
}, /* +0 */
559 { eSZ
, eIn
, eIn
, eNZ
, ePZ
}, /* -0 */
560 { eSI
, ePI
, eNI
, eIn
, eIn
}, /* +Inf */
561 { eSI
, eNI
, ePI
, eIn
, eIn
}, /* -Inf */
565 rxfp_div (fp_t fa
, fp_t fb
)
573 CHECK_EXCEPTIONS (a
, b
, rv
, ex_div_tab
);
575 da
= fp_to_double (&a
);
576 db
= fp_to_double (&b
);
577 tprintf("%g / %g = %g\n", da
, db
, da
/db
);
579 double_to_fp (da
/db
, &c
);
580 rv
= fp_implode (&c
);
585 static FP_ExceptionCases ex_cmp_tab
[5][5] = {
586 /* N +0 -0 +In -In */
587 { eNR
, eNR
, eNR
, eLT
, eGT
}, /* Normal */
588 { eNR
, eEQ
, eEQ
, eLT
, eGT
}, /* +0 */
589 { eNR
, eEQ
, eEQ
, eLT
, eGT
}, /* -0 */
590 { eGT
, eGT
, eGT
, eEQ
, eGT
}, /* +Inf */
591 { eLT
, eLT
, eLT
, eLT
, eEQ
}, /* -Inf */
595 rxfp_cmp (fp_t fa
, fp_t fb
)
599 FP_ExceptionCases reason
;
606 if (check_exceptions (&a
, &b
, &c
, ex_cmp_tab
, &reason
))
610 /* Special case - incomparable. */
611 set_flags (FLAGBIT_Z
| FLAGBIT_S
| FLAGBIT_O
, FLAGBIT_O
);
629 da
= fp_to_double (&a
);
630 db
= fp_to_double (&b
);
631 tprintf("fcmp: %g cmp %g\n", da
, db
);
643 set_flags (FLAGBIT_Z
| FLAGBIT_S
| FLAGBIT_O
, flags
);
647 rxfp_ftoi (fp_t fa
, int round_mode
)
652 int whole_bits
, frac_bits
;
655 sign
= fa
& 0x80000000UL
;
676 return sign
? 0x80000000U
: 0x7fffffff;
682 return sign
? 0x80000000U
: 0x7fffffff;
689 /* Less than 0.49999 */
695 frac_bits
= a
.mant
<< (32 + a
.exp
);
696 whole_bits
= a
.mant
>> (-a
.exp
);
701 whole_bits
= a
.mant
<< a
.exp
;
706 switch (round_mode
& 3)
709 if (frac_bits
& 0x80000000UL
)
725 rv
= sign
? -whole_bits
: whole_bits
;
731 rxfp_itof (long fa
, int round_mode
)
735 unsigned int frac_bits
;
736 volatile unsigned int whole_bits
;
754 while (! (whole_bits
& 0x80000000UL
))
759 frac_bits
= whole_bits
& 0xff;
760 whole_bits
= whole_bits
>> 8;
765 switch (round_mode
& 3)
768 if (frac_bits
& 0x80)
785 if (whole_bits
& 0xff000000UL
)
791 rv
= fp_implode (&a
);