File: /usr/src/linux/arch/i386/math-emu/fpu_etc.c

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