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.

187 lines
4.2 KiB

  1. page ,132
  2. title uldiv - unsigned long divide routine
  3. ;***
  4. ;uldiv.asm - unsigned long divide routine
  5. ;
  6. ; Copyright (c) 1985-1998 Microsoft Corporation
  7. ;
  8. ;Purpose:
  9. ; defines the unsigned long divide routine
  10. ; the following routines are created:
  11. ; __aFuldiv (large, medium models)
  12. ; __aNuldiv (small, compact models)
  13. ;
  14. ;*******************************************************************************
  15. .xlist
  16. ?PLM = 0
  17. ?WIN = 1
  18. PMODE= 1
  19. memM = 1
  20. include cmacros.inc
  21. include cmphlp.inc
  22. include mm.inc
  23. .list
  24. CreateSeg FIXMIDI, MidiFix, word, public, CODE
  25. sBegin MidiFix
  26. assumes cs,MidiFix
  27. assumes ds,data
  28. page
  29. ;***
  30. ;uldiv - unsigned long divide
  31. ;
  32. ;Purpose:
  33. ; Does a unsigned long divide of the arguments. Arguments are
  34. ; not changed.
  35. ;
  36. ;Entry:
  37. ; Arguments are passed on the stack:
  38. ; 1st pushed: divisor (DWORD)
  39. ; 2nd pushed: dividend (DWORD)
  40. ;
  41. ;Exit:
  42. ; DX:AX contains the quotient (dividend/divisor)
  43. ; NOTE: this routine removes the parameters from the stack.
  44. ;
  45. ;Uses:
  46. ; CX
  47. ;
  48. ;Exceptions:
  49. ;
  50. ;*******************************************************************************
  51. ; ASGN uldiv
  52. if sizeC
  53. cProc _aFuldiv,<PUBLIC>,<>
  54. else
  55. cProc _aNuldiv,<PUBLIC>,<>
  56. endif
  57. ParmD DVND1
  58. ParmD DVSR1
  59. cBegin
  60. push bx
  61. push si
  62. ; Set up the local stack and save the index registers. When this is done
  63. ; the stack frame will look as follows (assuming that the expression a/b will
  64. ; generate a call to uldiv(a, b)):
  65. ;
  66. ; -----------------
  67. ; | |
  68. ; |---------------|
  69. ; | |
  70. ; |--divisor (b)--|
  71. ; | |
  72. ; |---------------|
  73. ; | |
  74. ; |--dividend (a)-|
  75. ; | |
  76. ; |---------------|
  77. ; | return addr** |
  78. ; |---------------|
  79. ; BP----->| old BP |
  80. ; |---------------|
  81. ; | BX |
  82. ; |---------------|
  83. ; SP----->| SI |
  84. ; -----------------
  85. ;
  86. ; ** - 2 bytes if small/compact model; 4 bytes if medium/large model
  87. DVND equ BPARGBAS[bp] ; stack address of dividend (a)
  88. DVSR equ BPARGBAS+4[bp] ; stack address of divisor (b)
  89. ;
  90. ; Now do the divide. First look to see if the divisor is less than 64K.
  91. ; If so, then we can use a simple algorithm with word divides, otherwise
  92. ; things get a little more complex.
  93. ;
  94. mov ax,HIWORD(DVSR) ; check to see if divisor < 64K
  95. or ax,ax
  96. jnz L1 ; nope, gotta do this the hard way
  97. mov cx,LOWORD(DVSR) ; load divisor
  98. mov ax,HIWORD(DVND) ; load high word of dividend
  99. xor dx,dx
  100. div cx ; get high order bits of quotient
  101. mov bx,ax ; save high bits of quotient
  102. mov ax,LOWORD(DVND) ; dx:ax <- remainder:lo word of dividend
  103. div cx ; get low order bits of quotient
  104. mov dx,bx ; dx:ax <- quotient hi:quotient lo
  105. jmp short L2 ; restore stack and return
  106. ;
  107. ; Here we do it the hard way. Remember, ax contains DVSRHI
  108. ;
  109. L1:
  110. mov cx,ax ; cx:bx <- divisor
  111. mov bx,LOWORD(DVSR)
  112. mov dx,HIWORD(DVND) ; dx:ax <- dividend
  113. mov ax,LOWORD(DVND)
  114. L3:
  115. shr cx,1 ; shift divisor right one bit; hi bit <- 0
  116. rcr bx,1
  117. shr dx,1 ; shift dividend right one bit; hi bit <- 0
  118. rcr ax,1
  119. or cx,cx
  120. jnz L3 ; loop until divisor < 64K
  121. div bx ; now divide, ignore remainder
  122. mov si,ax ; save quotient
  123. ;
  124. ; We may be off by one, so to check, we will multiply the quotient
  125. ; by the divisor and check the result against the orignal dividend
  126. ; Note that we must also check for overflow, which can occur if the
  127. ; dividend is close to 2**32 and the quotient is off by 1.
  128. ;
  129. mul word ptr HIWORD(DVSR) ; QUOT * HIWORD(DVSR)
  130. xchg cx,ax ; "mov cx,ax" but only 1 byte
  131. mov ax,LOWORD(DVSR)
  132. mul si ; QUOT * LOWORD(DVSR)
  133. add dx,cx ; DX:AX = QUOT * DVSR
  134. jc L4 ; carry means Quotient is off by 1
  135. ;
  136. ; do long compare here between original dividend and the result of the
  137. ; multiply in dx:ax. If original is larger or equal, we are ok, otherwise
  138. ; subtract one (1) from the quotient.
  139. ;
  140. cmp dx,HIWORD(DVND) ; compare hi words of result and original
  141. ja L4 ; if result > original, do subtract
  142. jb L5 ; if result < original, we are ok
  143. cmp ax,LOWORD(DVND) ; hi words are equal, compare lo words
  144. jbe L5 ; if less or equal we are ok, else subtract
  145. L4:
  146. dec si ; subtract 1 from quotient
  147. L5:
  148. xor dx,dx ; dx:ax <- quotient
  149. xchg ax,si ; "mov ax,si" but only 1 byte
  150. ;
  151. ; Just the cleanup left to do. dx:ax contains the quotient.
  152. ; Restore the saved registers and return.
  153. ;
  154. L2:
  155. pop si
  156. pop bx
  157. cEnd <nolocals>
  158. return 8
  159. sEnd
  160. end