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.

170 lines
4.2 KiB

  1. title ulldiv - unsigned long divide routine
  2. ;***
  3. ;ulldiv.asm - unsigned long divide routine
  4. ;
  5. ; Copyright (c) 1985-2001, Microsoft Corporation. All rights reserved.
  6. ;
  7. ;Purpose:
  8. ; defines the unsigned long divide routine
  9. ; __aulldiv
  10. ;
  11. ;Revision History:
  12. ; 11-29-83 DFW initial version
  13. ; 06-01-84 RN modified to use cmacros
  14. ; 10-23-87 SKS fixed off-by-1 error for dividend close to 2**32.
  15. ; 05-18-89 SKS Remove redundant "MOV SP,BP" from epilog
  16. ; 11-28-89 GJF Fixed copyright
  17. ; 11-19-93 SMK Modified to work on 64 bit integers
  18. ; 01-17-94 GJF Minor changes to build with NT's masm386.
  19. ; 07-22-94 GJF Use esp-relative addressing for args. Shortened
  20. ; conditional jumps. Also, don't use xchg to do a
  21. ; simple move between regs.
  22. ;
  23. ;*******************************************************************************
  24. .xlist
  25. include cruntime.inc
  26. include mm.inc
  27. .list
  28. ;***
  29. ;ulldiv - unsigned long divide
  30. ;
  31. ;Purpose:
  32. ; Does a unsigned long divide of the arguments. Arguments are
  33. ; not changed.
  34. ;
  35. ;Entry:
  36. ; Arguments are passed on the stack:
  37. ; 1st pushed: divisor (QWORD)
  38. ; 2nd pushed: dividend (QWORD)
  39. ;
  40. ;Exit:
  41. ; EDX:EAX contains the quotient (dividend/divisor)
  42. ; NOTE: this routine removes the parameters from the stack.
  43. ;
  44. ;Uses:
  45. ; ECX
  46. ;
  47. ;Exceptions:
  48. ;
  49. ;*******************************************************************************
  50. CODESEG
  51. _aulldiv PROC NEAR
  52. push ebx
  53. push esi
  54. ; Set up the local stack and save the index registers. When this is done
  55. ; the stack frame will look as follows (assuming that the expression a/b will
  56. ; generate a call to uldiv(a, b)):
  57. ;
  58. ; -----------------
  59. ; | |
  60. ; |---------------|
  61. ; | |
  62. ; |--divisor (b)--|
  63. ; | |
  64. ; |---------------|
  65. ; | |
  66. ; |--dividend (a)-|
  67. ; | |
  68. ; |---------------|
  69. ; | return addr** |
  70. ; |---------------|
  71. ; | EBX |
  72. ; |---------------|
  73. ; ESP---->| ESI |
  74. ; -----------------
  75. ;
  76. DVND equ [esp + 12] ; stack address of dividend (a)
  77. DVSR equ [esp + 20] ; stack address of divisor (b)
  78. ;
  79. ; Now do the divide. First look to see if the divisor is less than 4194304K.
  80. ; If so, then we can use a simple algorithm with word divides, otherwise
  81. ; things get a little more complex.
  82. ;
  83. mov eax,HIWORD(DVSR) ; check to see if divisor < 4194304K
  84. or eax,eax
  85. jnz short L1 ; nope, gotta do this the hard way
  86. mov ecx,LOWORD(DVSR) ; load divisor
  87. mov eax,HIWORD(DVND) ; load high word of dividend
  88. xor edx,edx
  89. div ecx ; get high order bits of quotient
  90. mov ebx,eax ; save high bits of quotient
  91. mov eax,LOWORD(DVND) ; edx:eax <- remainder:lo word of dividend
  92. div ecx ; get low order bits of quotient
  93. mov edx,ebx ; edx:eax <- quotient hi:quotient lo
  94. jmp short L2 ; restore stack and return
  95. ;
  96. ; Here we do it the hard way. Remember, eax contains DVSRHI
  97. ;
  98. L1:
  99. mov ecx,eax ; ecx:ebx <- divisor
  100. mov ebx,LOWORD(DVSR)
  101. mov edx,HIWORD(DVND) ; edx:eax <- dividend
  102. mov eax,LOWORD(DVND)
  103. L3:
  104. shr ecx,1 ; shift divisor right one bit; hi bit <- 0
  105. rcr ebx,1
  106. shr edx,1 ; shift dividend right one bit; hi bit <- 0
  107. rcr eax,1
  108. or ecx,ecx
  109. jnz short L3 ; loop until divisor < 4194304K
  110. div ebx ; now divide, ignore remainder
  111. mov esi,eax ; save quotient
  112. ;
  113. ; We may be off by one, so to check, we will multiply the quotient
  114. ; by the divisor and check the result against the orignal dividend
  115. ; Note that we must also check for overflow, which can occur if the
  116. ; dividend is close to 2**64 and the quotient is off by 1.
  117. ;
  118. mul dword ptr HIWORD(DVSR) ; QUOT * HIWORD(DVSR)
  119. mov ecx,eax
  120. mov eax,LOWORD(DVSR)
  121. mul esi ; QUOT * LOWORD(DVSR)
  122. add edx,ecx ; EDX:EAX = QUOT * DVSR
  123. jc short L4 ; carry means Quotient is off by 1
  124. ;
  125. ; do long compare here between original dividend and the result of the
  126. ; multiply in edx:eax. If original is larger or equal, we are ok, otherwise
  127. ; subtract one (1) from the quotient.
  128. ;
  129. cmp edx,HIWORD(DVND) ; compare hi words of result and original
  130. ja short L4 ; if result > original, do subtract
  131. jb short L5 ; if result < original, we are ok
  132. cmp eax,LOWORD(DVND) ; hi words are equal, compare lo words
  133. jbe short L5 ; if less or equal we are ok, else subtract
  134. L4:
  135. dec esi ; subtract 1 from quotient
  136. L5:
  137. xor edx,edx ; edx:eax <- quotient
  138. mov eax,esi
  139. ;
  140. ; Just the cleanup left to do. edx:eax contains the quotient.
  141. ; Restore the saved registers and return.
  142. ;
  143. L2:
  144. pop esi
  145. pop ebx
  146. ret 16
  147. _aulldiv ENDP
  148. end