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