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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*---------------------------------------------------------------------------+
  2.  |  reg_add_sub.c                                                            |
  3.  |                                                                           |
  4.  | Functions to add or subtract two registers and put the result in a third. |
  5.  |                                                                           |
  6.  | Copyright (C) 1992,1993,1997                                              |
  7.  |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
  8.  |                  E-mail   billm@suburbia.net                              |
  9.  |                                                                           |
  10.  |                                                                           |
  11.  +---------------------------------------------------------------------------*/
  12. /*---------------------------------------------------------------------------+
  13.  |  For each function, the destination may be any FPU_REG, including one of  |
  14.  | the source FPU_REGs.                                                      |
  15.  |  Each function returns 0 if the answer is o.k., otherwise a non-zero      |
  16.  | value is returned, indicating either an exception condition or an         |
  17.  | internal error.                                                           |
  18.  +---------------------------------------------------------------------------*/
  19. #include "exception.h"
  20. #include "reg_constant.h"
  21. #include "fpu_emu.h"
  22. #include "control_w.h"
  23. #include "fpu_system.h"
  24. static
  25. int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa,
  26.      FPU_REG const *b, u_char tagb, u_char signb,
  27.      FPU_REG *dest, int deststnr, int control_w);
  28. /*
  29.   Operates on st(0) and st(n), or on st(0) and temporary data.
  30.   The destination must be one of the source st(x).
  31.   */
  32. int FPU_add(FPU_REG const *b, u_char tagb, int deststnr, int control_w)
  33. {
  34.   FPU_REG *a = &st(0);
  35.   FPU_REG *dest = &st(deststnr);
  36.   u_char signb = getsign(b);
  37.   u_char taga = FPU_gettag0();
  38.   u_char signa = getsign(a);
  39.   u_char saved_sign = getsign(dest);
  40.   int diff, tag, expa, expb;
  41.   
  42.   if ( !(taga | tagb) )
  43.     {
  44.       expa = exponent(a);
  45.       expb = exponent(b);
  46.     valid_add:
  47.       /* Both registers are valid */
  48.       if (!(signa ^ signb))
  49. {
  50.   /* signs are the same */
  51.   tag = FPU_u_add(a, b, dest, control_w, signa, expa, expb);
  52. }
  53.       else
  54. {
  55.   /* The signs are different, so do a subtraction */
  56.   diff = expa - expb;
  57.   if (!diff)
  58.     {
  59.       diff = a->sigh - b->sigh;  /* This works only if the ms bits
  60.     are identical. */
  61.       if (!diff)
  62. {
  63.   diff = a->sigl > b->sigl;
  64.   if (!diff)
  65.     diff = -(a->sigl < b->sigl);
  66. }
  67.     }
  68.       
  69.   if (diff > 0)
  70.     {
  71.       tag = FPU_u_sub(a, b, dest, control_w, signa, expa, expb);
  72.     }
  73.   else if ( diff < 0 )
  74.     {
  75.       tag = FPU_u_sub(b, a, dest, control_w, signb, expb, expa);
  76.     }
  77.   else
  78.     {
  79.       FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
  80.       /* sign depends upon rounding mode */
  81.       setsign(dest, ((control_w & CW_RC) != RC_DOWN)
  82.       ? SIGN_POS : SIGN_NEG);
  83.       return TAG_Zero;
  84.     }
  85. }
  86.       if ( tag < 0 )
  87. {
  88.   setsign(dest, saved_sign);
  89.   return tag;
  90. }
  91.       FPU_settagi(deststnr, tag);
  92.       return tag;
  93.     }
  94.   if ( taga == TAG_Special )
  95.     taga = FPU_Special(a);
  96.   if ( tagb == TAG_Special )
  97.     tagb = FPU_Special(b);
  98.   if ( ((taga == TAG_Valid) && (tagb == TW_Denormal))
  99.     || ((taga == TW_Denormal) && (tagb == TAG_Valid))
  100.     || ((taga == TW_Denormal) && (tagb == TW_Denormal)) )
  101.     {
  102.       FPU_REG x, y;
  103.       if ( denormal_operand() < 0 )
  104. return FPU_Exception;
  105.       FPU_to_exp16(a, &x);
  106.       FPU_to_exp16(b, &y);
  107.       a = &x;
  108.       b = &y;
  109.       expa = exponent16(a);
  110.       expb = exponent16(b);
  111.       goto valid_add;
  112.     }
  113.   if ( (taga == TW_NaN) || (tagb == TW_NaN) )
  114.     {
  115.       if ( deststnr == 0 )
  116. return real_2op_NaN(b, tagb, deststnr, a);
  117.       else
  118. return real_2op_NaN(a, taga, deststnr, a);
  119.     }
  120.   return add_sub_specials(a, taga, signa, b, tagb, signb,
  121.   dest, deststnr, control_w);
  122. }
  123. /* Subtract b from a.  (a-b) -> dest */
  124. int FPU_sub(int flags, int rm, int control_w)
  125. {
  126.   FPU_REG const *a, *b;
  127.   FPU_REG *dest;
  128.   u_char taga, tagb, signa, signb, saved_sign, sign;
  129.   int diff, tag = 0, expa, expb, deststnr;
  130.   a = &st(0);
  131.   taga = FPU_gettag0();
  132.   deststnr = 0;
  133.   if ( flags & LOADED )
  134.     {
  135.       b = (FPU_REG *)rm;
  136.       tagb = flags & 0x0f;
  137.     }
  138.   else
  139.     {
  140.       b = &st(rm);
  141.       tagb = FPU_gettagi(rm);
  142.       if ( flags & DEST_RM )
  143. deststnr = rm;
  144.     }
  145.   signa = getsign(a);
  146.   signb = getsign(b);
  147.   if ( flags & REV )
  148.     {
  149.       signa ^= SIGN_NEG;
  150.       signb ^= SIGN_NEG;
  151.     }
  152.   dest = &st(deststnr);
  153.   saved_sign = getsign(dest);
  154.   if ( !(taga | tagb) )
  155.     {
  156.       expa = exponent(a);
  157.       expb = exponent(b);
  158.     valid_subtract:
  159.       /* Both registers are valid */
  160.       diff = expa - expb;
  161.       if (!diff)
  162. {
  163.   diff = a->sigh - b->sigh;  /* Works only if ms bits are identical */
  164.   if (!diff)
  165.     {
  166.       diff = a->sigl > b->sigl;
  167.       if (!diff)
  168. diff = -(a->sigl < b->sigl);
  169.     }
  170. }
  171.       switch ( (((int)signa)*2 + signb) / SIGN_NEG )
  172. {
  173. case 0: /* P - P */
  174. case 3: /* N - N */
  175.   if (diff > 0)
  176.     {
  177.       /* |a| > |b| */
  178.       tag = FPU_u_sub(a, b, dest, control_w, signa, expa, expb);
  179.     }
  180.   else if ( diff == 0 )
  181.     {
  182.       FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
  183.       /* sign depends upon rounding mode */
  184.       setsign(dest, ((control_w & CW_RC) != RC_DOWN)
  185. ? SIGN_POS : SIGN_NEG);
  186.       return TAG_Zero;
  187.     }
  188.   else
  189.     {
  190.       sign = signa ^ SIGN_NEG;
  191.       tag = FPU_u_sub(b, a, dest, control_w, sign, expb, expa);
  192.     }
  193.   break;
  194. case 1: /* P - N */
  195.   tag = FPU_u_add(a, b, dest, control_w, SIGN_POS, expa, expb);
  196.   break;
  197. case 2: /* N - P */
  198.   tag = FPU_u_add(a, b, dest, control_w, SIGN_NEG, expa, expb);
  199.   break;
  200. #ifdef PARANOID
  201. default:
  202.   EXCEPTION(EX_INTERNAL|0x111);
  203.   return -1;
  204. #endif
  205. }
  206.       if ( tag < 0 )
  207. {
  208.   setsign(dest, saved_sign);
  209.   return tag;
  210. }
  211.       FPU_settagi(deststnr, tag);
  212.       return tag;
  213.     }
  214.   if ( taga == TAG_Special )
  215.     taga = FPU_Special(a);
  216.   if ( tagb == TAG_Special )
  217.     tagb = FPU_Special(b);
  218.   if ( ((taga == TAG_Valid) && (tagb == TW_Denormal))
  219.     || ((taga == TW_Denormal) && (tagb == TAG_Valid))
  220.     || ((taga == TW_Denormal) && (tagb == TW_Denormal)) )
  221.     {
  222.       FPU_REG x, y;
  223.       if ( denormal_operand() < 0 )
  224. return FPU_Exception;
  225.       FPU_to_exp16(a, &x);
  226.       FPU_to_exp16(b, &y);
  227.       a = &x;
  228.       b = &y;
  229.       expa = exponent16(a);
  230.       expb = exponent16(b);
  231.       goto valid_subtract;
  232.     }
  233.   if ( (taga == TW_NaN) || (tagb == TW_NaN) )
  234.     {
  235.       FPU_REG const *d1, *d2;
  236.       if ( flags & REV )
  237. {
  238.   d1 = b;
  239.   d2 = a;
  240. }
  241.       else
  242. {
  243.   d1 = a;
  244.   d2 = b;
  245. }
  246.       if ( flags & LOADED )
  247. return real_2op_NaN(b, tagb, deststnr, d1);
  248.       if ( flags & DEST_RM )
  249. return real_2op_NaN(a, taga, deststnr, d2);
  250.       else
  251. return real_2op_NaN(b, tagb, deststnr, d2);
  252.     }
  253.     return add_sub_specials(a, taga, signa, b, tagb, signb ^ SIGN_NEG,
  254.     dest, deststnr, control_w);
  255. }
  256. static
  257. int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa,
  258.      FPU_REG const *b, u_char tagb, u_char signb,
  259.      FPU_REG *dest, int deststnr, int control_w)
  260. {
  261.   if ( ((taga == TW_Denormal) || (tagb == TW_Denormal))
  262.        && (denormal_operand() < 0) )
  263.     return FPU_Exception;
  264.   if (taga == TAG_Zero)
  265.     {
  266.       if (tagb == TAG_Zero)
  267. {
  268.   /* Both are zero, result will be zero. */
  269.   u_char different_signs = signa ^ signb;
  270.   FPU_copy_to_regi(a, TAG_Zero, deststnr);
  271.   if ( different_signs )
  272.     {
  273.       /* Signs are different. */
  274.       /* Sign of answer depends upon rounding mode. */
  275.       setsign(dest, ((control_w & CW_RC) != RC_DOWN)
  276.       ? SIGN_POS : SIGN_NEG);
  277.     }
  278.   else
  279.     setsign(dest, signa);  /* signa may differ from the sign of a. */
  280.   return TAG_Zero;
  281. }
  282.       else
  283. {
  284.   reg_copy(b, dest);
  285.   if ( (tagb == TW_Denormal) && (b->sigh & 0x80000000) )
  286.     {
  287.       /* A pseudoDenormal, convert it. */
  288.       addexponent(dest, 1);
  289.       tagb = TAG_Valid;
  290.     }
  291.   else if ( tagb > TAG_Empty )
  292.     tagb = TAG_Special;
  293.   setsign(dest, signb);  /* signb may differ from the sign of b. */
  294.   FPU_settagi(deststnr, tagb);
  295.   return tagb;
  296. }
  297.     }
  298.   else if (tagb == TAG_Zero)
  299.     {
  300.       reg_copy(a, dest);
  301.       if ( (taga == TW_Denormal) && (a->sigh & 0x80000000) )
  302. {
  303.   /* A pseudoDenormal */
  304.   addexponent(dest, 1);
  305.   taga = TAG_Valid;
  306. }
  307.       else if ( taga > TAG_Empty )
  308. taga = TAG_Special;
  309.       setsign(dest, signa);  /* signa may differ from the sign of a. */
  310.       FPU_settagi(deststnr, taga);
  311.       return taga;
  312.     }
  313.   else if (taga == TW_Infinity)
  314.     {
  315.       if ( (tagb != TW_Infinity) || (signa == signb) )
  316. {
  317.   FPU_copy_to_regi(a, TAG_Special, deststnr);
  318.   setsign(dest, signa);  /* signa may differ from the sign of a. */
  319.   return taga;
  320. }
  321.       /* Infinity-Infinity is undefined. */
  322.       return arith_invalid(deststnr);
  323.     }
  324.   else if (tagb == TW_Infinity)
  325.     {
  326.       FPU_copy_to_regi(b, TAG_Special, deststnr);
  327.       setsign(dest, signb);  /* signb may differ from the sign of b. */
  328.       return tagb;
  329.     }
  330. #ifdef PARANOID
  331.   EXCEPTION(EX_INTERNAL|0x101);
  332. #endif
  333.   return FPU_Exception;
  334. }