xref: /openbmc/linux/arch/x86/math-emu/fpu_etc.c (revision da957e111bb0c189a4a3bf8a00caaecb59ed94ca)
1*da957e11SThomas Gleixner /*---------------------------------------------------------------------------+
2*da957e11SThomas Gleixner  |  fpu_etc.c                                                                |
3*da957e11SThomas Gleixner  |                                                                           |
4*da957e11SThomas Gleixner  | Implement a few FPU instructions.                                         |
5*da957e11SThomas Gleixner  |                                                                           |
6*da957e11SThomas Gleixner  | Copyright (C) 1992,1993,1994,1997                                         |
7*da957e11SThomas Gleixner  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
8*da957e11SThomas Gleixner  |                       Australia.  E-mail   billm@suburbia.net             |
9*da957e11SThomas Gleixner  |                                                                           |
10*da957e11SThomas Gleixner  |                                                                           |
11*da957e11SThomas Gleixner  +---------------------------------------------------------------------------*/
12*da957e11SThomas Gleixner 
13*da957e11SThomas Gleixner #include "fpu_system.h"
14*da957e11SThomas Gleixner #include "exception.h"
15*da957e11SThomas Gleixner #include "fpu_emu.h"
16*da957e11SThomas Gleixner #include "status_w.h"
17*da957e11SThomas Gleixner #include "reg_constant.h"
18*da957e11SThomas Gleixner 
19*da957e11SThomas Gleixner 
20*da957e11SThomas Gleixner static void fchs(FPU_REG *st0_ptr, u_char st0tag)
21*da957e11SThomas Gleixner {
22*da957e11SThomas Gleixner   if ( st0tag ^ TAG_Empty )
23*da957e11SThomas Gleixner     {
24*da957e11SThomas Gleixner       signbyte(st0_ptr) ^= SIGN_NEG;
25*da957e11SThomas Gleixner       clear_C1();
26*da957e11SThomas Gleixner     }
27*da957e11SThomas Gleixner   else
28*da957e11SThomas Gleixner     FPU_stack_underflow();
29*da957e11SThomas Gleixner }
30*da957e11SThomas Gleixner 
31*da957e11SThomas Gleixner 
32*da957e11SThomas Gleixner static void fabs(FPU_REG *st0_ptr, u_char st0tag)
33*da957e11SThomas Gleixner {
34*da957e11SThomas Gleixner   if ( st0tag ^ TAG_Empty )
35*da957e11SThomas Gleixner     {
36*da957e11SThomas Gleixner       setpositive(st0_ptr);
37*da957e11SThomas Gleixner       clear_C1();
38*da957e11SThomas Gleixner     }
39*da957e11SThomas Gleixner   else
40*da957e11SThomas Gleixner     FPU_stack_underflow();
41*da957e11SThomas Gleixner }
42*da957e11SThomas Gleixner 
43*da957e11SThomas Gleixner 
44*da957e11SThomas Gleixner static void ftst_(FPU_REG *st0_ptr, u_char st0tag)
45*da957e11SThomas Gleixner {
46*da957e11SThomas Gleixner   switch (st0tag)
47*da957e11SThomas Gleixner     {
48*da957e11SThomas Gleixner     case TAG_Zero:
49*da957e11SThomas Gleixner       setcc(SW_C3);
50*da957e11SThomas Gleixner       break;
51*da957e11SThomas Gleixner     case TAG_Valid:
52*da957e11SThomas Gleixner       if (getsign(st0_ptr) == SIGN_POS)
53*da957e11SThomas Gleixner         setcc(0);
54*da957e11SThomas Gleixner       else
55*da957e11SThomas Gleixner         setcc(SW_C0);
56*da957e11SThomas Gleixner       break;
57*da957e11SThomas Gleixner     case TAG_Special:
58*da957e11SThomas Gleixner       switch ( FPU_Special(st0_ptr) )
59*da957e11SThomas Gleixner 	{
60*da957e11SThomas Gleixner 	case TW_Denormal:
61*da957e11SThomas Gleixner 	  if (getsign(st0_ptr) == SIGN_POS)
62*da957e11SThomas Gleixner 	    setcc(0);
63*da957e11SThomas Gleixner 	  else
64*da957e11SThomas Gleixner 	    setcc(SW_C0);
65*da957e11SThomas Gleixner 	  if ( denormal_operand() < 0 )
66*da957e11SThomas Gleixner 	    {
67*da957e11SThomas Gleixner #ifdef PECULIAR_486
68*da957e11SThomas Gleixner 	      /* This is weird! */
69*da957e11SThomas Gleixner 	      if (getsign(st0_ptr) == SIGN_POS)
70*da957e11SThomas Gleixner 		setcc(SW_C3);
71*da957e11SThomas Gleixner #endif /* PECULIAR_486 */
72*da957e11SThomas Gleixner 	      return;
73*da957e11SThomas Gleixner 	    }
74*da957e11SThomas Gleixner 	  break;
75*da957e11SThomas Gleixner 	case TW_NaN:
76*da957e11SThomas Gleixner 	  setcc(SW_C0|SW_C2|SW_C3);   /* Operand is not comparable */
77*da957e11SThomas Gleixner 	  EXCEPTION(EX_Invalid);
78*da957e11SThomas Gleixner 	  break;
79*da957e11SThomas Gleixner 	case TW_Infinity:
80*da957e11SThomas Gleixner 	  if (getsign(st0_ptr) == SIGN_POS)
81*da957e11SThomas Gleixner 	    setcc(0);
82*da957e11SThomas Gleixner 	  else
83*da957e11SThomas Gleixner 	    setcc(SW_C0);
84*da957e11SThomas Gleixner 	  break;
85*da957e11SThomas Gleixner 	default:
86*da957e11SThomas Gleixner 	  setcc(SW_C0|SW_C2|SW_C3);   /* Operand is not comparable */
87*da957e11SThomas Gleixner 	  EXCEPTION(EX_INTERNAL|0x14);
88*da957e11SThomas Gleixner 	  break;
89*da957e11SThomas Gleixner 	}
90*da957e11SThomas Gleixner       break;
91*da957e11SThomas Gleixner     case TAG_Empty:
92*da957e11SThomas Gleixner       setcc(SW_C0|SW_C2|SW_C3);
93*da957e11SThomas Gleixner       EXCEPTION(EX_StackUnder);
94*da957e11SThomas Gleixner       break;
95*da957e11SThomas Gleixner     }
96*da957e11SThomas Gleixner }
97*da957e11SThomas Gleixner 
98*da957e11SThomas Gleixner 
99*da957e11SThomas Gleixner static void fxam(FPU_REG *st0_ptr, u_char st0tag)
100*da957e11SThomas Gleixner {
101*da957e11SThomas Gleixner   int c = 0;
102*da957e11SThomas Gleixner   switch (st0tag)
103*da957e11SThomas Gleixner     {
104*da957e11SThomas Gleixner     case TAG_Empty:
105*da957e11SThomas Gleixner       c = SW_C3|SW_C0;
106*da957e11SThomas Gleixner       break;
107*da957e11SThomas Gleixner     case TAG_Zero:
108*da957e11SThomas Gleixner       c = SW_C3;
109*da957e11SThomas Gleixner       break;
110*da957e11SThomas Gleixner     case TAG_Valid:
111*da957e11SThomas Gleixner       c = SW_C2;
112*da957e11SThomas Gleixner       break;
113*da957e11SThomas Gleixner     case TAG_Special:
114*da957e11SThomas Gleixner       switch ( FPU_Special(st0_ptr) )
115*da957e11SThomas Gleixner 	{
116*da957e11SThomas Gleixner 	case TW_Denormal:
117*da957e11SThomas Gleixner 	  c = SW_C2|SW_C3;  /* Denormal */
118*da957e11SThomas Gleixner 	  break;
119*da957e11SThomas Gleixner 	case TW_NaN:
120*da957e11SThomas Gleixner 	  /* We also use NaN for unsupported types. */
121*da957e11SThomas Gleixner 	  if ( (st0_ptr->sigh & 0x80000000) && (exponent(st0_ptr) == EXP_OVER) )
122*da957e11SThomas Gleixner 	    c = SW_C0;
123*da957e11SThomas Gleixner 	  break;
124*da957e11SThomas Gleixner 	case TW_Infinity:
125*da957e11SThomas Gleixner 	  c = SW_C2|SW_C0;
126*da957e11SThomas Gleixner 	  break;
127*da957e11SThomas Gleixner 	}
128*da957e11SThomas Gleixner     }
129*da957e11SThomas Gleixner   if ( getsign(st0_ptr) == SIGN_NEG )
130*da957e11SThomas Gleixner     c |= SW_C1;
131*da957e11SThomas Gleixner   setcc(c);
132*da957e11SThomas Gleixner }
133*da957e11SThomas Gleixner 
134*da957e11SThomas Gleixner 
135*da957e11SThomas Gleixner static FUNC_ST0 const fp_etc_table[] = {
136*da957e11SThomas Gleixner   fchs, fabs, (FUNC_ST0)FPU_illegal, (FUNC_ST0)FPU_illegal,
137*da957e11SThomas Gleixner   ftst_, fxam, (FUNC_ST0)FPU_illegal, (FUNC_ST0)FPU_illegal
138*da957e11SThomas Gleixner };
139*da957e11SThomas Gleixner 
140*da957e11SThomas Gleixner void FPU_etc(void)
141*da957e11SThomas Gleixner {
142*da957e11SThomas Gleixner   (fp_etc_table[FPU_rm])(&st(0), FPU_gettag0());
143*da957e11SThomas Gleixner }
144