2005-04-17 02:20:36 +04:00
/*---------------------------------------------------------------------------+
| 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"
2008-01-30 15:30:12 +03:00
static void fchs ( FPU_REG * st0_ptr , u_char st0tag )
2005-04-17 02:20:36 +04:00
{
2008-01-30 15:30:11 +03:00
if ( st0tag ^ TAG_Empty ) {
signbyte ( st0_ptr ) ^ = SIGN_NEG ;
clear_C1 ( ) ;
} else
FPU_stack_underflow ( ) ;
2005-04-17 02:20:36 +04:00
}
2008-01-30 15:30:12 +03:00
static void fabs ( FPU_REG * st0_ptr , u_char st0tag )
2005-04-17 02:20:36 +04:00
{
2008-01-30 15:30:11 +03:00
if ( st0tag ^ TAG_Empty ) {
setpositive ( st0_ptr ) ;
clear_C1 ( ) ;
} else
FPU_stack_underflow ( ) ;
2005-04-17 02:20:36 +04:00
}
2008-01-30 15:30:12 +03:00
static void ftst_ ( FPU_REG * st0_ptr , u_char st0tag )
2005-04-17 02:20:36 +04:00
{
2008-01-30 15:30:11 +03:00
switch ( st0tag ) {
case TAG_Zero :
2005-04-17 02:20:36 +04:00
setcc ( SW_C3 ) ;
2008-01-30 15:30:11 +03:00
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 ) ;
2005-04-17 02:20:36 +04:00
# endif /* PECULIAR_486 */
2008-01-30 15:30:11 +03:00
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 ;
2005-04-17 02:20:36 +04:00
}
}
2008-01-30 15:30:12 +03:00
static void fxam ( FPU_REG * st0_ptr , u_char st0tag )
2005-04-17 02:20:36 +04:00
{
2008-01-30 15:30:11 +03:00
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 ;
}
2005-04-17 02:20:36 +04:00
}
2008-01-30 15:30:11 +03:00
if ( getsign ( st0_ptr ) = = SIGN_NEG )
c | = SW_C1 ;
setcc ( c ) ;
2005-04-17 02:20:36 +04:00
}
static FUNC_ST0 const fp_etc_table [ ] = {
2008-01-30 15:30:11 +03:00
fchs , fabs , ( FUNC_ST0 ) FPU_illegal , ( FUNC_ST0 ) FPU_illegal ,
ftst_ , fxam , ( FUNC_ST0 ) FPU_illegal , ( FUNC_ST0 ) FPU_illegal
2005-04-17 02:20:36 +04:00
} ;
void FPU_etc ( void )
{
2008-01-30 15:30:11 +03:00
( fp_etc_table [ FPU_rm ] ) ( & st ( 0 ) , FPU_gettag0 ( ) ) ;
2005-04-17 02:20:36 +04:00
}