1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*---------------------------------------------------------------------------+
3*4882a593Smuzhiyun | fpu_etc.c |
4*4882a593Smuzhiyun | |
5*4882a593Smuzhiyun | Implement a few FPU instructions. |
6*4882a593Smuzhiyun | |
7*4882a593Smuzhiyun | Copyright (C) 1992,1993,1994,1997 |
8*4882a593Smuzhiyun | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
9*4882a593Smuzhiyun | Australia. E-mail billm@suburbia.net |
10*4882a593Smuzhiyun | |
11*4882a593Smuzhiyun | |
12*4882a593Smuzhiyun +---------------------------------------------------------------------------*/
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #include "fpu_system.h"
15*4882a593Smuzhiyun #include "exception.h"
16*4882a593Smuzhiyun #include "fpu_emu.h"
17*4882a593Smuzhiyun #include "status_w.h"
18*4882a593Smuzhiyun #include "reg_constant.h"
19*4882a593Smuzhiyun
fchs(FPU_REG * st0_ptr,u_char st0tag)20*4882a593Smuzhiyun static void fchs(FPU_REG *st0_ptr, u_char st0tag)
21*4882a593Smuzhiyun {
22*4882a593Smuzhiyun if (st0tag ^ TAG_Empty) {
23*4882a593Smuzhiyun signbyte(st0_ptr) ^= SIGN_NEG;
24*4882a593Smuzhiyun clear_C1();
25*4882a593Smuzhiyun } else
26*4882a593Smuzhiyun FPU_stack_underflow();
27*4882a593Smuzhiyun }
28*4882a593Smuzhiyun
fabs(FPU_REG * st0_ptr,u_char st0tag)29*4882a593Smuzhiyun static void fabs(FPU_REG *st0_ptr, u_char st0tag)
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun if (st0tag ^ TAG_Empty) {
32*4882a593Smuzhiyun setpositive(st0_ptr);
33*4882a593Smuzhiyun clear_C1();
34*4882a593Smuzhiyun } else
35*4882a593Smuzhiyun FPU_stack_underflow();
36*4882a593Smuzhiyun }
37*4882a593Smuzhiyun
ftst_(FPU_REG * st0_ptr,u_char st0tag)38*4882a593Smuzhiyun static void ftst_(FPU_REG *st0_ptr, u_char st0tag)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun switch (st0tag) {
41*4882a593Smuzhiyun case TAG_Zero:
42*4882a593Smuzhiyun setcc(SW_C3);
43*4882a593Smuzhiyun break;
44*4882a593Smuzhiyun case TAG_Valid:
45*4882a593Smuzhiyun if (getsign(st0_ptr) == SIGN_POS)
46*4882a593Smuzhiyun setcc(0);
47*4882a593Smuzhiyun else
48*4882a593Smuzhiyun setcc(SW_C0);
49*4882a593Smuzhiyun break;
50*4882a593Smuzhiyun case TAG_Special:
51*4882a593Smuzhiyun switch (FPU_Special(st0_ptr)) {
52*4882a593Smuzhiyun case TW_Denormal:
53*4882a593Smuzhiyun if (getsign(st0_ptr) == SIGN_POS)
54*4882a593Smuzhiyun setcc(0);
55*4882a593Smuzhiyun else
56*4882a593Smuzhiyun setcc(SW_C0);
57*4882a593Smuzhiyun if (denormal_operand() < 0) {
58*4882a593Smuzhiyun #ifdef PECULIAR_486
59*4882a593Smuzhiyun /* This is weird! */
60*4882a593Smuzhiyun if (getsign(st0_ptr) == SIGN_POS)
61*4882a593Smuzhiyun setcc(SW_C3);
62*4882a593Smuzhiyun #endif /* PECULIAR_486 */
63*4882a593Smuzhiyun return;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun break;
66*4882a593Smuzhiyun case TW_NaN:
67*4882a593Smuzhiyun setcc(SW_C0 | SW_C2 | SW_C3); /* Operand is not comparable */
68*4882a593Smuzhiyun EXCEPTION(EX_Invalid);
69*4882a593Smuzhiyun break;
70*4882a593Smuzhiyun case TW_Infinity:
71*4882a593Smuzhiyun if (getsign(st0_ptr) == SIGN_POS)
72*4882a593Smuzhiyun setcc(0);
73*4882a593Smuzhiyun else
74*4882a593Smuzhiyun setcc(SW_C0);
75*4882a593Smuzhiyun break;
76*4882a593Smuzhiyun default:
77*4882a593Smuzhiyun setcc(SW_C0 | SW_C2 | SW_C3); /* Operand is not comparable */
78*4882a593Smuzhiyun EXCEPTION(EX_INTERNAL | 0x14);
79*4882a593Smuzhiyun break;
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun break;
82*4882a593Smuzhiyun case TAG_Empty:
83*4882a593Smuzhiyun setcc(SW_C0 | SW_C2 | SW_C3);
84*4882a593Smuzhiyun EXCEPTION(EX_StackUnder);
85*4882a593Smuzhiyun break;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun
fxam(FPU_REG * st0_ptr,u_char st0tag)89*4882a593Smuzhiyun static void fxam(FPU_REG *st0_ptr, u_char st0tag)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun int c = 0;
92*4882a593Smuzhiyun switch (st0tag) {
93*4882a593Smuzhiyun case TAG_Empty:
94*4882a593Smuzhiyun c = SW_C3 | SW_C0;
95*4882a593Smuzhiyun break;
96*4882a593Smuzhiyun case TAG_Zero:
97*4882a593Smuzhiyun c = SW_C3;
98*4882a593Smuzhiyun break;
99*4882a593Smuzhiyun case TAG_Valid:
100*4882a593Smuzhiyun c = SW_C2;
101*4882a593Smuzhiyun break;
102*4882a593Smuzhiyun case TAG_Special:
103*4882a593Smuzhiyun switch (FPU_Special(st0_ptr)) {
104*4882a593Smuzhiyun case TW_Denormal:
105*4882a593Smuzhiyun c = SW_C2 | SW_C3; /* Denormal */
106*4882a593Smuzhiyun break;
107*4882a593Smuzhiyun case TW_NaN:
108*4882a593Smuzhiyun /* We also use NaN for unsupported types. */
109*4882a593Smuzhiyun if ((st0_ptr->sigh & 0x80000000)
110*4882a593Smuzhiyun && (exponent(st0_ptr) == EXP_OVER))
111*4882a593Smuzhiyun c = SW_C0;
112*4882a593Smuzhiyun break;
113*4882a593Smuzhiyun case TW_Infinity:
114*4882a593Smuzhiyun c = SW_C2 | SW_C0;
115*4882a593Smuzhiyun break;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun if (getsign(st0_ptr) == SIGN_NEG)
119*4882a593Smuzhiyun c |= SW_C1;
120*4882a593Smuzhiyun setcc(c);
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun static FUNC_ST0 const fp_etc_table[] = {
124*4882a593Smuzhiyun fchs, fabs, (FUNC_ST0) FPU_illegal, (FUNC_ST0) FPU_illegal,
125*4882a593Smuzhiyun ftst_, fxam, (FUNC_ST0) FPU_illegal, (FUNC_ST0) FPU_illegal
126*4882a593Smuzhiyun };
127*4882a593Smuzhiyun
FPU_etc(void)128*4882a593Smuzhiyun void FPU_etc(void)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun (fp_etc_table[FPU_rm]) (&st(0), FPU_gettag0());
131*4882a593Smuzhiyun }
132