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