1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
|
/************************************************************************/
/* This file contains the BCC compiler helper functions */
/* (C) Copyright Bruce Evans */
/* Function ldivmod */
#ifdef __AS386_16__
#asm
.text
.even
! ldivmod.s - 32 over 32 to 32 bit division and remainder for 8086
! ldivmod( dividend bx:ax, divisor di:cx ) [ signed quot di:cx, rem bx:ax ]
! ludivmod( dividend bx:ax, divisor di:cx ) [ unsigned quot di:cx, rem bx:ax ]
! dx is not preserved
! NB negatives are handled correctly, unlike by the processor
! divison by zero does not trap
! let dividend = a, divisor = b, quotient = q, remainder = r
! a = b * q + r mod 2**32
! where:
! if b = 0, q = 0 and r = a
! otherwise, q and r are uniquely determined by the requirements:
! r has the same sign as b and absolute value smaller than that of b, i.e.
! if b > 0, then 0 <= r < b
! if b < 0, then 0 >= r > b
! (the absoulute value and its comparison depend on signed/unsigned)
! the rule for the sign of r means that the quotient is truncated towards
! negative infinity in the usual case of a positive divisor
! if the divisor is negative, the division is done by negating a and b,
! doing the division, then negating q and r
.globl ldivmod
ldivmod:
mov dx,di ! sign byte of b in dh
mov dl,bh ! sign byte of a in dl
test di,di
jns set_asign
neg di
neg cx
sbb di,*0
set_asign:
test bx,bx
jns got_signs ! leave r = a positive
neg bx
neg ax
sbb bx,*0
j got_signs
.globl ludivmod
.even
ludivmod:
xor dx,dx ! both sign bytes 0
got_signs:
push bp
push si
mov bp,sp
push di ! remember b
push cx
b0 = -4
b16 = -2
test di,di
jne divlarge
test cx,cx
je divzero
cmp bx,cx
jae divlarge ! would overflow
xchg dx,bx ! a in dx:ax, signs in bx
div cx
xchg cx,ax ! q in di:cx, junk in ax
xchg ax,bx ! signs in ax, junk in bx
xchg ax,dx ! r in ax, signs back in dx
mov bx,di ! r in bx:ax
j zdivu1
divzero: ! return q = 0 and r = a
test dl,dl
jns return
j negr ! a initially minus, restore it
divlarge:
push dx ! remember sign bytes
mov si,di ! w in si:dx, initially b from di:cx
mov dx,cx
xor cx,cx ! q in di:cx, initially 0
mov di,cx
! r in bx:ax, initially a
! use di:cx rather than dx:cx in order to
! have dx free for a byte pair later
cmp si,bx
jb loop1
ja zdivu ! finished if b > r
cmp dx,ax
ja zdivu
! rotate w (= b) to greatest dyadic multiple of b <= r
loop1:
shl dx,*1 ! w = 2*w
rcl si,*1
jc loop1_exit ! w was > r counting overflow (unsigned)
cmp si,bx ! while w <= r (unsigned)
jb loop1
ja loop1_exit
cmp dx,ax
jbe loop1 ! else exit with carry clear for rcr
loop1_exit:
rcr si,*1
rcr dx,*1
loop2:
shl cx,*1 ! q = 2*q
rcl di,*1
cmp si,bx ! if w <= r
jb loop2_over
ja loop2_test
cmp dx,ax
ja loop2_test
loop2_over:
add cx,*1 ! q++
adc di,*0
sub ax,dx ! r = r-w
sbb bx,si
loop2_test:
shr si,*1 ! w = w/2
rcr dx,*1
cmp si,b16[bp] ! while w >= b
ja loop2
jb zdivu
cmp dx,b0[bp]
jae loop2
zdivu:
pop dx ! sign bytes
zdivu1:
test dh,dh
js zbminus
test dl,dl
jns return ! else a initially minus, b plus
mov dx,ax ! -a = b * q + r ==> a = b * (-q) + (-r)
or dx,bx
je negq ! use if r = 0
sub ax,b0[bp] ! use a = b * (-1 - q) + (b - r)
sbb bx,b16[bp]
not cx ! q = -1 - q (same as complement)
not di
negr:
neg bx
neg ax
sbb bx,*0
return:
mov sp,bp
pop si
pop bp
ret
.even
zbminus:
test dl,dl ! (-a) = (-b) * q + r ==> a = b * q + (-r)
js negr ! use if initial a was minus
mov dx,ax ! a = (-b) * q + r ==> a = b * (-q) + r
or dx,bx
je negq ! use if r = 0
sub ax,b0[bp] ! use a = b * (-1 - q) + (b + r) (b is now -b)
sbb bx,b16[bp]
not cx
not di
mov sp,bp
pop si
pop bp
ret
.even
negq:
neg di
neg cx
sbb di,*0
mov sp,bp
pop si
pop bp
ret
#endasm
#endif
|