xref: /386bsd/usr/src/kernel/fpu-emu/reg_add_sub.c (revision a2142627)
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