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