| /*---------------------------------------------------------------------------+ | |
| | fpu_etc.c | | |
| | | | |
| | Implement a few FPU instructions. | | |
| | | | |
| | Copyright (C) 1992,1993,1994,1997 | | |
| | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | |
| | Australia. E-mail billm@suburbia.net | | |
| | | | |
| | | | |
| +---------------------------------------------------------------------------*/ | |
| #include "fpu_system.h" | |
| #include "exception.h" | |
| #include "fpu_emu.h" | |
| #include "status_w.h" | |
| #include "reg_constant.h" | |
| static void fchs(FPU_REG *st0_ptr, u_char st0tag) | |
| { | |
| if (st0tag ^ TAG_Empty) { | |
| signbyte(st0_ptr) ^= SIGN_NEG; | |
| clear_C1(); | |
| } else | |
| FPU_stack_underflow(); | |
| } | |
| static void fabs(FPU_REG *st0_ptr, u_char st0tag) | |
| { | |
| if (st0tag ^ TAG_Empty) { | |
| setpositive(st0_ptr); | |
| clear_C1(); | |
| } else | |
| FPU_stack_underflow(); | |
| } | |
| static void ftst_(FPU_REG *st0_ptr, u_char st0tag) | |
| { | |
| switch (st0tag) { | |
| case TAG_Zero: | |
| setcc(SW_C3); | |
| break; | |
| case TAG_Valid: | |
| if (getsign(st0_ptr) == SIGN_POS) | |
| setcc(0); | |
| else | |
| setcc(SW_C0); | |
| break; | |
| case TAG_Special: | |
| switch (FPU_Special(st0_ptr)) { | |
| case TW_Denormal: | |
| if (getsign(st0_ptr) == SIGN_POS) | |
| setcc(0); | |
| else | |
| setcc(SW_C0); | |
| if (denormal_operand() < 0) { | |
| #ifdef PECULIAR_486 | |
| /* This is weird! */ | |
| if (getsign(st0_ptr) == SIGN_POS) | |
| setcc(SW_C3); | |
| #endif /* PECULIAR_486 */ | |
| return; | |
| } | |
| break; | |
| case TW_NaN: | |
| setcc(SW_C0 | SW_C2 | SW_C3); /* Operand is not comparable */ | |
| EXCEPTION(EX_Invalid); | |
| break; | |
| case TW_Infinity: | |
| if (getsign(st0_ptr) == SIGN_POS) | |
| setcc(0); | |
| else | |
| setcc(SW_C0); | |
| break; | |
| default: | |
| setcc(SW_C0 | SW_C2 | SW_C3); /* Operand is not comparable */ | |
| EXCEPTION(EX_INTERNAL | 0x14); | |
| break; | |
| } | |
| break; | |
| case TAG_Empty: | |
| setcc(SW_C0 | SW_C2 | SW_C3); | |
| EXCEPTION(EX_StackUnder); | |
| break; | |
| } | |
| } | |
| static void fxam(FPU_REG *st0_ptr, u_char st0tag) | |
| { | |
| int c = 0; | |
| switch (st0tag) { | |
| case TAG_Empty: | |
| c = SW_C3 | SW_C0; | |
| break; | |
| case TAG_Zero: | |
| c = SW_C3; | |
| break; | |
| case TAG_Valid: | |
| c = SW_C2; | |
| break; | |
| case TAG_Special: | |
| switch (FPU_Special(st0_ptr)) { | |
| case TW_Denormal: | |
| c = SW_C2 | SW_C3; /* Denormal */ | |
| break; | |
| case TW_NaN: | |
| /* We also use NaN for unsupported types. */ | |
| if ((st0_ptr->sigh & 0x80000000) | |
| && (exponent(st0_ptr) == EXP_OVER)) | |
| c = SW_C0; | |
| break; | |
| case TW_Infinity: | |
| c = SW_C2 | SW_C0; | |
| break; | |
| } | |
| } | |
| if (getsign(st0_ptr) == SIGN_NEG) | |
| c |= SW_C1; | |
| setcc(c); | |
| } | |
| static FUNC_ST0 const fp_etc_table[] = { | |
| fchs, fabs, (FUNC_ST0) FPU_illegal, (FUNC_ST0) FPU_illegal, | |
| ftst_, fxam, (FUNC_ST0) FPU_illegal, (FUNC_ST0) FPU_illegal | |
| }; | |
| void FPU_etc(void) | |
| { | |
| (fp_etc_table[FPU_rm]) (&st(0), FPU_gettag0()); | |
| } |