wolf3d

The original open source release of Wolfenstein 3D
Log | Files | Refs

H_LDIV.ASM (6284B)


      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