xref: /openbmc/linux/arch/x86/math-emu/reg_mul.c (revision da957e111bb0c189a4a3bf8a00caaecb59ed94ca)
1*da957e11SThomas Gleixner /*---------------------------------------------------------------------------+
2*da957e11SThomas Gleixner  |  reg_mul.c                                                                |
3*da957e11SThomas Gleixner  |                                                                           |
4*da957e11SThomas Gleixner  | Multiply one FPU_REG by another, put the result in a destination FPU_REG. |
5*da957e11SThomas Gleixner  |                                                                           |
6*da957e11SThomas Gleixner  | Copyright (C) 1992,1993,1997                                              |
7*da957e11SThomas Gleixner  |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
8*da957e11SThomas Gleixner  |                  E-mail   billm@suburbia.net                              |
9*da957e11SThomas Gleixner  |                                                                           |
10*da957e11SThomas Gleixner  | Returns the tag of the result if no exceptions or errors occurred.        |
11*da957e11SThomas Gleixner  |                                                                           |
12*da957e11SThomas Gleixner  +---------------------------------------------------------------------------*/
13*da957e11SThomas Gleixner 
14*da957e11SThomas Gleixner /*---------------------------------------------------------------------------+
15*da957e11SThomas Gleixner  | The destination may be any FPU_REG, including one of the source FPU_REGs. |
16*da957e11SThomas Gleixner  +---------------------------------------------------------------------------*/
17*da957e11SThomas Gleixner 
18*da957e11SThomas Gleixner #include "fpu_emu.h"
19*da957e11SThomas Gleixner #include "exception.h"
20*da957e11SThomas Gleixner #include "reg_constant.h"
21*da957e11SThomas Gleixner #include "fpu_system.h"
22*da957e11SThomas Gleixner 
23*da957e11SThomas Gleixner 
24*da957e11SThomas Gleixner /*
25*da957e11SThomas Gleixner   Multiply two registers to give a register result.
26*da957e11SThomas Gleixner   The sources are st(deststnr) and (b,tagb,signb).
27*da957e11SThomas Gleixner   The destination is st(deststnr).
28*da957e11SThomas Gleixner   */
29*da957e11SThomas Gleixner /* This routine must be called with non-empty source registers */
30*da957e11SThomas Gleixner int FPU_mul(FPU_REG const *b, u_char tagb, int deststnr, int control_w)
31*da957e11SThomas Gleixner {
32*da957e11SThomas Gleixner   FPU_REG *a = &st(deststnr);
33*da957e11SThomas Gleixner   FPU_REG *dest = a;
34*da957e11SThomas Gleixner   u_char taga = FPU_gettagi(deststnr);
35*da957e11SThomas Gleixner   u_char saved_sign = getsign(dest);
36*da957e11SThomas Gleixner   u_char sign = (getsign(a) ^ getsign(b));
37*da957e11SThomas Gleixner   int tag;
38*da957e11SThomas Gleixner 
39*da957e11SThomas Gleixner 
40*da957e11SThomas Gleixner   if ( !(taga | tagb) )
41*da957e11SThomas Gleixner     {
42*da957e11SThomas Gleixner       /* Both regs Valid, this should be the most common case. */
43*da957e11SThomas Gleixner 
44*da957e11SThomas Gleixner       tag = FPU_u_mul(a, b, dest, control_w, sign, exponent(a) + exponent(b));
45*da957e11SThomas Gleixner       if ( tag < 0 )
46*da957e11SThomas Gleixner 	{
47*da957e11SThomas Gleixner 	  setsign(dest, saved_sign);
48*da957e11SThomas Gleixner 	  return tag;
49*da957e11SThomas Gleixner 	}
50*da957e11SThomas Gleixner       FPU_settagi(deststnr, tag);
51*da957e11SThomas Gleixner       return tag;
52*da957e11SThomas Gleixner     }
53*da957e11SThomas Gleixner 
54*da957e11SThomas Gleixner   if ( taga == TAG_Special )
55*da957e11SThomas Gleixner     taga = FPU_Special(a);
56*da957e11SThomas Gleixner   if ( tagb == TAG_Special )
57*da957e11SThomas Gleixner     tagb = FPU_Special(b);
58*da957e11SThomas Gleixner 
59*da957e11SThomas Gleixner   if ( ((taga == TAG_Valid) && (tagb == TW_Denormal))
60*da957e11SThomas Gleixner 	    || ((taga == TW_Denormal) && (tagb == TAG_Valid))
61*da957e11SThomas Gleixner 	    || ((taga == TW_Denormal) && (tagb == TW_Denormal)) )
62*da957e11SThomas Gleixner     {
63*da957e11SThomas Gleixner       FPU_REG x, y;
64*da957e11SThomas Gleixner       if ( denormal_operand() < 0 )
65*da957e11SThomas Gleixner 	return FPU_Exception;
66*da957e11SThomas Gleixner 
67*da957e11SThomas Gleixner       FPU_to_exp16(a, &x);
68*da957e11SThomas Gleixner       FPU_to_exp16(b, &y);
69*da957e11SThomas Gleixner       tag = FPU_u_mul(&x, &y, dest, control_w, sign,
70*da957e11SThomas Gleixner 		      exponent16(&x) + exponent16(&y));
71*da957e11SThomas Gleixner       if ( tag < 0 )
72*da957e11SThomas Gleixner 	{
73*da957e11SThomas Gleixner 	  setsign(dest, saved_sign);
74*da957e11SThomas Gleixner 	  return tag;
75*da957e11SThomas Gleixner 	}
76*da957e11SThomas Gleixner       FPU_settagi(deststnr, tag);
77*da957e11SThomas Gleixner       return tag;
78*da957e11SThomas Gleixner     }
79*da957e11SThomas Gleixner   else if ( (taga <= TW_Denormal) && (tagb <= TW_Denormal) )
80*da957e11SThomas Gleixner     {
81*da957e11SThomas Gleixner       if ( ((tagb == TW_Denormal) || (taga == TW_Denormal))
82*da957e11SThomas Gleixner 	   && (denormal_operand() < 0) )
83*da957e11SThomas Gleixner 	return FPU_Exception;
84*da957e11SThomas Gleixner 
85*da957e11SThomas Gleixner       /* Must have either both arguments == zero, or
86*da957e11SThomas Gleixner 	 one valid and the other zero.
87*da957e11SThomas Gleixner 	 The result is therefore zero. */
88*da957e11SThomas Gleixner       FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
89*da957e11SThomas Gleixner       /* The 80486 book says that the answer is +0, but a real
90*da957e11SThomas Gleixner 	 80486 behaves this way.
91*da957e11SThomas Gleixner 	 IEEE-754 apparently says it should be this way. */
92*da957e11SThomas Gleixner       setsign(dest, sign);
93*da957e11SThomas Gleixner       return TAG_Zero;
94*da957e11SThomas Gleixner     }
95*da957e11SThomas Gleixner       /* Must have infinities, NaNs, etc */
96*da957e11SThomas Gleixner   else if ( (taga == TW_NaN) || (tagb == TW_NaN) )
97*da957e11SThomas Gleixner     {
98*da957e11SThomas Gleixner       return real_2op_NaN(b, tagb, deststnr, &st(0));
99*da957e11SThomas Gleixner     }
100*da957e11SThomas Gleixner   else if ( ((taga == TW_Infinity) && (tagb == TAG_Zero))
101*da957e11SThomas Gleixner 	    || ((tagb == TW_Infinity) && (taga == TAG_Zero)) )
102*da957e11SThomas Gleixner     {
103*da957e11SThomas Gleixner       return arith_invalid(deststnr);  /* Zero*Infinity is invalid */
104*da957e11SThomas Gleixner     }
105*da957e11SThomas Gleixner   else if ( ((taga == TW_Denormal) || (tagb == TW_Denormal))
106*da957e11SThomas Gleixner 	    && (denormal_operand() < 0) )
107*da957e11SThomas Gleixner     {
108*da957e11SThomas Gleixner       return FPU_Exception;
109*da957e11SThomas Gleixner     }
110*da957e11SThomas Gleixner   else if (taga == TW_Infinity)
111*da957e11SThomas Gleixner     {
112*da957e11SThomas Gleixner       FPU_copy_to_regi(a, TAG_Special, deststnr);
113*da957e11SThomas Gleixner       setsign(dest, sign);
114*da957e11SThomas Gleixner       return TAG_Special;
115*da957e11SThomas Gleixner     }
116*da957e11SThomas Gleixner   else if (tagb == TW_Infinity)
117*da957e11SThomas Gleixner     {
118*da957e11SThomas Gleixner       FPU_copy_to_regi(b, TAG_Special, deststnr);
119*da957e11SThomas Gleixner       setsign(dest, sign);
120*da957e11SThomas Gleixner       return TAG_Special;
121*da957e11SThomas Gleixner     }
122*da957e11SThomas Gleixner 
123*da957e11SThomas Gleixner #ifdef PARANOID
124*da957e11SThomas Gleixner   else
125*da957e11SThomas Gleixner     {
126*da957e11SThomas Gleixner       EXCEPTION(EX_INTERNAL|0x102);
127*da957e11SThomas Gleixner       return FPU_Exception;
128*da957e11SThomas Gleixner     }
129*da957e11SThomas Gleixner #endif /* PARANOID */
130*da957e11SThomas Gleixner 
131*da957e11SThomas Gleixner 	return 0;
132*da957e11SThomas Gleixner }
133