This source file includes following definitions.
- FPU_add
- FPU_sub
- add_sub_specials
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 #include "exception.h"
23 #include "reg_constant.h"
24 #include "fpu_emu.h"
25 #include "control_w.h"
26 #include "fpu_system.h"
27
28 static
29 int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa,
30 FPU_REG const *b, u_char tagb, u_char signb,
31 FPU_REG * dest, int deststnr, int control_w);
32
33
34
35
36
37 int FPU_add(FPU_REG const *b, u_char tagb, int deststnr, int control_w)
38 {
39 FPU_REG *a = &st(0);
40 FPU_REG *dest = &st(deststnr);
41 u_char signb = getsign(b);
42 u_char taga = FPU_gettag0();
43 u_char signa = getsign(a);
44 u_char saved_sign = getsign(dest);
45 int diff, tag, expa, expb;
46
47 if (!(taga | tagb)) {
48 expa = exponent(a);
49 expb = exponent(b);
50
51 valid_add:
52
53 if (!(signa ^ signb)) {
54
55 tag =
56 FPU_u_add(a, b, dest, control_w, signa, expa, expb);
57 } else {
58
59 diff = expa - expb;
60 if (!diff) {
61 diff = a->sigh - b->sigh;
62
63 if (!diff) {
64 diff = a->sigl > b->sigl;
65 if (!diff)
66 diff = -(a->sigl < b->sigl);
67 }
68 }
69
70 if (diff > 0) {
71 tag =
72 FPU_u_sub(a, b, dest, control_w, signa,
73 expa, expb);
74 } else if (diff < 0) {
75 tag =
76 FPU_u_sub(b, a, dest, control_w, signb,
77 expb, expa);
78 } else {
79 FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
80
81 setsign(dest, ((control_w & CW_RC) != RC_DOWN)
82 ? SIGN_POS : SIGN_NEG);
83 return TAG_Zero;
84 }
85 }
86
87 if (tag < 0) {
88 setsign(dest, saved_sign);
89 return tag;
90 }
91 FPU_settagi(deststnr, tag);
92 return tag;
93 }
94
95 if (taga == TAG_Special)
96 taga = FPU_Special(a);
97 if (tagb == TAG_Special)
98 tagb = FPU_Special(b);
99
100 if (((taga == TAG_Valid) && (tagb == TW_Denormal))
101 || ((taga == TW_Denormal) && (tagb == TAG_Valid))
102 || ((taga == TW_Denormal) && (tagb == TW_Denormal))) {
103 FPU_REG x, y;
104
105 if (denormal_operand() < 0)
106 return FPU_Exception;
107
108 FPU_to_exp16(a, &x);
109 FPU_to_exp16(b, &y);
110 a = &x;
111 b = &y;
112 expa = exponent16(a);
113 expb = exponent16(b);
114 goto valid_add;
115 }
116
117 if ((taga == TW_NaN) || (tagb == TW_NaN)) {
118 if (deststnr == 0)
119 return real_2op_NaN(b, tagb, deststnr, a);
120 else
121 return real_2op_NaN(a, taga, deststnr, a);
122 }
123
124 return add_sub_specials(a, taga, signa, b, tagb, signb,
125 dest, deststnr, control_w);
126 }
127
128
129 int FPU_sub(int flags, int rm, int control_w)
130 {
131 FPU_REG const *a, *b;
132 FPU_REG *dest;
133 u_char taga, tagb, signa, signb, saved_sign, sign;
134 int diff, tag = 0, expa, expb, deststnr;
135
136 a = &st(0);
137 taga = FPU_gettag0();
138
139 deststnr = 0;
140 if (flags & LOADED) {
141 b = (FPU_REG *) rm;
142 tagb = flags & 0x0f;
143 } else {
144 b = &st(rm);
145 tagb = FPU_gettagi(rm);
146
147 if (flags & DEST_RM)
148 deststnr = rm;
149 }
150
151 signa = getsign(a);
152 signb = getsign(b);
153
154 if (flags & REV) {
155 signa ^= SIGN_NEG;
156 signb ^= SIGN_NEG;
157 }
158
159 dest = &st(deststnr);
160 saved_sign = getsign(dest);
161
162 if (!(taga | tagb)) {
163 expa = exponent(a);
164 expb = exponent(b);
165
166 valid_subtract:
167
168
169 diff = expa - expb;
170
171 if (!diff) {
172 diff = a->sigh - b->sigh;
173 if (!diff) {
174 diff = a->sigl > b->sigl;
175 if (!diff)
176 diff = -(a->sigl < b->sigl);
177 }
178 }
179
180 switch ((((int)signa) * 2 + signb) / SIGN_NEG) {
181 case 0:
182 case 3:
183 if (diff > 0) {
184
185 tag =
186 FPU_u_sub(a, b, dest, control_w, signa,
187 expa, expb);
188 } else if (diff == 0) {
189 FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
190
191
192 setsign(dest, ((control_w & CW_RC) != RC_DOWN)
193 ? SIGN_POS : SIGN_NEG);
194 return TAG_Zero;
195 } else {
196 sign = signa ^ SIGN_NEG;
197 tag =
198 FPU_u_sub(b, a, dest, control_w, sign, expb,
199 expa);
200 }
201 break;
202 case 1:
203 tag =
204 FPU_u_add(a, b, dest, control_w, SIGN_POS, expa,
205 expb);
206 break;
207 case 2:
208 tag =
209 FPU_u_add(a, b, dest, control_w, SIGN_NEG, expa,
210 expb);
211 break;
212 #ifdef PARANOID
213 default:
214 EXCEPTION(EX_INTERNAL | 0x111);
215 return -1;
216 #endif
217 }
218 if (tag < 0) {
219 setsign(dest, saved_sign);
220 return tag;
221 }
222 FPU_settagi(deststnr, tag);
223 return tag;
224 }
225
226 if (taga == TAG_Special)
227 taga = FPU_Special(a);
228 if (tagb == TAG_Special)
229 tagb = FPU_Special(b);
230
231 if (((taga == TAG_Valid) && (tagb == TW_Denormal))
232 || ((taga == TW_Denormal) && (tagb == TAG_Valid))
233 || ((taga == TW_Denormal) && (tagb == TW_Denormal))) {
234 FPU_REG x, y;
235
236 if (denormal_operand() < 0)
237 return FPU_Exception;
238
239 FPU_to_exp16(a, &x);
240 FPU_to_exp16(b, &y);
241 a = &x;
242 b = &y;
243 expa = exponent16(a);
244 expb = exponent16(b);
245
246 goto valid_subtract;
247 }
248
249 if ((taga == TW_NaN) || (tagb == TW_NaN)) {
250 FPU_REG const *d1, *d2;
251 if (flags & REV) {
252 d1 = b;
253 d2 = a;
254 } else {
255 d1 = a;
256 d2 = b;
257 }
258 if (flags & LOADED)
259 return real_2op_NaN(b, tagb, deststnr, d1);
260 if (flags & DEST_RM)
261 return real_2op_NaN(a, taga, deststnr, d2);
262 else
263 return real_2op_NaN(b, tagb, deststnr, d2);
264 }
265
266 return add_sub_specials(a, taga, signa, b, tagb, signb ^ SIGN_NEG,
267 dest, deststnr, control_w);
268 }
269
270 static
271 int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa,
272 FPU_REG const *b, u_char tagb, u_char signb,
273 FPU_REG * dest, int deststnr, int control_w)
274 {
275 if (((taga == TW_Denormal) || (tagb == TW_Denormal))
276 && (denormal_operand() < 0))
277 return FPU_Exception;
278
279 if (taga == TAG_Zero) {
280 if (tagb == TAG_Zero) {
281
282 u_char different_signs = signa ^ signb;
283
284 FPU_copy_to_regi(a, TAG_Zero, deststnr);
285 if (different_signs) {
286
287
288 setsign(dest, ((control_w & CW_RC) != RC_DOWN)
289 ? SIGN_POS : SIGN_NEG);
290 } else
291 setsign(dest, signa);
292 return TAG_Zero;
293 } else {
294 reg_copy(b, dest);
295 if ((tagb == TW_Denormal) && (b->sigh & 0x80000000)) {
296
297 addexponent(dest, 1);
298 tagb = TAG_Valid;
299 } else if (tagb > TAG_Empty)
300 tagb = TAG_Special;
301 setsign(dest, signb);
302 FPU_settagi(deststnr, tagb);
303 return tagb;
304 }
305 } else if (tagb == TAG_Zero) {
306 reg_copy(a, dest);
307 if ((taga == TW_Denormal) && (a->sigh & 0x80000000)) {
308
309 addexponent(dest, 1);
310 taga = TAG_Valid;
311 } else if (taga > TAG_Empty)
312 taga = TAG_Special;
313 setsign(dest, signa);
314 FPU_settagi(deststnr, taga);
315 return taga;
316 } else if (taga == TW_Infinity) {
317 if ((tagb != TW_Infinity) || (signa == signb)) {
318 FPU_copy_to_regi(a, TAG_Special, deststnr);
319 setsign(dest, signa);
320 return taga;
321 }
322
323 return arith_invalid(deststnr);
324 } else if (tagb == TW_Infinity) {
325 FPU_copy_to_regi(b, TAG_Special, deststnr);
326 setsign(dest, signb);
327 return tagb;
328 }
329 #ifdef PARANOID
330 EXCEPTION(EX_INTERNAL | 0x101);
331 #endif
332
333 return FPU_Exception;
334 }