DOSSEG
.MODEL SMALL
.DATA
FACT1OFF DW ? ;Temp storage for offset
FACT2OFF DW ? ;Temp storage for offset
.CODE
;
; N-digit-precision division.
; Divides FACTOR1 by FACTOR2. Quotient is left in RESULT, FACTOR1
; holds the remainder. Returns -1 if ERROR (division by 0)
PUBLIC _ndiv
FACT1BASE = [BP+4]
FACT2BASE = [BP+6]
RESULTBASE = [BP+8]
NUMWORDS = [BP+10]
_ndiv PROC NEAR
push bp
mov bp,sp
push si
push di
push es
mov ax,ds
mov es,ax
mov cx,NUMWORDS ;Number of words of precision
mov dx,cx ;Save in DX - used a lot
mov si,FACT2BASE ;Addr of Factor2 start
xor ax,ax ;Clear ax
;Check for division by 0
NPD9: or ax,[si]
inc si
inc si
loop NPD9
or ax,ax
jnz NPD10
mov ax,-1 ;Show error
pop di
pop si
pop bp
ret
;Shift factor2 left until highmost bit is set
NPD10: xor bx,bx
mov si,dx ;NUMWORDS in si
dec si
shl si,1
mov di,FACT2BASE
add si,di
NPD11: test [si],8000h
jnz NPD12
push si
mov si,di
mov cx,dx
call SHLSI ;Shift it left
pop si
inc bx
jmp NPD11
;Clear the quotient
NPD12: inc bx
mov cx,dx
mov di,RESULTBASE
cld
xor ax,ax
rep stosw
NPD13: ;Save loop count
mov si,RESULTBASE
mov cx,dx ;Get # of words
call SHLSI
mov si,FACT2BASE
mov di,FACT1BASE
mov cx,dx ;Get # of words
call SUBSIDI ;Subtract factor2 from factor1
jnc NPD14
mov si,FACT2BASE
mov di,FACT1BASE
mov cx,dx
call ADDSIDI ;Add factor2 back in
jmp NPD15
NPD14: mov si,RESULTBASE
or word ptr [si],1
NPD15: mov si,FACT2BASE
mov cx,dx
call SHRSI
dec bx
jnz NPD13
pop es
pop di
pop si
pop bp
ret
_ndiv ENDP
;
; N-word precision multiply.
; Requires unsigned elements
; nmult(fact1,fact2,result,numwords)
PUBLIC _nmult
FACT1BASE = [BP+4]
FACT2BASE = [BP+6]
RESULTBASE = [BP+8]
NUMWORDS = [BP+10]
_nmult PROC NEAR
push bp
mov bp,sp
push si
push di
push es
mov ax,ds
mov es,ax ; Everyone in same segment
xor ax,ax
mov FACT1OFF,ax ;Initialize offset
mov FACT2OFF,ax
mov di,RESULTBASE
mov cx,NUMWORDS
cld
rep stosw ;Clear result
mov cx,NUMWORDS ;We'll need this later
dec cx
NPM10: mov ax,FACT1OFF
add ax,FACT2OFF
cmp ax,cx
jge npm1A
mov si,FACT1BASE
mov di,FACT2BASE
add si,FACT1OFF
add si,FACT1OFF ;Two adds for words
add di,FACT2OFF
add di,FACT2OFF ;Two adds for word alignment
mov ax,[si] ;Get a word
or ax,ax
jz NPM1A ;Skip multiply
mov bx,word ptr [di]
or bx,bx
jz NPM1A
mul bx
mov bx,FACT1OFF
add bx,FACT2OFF
mov di,RESULTBASE
NPM0B:
call ADDINAT ;Add partial products
NPM1A: mov ax,FACT2OFF
inc ax
cmp ax,cx
jz npm11
mov FACT2OFF,ax
jmp NPM10
NPM11: mov ax,FACT1OFF
inc ax
cmp ax,cx
jz npmx ;Done?
mov FACT1OFF,ax ;Restart
xor ax,ax
mov FACT2OFF,ax
jmp NPM10
NPMX: pop es
pop di
pop si
pop bp
ret
_nmult ENDP
;
; Add partial product into result.
; BX holds offset to add partial product in at.
; DI points to result base
ADDINAT PROC NEAR
push cx
sub cx,bx ;Loop size
shl bx,1
add [di+bx],ax
mov ax,0
jcxz ADDINX
ADDIN1:
inc bx
inc bx
adc [di+bx],dx
mov dx,ax
loop ADDIN1
ADDINX:
pop cx
ret
ADDINAT ENDP
;
; Add FACTOR1 to FACTOR2.
; npadd(fact1,fac2,numwords)
PUBLIC _npadd
FACTOR1BASE = [BP+4]
FACTOR2BASE = [BP+6]
NUMWORDS = [BP+8]
_npadd PROC NEAR
push bp
mov bp,sp
push cx
push si
push di
push es
mov ax,ds
mov es,ax
mov di,FACT1BASE
mov si,FACT2BASE
mov cx,NUMWORDS
call ADDSIDI
pop es
pop di
pop si
pop cx
pop bp
ret
_npadd ENDP
;
; Add [si] to [di]
; CX hold number of words.
ADDSIDI PROC NEAR
clc
ADDSD1: lodsw
adc [di],ax
inc di
inc di
loop ADDSD1
ret
ADDSIDI ENDP
;
;Subtract FACTOR2 from FACTOR1, result in FACTOR1.
; npsub(fact1,fact2,numwords)
PUBLIC _npsub
FACTOR1BASE = [BP+4]
FACTOR2BASE = [BP+6]
NUMWORDS = [BP+8]
_npsub PROC NEAR
push bp
mov bp,sp
push si
push di
push es
mov ax,ds
mov es,ax
mov di,FACTOR1BASE
mov si,FACTOR2BASE
mov cx,NUMWORDS
call SUBSIDI
pop es
pop di
pop si
pop bp
ret
_npsub ENDP
; Subtract [si] from [di].
; CX = # of words
SUBSIDI PROC NEAR
clc
SUBSD1: lodsw
sbb [di],ax
inc di
inc di
loop SUBSD1
ret
SUBSIDI ENDP
;
; Negate FACTOR1
; nneg(fact1,numwords)
PUBLIC _nneg
FACT1BASE = [BP+4]
NUMWORDS = [BP+6]
_nneg PROC NEAR
push bp
mov bp,sp
push si
xor ax,ax
mov bx,ax
mov si,FACT1BASE
mov cx,NUMWORDS
clc
NNEG1: mov ax,bx
sbb ax,[si]
mov [si],ax
inc si
inc si
loop NNEG1
pop si
pop bp
ret
_nneg ENDP
;
; Shift the quantity pointed to by SI right 1 bit.
; The number of words shifted is contained in CX.
; This is a logical shift.
SHRSI PROC NEAR
dec si
dec si
add si,cx ;Point to hi word
add si,cx
clc
SHRSI1: rcr word ptr [si],1
dec si
dec si
loop SHRSI1
ret
SHRSI ENDP
;
; Shift the quantity pointed to by SI left 1 bit.
; The number of words shifted is contained in CX.
; This is a logical shift.
SHLSI PROC NEAR
clc
SHLSI1: rcl word ptr [si],1
inc si
inc si
loop SHLSI1
ret
SHLSI ENDP
;
; Factcopy(dest,source,nwords)
; High-speed copy one factor to another.
; Thing's can't overlap...that's ok...they shouldn't.
PUBLIC _factcopy
_factcopy PROC NEAR
DEST = [BP+4]
SOURCE = [BP+6]
NUMWORDS = [BP+8]
PUSH BP
MOV BP,SP
PUSH CX
PUSH SI
PUSH DI
PUSH ES
;Set segment registers
MOV AX,DS
MOV ES,AX
;Get # of words
MOV CX,NUMWORDS
MOV SI,SOURCE
MOV DI,DEST
CLD
REP MOVSW
;That was easy.
POP ES
POP DI
POP SI
POP CX
POP BP
RET
_factcopy ENDP
;
; factshrin(fact,val,nw)
; Shift's factor right 1 bit and moves contents of val into
; highmost bit.
PUBLIC _factshrin
FACTOR = [BP+4]
VAL = [BP+6]
NUMWORDS = [BP+8]
_factshrin PROC NEAR
push bp
mov bp,sp
push cx
push si
; Get address of factor to shift
mov si,FACTOR
mov cx,NUMWORDS
call SHRSI
; Now move in val
mov ax,VAL
or ax,ax
jz FACTSHRX
mov si,FACTOR
mov cx,NUMWORDS
dec cx
add si,cx
add si,cx
or word ptr [si],8000h
FACTSHRX: pop si
pop cx
pop bp
ret
_factshrin ENDP
;
; factshlout(fact,nw)
; Shifts factor left, 1 bit. Returns value of bit shifted out.
PUBLIC _factshlout
FACTOR = [BP+4]
NUMWORDS = [BP+6]
_factshlout PROC NEAR
push bp
mov bp,sp
push cx
push si
;Get address of factor to shift
mov si,FACTOR
mov cx,NUMWORDS ;Factor size in words
call SHLSI
jc factshl1
xor ax,ax ;Return 0
factshlx: pop si
pop cx
pop bp
ret
factshl1: mov ax,1
jmp factshlx
_factshlout ENDP
;
; factclear(fact,nw)
; Clear the factor.
PUBLIC _factclear
FACT = [BP+4]
NUMWORDS = [BP+6]
_factclear PROC NEAR
push bp
mov bp,sp
push cx
push di
push es
mov ax,ds
mov es,ax
mov di,FACT
mov cx,NUMWORDS
xor ax,ax
cld
rep stosw
pop es
pop di
pop dx
pop bp
ret
_factclear ENDP
;
; testfactor(fact,nw)
; Returns -1, 0 , 1 if factor is <, =, or > 0.
PUBLIC _testfactor
FACT = [BP+4]
NUMWORDS = [BP+6]
_testfactor PROC NEAR
push bp
mov bp,sp
push si
push cx
; First do check for <0
mov si,FACT
add si,NUMWORDS
dec si
dec si
test word ptr [si],8000h
jz testf1
mov ax,0FFFFh
testfx: pop cx
pop si
pop bp
ret
;Now look for >= 0
testf1: mov si,FACT
mov cx,NUMWORDS
testf1a: lodsw
or ax,ax
jnz testf2
loop testf1a
jmp testfx ;ax holds 0
testf2: mov ax,1
jmp testfx
_testfactor ENDP
END