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