|
|
coherent
/*---------------------------------------------------------------------------+
| reg_compare.c |
| |
| Compare two floating point registers |
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail [email protected] |
| |
| |
+---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------+
| compare() is the core FPU_REG comparison function |
+---------------------------------------------------------------------------*/
#include "fpu_system.h"
#include "exception.h"
#include "fpu_emu.h"
#include "status_w.h"
int emCompare(FPU_REG *b)
{
int diff;
if ( FPU_st0_ptr->tag | b->tag )
{
if ( FPU_st0_ptr->tag == TW_Zero )
{
if ( b->tag == TW_Zero ) return COMP_A_EQ_B;
if ( b->tag == TW_Valid )
{
return (b->sign == SIGN_POS) ? COMP_A_LT_B : COMP_A_GT_B ;
}
}
else if ( b->tag == TW_Zero )
{
if ( FPU_st0_ptr->tag == TW_Valid )
{
return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_GT_B : COMP_A_LT_B ;
}
}
if ( FPU_st0_ptr->tag == TW_Infinity )
{
if ( (b->tag == TW_Valid) || (b->tag == TW_Zero) )
{
return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_GT_B : COMP_A_LT_B;
}
else if ( b->tag == TW_Infinity )
{
/* The 80486 book says that infinities can be equal! */
return (FPU_st0_ptr->sign == b->sign) ? COMP_A_EQ_B :
((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_GT_B : COMP_A_LT_B);
}
/* Fall through to the NaN code */
}
else if ( b->tag == TW_Infinity )
{
if ( (FPU_st0_ptr->tag == TW_Valid) || (FPU_st0_ptr->tag == TW_Zero) )
{
return (b->sign == SIGN_POS) ? COMP_A_LT_B : COMP_A_GT_B;
}
/* Fall through to the NaN code */
}
/* The only possibility now should be that one of the arguments
is a NaN */
if ( (FPU_st0_ptr->tag == TW_NaN) || (b->tag == TW_NaN) )
{
if ( ((FPU_st0_ptr->tag == TW_NaN) && !(FPU_st0_ptr->sigh & 0x40000000))
|| ((b->tag == TW_NaN) && !(b->sigh & 0x40000000)) )
/* At least one arg is a signaling NaN */
return COMP_NOCOMP | COMP_SNAN | COMP_NAN;
else
/* Neither is a signaling NaN */
return COMP_NOCOMP | COMP_NAN;
}
EXCEPTION(EX_Invalid);
}
#ifdef PARANOID
if (!(FPU_st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
#endif PARANOID
if (FPU_st0_ptr->sign != b->sign)
return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_GT_B : COMP_A_LT_B;
diff = FPU_st0_ptr->exp - b->exp;
if ( diff == 0 )
{
diff = FPU_st0_ptr->sigh - b->sigh;
if ( diff == 0 )
diff = FPU_st0_ptr->sigl - b->sigl;
}
if ( diff > 0 )
return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_GT_B : COMP_A_LT_B ;
if ( diff < 0 )
return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_LT_B : COMP_A_GT_B ;
return COMP_A_EQ_B;
}
void compare_st_data(void)
{
int f;
int c = emCompare(&FPU_loaded_data);
if (c & COMP_NAN)
{
EXCEPTION(EX_Invalid);
f = SW_C3 | SW_C2 | SW_C0;
}
else
switch (c)
{
case COMP_A_LT_B:
f = SW_C0;
break;
case COMP_A_EQ_B:
f = SW_C3;
break;
case COMP_A_GT_B:
f = 0;
break;
case COMP_NOCOMP:
f = SW_C3 | SW_C2 | SW_C0;
break;
#ifdef PARANOID
default:
EXCEPTION(EX_INTERNAL|0x121);
f = SW_C3 | SW_C2 | SW_C0;
break;
#endif PARANOID
}
setcc(f);
}
static void compare_st_st(int nr)
{
int c = emCompare(&st(nr));
int f;
if (c & COMP_NAN)
{
EXCEPTION(EX_Invalid);
f = SW_C3 | SW_C2 | SW_C0;
}
else
switch (c)
{
case COMP_A_LT_B:
f = SW_C0;
break;
case COMP_A_EQ_B:
f = SW_C3;
break;
case COMP_A_GT_B:
f = 0;
break;
case COMP_NOCOMP:
f = SW_C3 | SW_C2 | SW_C0;
break;
#ifdef PARANOID
default:
EXCEPTION(EX_INTERNAL|0x122);
f = SW_C3 | SW_C2 | SW_C0;
break;
#endif PARANOID
}
setcc(f);
}
static void compare_u_st_st(int nr)
{
int f;
int c = emCompare(&st(nr));
if (c & COMP_NAN)
{
if (c & COMP_SNAN) /* This is the only difference between
un-ordered and ordinary comparisons */
EXCEPTION(EX_Invalid);
f = SW_C3 | SW_C2 | SW_C0;
}
else
switch (c)
{
case COMP_A_LT_B:
f = SW_C0;
break;
case COMP_A_EQ_B:
f = SW_C3;
break;
case COMP_A_GT_B:
f = 0;
break;
case COMP_NOCOMP:
f = SW_C3 | SW_C2 | SW_C0;
break;
#ifdef PARANOID
default:
EXCEPTION(EX_INTERNAL|0x123);
f = SW_C3 | SW_C2 | SW_C0;
break;
#endif PARANOID
}
setcc(f);
}
/*---------------------------------------------------------------------------*/
void fcom_st()
{
/* fcom st(i) */
compare_st_st(FPU_rm);
}
void fcompst()
{
/* fcomp st(i) */
compare_st_st(FPU_rm);
pop();
}
void fcompp()
{
/* fcompp */
if (FPU_rm != 1)
return Un_impl();
compare_st_st(1);
pop(); FPU_st0_ptr = &st(0);
pop();
}
void fucom_()
{
/* fucom st(i) */
compare_u_st_st(FPU_rm);
}
void fucomp()
{
/* fucomp st(i) */
compare_u_st_st(FPU_rm);
pop();
}
void fucompp()
{
/* fucompp */
if (FPU_rm == 1)
{
compare_u_st_st(1);
pop(); FPU_st0_ptr = &st(0);
pop();
}
else
Un_impl();
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.