root/arch/i386/math-emu/reg_compare.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. compare
  2. compare_st_data
  3. compare_st_st
  4. compare_u_st_st
  5. fcom_st
  6. fcompst
  7. fcompp
  8. fucom_
  9. fucomp
  10. fucompp

   1 /*---------------------------------------------------------------------------+
   2  |  reg_compare.c                                                            |
   3  |                                                                           |
   4  | Compare two floating point registers                                      |
   5  |                                                                           |
   6  | Copyright (C) 1992,1993,1994                                              |
   7  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
   8  |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
   9  |                                                                           |
  10  |                                                                           |
  11  +---------------------------------------------------------------------------*/
  12 
  13 /*---------------------------------------------------------------------------+
  14  | compare() is the core FPU_REG comparison function                         |
  15  +---------------------------------------------------------------------------*/
  16 
  17 #include "fpu_system.h"
  18 #include "exception.h"
  19 #include "fpu_emu.h"
  20 #include "control_w.h"
  21 #include "status_w.h"
  22 
  23 
  24 int compare(FPU_REG const *b)
     /* [previous][next][first][last][top][bottom][index][help] */
  25 {
  26   int diff;
  27   char         st0_tag;
  28   FPU_REG      *st0_ptr;
  29 
  30   st0_ptr = &st(0);
  31   st0_tag = st0_ptr->tag;
  32 
  33   if ( st0_tag | b->tag )
  34     {
  35       if ( st0_tag == TW_Zero )
  36         {
  37           if ( b->tag == TW_Zero ) return COMP_A_eq_B;
  38           if ( b->tag == TW_Valid )
  39             {
  40               return ((b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
  41 #ifdef DENORM_OPERAND
  42                 | ((b->exp <= EXP_UNDER) ?
  43                    COMP_Denormal : 0)
  44 #endif DENORM_OPERAND
  45                   ;
  46             }
  47         }
  48       else if ( b->tag == TW_Zero )
  49         {
  50           if ( st0_tag == TW_Valid )
  51             {
  52               return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B
  53                       : COMP_A_lt_B)
  54 #ifdef DENORM_OPERAND
  55                 | ((st0_ptr->exp <= EXP_UNDER )
  56                    ? COMP_Denormal : 0 )
  57 #endif DENORM_OPERAND
  58                   ;
  59             }
  60         }
  61 
  62       if ( st0_tag == TW_Infinity )
  63         {
  64           if ( (b->tag == TW_Valid) || (b->tag == TW_Zero) )
  65             {
  66               return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B
  67                       : COMP_A_lt_B)
  68 #ifdef DENORM_OPERAND
  69               | (((b->tag == TW_Valid) && (b->exp <= EXP_UNDER)) ?
  70                 COMP_Denormal : 0 )
  71 #endif DENORM_OPERAND
  72 ;
  73             }
  74           else if ( b->tag == TW_Infinity )
  75             {
  76               /* The 80486 book says that infinities can be equal! */
  77               return (st0_ptr->sign == b->sign) ? COMP_A_eq_B :
  78                 ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
  79             }
  80           /* Fall through to the NaN code */
  81         }
  82       else if ( b->tag == TW_Infinity )
  83         {
  84           if ( (st0_tag == TW_Valid) || (st0_tag == TW_Zero) )
  85             {
  86               return ((b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
  87 #ifdef DENORM_OPERAND
  88                 | (((st0_tag == TW_Valid)
  89                     && (st0_ptr->exp <= EXP_UNDER)) ?
  90                    COMP_Denormal : 0)
  91 #endif DENORM_OPERAND
  92                   ;
  93             }
  94           /* Fall through to the NaN code */
  95         }
  96 
  97       /* The only possibility now should be that one of the arguments
  98          is a NaN */
  99       if ( (st0_tag == TW_NaN) || (b->tag == TW_NaN) )
 100         {
 101           if ( ((st0_tag == TW_NaN) && !(st0_ptr->sigh & 0x40000000))
 102               || ((b->tag == TW_NaN) && !(b->sigh & 0x40000000)) )
 103             /* At least one arg is a signaling NaN */
 104             return COMP_No_Comp | COMP_SNaN | COMP_NaN;
 105           else
 106             /* Neither is a signaling NaN */
 107             return COMP_No_Comp | COMP_NaN;
 108         }
 109       
 110       EXCEPTION(EX_Invalid);
 111     }
 112   
 113 #ifdef PARANOID
 114   if (!(st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
 115   if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
 116 #endif PARANOID
 117 
 118   
 119   if (st0_ptr->sign != b->sign)
 120     {
 121       return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
 122 #ifdef DENORM_OPERAND
 123         |
 124           ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
 125            COMP_Denormal : 0)
 126 #endif DENORM_OPERAND
 127             ;
 128     }
 129 
 130   diff = st0_ptr->exp - b->exp;
 131   if ( diff == 0 )
 132     {
 133       diff = st0_ptr->sigh - b->sigh;  /* Works only if ms bits are
 134                                               identical */
 135       if ( diff == 0 )
 136         {
 137         diff = st0_ptr->sigl > b->sigl;
 138         if ( diff == 0 )
 139           diff = -(st0_ptr->sigl < b->sigl);
 140         }
 141     }
 142 
 143   if ( diff > 0 )
 144     {
 145       return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
 146 #ifdef DENORM_OPERAND
 147         |
 148           ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
 149            COMP_Denormal : 0)
 150 #endif DENORM_OPERAND
 151             ;
 152     }
 153   if ( diff < 0 )
 154     {
 155       return ((st0_ptr->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
 156 #ifdef DENORM_OPERAND
 157         |
 158           ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
 159            COMP_Denormal : 0)
 160 #endif DENORM_OPERAND
 161             ;
 162     }
 163 
 164   return COMP_A_eq_B
 165 #ifdef DENORM_OPERAND
 166     |
 167       ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
 168        COMP_Denormal : 0)
 169 #endif DENORM_OPERAND
 170         ;
 171 
 172 }
 173 
 174 
 175 /* This function requires that st(0) is not empty */
 176 int compare_st_data(FPU_REG const *loaded_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 177 {
 178   int f, c;
 179 
 180   c = compare(loaded_data);
 181 
 182   if (c & COMP_NaN)
 183     {
 184       EXCEPTION(EX_Invalid);
 185       f = SW_C3 | SW_C2 | SW_C0;
 186     }
 187   else
 188     switch (c & 7)
 189       {
 190       case COMP_A_lt_B:
 191         f = SW_C0;
 192         break;
 193       case COMP_A_eq_B:
 194         f = SW_C3;
 195         break;
 196       case COMP_A_gt_B:
 197         f = 0;
 198         break;
 199       case COMP_No_Comp:
 200         f = SW_C3 | SW_C2 | SW_C0;
 201         break;
 202 #ifdef PARANOID
 203       default:
 204         EXCEPTION(EX_INTERNAL|0x121);
 205         f = SW_C3 | SW_C2 | SW_C0;
 206         break;
 207 #endif PARANOID
 208       }
 209   setcc(f);
 210   if (c & COMP_Denormal)
 211     {
 212       return denormal_operand();
 213     }
 214   return 0;
 215 }
 216 
 217 
 218 static int compare_st_st(int nr)
     /* [previous][next][first][last][top][bottom][index][help] */
 219 {
 220   int f, c;
 221 
 222   if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
 223     {
 224       setcc(SW_C3 | SW_C2 | SW_C0);
 225       /* Stack fault */
 226       EXCEPTION(EX_StackUnder);
 227       return !(control_word & CW_Invalid);
 228     }
 229 
 230   c = compare(&st(nr));
 231   if (c & COMP_NaN)
 232     {
 233       setcc(SW_C3 | SW_C2 | SW_C0);
 234       EXCEPTION(EX_Invalid);
 235       return !(control_word & CW_Invalid);
 236     }
 237   else
 238     switch (c & 7)
 239       {
 240       case COMP_A_lt_B:
 241         f = SW_C0;
 242         break;
 243       case COMP_A_eq_B:
 244         f = SW_C3;
 245         break;
 246       case COMP_A_gt_B:
 247         f = 0;
 248         break;
 249       case COMP_No_Comp:
 250         f = SW_C3 | SW_C2 | SW_C0;
 251         break;
 252 #ifdef PARANOID
 253       default:
 254         EXCEPTION(EX_INTERNAL|0x122);
 255         f = SW_C3 | SW_C2 | SW_C0;
 256         break;
 257 #endif PARANOID
 258       }
 259   setcc(f);
 260   if (c & COMP_Denormal)
 261     {
 262       return denormal_operand();
 263     }
 264   return 0;
 265 }
 266 
 267 
 268 static int compare_u_st_st(int nr)
     /* [previous][next][first][last][top][bottom][index][help] */
 269 {
 270   int f, c;
 271 
 272   if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
 273     {
 274       setcc(SW_C3 | SW_C2 | SW_C0);
 275       /* Stack fault */
 276       EXCEPTION(EX_StackUnder);
 277       return !(control_word & CW_Invalid);
 278     }
 279 
 280   c = compare(&st(nr));
 281   if (c & COMP_NaN)
 282     {
 283       setcc(SW_C3 | SW_C2 | SW_C0);
 284       if (c & COMP_SNaN)       /* This is the only difference between
 285                                   un-ordered and ordinary comparisons */
 286         {
 287           EXCEPTION(EX_Invalid);
 288           return !(control_word & CW_Invalid);
 289         }
 290       return 0;
 291     }
 292   else
 293     switch (c & 7)
 294       {
 295       case COMP_A_lt_B:
 296         f = SW_C0;
 297         break;
 298       case COMP_A_eq_B:
 299         f = SW_C3;
 300         break;
 301       case COMP_A_gt_B:
 302         f = 0;
 303         break;
 304       case COMP_No_Comp:
 305         f = SW_C3 | SW_C2 | SW_C0;
 306         break;
 307 #ifdef PARANOID
 308       default:
 309         EXCEPTION(EX_INTERNAL|0x123);
 310         f = SW_C3 | SW_C2 | SW_C0;
 311         break;
 312 #endif PARANOID
 313       }
 314   setcc(f);
 315   if (c & COMP_Denormal)
 316     {
 317       return denormal_operand();
 318     }
 319   return 0;
 320 }
 321 
 322 /*---------------------------------------------------------------------------*/
 323 
 324 void fcom_st()
     /* [previous][next][first][last][top][bottom][index][help] */
 325 {
 326   /* fcom st(i) */
 327   compare_st_st(FPU_rm);
 328 }
 329 
 330 
 331 void fcompst()
     /* [previous][next][first][last][top][bottom][index][help] */
 332 {
 333   /* fcomp st(i) */
 334   if ( !compare_st_st(FPU_rm) )
 335     pop();
 336 }
 337 
 338 
 339 void fcompp()
     /* [previous][next][first][last][top][bottom][index][help] */
 340 {
 341   /* fcompp */
 342   if (FPU_rm != 1)
 343     {
 344       FPU_illegal();
 345       return;
 346     }
 347   if ( !compare_st_st(1) )
 348       poppop();
 349 }
 350 
 351 
 352 void fucom_()
     /* [previous][next][first][last][top][bottom][index][help] */
 353 {
 354   /* fucom st(i) */
 355   compare_u_st_st(FPU_rm);
 356 
 357 }
 358 
 359 
 360 void fucomp()
     /* [previous][next][first][last][top][bottom][index][help] */
 361 {
 362   /* fucomp st(i) */
 363   if ( !compare_u_st_st(FPU_rm) )
 364     pop();
 365 }
 366 
 367 
 368 void fucompp()
     /* [previous][next][first][last][top][bottom][index][help] */
 369 {
 370   /* fucompp */
 371   if (FPU_rm == 1)
 372     {
 373       if ( !compare_u_st_st(1) )
 374         poppop();
 375     }
 376   else
 377     FPU_illegal();
 378 }

/* [previous][next][first][last][top][bottom][index][help] */