home *** CD-ROM | disk | FTP | other *** search
/ 100 af Verdens Bedste Spil / 100Spil.iso / dos / wolf3d / source / wolfsrc.1 / H_LDIV.ASM < prev    next >
Assembly Source File  |  1993-02-04  |  7KB  |  228 lines

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