reg_divide.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:5k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*---------------------------------------------------------------------------+
  2.  |  reg_divide.c                                                             |
  3.  |                                                                           |
  4.  | Divide one FPU_REG by another and put the result in a destination FPU_REG.|
  5.  |                                                                           |
  6.  | Copyright (C) 1996                                                        |
  7.  |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
  8.  |                  E-mail   billm@jacobi.maths.monash.edu.au                |
  9.  |                                                                           |
  10.  |    Return value is the tag of the answer, or-ed with FPU_Exception if     |
  11.  |    one was raised, or -1 on internal error.                               |
  12.  |                                                                           |
  13.  +---------------------------------------------------------------------------*/
  14. /*---------------------------------------------------------------------------+
  15.  | The destination may be any FPU_REG, including one of the source FPU_REGs. |
  16.  +---------------------------------------------------------------------------*/
  17. #include "exception.h"
  18. #include "reg_constant.h"
  19. #include "fpu_emu.h"
  20. #include "fpu_system.h"
  21. /*
  22.   Divide one register by another and put the result into a third register.
  23.   */
  24. int FPU_div(int flags, int rm, int control_w)
  25. {
  26.   FPU_REG x, y;
  27.   FPU_REG const *a, *b, *st0_ptr, *st_ptr;
  28.   FPU_REG *dest;
  29.   u_char taga, tagb, signa, signb, sign, saved_sign;
  30.   int tag, deststnr;
  31.   if ( flags & DEST_RM )
  32.     deststnr = rm;
  33.   else
  34.     deststnr = 0;
  35.   if ( flags & REV )
  36.     {
  37.       b = &st(0);
  38.       st0_ptr = b;
  39.       tagb = FPU_gettag0();
  40.       if ( flags & LOADED )
  41. {
  42.   a = (FPU_REG *)rm;
  43.   taga = flags & 0x0f;
  44. }
  45.       else
  46. {
  47.   a = &st(rm);
  48.   st_ptr = a;
  49.   taga = FPU_gettagi(rm);
  50. }
  51.     }
  52.   else
  53.     {
  54.       a = &st(0);
  55.       st0_ptr = a;
  56.       taga = FPU_gettag0();
  57.       if ( flags & LOADED )
  58. {
  59.   b = (FPU_REG *)rm;
  60.   tagb = flags & 0x0f;
  61. }
  62.       else
  63. {
  64.   b = &st(rm);
  65.   st_ptr = b;
  66.   tagb = FPU_gettagi(rm);
  67. }
  68.     }
  69.   signa = getsign(a);
  70.   signb = getsign(b);
  71.   sign = signa ^ signb;
  72.   dest = &st(deststnr);
  73.   saved_sign = getsign(dest);
  74.   if ( !(taga | tagb) )
  75.     {
  76.       /* Both regs Valid, this should be the most common case. */
  77.       reg_copy(a, &x);
  78.       reg_copy(b, &y);
  79.       setpositive(&x);
  80.       setpositive(&y);
  81.       tag = FPU_u_div(&x, &y, dest, control_w, sign);
  82.       if ( tag < 0 )
  83. return tag;
  84.       FPU_settagi(deststnr, tag);
  85.       return tag;
  86.     }
  87.   if ( taga == TAG_Special )
  88.     taga = FPU_Special(a);
  89.   if ( tagb == TAG_Special )
  90.     tagb = FPU_Special(b);
  91.   if ( ((taga == TAG_Valid) && (tagb == TW_Denormal))
  92.     || ((taga == TW_Denormal) && (tagb == TAG_Valid))
  93.     || ((taga == TW_Denormal) && (tagb == TW_Denormal)) )
  94.     {
  95.       if ( denormal_operand() < 0 )
  96. return FPU_Exception;
  97.       FPU_to_exp16(a, &x);
  98.       FPU_to_exp16(b, &y);
  99.       tag = FPU_u_div(&x, &y, dest, control_w, sign);
  100.       if ( tag < 0 )
  101. return tag;
  102.       FPU_settagi(deststnr, tag);
  103.       return tag;
  104.     }
  105.   else if ( (taga <= TW_Denormal) && (tagb <= TW_Denormal) )
  106.     {
  107.       if ( tagb != TAG_Zero )
  108. {
  109.   /* Want to find Zero/Valid */
  110.   if ( tagb == TW_Denormal )
  111.     {
  112.       if ( denormal_operand() < 0 )
  113. return FPU_Exception;
  114.     }
  115.   /* The result is zero. */
  116.   FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
  117.   setsign(dest, sign);
  118.   return TAG_Zero;
  119. }
  120.       /* We have an exception condition, either 0/0 or Valid/Zero. */
  121.       if ( taga == TAG_Zero )
  122. {
  123.   /* 0/0 */
  124.   return arith_invalid(deststnr);
  125. }
  126.       /* Valid/Zero */
  127.       return FPU_divide_by_zero(deststnr, sign);
  128.     }
  129.   /* Must have infinities, NaNs, etc */
  130.   else if ( (taga == TW_NaN) || (tagb == TW_NaN) )
  131.     {
  132.       if ( flags & LOADED )
  133. return real_2op_NaN((FPU_REG *)rm, flags & 0x0f, 0, st0_ptr);
  134.       if ( flags & DEST_RM )
  135. {
  136.   int tag;
  137.   tag = FPU_gettag0();
  138.   if ( tag == TAG_Special )
  139.     tag = FPU_Special(st0_ptr);
  140.   return real_2op_NaN(st0_ptr, tag, rm, (flags & REV) ? st0_ptr : &st(rm));
  141. }
  142.       else
  143. {
  144.   int tag;
  145.   tag = FPU_gettagi(rm);
  146.   if ( tag == TAG_Special )
  147.     tag = FPU_Special(&st(rm));
  148.   return real_2op_NaN(&st(rm), tag, 0, (flags & REV) ? st0_ptr : &st(rm));
  149. }
  150.     }
  151.   else if (taga == TW_Infinity)
  152.     {
  153.       if (tagb == TW_Infinity)
  154. {
  155.   /* infinity/infinity */
  156.   return arith_invalid(deststnr);
  157. }
  158.       else
  159. {
  160.   /* tagb must be Valid or Zero */
  161.   if ( (tagb == TW_Denormal) && (denormal_operand() < 0) )
  162.     return FPU_Exception;
  163.   
  164.   /* Infinity divided by Zero or Valid does
  165.      not raise and exception, but returns Infinity */
  166.   FPU_copy_to_regi(a, TAG_Special, deststnr);
  167.   setsign(dest, sign);
  168.   return taga;
  169. }
  170.     }
  171.   else if (tagb == TW_Infinity)
  172.     {
  173.       if ( (taga == TW_Denormal) && (denormal_operand() < 0) )
  174. return FPU_Exception;
  175.       /* The result is zero. */
  176.       FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
  177.       setsign(dest, sign);
  178.       return TAG_Zero;
  179.     }
  180. #ifdef PARANOID
  181.   else
  182.     {
  183.       EXCEPTION(EX_INTERNAL|0x102);
  184.       return FPU_Exception;
  185.     }
  186. #endif /* PARANOID */ 
  187. }