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