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