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

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