Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

251 lines
6.4 KiB

  1. title lldvrm - signed long divide and remainder routine
  2. ;***
  3. ;lldvrm.asm - signed long divide and remainder routine
  4. ;
  5. ; Copyright (c) 1985-2001, Microsoft Corporation. All rights reserved.
  6. ;
  7. ;Purpose:
  8. ; defines the signed long divide and remainder routine
  9. ; __alldvrm
  10. ;
  11. ;Revision History:
  12. ; 10-06-98 SMK Initial version.
  13. ;
  14. ;*******************************************************************************
  15. .xlist
  16. include cruntime.inc
  17. include mm.inc
  18. .list
  19. ;***
  20. ;lldvrm - signed long divide and remainder
  21. ;
  22. ;Purpose:
  23. ; Does a signed long divide and remainder of the arguments. Arguments are
  24. ; not changed.
  25. ;
  26. ;Entry:
  27. ; Arguments are passed on the stack:
  28. ; 1st pushed: divisor (QWORD)
  29. ; 2nd pushed: dividend (QWORD)
  30. ;
  31. ;Exit:
  32. ; EDX:EAX contains the quotient (dividend/divisor)
  33. ; EBX:ECX contains the remainder (divided % divisor)
  34. ; NOTE: this routine removes the parameters from the stack.
  35. ;
  36. ;Uses:
  37. ; ECX
  38. ;
  39. ;Exceptions:
  40. ;
  41. ;*******************************************************************************
  42. CODESEG
  43. _alldvrm PROC NEAR
  44. push edi
  45. push esi
  46. push ebp
  47. ; Set up the local stack and save the index registers. When this is done
  48. ; the stack frame will look as follows (assuming that the expression a/b will
  49. ; generate a call to alldvrm(a, b)):
  50. ;
  51. ; -----------------
  52. ; | |
  53. ; |---------------|
  54. ; | |
  55. ; |--divisor (b)--|
  56. ; | |
  57. ; |---------------|
  58. ; | |
  59. ; |--dividend (a)-|
  60. ; | |
  61. ; |---------------|
  62. ; | return addr** |
  63. ; |---------------|
  64. ; | EDI |
  65. ; |---------------|
  66. ; | ESI |
  67. ; |---------------|
  68. ; ESP---->| EBP |
  69. ; -----------------
  70. ;
  71. DVND equ [esp + 16] ; stack address of dividend (a)
  72. DVSR equ [esp + 24] ; stack address of divisor (b)
  73. ; Determine sign of the quotient (edi = 0 if result is positive, non-zero
  74. ; otherwise) and make operands positive.
  75. ; Sign of the remainder is kept in ebp.
  76. xor edi,edi ; result sign assumed positive
  77. xor ebp,ebp ; result sign assumed positive
  78. mov eax,HIWORD(DVND) ; hi word of a
  79. or eax,eax ; test to see if signed
  80. jge short L1 ; skip rest if a is already positive
  81. inc edi ; complement result sign flag
  82. inc ebp ; complement result sign flag
  83. mov edx,LOWORD(DVND) ; lo word of a
  84. neg eax ; make a positive
  85. neg edx
  86. sbb eax,0
  87. mov HIWORD(DVND),eax ; save positive value
  88. mov LOWORD(DVND),edx
  89. L1:
  90. mov eax,HIWORD(DVSR) ; hi word of b
  91. or eax,eax ; test to see if signed
  92. jge short L2 ; skip rest if b is already positive
  93. inc edi ; complement the result sign flag
  94. mov edx,LOWORD(DVSR) ; lo word of a
  95. neg eax ; make b positive
  96. neg edx
  97. sbb eax,0
  98. mov HIWORD(DVSR),eax ; save positive value
  99. mov LOWORD(DVSR),edx
  100. L2:
  101. ;
  102. ; Now do the divide. First look to see if the divisor is less than 4194304K.
  103. ; If so, then we can use a simple algorithm with word divides, otherwise
  104. ; things get a little more complex.
  105. ;
  106. ; NOTE - eax currently contains the high order word of DVSR
  107. ;
  108. or eax,eax ; check to see if divisor < 4194304K
  109. jnz short L3 ; nope, gotta do this the hard way
  110. mov ecx,LOWORD(DVSR) ; load divisor
  111. mov eax,HIWORD(DVND) ; load high word of dividend
  112. xor edx,edx
  113. div ecx ; eax <- high order bits of quotient
  114. mov ebx,eax ; save high bits of quotient
  115. mov eax,LOWORD(DVND) ; edx:eax <- remainder:lo word of dividend
  116. div ecx ; eax <- low order bits of quotient
  117. mov esi,eax ; ebx:esi <- quotient
  118. ;
  119. ; Now we need to do a multiply so that we can compute the remainder.
  120. ;
  121. mov eax,ebx ; set up high word of quotient
  122. mul dword ptr LOWORD(DVSR) ; HIWORD(QUOT) * DVSR
  123. mov ecx,eax ; save the result in ecx
  124. mov eax,esi ; set up low word of quotient
  125. mul dword ptr LOWORD(DVSR) ; LOWORD(QUOT) * DVSR
  126. add edx,ecx ; EDX:EAX = QUOT * DVSR
  127. jmp short L4 ; complete remainder calculation
  128. ;
  129. ; Here we do it the hard way. Remember, eax contains the high word of DVSR
  130. ;
  131. L3:
  132. mov ebx,eax ; ebx:ecx <- divisor
  133. mov ecx,LOWORD(DVSR)
  134. mov edx,HIWORD(DVND) ; edx:eax <- dividend
  135. mov eax,LOWORD(DVND)
  136. L5:
  137. shr ebx,1 ; shift divisor right one bit
  138. rcr ecx,1
  139. shr edx,1 ; shift dividend right one bit
  140. rcr eax,1
  141. or ebx,ebx
  142. jnz short L5 ; loop until divisor < 4194304K
  143. div ecx ; now divide, ignore remainder
  144. mov esi,eax ; save quotient
  145. ;
  146. ; We may be off by one, so to check, we will multiply the quotient
  147. ; by the divisor and check the result against the orignal dividend
  148. ; Note that we must also check for overflow, which can occur if the
  149. ; dividend is close to 2**64 and the quotient is off by 1.
  150. ;
  151. mul dword ptr HIWORD(DVSR) ; QUOT * HIWORD(DVSR)
  152. mov ecx,eax
  153. mov eax,LOWORD(DVSR)
  154. mul esi ; QUOT * LOWORD(DVSR)
  155. add edx,ecx ; EDX:EAX = QUOT * DVSR
  156. jc short L6 ; carry means Quotient is off by 1
  157. ;
  158. ; do long compare here between original dividend and the result of the
  159. ; multiply in edx:eax. If original is larger or equal, we are ok, otherwise
  160. ; subtract one (1) from the quotient.
  161. ;
  162. cmp edx,HIWORD(DVND) ; compare hi words of result and original
  163. ja short L6 ; if result > original, do subtract
  164. jb short L7 ; if result < original, we are ok
  165. cmp eax,LOWORD(DVND) ; hi words are equal, compare lo words
  166. jbe short L7 ; if less or equal we are ok, else subtract
  167. L6:
  168. dec esi ; subtract 1 from quotient
  169. sub eax,LOWORD(DVSR) ; subtract divisor from result
  170. sbb edx,HIWORD(DVSR)
  171. L7:
  172. xor ebx,ebx ; ebx:esi <- quotient
  173. L4:
  174. ;
  175. ; Calculate remainder by subtracting the result from the original dividend.
  176. ; Since the result is already in a register, we will do the subtract in the
  177. ; opposite direction and negate the result if necessary.
  178. ;
  179. sub eax,LOWORD(DVND) ; subtract dividend from result
  180. sbb edx,HIWORD(DVND)
  181. ;
  182. ; Now check the result sign flag to see if the result is supposed to be positive
  183. ; or negative. It is currently negated (because we subtracted in the 'wrong'
  184. ; direction), so if the sign flag is set we are done, otherwise we must negate
  185. ; the result to make it positive again.
  186. ;
  187. dec ebp ; check result sign flag
  188. jns short L9 ; result is ok, set up the quotient
  189. neg edx ; otherwise, negate the result
  190. neg eax
  191. sbb edx,0
  192. ;
  193. ; Now we need to get the quotient into edx:eax and the remainder into ebx:ecx.
  194. ;
  195. L9:
  196. mov ecx,edx
  197. mov edx,ebx
  198. mov ebx,ecx
  199. mov ecx,eax
  200. mov eax,esi
  201. ;
  202. ; Just the cleanup left to do. edx:eax contains the quotient. Set the sign
  203. ; according to the save value, cleanup the stack, and return.
  204. ;
  205. dec edi ; check to see if result is negative
  206. jnz short L8 ; if EDI == 0, result should be negative
  207. neg edx ; otherwise, negate the result
  208. neg eax
  209. sbb edx,0
  210. ;
  211. ; Restore the saved registers and return.
  212. ;
  213. L8:
  214. pop ebp
  215. pop esi
  216. pop edi
  217. ret 16
  218. _alldvrm ENDP
  219. end