Added original source code
Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
227
WOLFSRC/H_LDIV.ASM
Normal file
227
WOLFSRC/H_LDIV.ASM
Normal file
@@ -0,0 +1,227 @@
|
||||
;[]-----------------------------------------------------------------[]
|
||||
;| H_LDIV.ASM -- long division routine |
|
||||
;| |
|
||||
;| C/C++ Run Time Library Version 4.0 |
|
||||
;| |
|
||||
;| Copyright (c) 1987, 1991 by Borland International Inc. |
|
||||
;| All Rights Reserved. |
|
||||
;[]-----------------------------------------------------------------[]
|
||||
.model medium
|
||||
INCLUDE RULES.ASI
|
||||
.386C ;JAB - we use 386 instructions
|
||||
|
||||
_TEXT segment public byte 'CODE'
|
||||
assume cs:_TEXT
|
||||
public LDIV@
|
||||
public F_LDIV@
|
||||
public N_LDIV@
|
||||
public LUDIV@
|
||||
public F_LUDIV@
|
||||
public N_LUDIV@
|
||||
public LMOD@
|
||||
public F_LMOD@
|
||||
public N_LMOD@
|
||||
public LUMOD@
|
||||
public F_LUMOD@
|
||||
public N_LUMOD@
|
||||
|
||||
N_LDIV@:
|
||||
pop cx ;fix up far return
|
||||
push cs
|
||||
push cx
|
||||
LDIV@:
|
||||
F_LDIV@:
|
||||
xor cx,cx ; signed divide
|
||||
jmp short common
|
||||
|
||||
; JAB
|
||||
;
|
||||
; If we're using a 386 or better, the two instructions above get patched
|
||||
; to be NOP's (4 of them). So, instead of using the looping code,
|
||||
; we use the 386's long divide instruction.
|
||||
;
|
||||
; The stack after setting up the stack frame:
|
||||
; 12[bp]: divisor (high word)
|
||||
; 10[bp]: divisor (low word)
|
||||
; 8[bp]: dividend (high word)
|
||||
; 6[bp]: dividend (low word)
|
||||
; 4[bp]: return CS
|
||||
; 2[bp]: return IP
|
||||
; 0[bp]: previous BP
|
||||
;
|
||||
IDEAL
|
||||
|
||||
push bp
|
||||
mov bp,sp ;Save BP, and set it equal to stack
|
||||
|
||||
mov eax,[DWORD PTR bp+6]
|
||||
cdq
|
||||
idiv [DWORD PTR bp+10]
|
||||
mov edx,eax
|
||||
shr edx,16
|
||||
|
||||
pop bp ;Restore BP
|
||||
retf 8 ;Return to original caller
|
||||
|
||||
MASM
|
||||
|
||||
N_LUDIV@:
|
||||
pop cx ;fix up far return
|
||||
push cs
|
||||
push cx
|
||||
LUDIV@:
|
||||
F_LUDIV@:
|
||||
mov cx,1 ; unsigned divide
|
||||
jmp short common
|
||||
|
||||
N_LMOD@:
|
||||
pop cx ;fix up far return
|
||||
push cs
|
||||
push cx
|
||||
LMOD@:
|
||||
F_LMOD@:
|
||||
mov cx,2 ; signed remainder
|
||||
jmp short common
|
||||
|
||||
N_LUMOD@:
|
||||
pop cx ;fix up far return
|
||||
push cs
|
||||
push cx
|
||||
LUMOD@:
|
||||
F_LUMOD@:
|
||||
mov cx,3 ; unsigned remainder
|
||||
|
||||
;
|
||||
; di now contains a two bit control value. The low order
|
||||
; bit (test mask of 1) is on if the operation is unsigned,
|
||||
; signed otherwise. The next bit (test mask of 2) is on if
|
||||
; the operation returns the remainder, quotient otherwise.
|
||||
;
|
||||
common:
|
||||
push bp
|
||||
push si
|
||||
push di
|
||||
mov bp,sp ; set up frame
|
||||
mov di,cx
|
||||
;
|
||||
; dividend is pushed last, therefore the first in the args
|
||||
; divisor next.
|
||||
;
|
||||
mov ax,10[bp] ; get the first low word
|
||||
mov dx,12[bp] ; get the first high word
|
||||
mov bx,14[bp] ; get the second low word
|
||||
mov cx,16[bp] ; get the second high word
|
||||
|
||||
or cx,cx
|
||||
jnz slow@ldiv ; both high words are zero
|
||||
|
||||
or dx,dx
|
||||
jz quick@ldiv
|
||||
|
||||
or bx,bx
|
||||
jz quick@ldiv ; if cx:bx == 0 force a zero divide
|
||||
; we don't expect this to actually
|
||||
; work
|
||||
|
||||
slow@ldiv:
|
||||
|
||||
test di,1 ; signed divide?
|
||||
jnz positive ; no: skip
|
||||
;
|
||||
; Signed division should be done. Convert negative
|
||||
; values to positive and do an unsigned division.
|
||||
; Store the sign value in the next higher bit of
|
||||
; di (test mask of 4). Thus when we are done, testing
|
||||
; that bit will determine the sign of the result.
|
||||
;
|
||||
or dx,dx ; test sign of dividend
|
||||
jns onepos
|
||||
neg dx
|
||||
neg ax
|
||||
sbb dx,0 ; negate dividend
|
||||
or di,0Ch
|
||||
onepos:
|
||||
or cx,cx ; test sign of divisor
|
||||
jns positive
|
||||
neg cx
|
||||
neg bx
|
||||
sbb cx,0 ; negate divisor
|
||||
xor di,4
|
||||
positive:
|
||||
mov bp,cx
|
||||
mov cx,32 ; shift counter
|
||||
push di ; save the flags
|
||||
;
|
||||
; Now the stack looks something like this:
|
||||
;
|
||||
; 16[bp]: divisor (high word)
|
||||
; 14[bp]: divisor (low word)
|
||||
; 12[bp]: dividend (high word)
|
||||
; 10[bp]: dividend (low word)
|
||||
; 8[bp]: return CS
|
||||
; 6[bp]: return IP
|
||||
; 4[bp]: previous BP
|
||||
; 2[bp]: previous SI
|
||||
; [bp]: previous DI
|
||||
; -2[bp]: control bits
|
||||
; 01 - Unsigned divide
|
||||
; 02 - Remainder wanted
|
||||
; 04 - Negative quotient
|
||||
; 08 - Negative remainder
|
||||
;
|
||||
xor di,di ; fake a 64 bit dividend
|
||||
xor si,si ;
|
||||
xloop:
|
||||
shl ax,1 ; shift dividend left one bit
|
||||
rcl dx,1
|
||||
rcl si,1
|
||||
rcl di,1
|
||||
cmp di,bp ; dividend larger?
|
||||
jb nosub
|
||||
ja subtract
|
||||
cmp si,bx ; maybe
|
||||
jb nosub
|
||||
subtract:
|
||||
sub si,bx
|
||||
sbb di,bp ; subtract the divisor
|
||||
inc ax ; build quotient
|
||||
nosub:
|
||||
loop xloop
|
||||
;
|
||||
; When done with the loop the four register value look like:
|
||||
;
|
||||
; | di | si | dx | ax |
|
||||
; | remainder | quotient |
|
||||
;
|
||||
pop bx ; get control bits
|
||||
test bx,2 ; remainder?
|
||||
jz usequo
|
||||
mov ax,si
|
||||
mov dx,di ; use remainder
|
||||
shr bx,1 ; shift in the remainder sign bit
|
||||
usequo:
|
||||
test bx,4 ; needs negative
|
||||
jz finish
|
||||
neg dx
|
||||
neg ax
|
||||
sbb dx,0 ; negate
|
||||
finish:
|
||||
pop di
|
||||
pop si
|
||||
pop bp
|
||||
retf 8
|
||||
|
||||
quick@ldiv:
|
||||
div bx ; unsigned divide
|
||||
; DX = remainder AX = quotient
|
||||
test di,2 ; want remainder?
|
||||
jz quick@quo
|
||||
xchg ax,dx
|
||||
|
||||
quick@quo:
|
||||
|
||||
xor dx,dx
|
||||
jmp short finish
|
||||
|
||||
_TEXT ends
|
||||
end
|
||||
Reference in New Issue
Block a user