Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/x86/math-emu/fpu_aux.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0
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 [email protected] |
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
20
static void fnop(void)
21
{
22
}
23
24
static void fclex(void)
25
{
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;
31
}
32
33
/* Needs to be externally visible */
34
void fpstate_init_soft(struct swregs_state *soft)
35
{
36
struct address *oaddr, *iaddr;
37
memset(soft, 0, sizeof(*soft));
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;
42
/* The behaviour is different from that detailed in
43
Section 15.1.6 of the Intel manual */
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
{
56
fpstate_init_soft(&x86_task_fpu(current)->fpstate->regs.soft);
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[] = {
67
feni, fdisi, fclex, finit,
68
fsetpm, FPU_illegal, FPU_illegal, FPU_illegal
69
};
70
71
void finit_(void)
72
{
73
(finit_table[FPU_rm]) ();
74
}
75
76
static void fstsw_ax(void)
77
{
78
*(short *)&FPU_EAX = status_word();
79
no_ip_update = 1;
80
}
81
82
static FUNC const fstsw_table[] = {
83
fstsw_ax, FPU_illegal, FPU_illegal, FPU_illegal,
84
FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal
85
};
86
87
void fstsw_(void)
88
{
89
(fstsw_table[FPU_rm]) ();
90
}
91
92
static FUNC const fp_nop_table[] = {
93
fnop, FPU_illegal, FPU_illegal, FPU_illegal,
94
FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal
95
};
96
97
void fp_nop(void)
98
{
99
(fp_nop_table[FPU_rm]) ();
100
}
101
102
void fld_i_(void)
103
{
104
FPU_REG *st_new_ptr;
105
int i;
106
u_char tag;
107
108
if (STACK_OVERFLOW) {
109
FPU_stack_overflow();
110
return;
111
}
112
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
}
127
128
}
129
130
void fxch_i(void)
131
{
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;
153
}
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;
161
}
162
clear_C1();
163
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
}
172
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
243
void ffree_(void)
244
{
245
/* ffree st(i) */
246
FPU_settagi(FPU_rm, TAG_Empty);
247
}
248
249
void ffreep(void)
250
{
251
/* ffree st(i) + pop - unofficial code */
252
FPU_settagi(FPU_rm, TAG_Empty);
253
FPU_pop();
254
}
255
256
void fst_i_(void)
257
{
258
/* fst st(i) */
259
FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
260
}
261
262
void fstp_i(void)
263
{
264
/* fstp st(i) */
265
FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
266
FPU_pop();
267
}
268
269