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 20 static void fchs(FPU_REG *st0_ptr, u_char st0tag) 21 { 22 if ( st0tag ^ TAG_Empty ) 23 { 24 signbyte(st0_ptr) ^= SIGN_NEG; 25 clear_C1(); 26 } 27 else 28 FPU_stack_underflow(); 29 } 30 31 32 static void fabs(FPU_REG *st0_ptr, u_char st0tag) 33 { 34 if ( st0tag ^ TAG_Empty ) 35 { 36 setpositive(st0_ptr); 37 clear_C1(); 38 } 39 else 40 FPU_stack_underflow(); 41 } 42 43 44 static void ftst_(FPU_REG *st0_ptr, u_char st0tag) 45 { 46 switch (st0tag) 47 { 48 case TAG_Zero: 49 setcc(SW_C3); 50 break; 51 case TAG_Valid: 52 if (getsign(st0_ptr) == SIGN_POS) 53 setcc(0); 54 else 55 setcc(SW_C0); 56 break; 57 case TAG_Special: 58 switch ( FPU_Special(st0_ptr) ) 59 { 60 case TW_Denormal: 61 if (getsign(st0_ptr) == SIGN_POS) 62 setcc(0); 63 else 64 setcc(SW_C0); 65 if ( denormal_operand() < 0 ) 66 { 67 #ifdef PECULIAR_486 68 /* This is weird! */ 69 if (getsign(st0_ptr) == SIGN_POS) 70 setcc(SW_C3); 71 #endif /* PECULIAR_486 */ 72 return; 73 } 74 break; 75 case TW_NaN: 76 setcc(SW_C0|SW_C2|SW_C3); /* Operand is not comparable */ 77 EXCEPTION(EX_Invalid); 78 break; 79 case TW_Infinity: 80 if (getsign(st0_ptr) == SIGN_POS) 81 setcc(0); 82 else 83 setcc(SW_C0); 84 break; 85 default: 86 setcc(SW_C0|SW_C2|SW_C3); /* Operand is not comparable */ 87 EXCEPTION(EX_INTERNAL|0x14); 88 break; 89 } 90 break; 91 case TAG_Empty: 92 setcc(SW_C0|SW_C2|SW_C3); 93 EXCEPTION(EX_StackUnder); 94 break; 95 } 96 } 97 98 99 static void fxam(FPU_REG *st0_ptr, u_char st0tag) 100 { 101 int c = 0; 102 switch (st0tag) 103 { 104 case TAG_Empty: 105 c = SW_C3|SW_C0; 106 break; 107 case TAG_Zero: 108 c = SW_C3; 109 break; 110 case TAG_Valid: 111 c = SW_C2; 112 break; 113 case TAG_Special: 114 switch ( FPU_Special(st0_ptr) ) 115 { 116 case TW_Denormal: 117 c = SW_C2|SW_C3; /* Denormal */ 118 break; 119 case TW_NaN: 120 /* We also use NaN for unsupported types. */ 121 if ( (st0_ptr->sigh & 0x80000000) && (exponent(st0_ptr) == EXP_OVER) ) 122 c = SW_C0; 123 break; 124 case TW_Infinity: 125 c = SW_C2|SW_C0; 126 break; 127 } 128 } 129 if ( getsign(st0_ptr) == SIGN_NEG ) 130 c |= SW_C1; 131 setcc(c); 132 } 133 134 135 static FUNC_ST0 const fp_etc_table[] = { 136 fchs, fabs, (FUNC_ST0)FPU_illegal, (FUNC_ST0)FPU_illegal, 137 ftst_, fxam, (FUNC_ST0)FPU_illegal, (FUNC_ST0)FPU_illegal 138 }; 139 140 void FPU_etc(void) 141 { 142 (fp_etc_table[FPU_rm])(&st(0), FPU_gettag0()); 143 } 144