reg_u_sub.S 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. .file "reg_u_sub.S"
  2. /*---------------------------------------------------------------------------+
  3. | reg_u_sub.S |
  4. | |
  5. | Core floating point subtraction routine. |
  6. | |
  7. | Copyright (C) 1992,1993,1995,1997 |
  8. | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
  9. | E-mail billm@suburbia.net |
  10. | |
  11. | Call from C as: |
  12. | int FPU_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, |
  13. | int control_w) |
  14. | Return value is the tag of the answer, or-ed with FPU_Exception if |
  15. | one was raised, or -1 on internal error. |
  16. | |
  17. +---------------------------------------------------------------------------*/
  18. /*
  19. | Kernel subtraction routine FPU_u_sub(reg *arg1, reg *arg2, reg *answ).
  20. | Takes two valid reg f.p. numbers (TAG_Valid), which are
  21. | treated as unsigned numbers,
  22. | and returns their difference as a TAG_Valid or TAG_Zero f.p.
  23. | number.
  24. | The first number (arg1) must be the larger.
  25. | The returned number is normalized.
  26. | Basic checks are performed if PARANOID is defined.
  27. */
  28. #include "exception.h"
  29. #include "fpu_emu.h"
  30. #include "control_w.h"
  31. .text
  32. ENTRY(FPU_u_sub)
  33. pushl %ebp
  34. movl %esp,%ebp
  35. pushl %esi
  36. pushl %edi
  37. pushl %ebx
  38. movl PARAM1,%esi /* source 1 */
  39. movl PARAM2,%edi /* source 2 */
  40. movl PARAM6,%ecx
  41. subl PARAM7,%ecx /* exp1 - exp2 */
  42. #ifdef PARANOID
  43. /* source 2 is always smaller than source 1 */
  44. js L_bugged_1
  45. testl $0x80000000,SIGH(%edi) /* The args are assumed to be be normalized */
  46. je L_bugged_2
  47. testl $0x80000000,SIGH(%esi)
  48. je L_bugged_2
  49. #endif /* PARANOID */
  50. /*--------------------------------------+
  51. | Form a register holding the |
  52. | smaller number |
  53. +--------------------------------------*/
  54. movl SIGH(%edi),%eax /* register ms word */
  55. movl SIGL(%edi),%ebx /* register ls word */
  56. movl PARAM3,%edi /* destination */
  57. movl PARAM6,%edx
  58. movw %dx,EXP(%edi) /* Copy exponent to destination */
  59. xorl %edx,%edx /* register extension */
  60. /*--------------------------------------+
  61. | Shift the temporary register |
  62. | right the required number of |
  63. | places. |
  64. +--------------------------------------*/
  65. cmpw $32,%cx /* shrd only works for 0..31 bits */
  66. jnc L_more_than_31
  67. /* less than 32 bits */
  68. shrd %cl,%ebx,%edx
  69. shrd %cl,%eax,%ebx
  70. shr %cl,%eax
  71. jmp L_shift_done
  72. L_more_than_31:
  73. cmpw $64,%cx
  74. jnc L_more_than_63
  75. subb $32,%cl
  76. jz L_exactly_32
  77. shrd %cl,%eax,%edx
  78. shr %cl,%eax
  79. orl %ebx,%ebx
  80. jz L_more_31_no_low /* none of the lowest bits is set */
  81. orl $1,%edx /* record the fact in the extension */
  82. L_more_31_no_low:
  83. movl %eax,%ebx
  84. xorl %eax,%eax
  85. jmp L_shift_done
  86. L_exactly_32:
  87. movl %ebx,%edx
  88. movl %eax,%ebx
  89. xorl %eax,%eax
  90. jmp L_shift_done
  91. L_more_than_63:
  92. cmpw $65,%cx
  93. jnc L_more_than_64
  94. /* Shift right by 64 bits */
  95. movl %eax,%edx
  96. orl %ebx,%ebx
  97. jz L_more_63_no_low
  98. orl $1,%edx
  99. jmp L_more_63_no_low
  100. L_more_than_64:
  101. jne L_more_than_65
  102. /* Shift right by 65 bits */
  103. /* Carry is clear if we get here */
  104. movl %eax,%edx
  105. rcrl %edx
  106. jnc L_shift_65_nc
  107. orl $1,%edx
  108. jmp L_more_63_no_low
  109. L_shift_65_nc:
  110. orl %ebx,%ebx
  111. jz L_more_63_no_low
  112. orl $1,%edx
  113. jmp L_more_63_no_low
  114. L_more_than_65:
  115. movl $1,%edx /* The shifted nr always at least one '1' */
  116. L_more_63_no_low:
  117. xorl %ebx,%ebx
  118. xorl %eax,%eax
  119. L_shift_done:
  120. L_subtr:
  121. /*------------------------------+
  122. | Do the subtraction |
  123. +------------------------------*/
  124. xorl %ecx,%ecx
  125. subl %edx,%ecx
  126. movl %ecx,%edx
  127. movl SIGL(%esi),%ecx
  128. sbbl %ebx,%ecx
  129. movl %ecx,%ebx
  130. movl SIGH(%esi),%ecx
  131. sbbl %eax,%ecx
  132. movl %ecx,%eax
  133. #ifdef PARANOID
  134. /* We can never get a borrow */
  135. jc L_bugged
  136. #endif /* PARANOID */
  137. /*--------------------------------------+
  138. | Normalize the result |
  139. +--------------------------------------*/
  140. testl $0x80000000,%eax
  141. jnz L_round /* no shifting needed */
  142. orl %eax,%eax
  143. jnz L_shift_1 /* shift left 1 - 31 bits */
  144. orl %ebx,%ebx
  145. jnz L_shift_32 /* shift left 32 - 63 bits */
  146. /*
  147. * A rare case, the only one which is non-zero if we got here
  148. * is: 1000000 .... 0000
  149. * -0111111 .... 1111 1
  150. * --------------------
  151. * 0000000 .... 0000 1
  152. */
  153. cmpl $0x80000000,%edx
  154. jnz L_must_be_zero
  155. /* Shift left 64 bits */
  156. subw $64,EXP(%edi)
  157. xchg %edx,%eax
  158. jmp fpu_reg_round
  159. L_must_be_zero:
  160. #ifdef PARANOID
  161. orl %edx,%edx
  162. jnz L_bugged_3
  163. #endif /* PARANOID */
  164. /* The result is zero */
  165. movw $0,EXP(%edi) /* exponent */
  166. movl $0,SIGL(%edi)
  167. movl $0,SIGH(%edi)
  168. movl TAG_Zero,%eax
  169. jmp L_exit
  170. L_shift_32:
  171. movl %ebx,%eax
  172. movl %edx,%ebx
  173. movl $0,%edx
  174. subw $32,EXP(%edi) /* Can get underflow here */
  175. /* We need to shift left by 1 - 31 bits */
  176. L_shift_1:
  177. bsrl %eax,%ecx /* get the required shift in %ecx */
  178. subl $31,%ecx
  179. negl %ecx
  180. shld %cl,%ebx,%eax
  181. shld %cl,%edx,%ebx
  182. shl %cl,%edx
  183. subw %cx,EXP(%edi) /* Can get underflow here */
  184. L_round:
  185. jmp fpu_reg_round /* Round the result */
  186. #ifdef PARANOID
  187. L_bugged_1:
  188. pushl EX_INTERNAL|0x206
  189. call EXCEPTION
  190. pop %ebx
  191. jmp L_error_exit
  192. L_bugged_2:
  193. pushl EX_INTERNAL|0x209
  194. call EXCEPTION
  195. pop %ebx
  196. jmp L_error_exit
  197. L_bugged_3:
  198. pushl EX_INTERNAL|0x210
  199. call EXCEPTION
  200. pop %ebx
  201. jmp L_error_exit
  202. L_bugged_4:
  203. pushl EX_INTERNAL|0x211
  204. call EXCEPTION
  205. pop %ebx
  206. jmp L_error_exit
  207. L_bugged:
  208. pushl EX_INTERNAL|0x212
  209. call EXCEPTION
  210. pop %ebx
  211. jmp L_error_exit
  212. L_error_exit:
  213. movl $-1,%eax
  214. #endif /* PARANOID */
  215. L_exit:
  216. popl %ebx
  217. popl %edi
  218. popl %esi
  219. leave
  220. ret