Leaked source code of windows server 2003
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.

202 lines
6.5 KiB

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