Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
1da177e4 LT |
2 | /*---------------------------------------------------------------------------+ |
3 | | fpu_aux.c | | |
4 | | | | |
5 | | Code to implement some of the FPU auxiliary instructions. | | |
6 | | | | |
7 | | Copyright (C) 1992,1993,1994,1997 | | |
8 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | | |
9 | | E-mail billm@suburbia.net | | |
10 | | | | |
11 | | | | |
12 | +---------------------------------------------------------------------------*/ | |
13 | ||
14 | #include "fpu_system.h" | |
15 | #include "exception.h" | |
16 | #include "fpu_emu.h" | |
17 | #include "status_w.h" | |
18 | #include "control_w.h" | |
19 | ||
1da177e4 LT |
20 | static void fnop(void) |
21 | { | |
22 | } | |
23 | ||
24 | static void fclex(void) | |
25 | { | |
3d0d14f9 IM |
26 | partial_status &= |
27 | ~(SW_Backward | SW_Summary | SW_Stack_Fault | SW_Precision | | |
28 | SW_Underflow | SW_Overflow | SW_Zero_Div | SW_Denorm_Op | | |
29 | SW_Invalid); | |
30 | no_ip_update = 1; | |
1da177e4 LT |
31 | } |
32 | ||
33 | /* Needs to be externally visible */ | |
c47ada30 | 34 | void fpstate_init_soft(struct swregs_state *soft) |
1da177e4 | 35 | { |
ab9e1858 | 36 | struct address *oaddr, *iaddr; |
86603283 | 37 | memset(soft, 0, sizeof(*soft)); |
ab9e1858 DG |
38 | soft->cwd = 0x037f; |
39 | soft->swd = 0; | |
40 | soft->ftop = 0; /* We don't keep top in the status word internally. */ | |
41 | soft->twd = 0xffff; | |
3d0d14f9 IM |
42 | /* The behaviour is different from that detailed in |
43 | Section 15.1.6 of the Intel manual */ | |
ab9e1858 DG |
44 | oaddr = (struct address *)&soft->foo; |
45 | oaddr->offset = 0; | |
46 | oaddr->selector = 0; | |
47 | iaddr = (struct address *)&soft->fip; | |
48 | iaddr->offset = 0; | |
49 | iaddr->selector = 0; | |
50 | iaddr->opcode = 0; | |
51 | soft->no_update = 1; | |
52 | } | |
53 | ||
54 | void finit(void) | |
55 | { | |
63d6bdf3 | 56 | fpstate_init_soft(¤t->thread.fpu.fpstate->regs.soft); |
1da177e4 LT |
57 | } |
58 | ||
59 | /* | |
60 | * These are nops on the i387.. | |
61 | */ | |
62 | #define feni fnop | |
63 | #define fdisi fnop | |
64 | #define fsetpm fnop | |
65 | ||
66 | static FUNC const finit_table[] = { | |
3d0d14f9 IM |
67 | feni, fdisi, fclex, finit, |
68 | fsetpm, FPU_illegal, FPU_illegal, FPU_illegal | |
1da177e4 LT |
69 | }; |
70 | ||
71 | void finit_(void) | |
72 | { | |
3d0d14f9 | 73 | (finit_table[FPU_rm]) (); |
1da177e4 LT |
74 | } |
75 | ||
1da177e4 LT |
76 | static void fstsw_ax(void) |
77 | { | |
3d0d14f9 IM |
78 | *(short *)&FPU_EAX = status_word(); |
79 | no_ip_update = 1; | |
1da177e4 LT |
80 | } |
81 | ||
82 | static FUNC const fstsw_table[] = { | |
3d0d14f9 IM |
83 | fstsw_ax, FPU_illegal, FPU_illegal, FPU_illegal, |
84 | FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal | |
1da177e4 LT |
85 | }; |
86 | ||
87 | void fstsw_(void) | |
88 | { | |
3d0d14f9 | 89 | (fstsw_table[FPU_rm]) (); |
1da177e4 LT |
90 | } |
91 | ||
1da177e4 | 92 | static FUNC const fp_nop_table[] = { |
3d0d14f9 IM |
93 | fnop, FPU_illegal, FPU_illegal, FPU_illegal, |
94 | FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal | |
1da177e4 LT |
95 | }; |
96 | ||
97 | void fp_nop(void) | |
98 | { | |
3d0d14f9 | 99 | (fp_nop_table[FPU_rm]) (); |
1da177e4 LT |
100 | } |
101 | ||
1da177e4 LT |
102 | void fld_i_(void) |
103 | { | |
3d0d14f9 IM |
104 | FPU_REG *st_new_ptr; |
105 | int i; | |
106 | u_char tag; | |
107 | ||
108 | if (STACK_OVERFLOW) { | |
109 | FPU_stack_overflow(); | |
110 | return; | |
1da177e4 | 111 | } |
1da177e4 | 112 | |
3d0d14f9 IM |
113 | /* fld st(i) */ |
114 | i = FPU_rm; | |
115 | if (NOT_EMPTY(i)) { | |
116 | reg_copy(&st(i), st_new_ptr); | |
117 | tag = FPU_gettagi(i); | |
118 | push(); | |
119 | FPU_settag0(tag); | |
120 | } else { | |
121 | if (control_word & CW_Invalid) { | |
122 | /* The masked response */ | |
123 | FPU_stack_underflow(); | |
124 | } else | |
125 | EXCEPTION(EX_StackUnder); | |
126 | } | |
1da177e4 | 127 | |
3d0d14f9 | 128 | } |
1da177e4 LT |
129 | |
130 | void fxch_i(void) | |
131 | { | |
3d0d14f9 IM |
132 | /* fxch st(i) */ |
133 | FPU_REG t; | |
134 | int i = FPU_rm; | |
135 | FPU_REG *st0_ptr = &st(0), *sti_ptr = &st(i); | |
136 | long tag_word = fpu_tag_word; | |
137 | int regnr = top & 7, regnri = ((regnr + i) & 7); | |
138 | u_char st0_tag = (tag_word >> (regnr * 2)) & 3; | |
139 | u_char sti_tag = (tag_word >> (regnri * 2)) & 3; | |
140 | ||
141 | if (st0_tag == TAG_Empty) { | |
142 | if (sti_tag == TAG_Empty) { | |
143 | FPU_stack_underflow(); | |
144 | FPU_stack_underflow_i(i); | |
145 | return; | |
146 | } | |
147 | if (control_word & CW_Invalid) { | |
148 | /* Masked response */ | |
149 | FPU_copy_to_reg0(sti_ptr, sti_tag); | |
150 | } | |
151 | FPU_stack_underflow_i(i); | |
152 | return; | |
1da177e4 | 153 | } |
3d0d14f9 IM |
154 | if (sti_tag == TAG_Empty) { |
155 | if (control_word & CW_Invalid) { | |
156 | /* Masked response */ | |
157 | FPU_copy_to_regi(st0_ptr, st0_tag, i); | |
158 | } | |
159 | FPU_stack_underflow(); | |
160 | return; | |
1da177e4 | 161 | } |
3d0d14f9 | 162 | clear_C1(); |
1da177e4 | 163 | |
3d0d14f9 IM |
164 | reg_copy(st0_ptr, &t); |
165 | reg_copy(sti_ptr, st0_ptr); | |
166 | reg_copy(&t, sti_ptr); | |
167 | ||
168 | tag_word &= ~(3 << (regnr * 2)) & ~(3 << (regnri * 2)); | |
169 | tag_word |= (sti_tag << (regnr * 2)) | (st0_tag << (regnri * 2)); | |
170 | fpu_tag_word = tag_word; | |
171 | } | |
1da177e4 | 172 | |
9a9d8642 DV |
173 | static void fcmovCC(void) |
174 | { | |
175 | /* fcmovCC st(i) */ | |
176 | int i = FPU_rm; | |
177 | FPU_REG *st0_ptr = &st(0); | |
178 | FPU_REG *sti_ptr = &st(i); | |
179 | long tag_word = fpu_tag_word; | |
180 | int regnr = top & 7; | |
181 | int regnri = (top + i) & 7; | |
182 | u_char sti_tag = (tag_word >> (regnri * 2)) & 3; | |
183 | ||
184 | if (sti_tag == TAG_Empty) { | |
185 | FPU_stack_underflow(); | |
186 | clear_C1(); | |
187 | return; | |
188 | } | |
189 | reg_copy(sti_ptr, st0_ptr); | |
190 | tag_word &= ~(3 << (regnr * 2)); | |
191 | tag_word |= (sti_tag << (regnr * 2)); | |
192 | fpu_tag_word = tag_word; | |
193 | } | |
194 | ||
195 | void fcmovb(void) | |
196 | { | |
197 | if (FPU_EFLAGS & X86_EFLAGS_CF) | |
198 | fcmovCC(); | |
199 | } | |
200 | ||
201 | void fcmove(void) | |
202 | { | |
203 | if (FPU_EFLAGS & X86_EFLAGS_ZF) | |
204 | fcmovCC(); | |
205 | } | |
206 | ||
207 | void fcmovbe(void) | |
208 | { | |
209 | if (FPU_EFLAGS & (X86_EFLAGS_CF|X86_EFLAGS_ZF)) | |
210 | fcmovCC(); | |
211 | } | |
212 | ||
213 | void fcmovu(void) | |
214 | { | |
215 | if (FPU_EFLAGS & X86_EFLAGS_PF) | |
216 | fcmovCC(); | |
217 | } | |
218 | ||
219 | void fcmovnb(void) | |
220 | { | |
221 | if (!(FPU_EFLAGS & X86_EFLAGS_CF)) | |
222 | fcmovCC(); | |
223 | } | |
224 | ||
225 | void fcmovne(void) | |
226 | { | |
227 | if (!(FPU_EFLAGS & X86_EFLAGS_ZF)) | |
228 | fcmovCC(); | |
229 | } | |
230 | ||
231 | void fcmovnbe(void) | |
232 | { | |
233 | if (!(FPU_EFLAGS & (X86_EFLAGS_CF|X86_EFLAGS_ZF))) | |
234 | fcmovCC(); | |
235 | } | |
236 | ||
237 | void fcmovnu(void) | |
238 | { | |
239 | if (!(FPU_EFLAGS & X86_EFLAGS_PF)) | |
240 | fcmovCC(); | |
241 | } | |
242 | ||
1da177e4 LT |
243 | void ffree_(void) |
244 | { | |
3d0d14f9 IM |
245 | /* ffree st(i) */ |
246 | FPU_settagi(FPU_rm, TAG_Empty); | |
1da177e4 LT |
247 | } |
248 | ||
1da177e4 LT |
249 | void ffreep(void) |
250 | { | |
3d0d14f9 IM |
251 | /* ffree st(i) + pop - unofficial code */ |
252 | FPU_settagi(FPU_rm, TAG_Empty); | |
253 | FPU_pop(); | |
1da177e4 LT |
254 | } |
255 | ||
1da177e4 LT |
256 | void fst_i_(void) |
257 | { | |
3d0d14f9 IM |
258 | /* fst st(i) */ |
259 | FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm); | |
1da177e4 LT |
260 | } |
261 | ||
1da177e4 LT |
262 | void fstp_i(void) |
263 | { | |
3d0d14f9 IM |
264 | /* fstp st(i) */ |
265 | FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm); | |
266 | FPU_pop(); | |
1da177e4 | 267 | } |