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