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 
fnop(void)20 static void fnop(void)
21 {
22 }
23 
fclex(void)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 */
finit()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 
finit_()61 void finit_()
62 {
63   (finit_table[FPU_rm])();
64 }
65 
66 
fstsw_ax(void)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 
fstsw_()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 
fp_nop()89 void fp_nop()
90 {
91   (fp_nop_table[FPU_rm])();
92 }
93 
94 
fld_i_()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 
fxch_i()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 
ffree_()176 void ffree_()
177 {
178   /* ffree st(i) */
179   FPU_settagi(FPU_rm, TAG_Empty);
180 }
181 
182 
ffreep()183 void ffreep()
184 {
185   /* ffree st(i) + pop - unofficial code */
186   FPU_settagi(FPU_rm, TAG_Empty);
187   FPU_pop();
188 }
189 
190 
fst_i_()191 void fst_i_()
192 {
193   /* fst st(i) */
194   FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
195 }
196 
197 
fstp_i()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