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