OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [i386/] [math-emu/] [reg_compare.c] - Diff between revs 1765 and 1782

Only display areas with differences | Details | Blame | View Log

Rev 1765 Rev 1782
/*---------------------------------------------------------------------------+
/*---------------------------------------------------------------------------+
 |  reg_compare.c                                                            |
 |  reg_compare.c                                                            |
 |                                                                           |
 |                                                                           |
 | Compare two floating point registers                                      |
 | Compare two floating point registers                                      |
 |                                                                           |
 |                                                                           |
 | Copyright (C) 1992,1993,1994                                              |
 | Copyright (C) 1992,1993,1994                                              |
 |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
 |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
 |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
 |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
 |                                                                           |
 |                                                                           |
 |                                                                           |
 |                                                                           |
 +---------------------------------------------------------------------------*/
 +---------------------------------------------------------------------------*/
 
 
/*---------------------------------------------------------------------------+
/*---------------------------------------------------------------------------+
 | compare() is the core FPU_REG comparison function                         |
 | compare() is the core FPU_REG comparison function                         |
 +---------------------------------------------------------------------------*/
 +---------------------------------------------------------------------------*/
 
 
#include "fpu_system.h"
#include "fpu_system.h"
#include "exception.h"
#include "exception.h"
#include "fpu_emu.h"
#include "fpu_emu.h"
#include "control_w.h"
#include "control_w.h"
#include "status_w.h"
#include "status_w.h"
 
 
 
 
int compare(FPU_REG const *b)
int compare(FPU_REG const *b)
{
{
  int diff;
  int diff;
  char         st0_tag;
  char         st0_tag;
  FPU_REG      *st0_ptr;
  FPU_REG      *st0_ptr;
 
 
  st0_ptr = &st(0);
  st0_ptr = &st(0);
  st0_tag = st0_ptr->tag;
  st0_tag = st0_ptr->tag;
 
 
  if ( st0_tag | b->tag )
  if ( st0_tag | b->tag )
    {
    {
      if ( st0_tag == TW_Zero )
      if ( st0_tag == TW_Zero )
        {
        {
          if ( b->tag == TW_Zero ) return COMP_A_eq_B;
          if ( b->tag == TW_Zero ) return COMP_A_eq_B;
          if ( b->tag == TW_Valid )
          if ( b->tag == TW_Valid )
            {
            {
              return ((b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
              return ((b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
#ifdef DENORM_OPERAND
#ifdef DENORM_OPERAND
                | ((b->exp <= EXP_UNDER) ?
                | ((b->exp <= EXP_UNDER) ?
                   COMP_Denormal : 0)
                   COMP_Denormal : 0)
#endif DENORM_OPERAND
#endif DENORM_OPERAND
                  ;
                  ;
            }
            }
        }
        }
      else if ( b->tag == TW_Zero )
      else if ( b->tag == TW_Zero )
        {
        {
          if ( st0_tag == TW_Valid )
          if ( st0_tag == TW_Valid )
            {
            {
              return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B
              return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B
                      : COMP_A_lt_B)
                      : COMP_A_lt_B)
#ifdef DENORM_OPERAND
#ifdef DENORM_OPERAND
                | ((st0_ptr->exp <= EXP_UNDER )
                | ((st0_ptr->exp <= EXP_UNDER )
                   ? COMP_Denormal : 0 )
                   ? COMP_Denormal : 0 )
#endif DENORM_OPERAND
#endif DENORM_OPERAND
                  ;
                  ;
            }
            }
        }
        }
 
 
      if ( st0_tag == TW_Infinity )
      if ( st0_tag == TW_Infinity )
        {
        {
          if ( (b->tag == TW_Valid) || (b->tag == TW_Zero) )
          if ( (b->tag == TW_Valid) || (b->tag == TW_Zero) )
            {
            {
              return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B
              return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B
                      : COMP_A_lt_B)
                      : COMP_A_lt_B)
#ifdef DENORM_OPERAND
#ifdef DENORM_OPERAND
              | (((b->tag == TW_Valid) && (b->exp <= EXP_UNDER)) ?
              | (((b->tag == TW_Valid) && (b->exp <= EXP_UNDER)) ?
                COMP_Denormal : 0 )
                COMP_Denormal : 0 )
#endif DENORM_OPERAND
#endif DENORM_OPERAND
;
;
            }
            }
          else if ( b->tag == TW_Infinity )
          else if ( b->tag == TW_Infinity )
            {
            {
              /* The 80486 book says that infinities can be equal! */
              /* The 80486 book says that infinities can be equal! */
              return (st0_ptr->sign == b->sign) ? COMP_A_eq_B :
              return (st0_ptr->sign == b->sign) ? COMP_A_eq_B :
                ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
                ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
            }
            }
          /* Fall through to the NaN code */
          /* Fall through to the NaN code */
        }
        }
      else if ( b->tag == TW_Infinity )
      else if ( b->tag == TW_Infinity )
        {
        {
          if ( (st0_tag == TW_Valid) || (st0_tag == TW_Zero) )
          if ( (st0_tag == TW_Valid) || (st0_tag == TW_Zero) )
            {
            {
              return ((b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
              return ((b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
#ifdef DENORM_OPERAND
#ifdef DENORM_OPERAND
                | (((st0_tag == TW_Valid)
                | (((st0_tag == TW_Valid)
                    && (st0_ptr->exp <= EXP_UNDER)) ?
                    && (st0_ptr->exp <= EXP_UNDER)) ?
                   COMP_Denormal : 0)
                   COMP_Denormal : 0)
#endif DENORM_OPERAND
#endif DENORM_OPERAND
                  ;
                  ;
            }
            }
          /* Fall through to the NaN code */
          /* Fall through to the NaN code */
        }
        }
 
 
      /* The only possibility now should be that one of the arguments
      /* The only possibility now should be that one of the arguments
         is a NaN */
         is a NaN */
      if ( (st0_tag == TW_NaN) || (b->tag == TW_NaN) )
      if ( (st0_tag == TW_NaN) || (b->tag == TW_NaN) )
        {
        {
          if ( ((st0_tag == TW_NaN) && !(st0_ptr->sigh & 0x40000000))
          if ( ((st0_tag == TW_NaN) && !(st0_ptr->sigh & 0x40000000))
              || ((b->tag == TW_NaN) && !(b->sigh & 0x40000000)) )
              || ((b->tag == TW_NaN) && !(b->sigh & 0x40000000)) )
            /* At least one arg is a signaling NaN */
            /* At least one arg is a signaling NaN */
            return COMP_No_Comp | COMP_SNaN | COMP_NaN;
            return COMP_No_Comp | COMP_SNaN | COMP_NaN;
          else
          else
            /* Neither is a signaling NaN */
            /* Neither is a signaling NaN */
            return COMP_No_Comp | COMP_NaN;
            return COMP_No_Comp | COMP_NaN;
        }
        }
 
 
      EXCEPTION(EX_Invalid);
      EXCEPTION(EX_Invalid);
    }
    }
 
 
#ifdef PARANOID
#ifdef PARANOID
  if (!(st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
  if (!(st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
  if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
  if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
#endif PARANOID
#endif PARANOID
 
 
 
 
  if (st0_ptr->sign != b->sign)
  if (st0_ptr->sign != b->sign)
    {
    {
      return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
      return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
#ifdef DENORM_OPERAND
#ifdef DENORM_OPERAND
        |
        |
          ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
          ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
           COMP_Denormal : 0)
           COMP_Denormal : 0)
#endif DENORM_OPERAND
#endif DENORM_OPERAND
            ;
            ;
    }
    }
 
 
  diff = st0_ptr->exp - b->exp;
  diff = st0_ptr->exp - b->exp;
  if ( diff == 0 )
  if ( diff == 0 )
    {
    {
      diff = st0_ptr->sigh - b->sigh;  /* Works only if ms bits are
      diff = st0_ptr->sigh - b->sigh;  /* Works only if ms bits are
                                              identical */
                                              identical */
      if ( diff == 0 )
      if ( diff == 0 )
        {
        {
        diff = st0_ptr->sigl > b->sigl;
        diff = st0_ptr->sigl > b->sigl;
        if ( diff == 0 )
        if ( diff == 0 )
          diff = -(st0_ptr->sigl < b->sigl);
          diff = -(st0_ptr->sigl < b->sigl);
        }
        }
    }
    }
 
 
  if ( diff > 0 )
  if ( diff > 0 )
    {
    {
      return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
      return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
#ifdef DENORM_OPERAND
#ifdef DENORM_OPERAND
        |
        |
          ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
          ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
           COMP_Denormal : 0)
           COMP_Denormal : 0)
#endif DENORM_OPERAND
#endif DENORM_OPERAND
            ;
            ;
    }
    }
  if ( diff < 0 )
  if ( diff < 0 )
    {
    {
      return ((st0_ptr->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
      return ((st0_ptr->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
#ifdef DENORM_OPERAND
#ifdef DENORM_OPERAND
        |
        |
          ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
          ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
           COMP_Denormal : 0)
           COMP_Denormal : 0)
#endif DENORM_OPERAND
#endif DENORM_OPERAND
            ;
            ;
    }
    }
 
 
  return COMP_A_eq_B
  return COMP_A_eq_B
#ifdef DENORM_OPERAND
#ifdef DENORM_OPERAND
    |
    |
      ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
      ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
       COMP_Denormal : 0)
       COMP_Denormal : 0)
#endif DENORM_OPERAND
#endif DENORM_OPERAND
        ;
        ;
 
 
}
}
 
 
 
 
/* This function requires that st(0) is not empty */
/* This function requires that st(0) is not empty */
int compare_st_data(FPU_REG const *loaded_data)
int compare_st_data(FPU_REG const *loaded_data)
{
{
  int f, c;
  int f, c;
 
 
  c = compare(loaded_data);
  c = compare(loaded_data);
 
 
  if (c & COMP_NaN)
  if (c & COMP_NaN)
    {
    {
      EXCEPTION(EX_Invalid);
      EXCEPTION(EX_Invalid);
      f = SW_C3 | SW_C2 | SW_C0;
      f = SW_C3 | SW_C2 | SW_C0;
    }
    }
  else
  else
    switch (c & 7)
    switch (c & 7)
      {
      {
      case COMP_A_lt_B:
      case COMP_A_lt_B:
        f = SW_C0;
        f = SW_C0;
        break;
        break;
      case COMP_A_eq_B:
      case COMP_A_eq_B:
        f = SW_C3;
        f = SW_C3;
        break;
        break;
      case COMP_A_gt_B:
      case COMP_A_gt_B:
        f = 0;
        f = 0;
        break;
        break;
      case COMP_No_Comp:
      case COMP_No_Comp:
        f = SW_C3 | SW_C2 | SW_C0;
        f = SW_C3 | SW_C2 | SW_C0;
        break;
        break;
#ifdef PARANOID
#ifdef PARANOID
      default:
      default:
        EXCEPTION(EX_INTERNAL|0x121);
        EXCEPTION(EX_INTERNAL|0x121);
        f = SW_C3 | SW_C2 | SW_C0;
        f = SW_C3 | SW_C2 | SW_C0;
        break;
        break;
#endif PARANOID
#endif PARANOID
      }
      }
  setcc(f);
  setcc(f);
  if (c & COMP_Denormal)
  if (c & COMP_Denormal)
    {
    {
      return denormal_operand();
      return denormal_operand();
    }
    }
  return 0;
  return 0;
}
}
 
 
 
 
static int compare_st_st(int nr)
static int compare_st_st(int nr)
{
{
  int f, c;
  int f, c;
 
 
  if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
  if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
    {
    {
      setcc(SW_C3 | SW_C2 | SW_C0);
      setcc(SW_C3 | SW_C2 | SW_C0);
      /* Stack fault */
      /* Stack fault */
      EXCEPTION(EX_StackUnder);
      EXCEPTION(EX_StackUnder);
      return !(control_word & CW_Invalid);
      return !(control_word & CW_Invalid);
    }
    }
 
 
  c = compare(&st(nr));
  c = compare(&st(nr));
  if (c & COMP_NaN)
  if (c & COMP_NaN)
    {
    {
      setcc(SW_C3 | SW_C2 | SW_C0);
      setcc(SW_C3 | SW_C2 | SW_C0);
      EXCEPTION(EX_Invalid);
      EXCEPTION(EX_Invalid);
      return !(control_word & CW_Invalid);
      return !(control_word & CW_Invalid);
    }
    }
  else
  else
    switch (c & 7)
    switch (c & 7)
      {
      {
      case COMP_A_lt_B:
      case COMP_A_lt_B:
        f = SW_C0;
        f = SW_C0;
        break;
        break;
      case COMP_A_eq_B:
      case COMP_A_eq_B:
        f = SW_C3;
        f = SW_C3;
        break;
        break;
      case COMP_A_gt_B:
      case COMP_A_gt_B:
        f = 0;
        f = 0;
        break;
        break;
      case COMP_No_Comp:
      case COMP_No_Comp:
        f = SW_C3 | SW_C2 | SW_C0;
        f = SW_C3 | SW_C2 | SW_C0;
        break;
        break;
#ifdef PARANOID
#ifdef PARANOID
      default:
      default:
        EXCEPTION(EX_INTERNAL|0x122);
        EXCEPTION(EX_INTERNAL|0x122);
        f = SW_C3 | SW_C2 | SW_C0;
        f = SW_C3 | SW_C2 | SW_C0;
        break;
        break;
#endif PARANOID
#endif PARANOID
      }
      }
  setcc(f);
  setcc(f);
  if (c & COMP_Denormal)
  if (c & COMP_Denormal)
    {
    {
      return denormal_operand();
      return denormal_operand();
    }
    }
  return 0;
  return 0;
}
}
 
 
 
 
static int compare_u_st_st(int nr)
static int compare_u_st_st(int nr)
{
{
  int f, c;
  int f, c;
 
 
  if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
  if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
    {
    {
      setcc(SW_C3 | SW_C2 | SW_C0);
      setcc(SW_C3 | SW_C2 | SW_C0);
      /* Stack fault */
      /* Stack fault */
      EXCEPTION(EX_StackUnder);
      EXCEPTION(EX_StackUnder);
      return !(control_word & CW_Invalid);
      return !(control_word & CW_Invalid);
    }
    }
 
 
  c = compare(&st(nr));
  c = compare(&st(nr));
  if (c & COMP_NaN)
  if (c & COMP_NaN)
    {
    {
      setcc(SW_C3 | SW_C2 | SW_C0);
      setcc(SW_C3 | SW_C2 | SW_C0);
      if (c & COMP_SNaN)       /* This is the only difference between
      if (c & COMP_SNaN)       /* This is the only difference between
                                  un-ordered and ordinary comparisons */
                                  un-ordered and ordinary comparisons */
        {
        {
          EXCEPTION(EX_Invalid);
          EXCEPTION(EX_Invalid);
          return !(control_word & CW_Invalid);
          return !(control_word & CW_Invalid);
        }
        }
      return 0;
      return 0;
    }
    }
  else
  else
    switch (c & 7)
    switch (c & 7)
      {
      {
      case COMP_A_lt_B:
      case COMP_A_lt_B:
        f = SW_C0;
        f = SW_C0;
        break;
        break;
      case COMP_A_eq_B:
      case COMP_A_eq_B:
        f = SW_C3;
        f = SW_C3;
        break;
        break;
      case COMP_A_gt_B:
      case COMP_A_gt_B:
        f = 0;
        f = 0;
        break;
        break;
      case COMP_No_Comp:
      case COMP_No_Comp:
        f = SW_C3 | SW_C2 | SW_C0;
        f = SW_C3 | SW_C2 | SW_C0;
        break;
        break;
#ifdef PARANOID
#ifdef PARANOID
      default:
      default:
        EXCEPTION(EX_INTERNAL|0x123);
        EXCEPTION(EX_INTERNAL|0x123);
        f = SW_C3 | SW_C2 | SW_C0;
        f = SW_C3 | SW_C2 | SW_C0;
        break;
        break;
#endif PARANOID
#endif PARANOID
      }
      }
  setcc(f);
  setcc(f);
  if (c & COMP_Denormal)
  if (c & COMP_Denormal)
    {
    {
      return denormal_operand();
      return denormal_operand();
    }
    }
  return 0;
  return 0;
}
}
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
void fcom_st()
void fcom_st()
{
{
  /* fcom st(i) */
  /* fcom st(i) */
  compare_st_st(FPU_rm);
  compare_st_st(FPU_rm);
}
}
 
 
 
 
void fcompst()
void fcompst()
{
{
  /* fcomp st(i) */
  /* fcomp st(i) */
  if ( !compare_st_st(FPU_rm) )
  if ( !compare_st_st(FPU_rm) )
    pop();
    pop();
}
}
 
 
 
 
void fcompp()
void fcompp()
{
{
  /* fcompp */
  /* fcompp */
  if (FPU_rm != 1)
  if (FPU_rm != 1)
    {
    {
      FPU_illegal();
      FPU_illegal();
      return;
      return;
    }
    }
  if ( !compare_st_st(1) )
  if ( !compare_st_st(1) )
      poppop();
      poppop();
}
}
 
 
 
 
void fucom_()
void fucom_()
{
{
  /* fucom st(i) */
  /* fucom st(i) */
  compare_u_st_st(FPU_rm);
  compare_u_st_st(FPU_rm);
 
 
}
}
 
 
 
 
void fucomp()
void fucomp()
{
{
  /* fucomp st(i) */
  /* fucomp st(i) */
  if ( !compare_u_st_st(FPU_rm) )
  if ( !compare_u_st_st(FPU_rm) )
    pop();
    pop();
}
}
 
 
 
 
void fucompp()
void fucompp()
{
{
  /* fucompp */
  /* fucompp */
  if (FPU_rm == 1)
  if (FPU_rm == 1)
    {
    {
      if ( !compare_u_st_st(1) )
      if ( !compare_u_st_st(1) )
        poppop();
        poppop();
    }
    }
  else
  else
    FPU_illegal();
    FPU_illegal();
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.