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

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