File: /usr/src/linux/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     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()
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_()
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_()
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()
90     {
91       (fp_nop_table[FPU_rm])();
92     }
93     
94     
95     void fld_i_()
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()
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_()
177     {
178       /* ffree st(i) */
179       FPU_settagi(FPU_rm, TAG_Empty);
180     }
181     
182     
183     void ffreep()
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_()
192     {
193       /* fst st(i) */
194       FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
195     }
196     
197     
198     void fstp_i()
199     {
200       /* fstp st(i) */
201       FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
202       FPU_pop();
203     }
204     
205