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.

158 lines
4.8 KiB

  1. title ulldiv - unsigned long divide routine
  2. ;***
  3. ;ulldiv.asm - unsigned long divide routine
  4. ;
  5. ; Copyright (c) 1985-1994, Microsoft Corporation. All rights reserved.
  6. ;
  7. ;Purpose:
  8. ; defines the unsigned long divide routine
  9. ; __aulldiv
  10. ;
  11. ;*******************************************************************************
  12. .xlist
  13. include cruntime.inc
  14. include mm.inc
  15. .list
  16. ;***
  17. ;ulldiv - unsigned long divide
  18. ;
  19. ;Purpose:
  20. ; Does a unsigned 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. _aulldiv PROC NEAR
  40. push ebx
  41. push esi
  42. ; Set up the local stack and save the index registers. When this is done
  43. ; the stack frame will look as follows (assuming that the expression a/b will
  44. ; generate a call to uldiv(a, b)):
  45. ;
  46. ; -----------------
  47. ; | |
  48. ; |---------------|
  49. ; | |
  50. ; |--divisor (b)--|
  51. ; | |
  52. ; |---------------|
  53. ; | |
  54. ; |--dividend (a)-|
  55. ; | |
  56. ; |---------------|
  57. ; | return addr** |
  58. ; |---------------|
  59. ; | EBX |
  60. ; |---------------|
  61. ; ESP---->| ESI |
  62. ; -----------------
  63. ;
  64. DVND equ [esp + 12] ; stack address of dividend (a)
  65. DVSR equ [esp + 20] ; stack address of divisor (b)
  66. ;
  67. ; Now do the divide. First look to see if the divisor is less than 4194304K.
  68. ; If so, then we can use a simple algorithm with word divides, otherwise
  69. ; things get a little more complex.
  70. ;
  71. mov eax,HIWORD(DVSR) ; check to see if divisor < 4194304K
  72. or eax,eax
  73. jnz short L1 ; nope, gotta do this the hard way
  74. mov ecx,LOWORD(DVSR) ; load divisor
  75. mov eax,HIWORD(DVND) ; load high word of dividend
  76. xor edx,edx
  77. div ecx ; get high order bits of quotient
  78. mov ebx,eax ; save high bits of quotient
  79. mov eax,LOWORD(DVND) ; edx:eax <- remainder:lo word of dividend
  80. div ecx ; get low order bits of quotient
  81. mov edx,ebx ; edx:eax <- quotient hi:quotient lo
  82. jmp short L2 ; restore stack and return
  83. ;
  84. ; Here we do it the hard way. Remember, eax contains DVSRHI
  85. ;
  86. L1:
  87. mov ecx,eax ; ecx:ebx <- divisor
  88. mov ebx,LOWORD(DVSR)
  89. mov edx,HIWORD(DVND) ; edx:eax <- dividend
  90. mov eax,LOWORD(DVND)
  91. L3:
  92. shr ecx,1 ; shift divisor right one bit; hi bit <- 0
  93. rcr ebx,1
  94. shr edx,1 ; shift dividend right one bit; hi bit <- 0
  95. rcr eax,1
  96. or ecx,ecx
  97. jnz short L3 ; loop until divisor < 4194304K
  98. div ebx ; now divide, ignore remainder
  99. mov esi,eax ; save quotient
  100. ;
  101. ; We may be off by one, so to check, we will multiply the quotient
  102. ; by the divisor and check the result against the orignal dividend
  103. ; Note that we must also check for overflow, which can occur if the
  104. ; dividend is close to 2**64 and the quotient is off by 1.
  105. ;
  106. mul dword ptr HIWORD(DVSR) ; QUOT * HIWORD(DVSR)
  107. mov ecx,eax
  108. mov eax,LOWORD(DVSR)
  109. mul esi ; QUOT * LOWORD(DVSR)
  110. add edx,ecx ; EDX:EAX = QUOT * DVSR
  111. jc short L4 ; carry means Quotient is off by 1
  112. ;
  113. ; do long compare here between original dividend and the result of the
  114. ; multiply in edx:eax. If original is larger or equal, we are ok, otherwise
  115. ; subtract one (1) from the quotient.
  116. ;
  117. cmp edx,HIWORD(DVND) ; compare hi words of result and original
  118. ja short L4 ; if result > original, do subtract
  119. jb short L5 ; if result < original, we are ok
  120. cmp eax,LOWORD(DVND) ; hi words are equal, compare lo words
  121. jbe short L5 ; if less or equal we are ok, else subtract
  122. L4:
  123. dec esi ; subtract 1 from quotient
  124. L5:
  125. xor edx,edx ; edx:eax <- quotient
  126. mov eax,esi
  127. ;
  128. ; Just the cleanup left to do. edx:eax contains the quotient.
  129. ; Restore the saved registers and return.
  130. ;
  131. L2:
  132. pop esi
  133. pop ebx
  134. ret 16
  135. _aulldiv ENDP
  136. end