home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / arch / i386 / math-emu / reg_compare.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-02  |  7.7 KB  |  379 lines

  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)
  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)
  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)
  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)
  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()
  325. {
  326.   /* fcom st(i) */
  327.   compare_st_st(FPU_rm);
  328. }
  329.  
  330.  
  331. void fcompst()
  332. {
  333.   /* fcomp st(i) */
  334.   if ( !compare_st_st(FPU_rm) )
  335.     pop();
  336. }
  337.  
  338.  
  339. void fcompp()
  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_()
  353. {
  354.   /* fucom st(i) */
  355.   compare_u_st_st(FPU_rm);
  356.  
  357. }
  358.  
  359.  
  360. void fucomp()
  361. {
  362.   /* fucomp st(i) */
  363.   if ( !compare_u_st_st(FPU_rm) )
  364.     pop();
  365. }
  366.  
  367.  
  368. void fucompp()
  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. }
  379.