home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1996 September / PCWK996.iso / polskie / orhmet / dfdisk / rlibc / h_ldiv.asm < prev    next >
Assembly Source File  |  1995-09-24  |  6KB  |  198 lines

  1. ;[]-----------------------------------------------------------------[]
  2. ;|      H_LDIV.ASM -- long division routine                          |
  3. ;[]-----------------------------------------------------------------[]
  4.  
  5. ;
  6. ;       C/C++ Run Time Library - Version 5.0
  7. ;       Copyright (c) 1987, 1992 by Borland International
  8. ;       All Rights Reserved.
  9.  
  10.         INCLUDE RULES.ASI
  11.  
  12. _TEXT   segment public byte 'CODE'
  13.         assume  cs:_TEXT
  14.         public  LDIV@
  15.         public  F_LDIV@
  16.         public  N_LDIV@
  17.         public  LUDIV@
  18.         public  F_LUDIV@
  19.         public  N_LUDIV@
  20.         public  LMOD@
  21.         public  F_LMOD@
  22.         public  N_LMOD@
  23.         public  LUMOD@
  24.         public  F_LUMOD@
  25.         public  N_LUMOD@
  26.  
  27. N_LDIV@:
  28.         pop     cx                      ;fix up far return
  29.         push    cs
  30.         push    cx
  31. LDIV@:
  32. F_LDIV@:
  33.         xor     cx,cx                   ; signed divide
  34.         jmp     short common
  35.  
  36. N_LUDIV@:
  37.         pop     cx                      ;fix up far return
  38.         push    cs
  39.         push    cx
  40. LUDIV@:
  41. F_LUDIV@:
  42.         mov     cx,1                    ; unsigned divide
  43.         jmp     short common
  44.  
  45. N_LMOD@:
  46.         pop     cx                      ;fix up far return
  47.         push    cs
  48.         push    cx
  49. LMOD@:
  50. F_LMOD@:
  51.         mov     cx,2                    ; signed remainder
  52.         jmp     short   common
  53.  
  54. N_LUMOD@:
  55.         pop     cx                      ;fix up far return
  56.         push    cs
  57.         push    cx
  58. LUMOD@:
  59. F_LUMOD@:
  60.         mov     cx,3                    ; unsigned remainder
  61.  
  62. ;
  63. ;       di now contains a two bit control value.  The low order
  64. ;       bit (test mask of 1) is on if the operation is unsigned,
  65. ;       signed otherwise.  The next bit (test mask of 2) is on if
  66. ;       the operation returns the remainder, quotient otherwise.
  67. ;
  68. common:
  69.         push    bp
  70.         push    si
  71.         push    di
  72.         mov     bp,sp                   ; set up frame
  73.         mov     di,cx
  74. ;
  75. ;       dividend is pushed last, therefore the first in the args
  76. ;       divisor next.
  77. ;
  78.         mov     ax,10[bp]               ; get the first low word
  79.         mov     dx,12[bp]               ; get the first high word
  80.         mov     bx,14[bp]               ; get the second low word
  81.         mov     cx,16[bp]               ; get the second high word
  82.  
  83.         or      cx,cx
  84.         jnz     slow@ldiv               ; both high words are zero
  85.  
  86.         or      dx,dx
  87.         jz      quick@ldiv
  88.  
  89.         or      bx,bx
  90.         jz      quick@ldiv              ; if cx:bx == 0 force a zero divide
  91.                                         ; we don't expect this to actually
  92.                                         ; work
  93.  
  94. slow@ldiv:
  95.  
  96.         test    di,1                    ; signed divide?
  97.         jnz     positive                ; no: skip
  98. ;
  99. ;               Signed division should be done.  Convert negative
  100. ;               values to positive and do an unsigned division.
  101. ;               Store the sign value in the next higher bit of
  102. ;               di (test mask of 4).  Thus when we are done, testing
  103. ;               that bit will determine the sign of the result.
  104. ;
  105.         or      dx,dx                   ; test sign of dividend
  106.         jns     onepos
  107.         neg     dx
  108.         neg     ax
  109.         sbb     dx,0                    ; negate dividend
  110.         or      di,0Ch
  111. onepos:
  112.         or      cx,cx                   ; test sign of divisor
  113.         jns     positive
  114.         neg     cx
  115.         neg     bx
  116.         sbb     cx,0                    ; negate divisor
  117.         xor     di,4
  118. positive:
  119.         mov     bp,cx
  120.         mov     cx,32                   ; shift counter
  121.         push    di                      ; save the flags
  122. ;
  123. ;       Now the stack looks something like this:
  124. ;
  125. ;               16[bp]: divisor (high word)
  126. ;               14[bp]: divisor (low word)
  127. ;               12[bp]: dividend (high word)
  128. ;               10[bp]: dividend (low word)
  129. ;                8[bp]: return CS
  130. ;                6[bp]: return IP
  131. ;                4[bp]: previous BP
  132. ;                2[bp]: previous SI
  133. ;                 [bp]: previous DI
  134. ;               -2[bp]: control bits
  135. ;                       01 - Unsigned divide
  136. ;                       02 - Remainder wanted
  137. ;                       04 - Negative quotient
  138. ;                       08 - Negative remainder
  139. ;
  140.         xor     di,di                   ; fake a 64 bit dividend
  141.         xor     si,si                   ;
  142. xloop:
  143.         shl     ax,1                    ; shift dividend left one bit
  144.         rcl     dx,1
  145.         rcl     si,1
  146.         rcl     di,1
  147.         cmp     di,bp                   ; dividend larger?
  148.         jb      nosub
  149.         ja      subtract
  150.         cmp     si,bx                   ; maybe
  151.         jb      nosub
  152. subtract:
  153.         sub     si,bx
  154.         sbb     di,bp                   ; subtract the divisor
  155.         inc     ax                      ; build quotient
  156. nosub:
  157.         loop    xloop
  158. ;
  159. ;       When done with the loop the four register value look like:
  160. ;
  161. ;       |     di     |     si     |     dx     |     ax     |
  162. ;       |        remainder        |         quotient        |
  163. ;
  164.         pop     bx                      ; get control bits
  165.         test    bx,2                    ; remainder?
  166.         jz      usequo
  167.         mov     ax,si
  168.         mov     dx,di                   ; use remainder
  169.         shr     bx,1                    ; shift in the remainder sign bit
  170. usequo:
  171.         test    bx,4                    ; needs negative
  172.         jz      finish
  173.         neg     dx
  174.         neg     ax
  175.         sbb     dx,0                    ; negate
  176. finish:
  177.         pop     di
  178.         pop     si
  179.         pop     bp
  180.         retf    8
  181.  
  182. quick@ldiv:
  183.         div     bx                      ; unsigned divide
  184.                                         ; DX = remainder AX = quotient
  185.         test    di,2                    ; want remainder?
  186.         jz      quick@quo
  187.         xchg    ax,dx
  188.  
  189. quick@quo:
  190.  
  191.         xor     dx,dx
  192.         jmp     short finish
  193.  
  194. _TEXT   ends
  195.         end
  196.