home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / crt / src / platform / ulldiv.asm < prev    next >
Assembly Source File  |  1998-06-17  |  5KB  |  159 lines

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