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