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