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

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