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

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