reg_compare.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:8k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*---------------------------------------------------------------------------+
  2.  |  reg_compare.c                                                            |
  3.  |                                                                           |
  4.  | Compare two floating point registers                                      |
  5.  |                                                                           |
  6.  | Copyright (C) 1992,1993,1994,1997                                         |
  7.  |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
  8.  |                  E-mail   billm@suburbia.net                              |
  9.  |                                                                           |
  10.  |                                                                           |
  11.  +---------------------------------------------------------------------------*/
  12. /*---------------------------------------------------------------------------+
  13.  | compare() is the core FPU_REG comparison function                         |
  14.  +---------------------------------------------------------------------------*/
  15. #include "fpu_system.h"
  16. #include "exception.h"
  17. #include "fpu_emu.h"
  18. #include "control_w.h"
  19. #include "status_w.h"
  20. static int compare(FPU_REG const *b, int tagb)
  21. {
  22.   int diff, exp0, expb;
  23.   u_char    st0_tag;
  24.   FPU_REG   *st0_ptr;
  25.   FPU_REG x, y;
  26.   u_char st0_sign, signb = getsign(b);
  27.   st0_ptr = &st(0);
  28.   st0_tag = FPU_gettag0();
  29.   st0_sign = getsign(st0_ptr);
  30.   if ( tagb == TAG_Special )
  31.     tagb = FPU_Special(b);
  32.   if ( st0_tag == TAG_Special )
  33.     st0_tag = FPU_Special(st0_ptr);
  34.   if ( ((st0_tag != TAG_Valid) && (st0_tag != TW_Denormal))
  35.        || ((tagb != TAG_Valid) && (tagb != TW_Denormal)) )
  36.     {
  37.       if ( st0_tag == TAG_Zero )
  38. {
  39.   if ( tagb == TAG_Zero ) return COMP_A_eq_B;
  40.   if ( tagb == TAG_Valid )
  41.     return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
  42.   if ( tagb == TW_Denormal )
  43.     return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
  44.     | COMP_Denormal;
  45. }
  46.       else if ( tagb == TAG_Zero )
  47. {
  48.   if ( st0_tag == TAG_Valid )
  49.     return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
  50.   if ( st0_tag == TW_Denormal )
  51.     return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
  52.     | COMP_Denormal;
  53. }
  54.       if ( st0_tag == TW_Infinity )
  55. {
  56.   if ( (tagb == TAG_Valid) || (tagb == TAG_Zero) )
  57.     return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
  58.   else if ( tagb == TW_Denormal )
  59.     return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
  60.       | COMP_Denormal;
  61.   else if ( tagb == TW_Infinity )
  62.     {
  63.       /* The 80486 book says that infinities can be equal! */
  64.       return (st0_sign == signb) ? COMP_A_eq_B :
  65. ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
  66.     }
  67.   /* Fall through to the NaN code */
  68. }
  69.       else if ( tagb == TW_Infinity )
  70. {
  71.   if ( (st0_tag == TAG_Valid) || (st0_tag == TAG_Zero) )
  72.     return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
  73.   if ( st0_tag == TW_Denormal )
  74.     return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
  75. | COMP_Denormal;
  76.   /* Fall through to the NaN code */
  77. }
  78.       /* The only possibility now should be that one of the arguments
  79.  is a NaN */
  80.       if ( (st0_tag == TW_NaN) || (tagb == TW_NaN) )
  81. {
  82.   int signalling = 0, unsupported = 0;
  83.   if ( st0_tag == TW_NaN )
  84.     {
  85.       signalling = (st0_ptr->sigh & 0xc0000000) == 0x80000000;
  86.       unsupported = !((exponent(st0_ptr) == EXP_OVER)
  87.       && (st0_ptr->sigh & 0x80000000));
  88.     }
  89.   if ( tagb == TW_NaN )
  90.     {
  91.       signalling |= (b->sigh & 0xc0000000) == 0x80000000;
  92.       unsupported |= !((exponent(b) == EXP_OVER)
  93.        && (b->sigh & 0x80000000));
  94.     }
  95.   if ( signalling || unsupported )
  96.     return COMP_No_Comp | COMP_SNaN | COMP_NaN;
  97.   else
  98.     /* Neither is a signaling NaN */
  99.     return COMP_No_Comp | COMP_NaN;
  100. }
  101.       
  102.       EXCEPTION(EX_Invalid);
  103.     }
  104.   
  105.   if (st0_sign != signb)
  106.     {
  107.       return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
  108. | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
  109.     COMP_Denormal : 0);
  110.     }
  111.   if ( (st0_tag == TW_Denormal) || (tagb == TW_Denormal) )
  112.     {
  113.       FPU_to_exp16(st0_ptr, &x);
  114.       FPU_to_exp16(b, &y);
  115.       st0_ptr = &x;
  116.       b = &y;
  117.       exp0 = exponent16(st0_ptr);
  118.       expb = exponent16(b);
  119.     }
  120.   else
  121.     {
  122.       exp0 = exponent(st0_ptr);
  123.       expb = exponent(b);
  124.     }
  125. #ifdef PARANOID
  126.   if (!(st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
  127.   if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
  128. #endif /* PARANOID */
  129.   diff = exp0 - expb;
  130.   if ( diff == 0 )
  131.     {
  132.       diff = st0_ptr->sigh - b->sigh;  /* Works only if ms bits are
  133.       identical */
  134.       if ( diff == 0 )
  135. {
  136. diff = st0_ptr->sigl > b->sigl;
  137. if ( diff == 0 )
  138.   diff = -(st0_ptr->sigl < b->sigl);
  139. }
  140.     }
  141.   if ( diff > 0 )
  142.     {
  143.       return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
  144. | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
  145.     COMP_Denormal : 0);
  146.     }
  147.   if ( diff < 0 )
  148.     {
  149.       return ((st0_sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
  150. | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
  151.     COMP_Denormal : 0);
  152.     }
  153.   return COMP_A_eq_B
  154.     | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
  155. COMP_Denormal : 0);
  156. }
  157. /* This function requires that st(0) is not empty */
  158. int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag)
  159. {
  160.   int f = 0, c;
  161.   c = compare(loaded_data, loaded_tag);
  162.   if (c & COMP_NaN)
  163.     {
  164.       EXCEPTION(EX_Invalid);
  165.       f = SW_C3 | SW_C2 | SW_C0;
  166.     }
  167.   else
  168.     switch (c & 7)
  169.       {
  170.       case COMP_A_lt_B:
  171. f = SW_C0;
  172. break;
  173.       case COMP_A_eq_B:
  174. f = SW_C3;
  175. break;
  176.       case COMP_A_gt_B:
  177. f = 0;
  178. break;
  179.       case COMP_No_Comp:
  180. f = SW_C3 | SW_C2 | SW_C0;
  181. break;
  182. #ifdef PARANOID
  183.       default:
  184. EXCEPTION(EX_INTERNAL|0x121);
  185. f = SW_C3 | SW_C2 | SW_C0;
  186. break;
  187. #endif /* PARANOID */
  188.       }
  189.   setcc(f);
  190.   if (c & COMP_Denormal)
  191.     {
  192.       return denormal_operand() < 0;
  193.     }
  194.   return 0;
  195. }
  196. static int compare_st_st(int nr)
  197. {
  198.   int f = 0, c;
  199.   FPU_REG *st_ptr;
  200.   if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
  201.     {
  202.       setcc(SW_C3 | SW_C2 | SW_C0);
  203.       /* Stack fault */
  204.       EXCEPTION(EX_StackUnder);
  205.       return !(control_word & CW_Invalid);
  206.     }
  207.   st_ptr = &st(nr);
  208.   c = compare(st_ptr, FPU_gettagi(nr));
  209.   if (c & COMP_NaN)
  210.     {
  211.       setcc(SW_C3 | SW_C2 | SW_C0);
  212.       EXCEPTION(EX_Invalid);
  213.       return !(control_word & CW_Invalid);
  214.     }
  215.   else
  216.     switch (c & 7)
  217.       {
  218.       case COMP_A_lt_B:
  219. f = SW_C0;
  220. break;
  221.       case COMP_A_eq_B:
  222. f = SW_C3;
  223. break;
  224.       case COMP_A_gt_B:
  225. f = 0;
  226. break;
  227.       case COMP_No_Comp:
  228. f = SW_C3 | SW_C2 | SW_C0;
  229. break;
  230. #ifdef PARANOID
  231.       default:
  232. EXCEPTION(EX_INTERNAL|0x122);
  233. f = SW_C3 | SW_C2 | SW_C0;
  234. break;
  235. #endif /* PARANOID */
  236.       }
  237.   setcc(f);
  238.   if (c & COMP_Denormal)
  239.     {
  240.       return denormal_operand() < 0;
  241.     }
  242.   return 0;
  243. }
  244. static int compare_u_st_st(int nr)
  245. {
  246.   int f = 0, c;
  247.   FPU_REG *st_ptr;
  248.   if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
  249.     {
  250.       setcc(SW_C3 | SW_C2 | SW_C0);
  251.       /* Stack fault */
  252.       EXCEPTION(EX_StackUnder);
  253.       return !(control_word & CW_Invalid);
  254.     }
  255.   st_ptr = &st(nr);
  256.   c = compare(st_ptr, FPU_gettagi(nr));
  257.   if (c & COMP_NaN)
  258.     {
  259.       setcc(SW_C3 | SW_C2 | SW_C0);
  260.       if (c & COMP_SNaN)       /* This is the only difference between
  261.   un-ordered and ordinary comparisons */
  262. {
  263.   EXCEPTION(EX_Invalid);
  264.   return !(control_word & CW_Invalid);
  265. }
  266.       return 0;
  267.     }
  268.   else
  269.     switch (c & 7)
  270.       {
  271.       case COMP_A_lt_B:
  272. f = SW_C0;
  273. break;
  274.       case COMP_A_eq_B:
  275. f = SW_C3;
  276. break;
  277.       case COMP_A_gt_B:
  278. f = 0;
  279. break;
  280.       case COMP_No_Comp:
  281. f = SW_C3 | SW_C2 | SW_C0;
  282. break;
  283. #ifdef PARANOID
  284.       default:
  285. EXCEPTION(EX_INTERNAL|0x123);
  286. f = SW_C3 | SW_C2 | SW_C0;
  287. break;
  288. #endif /* PARANOID */ 
  289.       }
  290.   setcc(f);
  291.   if (c & COMP_Denormal)
  292.     {
  293.       return denormal_operand() < 0;
  294.     }
  295.   return 0;
  296. }
  297. /*---------------------------------------------------------------------------*/
  298. void fcom_st()
  299. {
  300.   /* fcom st(i) */
  301.   compare_st_st(FPU_rm);
  302. }
  303. void fcompst()
  304. {
  305.   /* fcomp st(i) */
  306.   if ( !compare_st_st(FPU_rm) )
  307.     FPU_pop();
  308. }
  309. void fcompp()
  310. {
  311.   /* fcompp */
  312.   if (FPU_rm != 1)
  313.     {
  314.       FPU_illegal();
  315.       return;
  316.     }
  317.   if ( !compare_st_st(1) )
  318.       poppop();
  319. }
  320. void fucom_()
  321. {
  322.   /* fucom st(i) */
  323.   compare_u_st_st(FPU_rm);
  324. }
  325. void fucomp()
  326. {
  327.   /* fucomp st(i) */
  328.   if ( !compare_u_st_st(FPU_rm) )
  329.     FPU_pop();
  330. }
  331. void fucompp()
  332. {
  333.   /* fucompp */
  334.   if (FPU_rm == 1)
  335.     {
  336.       if ( !compare_u_st_st(1) )
  337. poppop();
  338.     }
  339.   else
  340.     FPU_illegal();
  341. }