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 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 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 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 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 128da957e11SThomas Gleixner void FPU_etc(void) 129da957e11SThomas Gleixner { 130da957e11SThomas Gleixner (fp_etc_table[FPU_rm]) (&st(0), FPU_gettag0()); 131da957e11SThomas Gleixner } 132