reg_divide.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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. b = &st(0);
  37. st0_ptr = b;
  38. tagb = FPU_gettag0();
  39. if (flags & LOADED) {
  40. a = (FPU_REG *) rm;
  41. taga = flags & 0x0f;
  42. } else {
  43. a = &st(rm);
  44. st_ptr = a;
  45. taga = FPU_gettagi(rm);
  46. }
  47. } else {
  48. a = &st(0);
  49. st0_ptr = a;
  50. taga = FPU_gettag0();
  51. if (flags & LOADED) {
  52. b = (FPU_REG *) rm;
  53. tagb = flags & 0x0f;
  54. } else {
  55. b = &st(rm);
  56. st_ptr = b;
  57. tagb = FPU_gettagi(rm);
  58. }
  59. }
  60. signa = getsign(a);
  61. signb = getsign(b);
  62. sign = signa ^ signb;
  63. dest = &st(deststnr);
  64. saved_sign = getsign(dest);
  65. if (!(taga | tagb)) {
  66. /* Both regs Valid, this should be the most common case. */
  67. reg_copy(a, &x);
  68. reg_copy(b, &y);
  69. setpositive(&x);
  70. setpositive(&y);
  71. tag = FPU_u_div(&x, &y, dest, control_w, sign);
  72. if (tag < 0)
  73. return tag;
  74. FPU_settagi(deststnr, tag);
  75. return tag;
  76. }
  77. if (taga == TAG_Special)
  78. taga = FPU_Special(a);
  79. if (tagb == TAG_Special)
  80. tagb = FPU_Special(b);
  81. if (((taga == TAG_Valid) && (tagb == TW_Denormal))
  82. || ((taga == TW_Denormal) && (tagb == TAG_Valid))
  83. || ((taga == TW_Denormal) && (tagb == TW_Denormal))) {
  84. if (denormal_operand() < 0)
  85. return FPU_Exception;
  86. FPU_to_exp16(a, &x);
  87. FPU_to_exp16(b, &y);
  88. tag = FPU_u_div(&x, &y, dest, control_w, sign);
  89. if (tag < 0)
  90. return tag;
  91. FPU_settagi(deststnr, tag);
  92. return tag;
  93. } else if ((taga <= TW_Denormal) && (tagb <= TW_Denormal)) {
  94. if (tagb != TAG_Zero) {
  95. /* Want to find Zero/Valid */
  96. if (tagb == TW_Denormal) {
  97. if (denormal_operand() < 0)
  98. return FPU_Exception;
  99. }
  100. /* The result is zero. */
  101. FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
  102. setsign(dest, sign);
  103. return TAG_Zero;
  104. }
  105. /* We have an exception condition, either 0/0 or Valid/Zero. */
  106. if (taga == TAG_Zero) {
  107. /* 0/0 */
  108. return arith_invalid(deststnr);
  109. }
  110. /* Valid/Zero */
  111. return FPU_divide_by_zero(deststnr, sign);
  112. }
  113. /* Must have infinities, NaNs, etc */
  114. else if ((taga == TW_NaN) || (tagb == TW_NaN)) {
  115. if (flags & LOADED)
  116. return real_2op_NaN((FPU_REG *) rm, flags & 0x0f, 0,
  117. st0_ptr);
  118. if (flags & DEST_RM) {
  119. int tag;
  120. tag = FPU_gettag0();
  121. if (tag == TAG_Special)
  122. tag = FPU_Special(st0_ptr);
  123. return real_2op_NaN(st0_ptr, tag, rm,
  124. (flags & REV) ? st0_ptr : &st(rm));
  125. } else {
  126. int tag;
  127. tag = FPU_gettagi(rm);
  128. if (tag == TAG_Special)
  129. tag = FPU_Special(&st(rm));
  130. return real_2op_NaN(&st(rm), tag, 0,
  131. (flags & REV) ? st0_ptr : &st(rm));
  132. }
  133. } else if (taga == TW_Infinity) {
  134. if (tagb == TW_Infinity) {
  135. /* infinity/infinity */
  136. return arith_invalid(deststnr);
  137. } else {
  138. /* tagb must be Valid or Zero */
  139. if ((tagb == TW_Denormal) && (denormal_operand() < 0))
  140. return FPU_Exception;
  141. /* Infinity divided by Zero or Valid does
  142. not raise and exception, but returns Infinity */
  143. FPU_copy_to_regi(a, TAG_Special, deststnr);
  144. setsign(dest, sign);
  145. return taga;
  146. }
  147. } else if (tagb == TW_Infinity) {
  148. if ((taga == TW_Denormal) && (denormal_operand() < 0))
  149. return FPU_Exception;
  150. /* The result is zero. */
  151. FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
  152. setsign(dest, sign);
  153. return TAG_Zero;
  154. }
  155. #ifdef PARANOID
  156. else {
  157. EXCEPTION(EX_INTERNAL | 0x102);
  158. return FPU_Exception;
  159. }
  160. #endif /* PARANOID */
  161. return 0;
  162. }