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 "status_w.h"
  21 
  22 
  23 int compare(FPU_REG *b)
     /* [previous][next][first][last][top][bottom][index][help] */
  24 {
  25   int diff;
  26 
  27   if ( FPU_st0_ptr->tag | b->tag )
  28     {
  29       if ( FPU_st0_ptr->tag == TW_Zero )
  30         {
  31           if ( b->tag == TW_Zero ) return COMP_A_EQ_B;
  32           if ( b->tag == TW_Valid )
  33             {
  34               return (b->sign == SIGN_POS) ? COMP_A_LT_B : COMP_A_GT_B ;
  35             }
  36         }
  37       else if ( b->tag == TW_Zero )
  38         {
  39           if ( FPU_st0_ptr->tag == TW_Valid )
  40             {
  41               return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_GT_B : COMP_A_LT_B ;
  42             }
  43         }
  44 
  45       if ( FPU_st0_ptr->tag == TW_Infinity )
  46         {
  47           if ( (b->tag == TW_Valid) || (b->tag == TW_Zero) )
  48             {
  49               return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_GT_B : COMP_A_LT_B;
  50             }
  51           else if ( b->tag == TW_Infinity )
  52             {
  53               /* The 80486 book says that infinities can be equal! */
  54               return (FPU_st0_ptr->sign == b->sign) ? COMP_A_EQ_B :
  55                 ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_GT_B : COMP_A_LT_B);
  56             }
  57           /* Fall through to the NaN code */
  58         }
  59       else if ( b->tag == TW_Infinity )
  60         {
  61           if ( (FPU_st0_ptr->tag == TW_Valid) || (FPU_st0_ptr->tag == TW_Zero) )
  62             {
  63               return (b->sign == SIGN_POS) ? COMP_A_LT_B : COMP_A_GT_B;
  64             }
  65           /* Fall through to the NaN code */
  66         }
  67 
  68       /* The only possibility now should be that one of the arguments
  69          is a NaN */
  70       if ( (FPU_st0_ptr->tag == TW_NaN) || (b->tag == TW_NaN) )
  71         {
  72           if ( ((FPU_st0_ptr->tag == TW_NaN) && !(FPU_st0_ptr->sigh & 0x40000000))
  73               || ((b->tag == TW_NaN) && !(b->sigh & 0x40000000)) )
  74             /* At least one arg is a signaling NaN */
  75             return COMP_NOCOMP | COMP_SNAN | COMP_NAN;
  76           else
  77             /* Neither is a signaling NaN */
  78             return COMP_NOCOMP | COMP_NAN;
  79         }
  80       
  81       EXCEPTION(EX_Invalid);
  82     }
  83   
  84 #ifdef PARANOID
  85   if (!(FPU_st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
  86   if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
  87 #endif PARANOID
  88   
  89   if (FPU_st0_ptr->sign != b->sign)
  90     return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_GT_B : COMP_A_LT_B;
  91   
  92   diff = FPU_st0_ptr->exp - b->exp;
  93   if ( diff == 0 )
  94     {
  95       diff = FPU_st0_ptr->sigh - b->sigh;  /* Works only if ms bits are
  96                                               identical */
  97       if ( diff == 0 )
  98         {
  99         diff = FPU_st0_ptr->sigl > b->sigl;
 100         if ( diff == 0 )
 101           diff = -(FPU_st0_ptr->sigl < b->sigl);
 102         }
 103     }
 104 
 105   if ( diff > 0 )
 106     return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_GT_B : COMP_A_LT_B ;
 107   if ( diff < 0 )
 108     return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_LT_B : COMP_A_GT_B ;
 109   return COMP_A_EQ_B;
 110 
 111 }
 112 
 113 
 114 void compare_st_data(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 115 {
 116   int f;
 117   int c = compare(&FPU_loaded_data);
 118 
 119   if (c & COMP_NAN)
 120     {
 121       EXCEPTION(EX_Invalid);
 122       f = SW_C3 | SW_C2 | SW_C0;
 123     }
 124   else
 125     switch (c)
 126       {
 127       case COMP_A_LT_B:
 128         f = SW_C0;
 129         break;
 130       case COMP_A_EQ_B:
 131         f = SW_C3;
 132         break;
 133       case COMP_A_GT_B:
 134         f = 0;
 135         break;
 136       case COMP_NOCOMP:
 137         f = SW_C3 | SW_C2 | SW_C0;
 138         break;
 139 #ifdef PARANOID
 140       default:
 141         EXCEPTION(EX_INTERNAL|0x121);
 142         f = SW_C3 | SW_C2 | SW_C0;
 143         break;
 144 #endif PARANOID
 145       }
 146   setcc(f);
 147 }
 148 
 149 
 150 static void compare_st_st(int nr)
     /* [previous][next][first][last][top][bottom][index][help] */
 151 {
 152   int c = compare(&st(nr));
 153   int f;
 154   if (c & COMP_NAN)
 155     {
 156       EXCEPTION(EX_Invalid);
 157       f = SW_C3 | SW_C2 | SW_C0;
 158     }
 159   else
 160     switch (c)
 161       {
 162       case COMP_A_LT_B:
 163         f = SW_C0;
 164         break;
 165       case COMP_A_EQ_B:
 166         f = SW_C3;
 167         break;
 168       case COMP_A_GT_B:
 169         f = 0;
 170         break;
 171       case COMP_NOCOMP:
 172         f = SW_C3 | SW_C2 | SW_C0;
 173         break;
 174 #ifdef PARANOID
 175       default:
 176         EXCEPTION(EX_INTERNAL|0x122);
 177         f = SW_C3 | SW_C2 | SW_C0;
 178         break;
 179 #endif PARANOID
 180       }
 181   setcc(f);
 182 }
 183 
 184 
 185 static void compare_u_st_st(int nr)
     /* [previous][next][first][last][top][bottom][index][help] */
 186 {
 187   int f;
 188   int c = compare(&st(nr));
 189   if (c & COMP_NAN)
 190     {
 191       if (c & COMP_SNAN)       /* This is the only difference between
 192                                   un-ordered and ordinary comparisons */
 193         EXCEPTION(EX_Invalid);
 194       f = SW_C3 | SW_C2 | SW_C0;
 195     }
 196   else
 197     switch (c)
 198       {
 199       case COMP_A_LT_B:
 200         f = SW_C0;
 201         break;
 202       case COMP_A_EQ_B:
 203         f = SW_C3;
 204         break;
 205       case COMP_A_GT_B:
 206         f = 0;
 207         break;
 208       case COMP_NOCOMP:
 209         f = SW_C3 | SW_C2 | SW_C0;
 210         break;
 211 #ifdef PARANOID
 212       default:
 213         EXCEPTION(EX_INTERNAL|0x123);
 214         f = SW_C3 | SW_C2 | SW_C0;
 215         break;
 216 #endif PARANOID
 217       }
 218   setcc(f);
 219 }
 220 
 221 /*---------------------------------------------------------------------------*/
 222 
 223 void fcom_st()
     /* [previous][next][first][last][top][bottom][index][help] */
 224 {
 225   /* fcom st(i) */
 226   compare_st_st(FPU_rm);
 227 }
 228 
 229 
 230 void fcompst()
     /* [previous][next][first][last][top][bottom][index][help] */
 231 {
 232   /* fcomp st(i) */
 233   compare_st_st(FPU_rm);
 234   pop();
 235 }
 236 
 237 
 238 void fcompp()
     /* [previous][next][first][last][top][bottom][index][help] */
 239 {
 240   /* fcompp */
 241   if (FPU_rm != 1)
 242     return Un_impl();
 243   compare_st_st(1);
 244   pop(); FPU_st0_ptr = &st(0);
 245   pop();
 246 }
 247 
 248 
 249 void fucom_()
     /* [previous][next][first][last][top][bottom][index][help] */
 250 {
 251   /* fucom st(i) */
 252   compare_u_st_st(FPU_rm);
 253 }
 254 
 255 
 256 void fucomp()
     /* [previous][next][first][last][top][bottom][index][help] */
 257 {
 258   /* fucomp st(i) */
 259   compare_u_st_st(FPU_rm);
 260   pop();
 261 }
 262 
 263 
 264 void fucompp()
     /* [previous][next][first][last][top][bottom][index][help] */
 265 {
 266   /* fucompp */
 267   if (FPU_rm == 1)
 268     {
 269       compare_u_st_st(1);
 270       pop(); FPU_st0_ptr = &st(0);
 271       pop();
 272     }
 273   else
 274     Un_impl();
 275 }

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