reg_u_sub.S 6.0 KB

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