xref: /openbmc/linux/arch/x86/math-emu/fpu_etc.c (revision 3d0d14f983b55a570b976976284df4c434af3223)
1da957e11SThomas Gleixner /*---------------------------------------------------------------------------+
2da957e11SThomas Gleixner  |  fpu_etc.c                                                                |
3da957e11SThomas Gleixner  |                                                                           |
4da957e11SThomas Gleixner  | Implement a few FPU instructions.                                         |
5da957e11SThomas Gleixner  |                                                                           |
6da957e11SThomas Gleixner  | Copyright (C) 1992,1993,1994,1997                                         |
7da957e11SThomas Gleixner  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
8da957e11SThomas Gleixner  |                       Australia.  E-mail   billm@suburbia.net             |
9da957e11SThomas Gleixner  |                                                                           |
10da957e11SThomas Gleixner  |                                                                           |
11da957e11SThomas Gleixner  +---------------------------------------------------------------------------*/
12da957e11SThomas Gleixner 
13da957e11SThomas Gleixner #include "fpu_system.h"
14da957e11SThomas Gleixner #include "exception.h"
15da957e11SThomas Gleixner #include "fpu_emu.h"
16da957e11SThomas Gleixner #include "status_w.h"
17da957e11SThomas Gleixner #include "reg_constant.h"
18da957e11SThomas Gleixner 
19da957e11SThomas Gleixner static void fchs(FPU_REG * st0_ptr, u_char st0tag)
20da957e11SThomas Gleixner {
21*3d0d14f9SIngo Molnar 	if (st0tag ^ TAG_Empty) {
22da957e11SThomas Gleixner 		signbyte(st0_ptr) ^= SIGN_NEG;
23da957e11SThomas Gleixner 		clear_C1();
24*3d0d14f9SIngo Molnar 	} else
25da957e11SThomas Gleixner 		FPU_stack_underflow();
26da957e11SThomas Gleixner }
27da957e11SThomas Gleixner 
28da957e11SThomas Gleixner static void fabs(FPU_REG * st0_ptr, u_char st0tag)
29da957e11SThomas Gleixner {
30*3d0d14f9SIngo Molnar 	if (st0tag ^ TAG_Empty) {
31da957e11SThomas Gleixner 		setpositive(st0_ptr);
32da957e11SThomas Gleixner 		clear_C1();
33*3d0d14f9SIngo Molnar 	} else
34da957e11SThomas Gleixner 		FPU_stack_underflow();
35da957e11SThomas Gleixner }
36da957e11SThomas Gleixner 
37da957e11SThomas Gleixner static void ftst_(FPU_REG * st0_ptr, u_char st0tag)
38da957e11SThomas Gleixner {
39*3d0d14f9SIngo Molnar 	switch (st0tag) {
40da957e11SThomas Gleixner 	case TAG_Zero:
41da957e11SThomas Gleixner 		setcc(SW_C3);
42da957e11SThomas Gleixner 		break;
43da957e11SThomas Gleixner 	case TAG_Valid:
44da957e11SThomas Gleixner 		if (getsign(st0_ptr) == SIGN_POS)
45da957e11SThomas Gleixner 			setcc(0);
46da957e11SThomas Gleixner 		else
47da957e11SThomas Gleixner 			setcc(SW_C0);
48da957e11SThomas Gleixner 		break;
49da957e11SThomas Gleixner 	case TAG_Special:
50*3d0d14f9SIngo Molnar 		switch (FPU_Special(st0_ptr)) {
51da957e11SThomas Gleixner 		case TW_Denormal:
52da957e11SThomas Gleixner 			if (getsign(st0_ptr) == SIGN_POS)
53da957e11SThomas Gleixner 				setcc(0);
54da957e11SThomas Gleixner 			else
55da957e11SThomas Gleixner 				setcc(SW_C0);
56*3d0d14f9SIngo Molnar 			if (denormal_operand() < 0) {
57da957e11SThomas Gleixner #ifdef PECULIAR_486
58da957e11SThomas Gleixner 				/* This is weird! */
59da957e11SThomas Gleixner 				if (getsign(st0_ptr) == SIGN_POS)
60da957e11SThomas Gleixner 					setcc(SW_C3);
61da957e11SThomas Gleixner #endif /* PECULIAR_486 */
62da957e11SThomas Gleixner 				return;
63da957e11SThomas Gleixner 			}
64da957e11SThomas Gleixner 			break;
65da957e11SThomas Gleixner 		case TW_NaN:
66da957e11SThomas Gleixner 			setcc(SW_C0 | SW_C2 | SW_C3);	/* Operand is not comparable */
67da957e11SThomas Gleixner 			EXCEPTION(EX_Invalid);
68da957e11SThomas Gleixner 			break;
69da957e11SThomas Gleixner 		case TW_Infinity:
70da957e11SThomas Gleixner 			if (getsign(st0_ptr) == SIGN_POS)
71da957e11SThomas Gleixner 				setcc(0);
72da957e11SThomas Gleixner 			else
73da957e11SThomas Gleixner 				setcc(SW_C0);
74da957e11SThomas Gleixner 			break;
75da957e11SThomas Gleixner 		default:
76da957e11SThomas Gleixner 			setcc(SW_C0 | SW_C2 | SW_C3);	/* Operand is not comparable */
77da957e11SThomas Gleixner 			EXCEPTION(EX_INTERNAL | 0x14);
78da957e11SThomas Gleixner 			break;
79da957e11SThomas Gleixner 		}
80da957e11SThomas Gleixner 		break;
81da957e11SThomas Gleixner 	case TAG_Empty:
82da957e11SThomas Gleixner 		setcc(SW_C0 | SW_C2 | SW_C3);
83da957e11SThomas Gleixner 		EXCEPTION(EX_StackUnder);
84da957e11SThomas Gleixner 		break;
85da957e11SThomas Gleixner 	}
86da957e11SThomas Gleixner }
87da957e11SThomas Gleixner 
88da957e11SThomas Gleixner static void fxam(FPU_REG * st0_ptr, u_char st0tag)
89da957e11SThomas Gleixner {
90da957e11SThomas Gleixner 	int c = 0;
91*3d0d14f9SIngo Molnar 	switch (st0tag) {
92da957e11SThomas Gleixner 	case TAG_Empty:
93da957e11SThomas Gleixner 		c = SW_C3 | SW_C0;
94da957e11SThomas Gleixner 		break;
95da957e11SThomas Gleixner 	case TAG_Zero:
96da957e11SThomas Gleixner 		c = SW_C3;
97da957e11SThomas Gleixner 		break;
98da957e11SThomas Gleixner 	case TAG_Valid:
99da957e11SThomas Gleixner 		c = SW_C2;
100da957e11SThomas Gleixner 		break;
101da957e11SThomas Gleixner 	case TAG_Special:
102*3d0d14f9SIngo Molnar 		switch (FPU_Special(st0_ptr)) {
103da957e11SThomas Gleixner 		case TW_Denormal:
104da957e11SThomas Gleixner 			c = SW_C2 | SW_C3;	/* Denormal */
105da957e11SThomas Gleixner 			break;
106da957e11SThomas Gleixner 		case TW_NaN:
107da957e11SThomas Gleixner 			/* We also use NaN for unsupported types. */
108*3d0d14f9SIngo Molnar 			if ((st0_ptr->sigh & 0x80000000)
109*3d0d14f9SIngo Molnar 			    && (exponent(st0_ptr) == EXP_OVER))
110da957e11SThomas Gleixner 				c = SW_C0;
111da957e11SThomas Gleixner 			break;
112da957e11SThomas Gleixner 		case TW_Infinity:
113da957e11SThomas Gleixner 			c = SW_C2 | SW_C0;
114da957e11SThomas Gleixner 			break;
115da957e11SThomas Gleixner 		}
116da957e11SThomas Gleixner 	}
117da957e11SThomas Gleixner 	if (getsign(st0_ptr) == SIGN_NEG)
118da957e11SThomas Gleixner 		c |= SW_C1;
119da957e11SThomas Gleixner 	setcc(c);
120da957e11SThomas Gleixner }
121da957e11SThomas Gleixner 
122da957e11SThomas Gleixner static FUNC_ST0 const fp_etc_table[] = {
123da957e11SThomas Gleixner 	fchs, fabs, (FUNC_ST0) FPU_illegal, (FUNC_ST0) FPU_illegal,
124da957e11SThomas Gleixner 	ftst_, fxam, (FUNC_ST0) FPU_illegal, (FUNC_ST0) FPU_illegal
125da957e11SThomas Gleixner };
126da957e11SThomas Gleixner 
127da957e11SThomas Gleixner void FPU_etc(void)
128da957e11SThomas Gleixner {
129da957e11SThomas Gleixner 	(fp_etc_table[FPU_rm]) (&st(0), FPU_gettag0());
130da957e11SThomas Gleixner }
131