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

Linux/Unix编程

开发平台:

Unix_Linux

  1. .file "div_Xsig.S"
  2. /*---------------------------------------------------------------------------+
  3.  |  div_Xsig.S                                                               |
  4.  |                                                                           |
  5.  | Division subroutine for 96 bit quantities                                 |
  6.  |                                                                           |
  7.  | Copyright (C) 1994,1995                                                   |
  8.  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
  9.  |                       Australia.  E-mail billm@jacobi.maths.monash.edu.au |
  10.  |                                                                           |
  11.  |                                                                           |
  12.  +---------------------------------------------------------------------------*/
  13. /*---------------------------------------------------------------------------+
  14.  | Divide the 96 bit quantity pointed to by a, by that pointed to by b, and  |
  15.  | put the 96 bit result at the location d.                                  |
  16.  |                                                                           |
  17.  | The result may not be accurate to 96 bits. It is intended for use where   |
  18.  | a result better than 64 bits is required. The result should usually be    |
  19.  | good to at least 94 bits.                                                 |
  20.  | The returned result is actually divided by one half. This is done to      |
  21.  | prevent overflow.                                                         |
  22.  |                                                                           |
  23.  |  .aaaaaaaaaaaaaa / .bbbbbbbbbbbbb  ->  .dddddddddddd                      |
  24.  |                                                                           |
  25.  |  void div_Xsig(Xsig *a, Xsig *b, Xsig *dest)                              |
  26.  |                                                                           |
  27.  +---------------------------------------------------------------------------*/
  28. #include "exception.h"
  29. #include "fpu_emu.h"
  30. #define XsigLL(x) (x)
  31. #define XsigL(x) 4(x)
  32. #define XsigH(x) 8(x)
  33. #ifndef NON_REENTRANT_FPU
  34. /*
  35. Local storage on the stack:
  36. Accumulator: FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0
  37.  */
  38. #define FPU_accum_3 -4(%ebp)
  39. #define FPU_accum_2 -8(%ebp)
  40. #define FPU_accum_1 -12(%ebp)
  41. #define FPU_accum_0 -16(%ebp)
  42. #define FPU_result_3 -20(%ebp)
  43. #define FPU_result_2 -24(%ebp)
  44. #define FPU_result_1 -28(%ebp)
  45. #else
  46. .data
  47. /*
  48. Local storage in a static area:
  49. Accumulator: FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0
  50.  */
  51. .align 4,0
  52. FPU_accum_3:
  53. .long 0
  54. FPU_accum_2:
  55. .long 0
  56. FPU_accum_1:
  57. .long 0
  58. FPU_accum_0:
  59. .long 0
  60. FPU_result_3:
  61. .long 0
  62. FPU_result_2:
  63. .long 0
  64. FPU_result_1:
  65. .long 0
  66. #endif /* NON_REENTRANT_FPU */
  67. .text
  68. ENTRY(div_Xsig)
  69. pushl %ebp
  70. movl %esp,%ebp
  71. #ifndef NON_REENTRANT_FPU
  72. subl $28,%esp
  73. #endif /* NON_REENTRANT_FPU */ 
  74. pushl %esi
  75. pushl %edi
  76. pushl %ebx
  77. movl PARAM1,%esi /* pointer to num */
  78. movl PARAM2,%ebx /* pointer to denom */
  79. #ifdef PARANOID
  80. testl $0x80000000, XsigH(%ebx) /* Divisor */
  81. je L_bugged
  82. #endif /* PARANOID */
  83. /*---------------------------------------------------------------------------+
  84.  |  Divide:   Return  arg1/arg2 to arg3.                                     |
  85.  |                                                                           |
  86.  |  The maximum returned value is (ignoring exponents)                       |
  87.  |               .ffffffff ffffffff                                          |
  88.  |               ------------------  =  1.ffffffff fffffffe                  |
  89.  |               .80000000 00000000                                          |
  90.  | and the minimum is                                                        |
  91.  |               .80000000 00000000                                          |
  92.  |               ------------------  =  .80000000 00000001   (rounded)       |
  93.  |               .ffffffff ffffffff                                          |
  94.  |                                                                           |
  95.  +---------------------------------------------------------------------------*/
  96. /* Save extended dividend in local register */
  97. /* Divide by 2 to prevent overflow */
  98. clc
  99. movl XsigH(%esi),%eax
  100. rcrl %eax
  101. movl %eax,FPU_accum_3
  102. movl XsigL(%esi),%eax
  103. rcrl %eax
  104. movl %eax,FPU_accum_2
  105. movl XsigLL(%esi),%eax
  106. rcrl %eax
  107. movl %eax,FPU_accum_1
  108. movl $0,%eax
  109. rcrl %eax
  110. movl %eax,FPU_accum_0
  111. movl FPU_accum_2,%eax /* Get the current num */
  112. movl FPU_accum_3,%edx
  113. /*----------------------------------------------------------------------*/
  114. /* Initialization done.
  115.    Do the first 32 bits. */
  116. /* We will divide by a number which is too large */
  117. movl XsigH(%ebx),%ecx
  118. addl $1,%ecx
  119. jnc LFirst_div_not_1
  120. /* here we need to divide by 100000000h,
  121.    i.e., no division at all.. */
  122. mov %edx,%eax
  123. jmp LFirst_div_done
  124. LFirst_div_not_1:
  125. divl %ecx /* Divide the numerator by the augmented
  126.    denom ms dw */
  127. LFirst_div_done:
  128. movl %eax,FPU_result_3 /* Put the result in the answer */
  129. mull XsigH(%ebx) /* mul by the ms dw of the denom */
  130. subl %eax,FPU_accum_2 /* Subtract from the num local reg */
  131. sbbl %edx,FPU_accum_3
  132. movl FPU_result_3,%eax /* Get the result back */
  133. mull XsigL(%ebx) /* now mul the ls dw of the denom */
  134. subl %eax,FPU_accum_1 /* Subtract from the num local reg */
  135. sbbl %edx,FPU_accum_2
  136. sbbl $0,FPU_accum_3
  137. je LDo_2nd_32_bits /* Must check for non-zero result here */
  138. #ifdef PARANOID
  139. jb L_bugged_1
  140. #endif /* PARANOID */ 
  141. /* need to subtract another once of the denom */
  142. incl FPU_result_3 /* Correct the answer */
  143. movl XsigL(%ebx),%eax
  144. movl XsigH(%ebx),%edx
  145. subl %eax,FPU_accum_1 /* Subtract from the num local reg */
  146. sbbl %edx,FPU_accum_2
  147. #ifdef PARANOID
  148. sbbl $0,FPU_accum_3
  149. jne L_bugged_1 /* Must check for non-zero result here */
  150. #endif /* PARANOID */ 
  151. /*----------------------------------------------------------------------*/
  152. /* Half of the main problem is done, there is just a reduced numerator
  153.    to handle now.
  154.    Work with the second 32 bits, FPU_accum_0 not used from now on */
  155. LDo_2nd_32_bits:
  156. movl FPU_accum_2,%edx /* get the reduced num */
  157. movl FPU_accum_1,%eax
  158. /* need to check for possible subsequent overflow */
  159. cmpl XsigH(%ebx),%edx
  160. jb LDo_2nd_div
  161. ja LPrevent_2nd_overflow
  162. cmpl XsigL(%ebx),%eax
  163. jb LDo_2nd_div
  164. LPrevent_2nd_overflow:
  165. /* The numerator is greater or equal, would cause overflow */
  166. /* prevent overflow */
  167. subl XsigL(%ebx),%eax
  168. sbbl XsigH(%ebx),%edx
  169. movl %edx,FPU_accum_2
  170. movl %eax,FPU_accum_1
  171. incl FPU_result_3 /* Reflect the subtraction in the answer */
  172. #ifdef PARANOID
  173. je L_bugged_2 /* Can't bump the result to 1.0 */
  174. #endif /* PARANOID */ 
  175. LDo_2nd_div:
  176. cmpl $0,%ecx /* augmented denom msw */
  177. jnz LSecond_div_not_1
  178. /* %ecx == 0, we are dividing by 1.0 */
  179. mov %edx,%eax
  180. jmp LSecond_div_done
  181. LSecond_div_not_1:
  182. divl %ecx /* Divide the numerator by the denom ms dw */
  183. LSecond_div_done:
  184. movl %eax,FPU_result_2 /* Put the result in the answer */
  185. mull XsigH(%ebx) /* mul by the ms dw of the denom */
  186. subl %eax,FPU_accum_1 /* Subtract from the num local reg */
  187. sbbl %edx,FPU_accum_2
  188. #ifdef PARANOID
  189. jc L_bugged_2
  190. #endif /* PARANOID */
  191. movl FPU_result_2,%eax /* Get the result back */
  192. mull XsigL(%ebx) /* now mul the ls dw of the denom */
  193. subl %eax,FPU_accum_0 /* Subtract from the num local reg */
  194. sbbl %edx,FPU_accum_1 /* Subtract from the num local reg */
  195. sbbl $0,FPU_accum_2
  196. #ifdef PARANOID
  197. jc L_bugged_2
  198. #endif /* PARANOID */
  199. jz LDo_3rd_32_bits
  200. #ifdef PARANOID
  201. cmpl $1,FPU_accum_2
  202. jne L_bugged_2
  203. #endif /* PARANOID */ 
  204. /* need to subtract another once of the denom */
  205. movl XsigL(%ebx),%eax
  206. movl XsigH(%ebx),%edx
  207. subl %eax,FPU_accum_0 /* Subtract from the num local reg */
  208. sbbl %edx,FPU_accum_1
  209. sbbl $0,FPU_accum_2
  210. #ifdef PARANOID
  211. jc L_bugged_2
  212. jne L_bugged_2
  213. #endif /* PARANOID */ 
  214. addl $1,FPU_result_2 /* Correct the answer */
  215. adcl $0,FPU_result_3
  216. #ifdef PARANOID
  217. jc L_bugged_2 /* Must check for non-zero result here */
  218. #endif /* PARANOID */ 
  219. /*----------------------------------------------------------------------*/
  220. /* The division is essentially finished here, we just need to perform
  221.    tidying operations.
  222.    Deal with the 3rd 32 bits */
  223. LDo_3rd_32_bits:
  224. /* We use an approximation for the third 32 bits.
  225. To take account of the 3rd 32 bits of the divisor
  226. (call them del), we subtract  del * (a/b) */
  227. movl FPU_result_3,%eax /* a/b */
  228. mull XsigLL(%ebx) /* del */
  229. subl %edx,FPU_accum_1
  230. /* A borrow indicates that the result is negative */
  231. jnb LTest_over
  232. movl XsigH(%ebx),%edx
  233. addl %edx,FPU_accum_1
  234. subl $1,FPU_result_2 /* Adjust the answer */
  235. sbbl $0,FPU_result_3
  236. /* The above addition might not have been enough, check again. */
  237. movl FPU_accum_1,%edx /* get the reduced num */
  238. cmpl XsigH(%ebx),%edx /* denom */
  239. jb LDo_3rd_div
  240. movl XsigH(%ebx),%edx
  241. addl %edx,FPU_accum_1
  242. subl $1,FPU_result_2 /* Adjust the answer */
  243. sbbl $0,FPU_result_3
  244. jmp LDo_3rd_div
  245. LTest_over:
  246. movl FPU_accum_1,%edx /* get the reduced num */
  247. /* need to check for possible subsequent overflow */
  248. cmpl XsigH(%ebx),%edx /* denom */
  249. jb LDo_3rd_div
  250. /* prevent overflow */
  251. subl XsigH(%ebx),%edx
  252. movl %edx,FPU_accum_1
  253. addl $1,FPU_result_2 /* Reflect the subtraction in the answer */
  254. adcl $0,FPU_result_3
  255. LDo_3rd_div:
  256. movl FPU_accum_0,%eax
  257. movl FPU_accum_1,%edx
  258. divl XsigH(%ebx)
  259. movl    %eax,FPU_result_1       /* Rough estimate of third word */
  260. movl PARAM3,%esi /* pointer to answer */
  261. movl FPU_result_1,%eax
  262. movl %eax,XsigLL(%esi)
  263. movl FPU_result_2,%eax
  264. movl %eax,XsigL(%esi)
  265. movl FPU_result_3,%eax
  266. movl %eax,XsigH(%esi)
  267. L_exit:
  268. popl %ebx
  269. popl %edi
  270. popl %esi
  271. leave
  272. ret
  273. #ifdef PARANOID
  274. /* The logic is wrong if we got here */
  275. L_bugged:
  276. pushl EX_INTERNAL|0x240
  277. call EXCEPTION
  278. pop %ebx
  279. jmp L_exit
  280. L_bugged_1:
  281. pushl EX_INTERNAL|0x241
  282. call EXCEPTION
  283. pop %ebx
  284. jmp L_exit
  285. L_bugged_2:
  286. pushl EX_INTERNAL|0x242
  287. call EXCEPTION
  288. pop %ebx
  289. jmp L_exit
  290. #endif /* PARANOID */