1*a2142627SBen Jolitz /*
2*a2142627SBen Jolitz * reg_add_sub.c
3*a2142627SBen Jolitz *
4*a2142627SBen Jolitz * Functions to add or subtract two registers and put the result in a third.
5*a2142627SBen Jolitz *
6*a2142627SBen Jolitz * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
7*a2142627SBen Jolitz * Vic 3163, Australia.
8*a2142627SBen Jolitz * E-mail apm233m@vaxc.cc.monash.edu.au
9*a2142627SBen Jolitz * All rights reserved.
10*a2142627SBen Jolitz *
11*a2142627SBen Jolitz * This copyright notice covers the redistribution and use of the
12*a2142627SBen Jolitz * FPU emulator developed by W. Metzenthen. It covers only its use
13*a2142627SBen Jolitz * in the 386BSD operating system. Any other use is not permitted
14*a2142627SBen Jolitz * under this copyright.
15*a2142627SBen Jolitz *
16*a2142627SBen Jolitz * Redistribution and use in source and binary forms, with or without
17*a2142627SBen Jolitz * modification, are permitted provided that the following conditions
18*a2142627SBen Jolitz * are met:
19*a2142627SBen Jolitz * 1. Redistributions of source code must retain the above copyright
20*a2142627SBen Jolitz * notice, this list of conditions and the following disclaimer.
21*a2142627SBen Jolitz * 2. Redistributions in binary form must include information specifying
22*a2142627SBen Jolitz * that source code for the emulator is freely available and include
23*a2142627SBen Jolitz * either:
24*a2142627SBen Jolitz * a) an offer to provide the source code for a nominal distribution
25*a2142627SBen Jolitz * fee, or
26*a2142627SBen Jolitz * b) list at least two alternative methods whereby the source
27*a2142627SBen Jolitz * can be obtained, e.g. a publically accessible bulletin board
28*a2142627SBen Jolitz * and an anonymous ftp site from which the software can be
29*a2142627SBen Jolitz * downloaded.
30*a2142627SBen Jolitz * 3. All advertising materials specifically mentioning features or use of
31*a2142627SBen Jolitz * this emulator must acknowledge that it was developed by W. Metzenthen.
32*a2142627SBen Jolitz * 4. The name of W. Metzenthen may not be used to endorse or promote
33*a2142627SBen Jolitz * products derived from this software without specific prior written
34*a2142627SBen Jolitz * permission.
35*a2142627SBen Jolitz *
36*a2142627SBen Jolitz * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
37*a2142627SBen Jolitz * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
38*a2142627SBen Jolitz * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
39*a2142627SBen Jolitz * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
40*a2142627SBen Jolitz * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
41*a2142627SBen Jolitz * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
42*a2142627SBen Jolitz * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
43*a2142627SBen Jolitz * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
44*a2142627SBen Jolitz * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
45*a2142627SBen Jolitz * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46*a2142627SBen Jolitz *
47*a2142627SBen Jolitz */
48*a2142627SBen Jolitz
49*a2142627SBen Jolitz /*---------------------------------------------------------------------------+
50*a2142627SBen Jolitz | For each function, the destination may be any FPU_REG, including one of |
51*a2142627SBen Jolitz | the source FPU_REGs. |
52*a2142627SBen Jolitz +---------------------------------------------------------------------------*/
53*a2142627SBen Jolitz
54*a2142627SBen Jolitz #include "exception.h"
55*a2142627SBen Jolitz #include "reg_constant.h"
56*a2142627SBen Jolitz #include "fpu_emu.h"
57*a2142627SBen Jolitz #include "control_w.h"
58*a2142627SBen Jolitz #include "fpu_system.h"
59*a2142627SBen Jolitz
60*a2142627SBen Jolitz
reg_add(FPU_REG * a,FPU_REG * b,FPU_REG * dest,int control_w)61*a2142627SBen Jolitz void reg_add(FPU_REG *a, FPU_REG *b, FPU_REG *dest, int control_w)
62*a2142627SBen Jolitz {
63*a2142627SBen Jolitz int diff;
64*a2142627SBen Jolitz
65*a2142627SBen Jolitz if ( !(a->tag | b->tag) )
66*a2142627SBen Jolitz {
67*a2142627SBen Jolitz /* Both registers are valid */
68*a2142627SBen Jolitz if (!(a->sign ^ b->sign))
69*a2142627SBen Jolitz {
70*a2142627SBen Jolitz /* signs are the same */
71*a2142627SBen Jolitz reg_u_add(a, b, dest, control_w);
72*a2142627SBen Jolitz dest->sign = a->sign;
73*a2142627SBen Jolitz return;
74*a2142627SBen Jolitz }
75*a2142627SBen Jolitz
76*a2142627SBen Jolitz /* The signs are different, so do a subtraction */
77*a2142627SBen Jolitz diff = a->exp - b->exp;
78*a2142627SBen Jolitz if (!diff)
79*a2142627SBen Jolitz {
80*a2142627SBen Jolitz diff = a->sigh - b->sigh; /* Works only if ms bits are identical */
81*a2142627SBen Jolitz if (!diff)
82*a2142627SBen Jolitz {
83*a2142627SBen Jolitz diff = a->sigl > b->sigl;
84*a2142627SBen Jolitz if (!diff)
85*a2142627SBen Jolitz diff = -(a->sigl < b->sigl);
86*a2142627SBen Jolitz }
87*a2142627SBen Jolitz }
88*a2142627SBen Jolitz
89*a2142627SBen Jolitz if (diff > 0)
90*a2142627SBen Jolitz {
91*a2142627SBen Jolitz reg_u_sub(a, b, dest, control_w);
92*a2142627SBen Jolitz dest->sign = a->sign;
93*a2142627SBen Jolitz }
94*a2142627SBen Jolitz else if ( diff == 0 )
95*a2142627SBen Jolitz {
96*a2142627SBen Jolitz reg_move(&CONST_Z, dest);
97*a2142627SBen Jolitz /* sign depends upon rounding mode */
98*a2142627SBen Jolitz dest->sign = ((control_w & CW_RC) != RC_DOWN)
99*a2142627SBen Jolitz ? SIGN_POS : SIGN_NEG;
100*a2142627SBen Jolitz }
101*a2142627SBen Jolitz else
102*a2142627SBen Jolitz {
103*a2142627SBen Jolitz reg_u_sub(b, a, dest, control_w);
104*a2142627SBen Jolitz dest->sign = b->sign;
105*a2142627SBen Jolitz }
106*a2142627SBen Jolitz return;
107*a2142627SBen Jolitz }
108*a2142627SBen Jolitz else
109*a2142627SBen Jolitz {
110*a2142627SBen Jolitz if ( (a->tag == TW_NaN) || (b->tag == TW_NaN) )
111*a2142627SBen Jolitz { real_2op_NaN(a, b, dest); return; }
112*a2142627SBen Jolitz else if (a->tag == TW_Zero)
113*a2142627SBen Jolitz {
114*a2142627SBen Jolitz if (b->tag == TW_Zero)
115*a2142627SBen Jolitz {
116*a2142627SBen Jolitz char different_signs = a->sign ^ b->sign;
117*a2142627SBen Jolitz /* Both are zero, result will be zero. */
118*a2142627SBen Jolitz reg_move(a, dest);
119*a2142627SBen Jolitz if (different_signs)
120*a2142627SBen Jolitz {
121*a2142627SBen Jolitz /* Signs are different. */
122*a2142627SBen Jolitz /* Sign of answer depends upon rounding mode. */
123*a2142627SBen Jolitz dest->sign = ((control_w & CW_RC) != RC_DOWN)
124*a2142627SBen Jolitz ? SIGN_POS : SIGN_NEG;
125*a2142627SBen Jolitz }
126*a2142627SBen Jolitz }
127*a2142627SBen Jolitz else
128*a2142627SBen Jolitz {
129*a2142627SBen Jolitz #ifdef DENORM_OPERAND
130*a2142627SBen Jolitz if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
131*a2142627SBen Jolitz denormal_operand() )
132*a2142627SBen Jolitz return;
133*a2142627SBen Jolitz #endif DENORM_OPERAND
134*a2142627SBen Jolitz reg_move(b, dest);
135*a2142627SBen Jolitz }
136*a2142627SBen Jolitz return;
137*a2142627SBen Jolitz }
138*a2142627SBen Jolitz else if (b->tag == TW_Zero)
139*a2142627SBen Jolitz {
140*a2142627SBen Jolitz #ifdef DENORM_OPERAND
141*a2142627SBen Jolitz if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
142*a2142627SBen Jolitz denormal_operand() )
143*a2142627SBen Jolitz return;
144*a2142627SBen Jolitz #endif DENORM_OPERAND
145*a2142627SBen Jolitz reg_move(a, dest); return;
146*a2142627SBen Jolitz }
147*a2142627SBen Jolitz else if (a->tag == TW_Infinity)
148*a2142627SBen Jolitz {
149*a2142627SBen Jolitz if (b->tag != TW_Infinity)
150*a2142627SBen Jolitz {
151*a2142627SBen Jolitz #ifdef DENORM_OPERAND
152*a2142627SBen Jolitz if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
153*a2142627SBen Jolitz denormal_operand() )
154*a2142627SBen Jolitz return;
155*a2142627SBen Jolitz #endif DENORM_OPERAND
156*a2142627SBen Jolitz reg_move(a, dest); return;
157*a2142627SBen Jolitz }
158*a2142627SBen Jolitz if (a->sign == b->sign)
159*a2142627SBen Jolitz {
160*a2142627SBen Jolitz /* They are both + or - infinity */
161*a2142627SBen Jolitz reg_move(a, dest); return;
162*a2142627SBen Jolitz }
163*a2142627SBen Jolitz arith_invalid(dest); /* Infinity-Infinity is undefined. */
164*a2142627SBen Jolitz return;
165*a2142627SBen Jolitz }
166*a2142627SBen Jolitz else if (b->tag == TW_Infinity)
167*a2142627SBen Jolitz {
168*a2142627SBen Jolitz #ifdef DENORM_OPERAND
169*a2142627SBen Jolitz if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
170*a2142627SBen Jolitz denormal_operand() )
171*a2142627SBen Jolitz return;
172*a2142627SBen Jolitz #endif DENORM_OPERAND
173*a2142627SBen Jolitz reg_move(b, dest); return;
174*a2142627SBen Jolitz }
175*a2142627SBen Jolitz }
176*a2142627SBen Jolitz #ifdef PARANOID
177*a2142627SBen Jolitz EXCEPTION(EX_INTERNAL|0x101);
178*a2142627SBen Jolitz #endif
179*a2142627SBen Jolitz }
180*a2142627SBen Jolitz
181*a2142627SBen Jolitz
182*a2142627SBen Jolitz /* Subtract b from a. (a-b) -> dest */
reg_sub(FPU_REG * a,FPU_REG * b,FPU_REG * dest,int control_w)183*a2142627SBen Jolitz void reg_sub(FPU_REG *a, FPU_REG *b, FPU_REG *dest, int control_w)
184*a2142627SBen Jolitz {
185*a2142627SBen Jolitz int diff;
186*a2142627SBen Jolitz
187*a2142627SBen Jolitz if ( !(a->tag | b->tag) )
188*a2142627SBen Jolitz {
189*a2142627SBen Jolitz /* Both registers are valid */
190*a2142627SBen Jolitz diff = a->exp - b->exp;
191*a2142627SBen Jolitz if (!diff)
192*a2142627SBen Jolitz {
193*a2142627SBen Jolitz diff = a->sigh - b->sigh; /* Works only if ms bits are identical */
194*a2142627SBen Jolitz if (!diff)
195*a2142627SBen Jolitz {
196*a2142627SBen Jolitz diff = a->sigl > b->sigl;
197*a2142627SBen Jolitz if (!diff)
198*a2142627SBen Jolitz diff = -(a->sigl < b->sigl);
199*a2142627SBen Jolitz }
200*a2142627SBen Jolitz }
201*a2142627SBen Jolitz
202*a2142627SBen Jolitz switch (a->sign*2 + b->sign)
203*a2142627SBen Jolitz {
204*a2142627SBen Jolitz case 0: /* P - P */
205*a2142627SBen Jolitz case 3: /* N - N */
206*a2142627SBen Jolitz if (diff > 0)
207*a2142627SBen Jolitz {
208*a2142627SBen Jolitz reg_u_sub(a, b, dest, control_w);
209*a2142627SBen Jolitz dest->sign = a->sign;
210*a2142627SBen Jolitz }
211*a2142627SBen Jolitz else if ( diff == 0 )
212*a2142627SBen Jolitz {
213*a2142627SBen Jolitz #ifdef DENORM_OPERAND
214*a2142627SBen Jolitz if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
215*a2142627SBen Jolitz denormal_operand() )
216*a2142627SBen Jolitz return;
217*a2142627SBen Jolitz #endif DENORM_OPERAND
218*a2142627SBen Jolitz reg_move(&CONST_Z, dest);
219*a2142627SBen Jolitz /* sign depends upon rounding mode */
220*a2142627SBen Jolitz dest->sign = ((control_w & CW_RC) != RC_DOWN)
221*a2142627SBen Jolitz ? SIGN_POS : SIGN_NEG;
222*a2142627SBen Jolitz }
223*a2142627SBen Jolitz else
224*a2142627SBen Jolitz {
225*a2142627SBen Jolitz reg_u_sub(b, a, dest, control_w);
226*a2142627SBen Jolitz dest->sign = a->sign ^ SIGN_POS^SIGN_NEG;
227*a2142627SBen Jolitz }
228*a2142627SBen Jolitz return;
229*a2142627SBen Jolitz case 1: /* P - N */
230*a2142627SBen Jolitz reg_u_add(a, b, dest, control_w);
231*a2142627SBen Jolitz dest->sign = SIGN_POS;
232*a2142627SBen Jolitz return;
233*a2142627SBen Jolitz case 2: /* N - P */
234*a2142627SBen Jolitz reg_u_add(a, b, dest, control_w);
235*a2142627SBen Jolitz dest->sign = SIGN_NEG;
236*a2142627SBen Jolitz return;
237*a2142627SBen Jolitz }
238*a2142627SBen Jolitz }
239*a2142627SBen Jolitz else
240*a2142627SBen Jolitz {
241*a2142627SBen Jolitz if ( (a->tag == TW_NaN) || (b->tag == TW_NaN) )
242*a2142627SBen Jolitz { real_2op_NaN(a, b, dest); return; }
243*a2142627SBen Jolitz else if (b->tag == TW_Zero)
244*a2142627SBen Jolitz {
245*a2142627SBen Jolitz if (a->tag == TW_Zero)
246*a2142627SBen Jolitz {
247*a2142627SBen Jolitz char same_signs = !(a->sign ^ b->sign);
248*a2142627SBen Jolitz /* Both are zero, result will be zero. */
249*a2142627SBen Jolitz reg_move(a, dest); /* Answer for different signs. */
250*a2142627SBen Jolitz if (same_signs)
251*a2142627SBen Jolitz {
252*a2142627SBen Jolitz /* Sign depends upon rounding mode */
253*a2142627SBen Jolitz dest->sign = ((control_w & CW_RC) != RC_DOWN)
254*a2142627SBen Jolitz ? SIGN_POS : SIGN_NEG;
255*a2142627SBen Jolitz }
256*a2142627SBen Jolitz }
257*a2142627SBen Jolitz else
258*a2142627SBen Jolitz {
259*a2142627SBen Jolitz #ifdef DENORM_OPERAND
260*a2142627SBen Jolitz if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
261*a2142627SBen Jolitz denormal_operand() )
262*a2142627SBen Jolitz return;
263*a2142627SBen Jolitz #endif DENORM_OPERAND
264*a2142627SBen Jolitz reg_move(a, dest);
265*a2142627SBen Jolitz }
266*a2142627SBen Jolitz return;
267*a2142627SBen Jolitz }
268*a2142627SBen Jolitz else if (a->tag == TW_Zero)
269*a2142627SBen Jolitz {
270*a2142627SBen Jolitz #ifdef DENORM_OPERAND
271*a2142627SBen Jolitz if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
272*a2142627SBen Jolitz denormal_operand() )
273*a2142627SBen Jolitz return;
274*a2142627SBen Jolitz #endif DENORM_OPERAND
275*a2142627SBen Jolitz reg_move(b, dest);
276*a2142627SBen Jolitz dest->sign ^= SIGN_POS^SIGN_NEG;
277*a2142627SBen Jolitz return;
278*a2142627SBen Jolitz }
279*a2142627SBen Jolitz else if (a->tag == TW_Infinity)
280*a2142627SBen Jolitz {
281*a2142627SBen Jolitz if (b->tag != TW_Infinity)
282*a2142627SBen Jolitz {
283*a2142627SBen Jolitz #ifdef DENORM_OPERAND
284*a2142627SBen Jolitz if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
285*a2142627SBen Jolitz denormal_operand() )
286*a2142627SBen Jolitz return;
287*a2142627SBen Jolitz #endif DENORM_OPERAND
288*a2142627SBen Jolitz reg_move(a, dest); return;
289*a2142627SBen Jolitz }
290*a2142627SBen Jolitz /* Both args are Infinity */
291*a2142627SBen Jolitz if (a->sign == b->sign)
292*a2142627SBen Jolitz {
293*a2142627SBen Jolitz arith_invalid(dest); /* Infinity-Infinity is undefined. */
294*a2142627SBen Jolitz return;
295*a2142627SBen Jolitz }
296*a2142627SBen Jolitz reg_move(a, dest);
297*a2142627SBen Jolitz return;
298*a2142627SBen Jolitz }
299*a2142627SBen Jolitz else if (b->tag == TW_Infinity)
300*a2142627SBen Jolitz {
301*a2142627SBen Jolitz #ifdef DENORM_OPERAND
302*a2142627SBen Jolitz if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
303*a2142627SBen Jolitz denormal_operand() )
304*a2142627SBen Jolitz return;
305*a2142627SBen Jolitz #endif DENORM_OPERAND
306*a2142627SBen Jolitz reg_move(b, dest);
307*a2142627SBen Jolitz dest->sign ^= SIGN_POS^SIGN_NEG;
308*a2142627SBen Jolitz return;
309*a2142627SBen Jolitz }
310*a2142627SBen Jolitz }
311*a2142627SBen Jolitz #ifdef PARANOID
312*a2142627SBen Jolitz EXCEPTION(EX_INTERNAL|0x110);
313*a2142627SBen Jolitz #endif
314*a2142627SBen Jolitz }
315*a2142627SBen Jolitz
316