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

Linux/Unix编程

开发平台:

Unix_Linux

  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