Linux-2.6.12-rc2
[linux-2.6.git] / arch / i386 / math-emu / fpu_aux.c
1 /*---------------------------------------------------------------------------+
2  |  fpu_aux.c                                                                |
3  |                                                                           |
4  | Code to implement some of the FPU auxiliary instructions.                 |
5  |                                                                           |
6  | Copyright (C) 1992,1993,1994,1997                                         |
7  |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
8  |                  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 "control_w.h"
18
19
20 static void fnop(void)
21 {
22 }
23
24 static void fclex(void)
25 {
26   partial_status &= ~(SW_Backward|SW_Summary|SW_Stack_Fault|SW_Precision|
27                    SW_Underflow|SW_Overflow|SW_Zero_Div|SW_Denorm_Op|
28                    SW_Invalid);
29   no_ip_update = 1;
30 }
31
32 /* Needs to be externally visible */
33 void finit(void)
34 {
35   control_word = 0x037f;
36   partial_status = 0;
37   top = 0;            /* We don't keep top in the status word internally. */
38   fpu_tag_word = 0xffff;
39   /* The behaviour is different from that detailed in
40      Section 15.1.6 of the Intel manual */
41   operand_address.offset = 0;
42   operand_address.selector = 0;
43   instruction_address.offset = 0;
44   instruction_address.selector = 0;
45   instruction_address.opcode = 0;
46   no_ip_update = 1;
47 }
48
49 /*
50  * These are nops on the i387..
51  */
52 #define feni fnop
53 #define fdisi fnop
54 #define fsetpm fnop
55
56 static FUNC const finit_table[] = {
57   feni, fdisi, fclex, finit,
58   fsetpm, FPU_illegal, FPU_illegal, FPU_illegal
59 };
60
61 void finit_(void)
62 {
63   (finit_table[FPU_rm])();
64 }
65
66
67 static void fstsw_ax(void)
68 {
69   *(short *) &FPU_EAX = status_word();
70   no_ip_update = 1;
71 }
72
73 static FUNC const fstsw_table[] = {
74   fstsw_ax, FPU_illegal, FPU_illegal, FPU_illegal,
75   FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal
76 };
77
78 void fstsw_(void)
79 {
80   (fstsw_table[FPU_rm])();
81 }
82
83
84 static FUNC const fp_nop_table[] = {
85   fnop, FPU_illegal, FPU_illegal, FPU_illegal,
86   FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal
87 };
88
89 void fp_nop(void)
90 {
91   (fp_nop_table[FPU_rm])();
92 }
93
94
95 void fld_i_(void)
96 {
97   FPU_REG *st_new_ptr;
98   int i;
99   u_char tag;
100
101   if ( STACK_OVERFLOW )
102     { FPU_stack_overflow(); return; }
103
104   /* fld st(i) */
105   i = FPU_rm;
106   if ( NOT_EMPTY(i) )
107     {
108       reg_copy(&st(i), st_new_ptr);
109       tag = FPU_gettagi(i);
110       push();
111       FPU_settag0(tag);
112     }
113   else
114     {
115       if ( control_word & CW_Invalid )
116         {
117           /* The masked response */
118           FPU_stack_underflow();
119         }
120       else
121         EXCEPTION(EX_StackUnder);
122     }
123
124 }
125
126
127 void fxch_i(void)
128 {
129   /* fxch st(i) */
130   FPU_REG t;
131   int i = FPU_rm;
132   FPU_REG *st0_ptr = &st(0), *sti_ptr = &st(i);
133   long tag_word = fpu_tag_word;
134   int regnr = top & 7, regnri = ((regnr + i) & 7);
135   u_char st0_tag = (tag_word >> (regnr*2)) & 3;
136   u_char sti_tag = (tag_word >> (regnri*2)) & 3;
137
138   if ( st0_tag == TAG_Empty )
139     {
140       if ( sti_tag == TAG_Empty )
141         {
142           FPU_stack_underflow();
143           FPU_stack_underflow_i(i);
144           return;
145         }
146       if ( control_word & CW_Invalid )
147         {
148           /* Masked response */
149           FPU_copy_to_reg0(sti_ptr, sti_tag);
150         }
151       FPU_stack_underflow_i(i);
152       return;
153     }
154   if ( sti_tag == TAG_Empty )
155     {
156       if ( control_word & CW_Invalid )
157         {
158           /* Masked response */
159           FPU_copy_to_regi(st0_ptr, st0_tag, i);
160         }
161       FPU_stack_underflow();
162       return;
163     }
164   clear_C1();
165
166   reg_copy(st0_ptr, &t);
167   reg_copy(sti_ptr, st0_ptr);
168   reg_copy(&t, sti_ptr);
169
170   tag_word &= ~(3 << (regnr*2)) & ~(3 << (regnri*2));
171   tag_word |= (sti_tag << (regnr*2)) | (st0_tag << (regnri*2));
172   fpu_tag_word = tag_word;
173 }
174
175
176 void ffree_(void)
177 {
178   /* ffree st(i) */
179   FPU_settagi(FPU_rm, TAG_Empty);
180 }
181
182
183 void ffreep(void)
184 {
185   /* ffree st(i) + pop - unofficial code */
186   FPU_settagi(FPU_rm, TAG_Empty);
187   FPU_pop();
188 }
189
190
191 void fst_i_(void)
192 {
193   /* fst st(i) */
194   FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
195 }
196
197
198 void fstp_i(void)
199 {
200   /* fstp st(i) */
201   FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
202   FPU_pop();
203 }
204