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

  1.         title   llrem - signed long remainder routine
  2. ;***
  3. ;llrem.asm - signed long remainder routine
  4. ;
  5. ;       Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
  6. ;
  7. ;Purpose:
  8. ;       defines the signed long remainder routine
  9. ;           __allrem
  10. ;
  11. ;*******************************************************************************
  12.  
  13.  
  14. .xlist
  15. include cruntime.inc
  16. include mm.inc
  17. .list
  18.  
  19. ;***
  20. ;llrem - signed long remainder
  21. ;
  22. ;Purpose:
  23. ;       Does a signed long remainder 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 remainder (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. _allrem PROC NEAR
  45.  
  46.         push    ebx
  47.         push    edi
  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 lrem(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---->|       EDI     |
  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. ; Determine sign of the result (edi = 0 if result is positive, non-zero
  77. ; otherwise) and make operands positive.
  78.  
  79.         xor     edi,edi         ; result sign assumed positive
  80.  
  81.         mov     eax,HIWORD(DVND) ; hi word of a
  82.         or      eax,eax         ; test to see if signed
  83.         jge     short L1        ; skip rest if a is already positive
  84.         inc     edi             ; complement result sign flag bit
  85.         mov     edx,LOWORD(DVND) ; lo word of a
  86.         neg     eax             ; make a positive
  87.         neg     edx
  88.         sbb     eax,0
  89.         mov     HIWORD(DVND),eax ; save positive value
  90.         mov     LOWORD(DVND),edx
  91. L1:
  92.         mov     eax,HIWORD(DVSR) ; hi word of b
  93.         or      eax,eax         ; test to see if signed
  94.         jge     short L2        ; skip rest if b is already positive
  95.         mov     edx,LOWORD(DVSR) ; lo word of b
  96.         neg     eax             ; make b positive
  97.         neg     edx
  98.         sbb     eax,0
  99.         mov     HIWORD(DVSR),eax ; save positive value
  100.         mov     LOWORD(DVSR),edx
  101. L2:
  102.  
  103. ;
  104. ; Now do the divide.  First look to see if the divisor is less than 4194304K.
  105. ; If so, then we can use a simple algorithm with word divides, otherwise
  106. ; things get a little more complex.
  107. ;
  108. ; NOTE - eax currently contains the high order word of DVSR
  109. ;
  110.  
  111.         or      eax,eax         ; check to see if divisor < 4194304K
  112.         jnz     short L3        ; nope, gotta do this the hard way
  113.         mov     ecx,LOWORD(DVSR) ; load divisor
  114.         mov     eax,HIWORD(DVND) ; load high word of dividend
  115.         xor     edx,edx
  116.         div     ecx             ; edx <- remainder
  117.         mov     eax,LOWORD(DVND) ; edx:eax <- remainder:lo word of dividend
  118.         div     ecx             ; edx <- final remainder
  119.         mov     eax,edx         ; edx:eax <- remainder
  120.         xor     edx,edx
  121.         dec     edi             ; check result sign flag
  122.         jns     short L4        ; negate result, restore stack and return
  123.         jmp     short L8        ; result sign ok, restore stack and return
  124.  
  125. ;
  126. ; Here we do it the hard way.  Remember, eax contains the high word of DVSR
  127. ;
  128.  
  129. L3:
  130.         mov     ebx,eax         ; ebx:ecx <- divisor
  131.         mov     ecx,LOWORD(DVSR)
  132.         mov     edx,HIWORD(DVND) ; edx:eax <- dividend
  133.         mov     eax,LOWORD(DVND)
  134. L5:
  135.         shr     ebx,1           ; shift divisor right one bit
  136.         rcr     ecx,1
  137.         shr     edx,1           ; shift dividend right one bit
  138.         rcr     eax,1
  139.         or      ebx,ebx
  140.         jnz     short L5        ; loop until divisor < 4194304K
  141.         div     ecx             ; now divide, ignore remainder
  142.  
  143. ;
  144. ; We may be off by one, so to check, we will multiply the quotient
  145. ; by the divisor and check the result against the orignal dividend
  146. ; Note that we must also check for overflow, which can occur if the
  147. ; dividend is close to 2**64 and the quotient is off by 1.
  148. ;
  149.  
  150.         mov     ecx,eax         ; save a copy of quotient in ECX
  151.         mul     dword ptr HIWORD(DVSR)
  152.         xchg    ecx,eax         ; save product, get quotient in EAX
  153.         mul     dword ptr LOWORD(DVSR)
  154.         add     edx,ecx         ; EDX:EAX = QUOT * DVSR
  155.         jc      short L6        ; carry means Quotient is off by 1
  156.  
  157. ;
  158. ; do long compare here between original dividend and the result of the
  159. ; multiply in edx:eax.  If original is larger or equal, we are ok, otherwise
  160. ; subtract the original divisor from the result.
  161. ;
  162.  
  163.         cmp     edx,HIWORD(DVND) ; compare hi words of result and original
  164.         ja      short L6        ; if result > original, do subtract
  165.         jb      short L7        ; if result < original, we are ok
  166.         cmp     eax,LOWORD(DVND) ; hi words are equal, compare lo words
  167.         jbe     short L7        ; if less or equal we are ok, else subtract
  168. L6:
  169.         sub     eax,LOWORD(DVSR) ; subtract divisor from result
  170.         sbb     edx,HIWORD(DVSR)
  171. L7:
  172.  
  173. ;
  174. ; Calculate remainder by subtracting the result from the original dividend.
  175. ; Since the result is already in a register, we will do the subtract in the
  176. ; opposite direction and negate the result if necessary.
  177. ;
  178.  
  179.         sub     eax,LOWORD(DVND) ; subtract dividend from result
  180.         sbb     edx,HIWORD(DVND)
  181.  
  182. ;
  183. ; Now check the result sign flag to see if the result is supposed to be positive
  184. ; or negative.  It is currently negated (because we subtracted in the 'wrong'
  185. ; direction), so if the sign flag is set we are done, otherwise we must negate
  186. ; the result to make it positive again.
  187. ;
  188.  
  189.         dec     edi             ; check result sign flag
  190.         jns     short L8        ; result is ok, restore stack and return
  191. L4:
  192.         neg     edx             ; otherwise, negate the result
  193.         neg     eax
  194.         sbb     edx,0
  195.  
  196. ;
  197. ; Just the cleanup left to do.  edx:eax contains the quotient.
  198. ; Restore the saved registers and return.
  199. ;
  200.  
  201. L8:
  202.         pop     edi
  203.         pop     ebx
  204.  
  205.         ret     16
  206.  
  207. _allrem ENDP
  208.  
  209.         end
  210.