707 lines
22 KiB
NASM
707 lines
22 KiB
NASM
|
; =====> SBIGMATH.ASM
|
|||
|
;***************************************
|
|||
|
;* TIPC Scheme '84 Runtime Support *
|
|||
|
;* Bignum Math Utilities *
|
|||
|
;* *
|
|||
|
;* (C) Copyright 1984,1985 by Texas *
|
|||
|
;* Instruments Incorporated. *
|
|||
|
;* All rights reserved. *
|
|||
|
;* *
|
|||
|
;* Date Written: June 1984 *
|
|||
|
;* Last Modification: 27 May 1986 *
|
|||
|
;***************************************
|
|||
|
include scheme.equ
|
|||
|
|
|||
|
DGROUP group data
|
|||
|
data segment word public 'DATA'
|
|||
|
assume DS:DGROUP
|
|||
|
data ends
|
|||
|
|
|||
|
XGROUP GROUP PROGX
|
|||
|
PROGX segment byte public 'PROGX'
|
|||
|
assume CS:XGROUP,DS:DGROUP
|
|||
|
|
|||
|
; Convert a bignum to a flonum
|
|||
|
; Calling sequence: big2flo(bigptr,floptr)
|
|||
|
; Where: bigptr ---- pointer to bignum workspace
|
|||
|
; floptr ---- pointer to flonum
|
|||
|
b2fargs struc
|
|||
|
dw ? ;Caller's BP
|
|||
|
dd ? ;Return address
|
|||
|
dw ? ;Another return address
|
|||
|
big dw ? ;Pointer to bignum
|
|||
|
flo dw ? ;Pointer to flonum
|
|||
|
b2fargs ends
|
|||
|
|
|||
|
%big2flo proc far
|
|||
|
push BP
|
|||
|
mov BP,SP
|
|||
|
cld ;Direction forward
|
|||
|
mov SI,[BP].big ;Point DS:SI to working bignum
|
|||
|
mov CX,[SI] ;Get size
|
|||
|
cmp CX,3
|
|||
|
ja all64 ;Jump if at least 64 bits
|
|||
|
add SI,3 ;Point to bignum proper
|
|||
|
xor BX,BX
|
|||
|
xor DI,DI
|
|||
|
lodsw ;Fetch least sig. word
|
|||
|
mov DX,AX ;Store in DX
|
|||
|
dec CX
|
|||
|
jcxz smljust ;Jump if no more bignum words
|
|||
|
lodsw ;Else get next least sig. word
|
|||
|
mov DI,AX
|
|||
|
dec CX
|
|||
|
jcxz smljust ;Jump if no more bignum words
|
|||
|
lodsw ;Get 3rd least sig. word
|
|||
|
mov BX,AX
|
|||
|
smljust: xor AX,AX ;Clear most sig. word
|
|||
|
jmp short justify ;Left-justify the number
|
|||
|
all64: shl CX,1 ;Point SI to 4th most sig. word
|
|||
|
add SI,CX
|
|||
|
sub SI,5
|
|||
|
lodsw ;Load bignum into registers
|
|||
|
mov DX,AX
|
|||
|
lodsw
|
|||
|
mov DI,AX
|
|||
|
lodsw
|
|||
|
mov BX,AX
|
|||
|
lodsw
|
|||
|
;JUSTIFY: At this stage, the 64 most significant bignum bits are in
|
|||
|
; AX:BX:DI:DX respectively, AX most significant
|
|||
|
justify: mov SI,[BP].big ;Fetch pointer to bignum again
|
|||
|
mov CX,[SI] ;Get size (words)
|
|||
|
cmp CX,40h
|
|||
|
ja toobig ;Jump if bignum too big
|
|||
|
cmp CX,4 ;Skip if not a small bignum
|
|||
|
jae enough
|
|||
|
mov CX,4 ;Otherwise, start with constant
|
|||
|
enough: shl CX,1 ;Multiply by 16 (size in bits)
|
|||
|
shl CX,1
|
|||
|
shl CX,1
|
|||
|
shl CX,1
|
|||
|
justflp: dec CX ;Reduce exponent
|
|||
|
shl DX,1 ;Shift bignum left
|
|||
|
rcl DI,1
|
|||
|
rcl BX,1
|
|||
|
rcl AX,1
|
|||
|
jnc justflp ;Until most significant 1 vanishes
|
|||
|
add CX,3ffh ;Add flonum exponent constant
|
|||
|
mov SI,DI ;Now use SI for num, DI for address
|
|||
|
shftrt: shr CX,1 ;Shift CX:AX:BX:SI:DX as one
|
|||
|
rcr AX,1
|
|||
|
rcr BX,1
|
|||
|
rcr SI,1
|
|||
|
rcr DX,1
|
|||
|
cmp CX,80h ;Until most sig. exponent bit is in 2nd
|
|||
|
jae shftrt ; most sig. bit of CL
|
|||
|
mov DI,[BP].big ;Get pointer to bignum again
|
|||
|
test byte ptr[DI]+2,1 ;Negative?
|
|||
|
jz posskip ;No, skip
|
|||
|
or CL,80h ;Set sign bit
|
|||
|
posskip: mov DI,[BP].flo ;Point ES:DI to flonum
|
|||
|
push AX ;Save part of new flonum
|
|||
|
mov AL,DH ;Write to flonum space
|
|||
|
stosb
|
|||
|
mov AX,SI
|
|||
|
stosw
|
|||
|
mov AX,BX
|
|||
|
stosw
|
|||
|
pop AX
|
|||
|
stosw
|
|||
|
mov AL,CL
|
|||
|
stosb
|
|||
|
xor AX,AX ;Return 0 if all well
|
|||
|
pop BP ;Restore BP
|
|||
|
ret
|
|||
|
toobig: mov AX,1 ;Return 1 if conversion impossible
|
|||
|
pop BP
|
|||
|
ret
|
|||
|
%big2flo endp
|
|||
|
|
|||
|
; Convert fixnum to bignum
|
|||
|
; Calling sequence: fix2big(fixnum,bigptr)
|
|||
|
; Where: fixnum ---- Integer of small absolute value
|
|||
|
; bigptr ---- Pointer to bignum space
|
|||
|
f2bargs struc
|
|||
|
dw ? ;Caller's BP
|
|||
|
dd ? ;Return address
|
|||
|
dw ? ;Another return address
|
|||
|
fix dw ? ;Fixnum
|
|||
|
bigp dw ? ;Pointer to bignum
|
|||
|
f2bargs ends
|
|||
|
|
|||
|
%fix2big proc far
|
|||
|
push BP
|
|||
|
mov BP,SP
|
|||
|
mov DI,[BP].bigp ;Point ES:DI to bignum
|
|||
|
mov AX,1 ;Fill size field
|
|||
|
stosw
|
|||
|
xor AL,AL ;Clear AL
|
|||
|
mov BX,[BP].fix ;Fetch fixnum value
|
|||
|
shl BX,1 ;Put sign bit in AL
|
|||
|
rcl AL,1
|
|||
|
stosb ;Fill sign field
|
|||
|
sar BX,1 ;Restore fixnum
|
|||
|
or AL,AL ;Negative fixnum?
|
|||
|
jz posfx ;Skip if positive
|
|||
|
neg BX ;Otherwise, find absolute value
|
|||
|
posfx: mov [DI],BX ;Store magnitude of fixnum
|
|||
|
pop BP ;Restore BP
|
|||
|
ret
|
|||
|
%fix2big endp
|
|||
|
|
|||
|
;;;; Decrement bignum
|
|||
|
;;;; Calling sequence: sub1big(buf)
|
|||
|
;;;; Where: buf ---- pointer to bignum
|
|||
|
;;;unibig struc
|
|||
|
;;; dw ? ;Return address
|
|||
|
;;;bbuf dw ? ;Pointer to working bignum
|
|||
|
;;;unibig ends
|
|||
|
;;; public sub1big
|
|||
|
;;;sub1big proc far
|
|||
|
;;; mov BX,SP ;Get bignum pointer
|
|||
|
;;; mov SI,SS:[BX].bbuf
|
|||
|
;;; test byte ptr[SI]+2,1 ;Is bignum negative?
|
|||
|
;;; jnz incbig ;If so, increase magnitude
|
|||
|
;;; jmp short decbig ;Else decrease magnitude
|
|||
|
;;;sub1big endp
|
|||
|
|
|||
|
;;;; Increment bignum
|
|||
|
;;;; Calling sequence: add1big(buf)
|
|||
|
;;; public add1big
|
|||
|
;;;add1big proc far
|
|||
|
;;; mov BX,SP ;Get bignum pointer
|
|||
|
;;; mov SI,SS:[BX].bbuf
|
|||
|
;;; test byte ptr[SI]+2,1 ;Is bignum negative?
|
|||
|
;;; jnz decbig ;Yes, decrease magnitude
|
|||
|
;;;;INCBIG increments magnitude of working bignum at DS:SI
|
|||
|
;;;incbig: mov DI,SI ;Save bignum pointer
|
|||
|
;;; mov CX,[SI] ;Get length (words)
|
|||
|
;;; add SI,3 ;Point to bignum proper
|
|||
|
;;;carrylp: inc word ptr[SI] ;Increment bignum
|
|||
|
;;; jnz done ;If no carry, finished
|
|||
|
;;; inc SI ;Else go to next word
|
|||
|
;;; inc SI
|
|||
|
;;; loop carrylp ;Loop while not end of bignum
|
|||
|
;;; mov word ptr[SI],1 ;Else place final 1
|
|||
|
;;; inc word ptr[DI] ;Lengthen bignum
|
|||
|
;;;done: ret
|
|||
|
;;;;DECBIG decrements magnitude of working bignum at DS:SI
|
|||
|
;;;decbig: mov DI,SI ;Save pointer
|
|||
|
;;; mov CX,[SI] ;Get length
|
|||
|
;;; add SI,3 ;Point to bignum proper
|
|||
|
;;; dec CX ;CX = (length - 1)
|
|||
|
;;;borrowlp: lodsw ;Load current word
|
|||
|
;;; sub AX,1 ;Decrement and store
|
|||
|
;;; mov [SI-2],AX
|
|||
|
;;; jnc done ;Jump if no borrow
|
|||
|
;;; loop borrowlp ;Loop if not on last word
|
|||
|
;;; dec word ptr[SI] ;Else decrement last word
|
|||
|
;;; jnz done ;Jump if bignum not to be shortened
|
|||
|
;;; dec word ptr[DI] ;Else shorten
|
|||
|
;;; ret
|
|||
|
;;;add1big endp
|
|||
|
|
|||
|
; set up big1's index for comparison, used with %magcomp
|
|||
|
%pbig1 proc near
|
|||
|
shl CX,1
|
|||
|
dec SI
|
|||
|
add SI,CX
|
|||
|
shr CX,1
|
|||
|
ret
|
|||
|
%pbig1 endp
|
|||
|
|
|||
|
; set up big1's index for comparison, used with %magcomp
|
|||
|
%pbig2 proc near
|
|||
|
shl CX,1
|
|||
|
dec DI
|
|||
|
add DI,CX
|
|||
|
shr CX,1
|
|||
|
ret
|
|||
|
%pbig2 endp
|
|||
|
|
|||
|
; Compare magnitudes of two bignums
|
|||
|
; Calling sequence: data = magcomp(big1,big2)
|
|||
|
; Where: big1,big2 -- pointers to bignum buffers
|
|||
|
; data ------- a positive integer as follows:
|
|||
|
; Bit 0 set iff |BIG1| < |BIG2|
|
|||
|
; Bit 1 set iff |BIG1| > |BIG2|
|
|||
|
; Bit 2 set iff BIG1 < BIG2
|
|||
|
; Bit 3 set iff BIG1 > BIG2
|
|||
|
; Bit 4 set iff BIG1,BIG2 have same sign
|
|||
|
twobigs struc
|
|||
|
dd ? ;Return address
|
|||
|
dw ? ;Another return address
|
|||
|
big1 dw ? ;First bignum
|
|||
|
big2 dw ? ;Second bignum
|
|||
|
twobigs ends
|
|||
|
|
|||
|
%magcomp proc far
|
|||
|
xor AL,AL ;Clear AL
|
|||
|
xor DX,DX ; clear DX
|
|||
|
mov BX,SP ;Fetch bignum pointers
|
|||
|
mov SI,[BX].big1
|
|||
|
mov DI,[BX].big2
|
|||
|
mov AH,[SI]+2 ;Get sign bits
|
|||
|
mov DH,[DI]+2
|
|||
|
xor DH,AH ;Put XOR of signs into carry
|
|||
|
shr DH,1
|
|||
|
jc sgnskp ;Jump if different signs
|
|||
|
or AL,16 ;Else set proper bit in AL
|
|||
|
sgnskp: rcl AH,1
|
|||
|
mov CX,[SI] ;Get BIG1's length
|
|||
|
mov DX,[DI] ; get BIG2's length
|
|||
|
cld ;Direction forward
|
|||
|
cmpsw ;Compare lengths
|
|||
|
jb bigr2 ;Jump if BIG2 longer
|
|||
|
ja bigr1 ;Jump if BIG1 longer
|
|||
|
same_ln: call %pbig1 ;If same size, point SI,DI to last words
|
|||
|
call %pbig2 ; (most significant)
|
|||
|
std ;Direction backward
|
|||
|
repe cmpsw ;Repeat until unequal
|
|||
|
jb rbig2
|
|||
|
ja rbig1
|
|||
|
test AH,1 ;Signs same?
|
|||
|
jz compend ;Yes, exit
|
|||
|
difsign: test AH,2 ;Is BIG1 positive?
|
|||
|
jnz grtr2 ;No, BIG2 is greater
|
|||
|
jz grtr1 ;Else BIG1 is greater
|
|||
|
bigr1: call %pbig1
|
|||
|
cmp word ptr [SI],0 ; check high word,
|
|||
|
jne rbig1 ; big1 is really bigger
|
|||
|
mov SI,[BX].big1 ; restore SI
|
|||
|
inc SI
|
|||
|
inc SI
|
|||
|
dec CX ; high order word is empty
|
|||
|
cmp CX,DX ; compare length's again
|
|||
|
je same_ln ; same length
|
|||
|
jmp bigr1 ; repeat until unequal or same lengths
|
|||
|
|
|||
|
rbig1: or AL,2 ;Set the |BIG1|>|BIG2| bit
|
|||
|
test AH,1 ;Signs same?
|
|||
|
jnz difsign ;No, different signs
|
|||
|
test AH,2 ;Both positive?
|
|||
|
jnz grtr2 ;No, so BIG2 is greater
|
|||
|
grtr1: or AL,8 ;Set the BIG1>BIG2 bit
|
|||
|
cld ; Set direction forward (JCJ-12/6/84)
|
|||
|
ret
|
|||
|
bigr2: push CX
|
|||
|
mov CX,DX ; swap CX and DX
|
|||
|
pop DX
|
|||
|
call %pbig2 ; Set up big2's pointers
|
|||
|
cmp word ptr [DI],0 ; check high word
|
|||
|
jne rbig2 ; big2 really is bigger
|
|||
|
mov DI,[BX].big2 ; restore DI
|
|||
|
inc DI
|
|||
|
inc DI
|
|||
|
dec CX ; high order word is empty
|
|||
|
cmp DX,CX ; compare length's again
|
|||
|
je same_ln ;
|
|||
|
jmp bigr2 ; repeat until unequal or same lengths
|
|||
|
|
|||
|
rbig2: or AL,1 ;Set the |BIG1|<|BIG2| bit
|
|||
|
test AH,1 ;Signs same?
|
|||
|
jnz difsign ;No, different signs
|
|||
|
test AH,2 ;Both positive?
|
|||
|
jnz grtr1 ;No, BIG1 is greater
|
|||
|
grtr2: or AL,4 ;Set the BIG1<BIG2 bit
|
|||
|
compend: cld ; Set direction forward (JCJ-12/6/84)
|
|||
|
ret
|
|||
|
%magcomp endp
|
|||
|
|
|||
|
; Add magnitudes of bignums
|
|||
|
; Calling sequence: bigadd(big1,big2)
|
|||
|
; Where: big1 ---- bignum of lesser magnitude
|
|||
|
; big2 ---- bignum of greater magnitude
|
|||
|
; When done, BIG2 will hold the sum
|
|||
|
|
|||
|
%bigadd proc far
|
|||
|
mov BX,SP ;Fetch bignum pointers
|
|||
|
mov SI,[BX].big1
|
|||
|
mov DI,[BX].big2
|
|||
|
cld ;Direction forward
|
|||
|
lodsw ;Get length of smaller bignum
|
|||
|
mov CX,AX ;Save length
|
|||
|
sub AX,[DI] ;Find and push difference in lengths
|
|||
|
neg AX
|
|||
|
push AX
|
|||
|
inc SI ;Point SI,DI to bignums proper
|
|||
|
add DI,3
|
|||
|
clc ;Prepare to add
|
|||
|
addlp: lodsw ;Fetch source addend
|
|||
|
adc [DI],AX ;Add to destination addend
|
|||
|
inc DI ;Point DI to next word
|
|||
|
inc DI
|
|||
|
loop addlp ;Do until smaller bignum exhausted
|
|||
|
pop CX ;Fetch length difference (CF unchanged)
|
|||
|
jnc doneadd ;Stop if no carry
|
|||
|
mov SI,[BX].big2 ;Point SI to destination bignum
|
|||
|
jcxz samlen ;Jump if bignums the same length
|
|||
|
adclp: inc word ptr[DI] ;Otherwise, add carry
|
|||
|
jnz doneadd ;Jump if no resultant carry
|
|||
|
add DI,2 ;Point DI to next word
|
|||
|
loop adclp ;Do until whole number is done or no carry
|
|||
|
samlen: mov word ptr[DI],1 ;Store last carry
|
|||
|
inc word ptr[SI] ;Note bignum's size increase
|
|||
|
doneadd: ret
|
|||
|
%bigadd endp
|
|||
|
|
|||
|
; Subtract magnitudes of bignums
|
|||
|
; Calling sequence: bigsub(big1,big2)
|
|||
|
; Where: big1 ---- bignum of lesser magnitude
|
|||
|
; big2 ---- bignum of greater magnitude
|
|||
|
; When done, BIG2 will hold the difference
|
|||
|
; When done, BIG2 will hold the sum
|
|||
|
|
|||
|
%bigsub proc far
|
|||
|
mov BX,SP ;Fetch pointers to bignums
|
|||
|
mov SI,[BX].big1
|
|||
|
mov DI,[BX].big2
|
|||
|
cld ;Direction forward
|
|||
|
lodsw ;Get length of smaller bignum
|
|||
|
mov CX,AX
|
|||
|
inc SI ;Point SI,DI to bignums proper
|
|||
|
add DI,3
|
|||
|
clc ;Prepare to subtract
|
|||
|
sublp: lodsw ;Fetch subtrahend
|
|||
|
sbb [DI],AX ;Subtract
|
|||
|
inc DI ;Point DI to next word
|
|||
|
inc DI
|
|||
|
loop sublp ;Do until smaller bignum exhausted
|
|||
|
jnc pack ;Jump if no borrow
|
|||
|
borlp: mov AX,[DI] ;Fetch word
|
|||
|
sub AX,1 ;Decrement and store
|
|||
|
stosw
|
|||
|
jc borlp ;Jump if further borrowing needed
|
|||
|
pack: mov DI,[BX].big2 ;Fetch pointer to 2nd bignum
|
|||
|
mov SI,DI ;Save pointer in SI
|
|||
|
mov AX,[SI] ;Fetch bignum length
|
|||
|
mov CX,AX ;Save (length-1) in CX
|
|||
|
dec CX
|
|||
|
shl AX,1 ;Point DI to last word of bignum
|
|||
|
inc AX
|
|||
|
add DI,AX
|
|||
|
std ;Direction backward
|
|||
|
xor AX,AX ;Find number of leading 0-words
|
|||
|
repe scasw ; (not counting least sig. word)
|
|||
|
jz smlskp ;Jump if only one non-0 word
|
|||
|
inc CX ;Else, at least 2 non-0 words
|
|||
|
smlskp: inc CX ;Form (length - # of leading 0-words)
|
|||
|
mov [SI],CX ;Save in bignum size field
|
|||
|
cld ;Clear the direction flag
|
|||
|
ret
|
|||
|
%bigsub endp
|
|||
|
|
|||
|
; Multiply two bignums
|
|||
|
; Calling sequence: bigmul(big1,big2,big3)
|
|||
|
; Where: big1,big2 -- factors
|
|||
|
; big3 ------- destination of product
|
|||
|
mulargs struc
|
|||
|
carry dw ? ;Multiplication carry
|
|||
|
dw ? ;Caller's BP
|
|||
|
dd ? ;Return address
|
|||
|
dw ? ;Another return address
|
|||
|
mbig1 dw ? ;Factor of greater magnitude
|
|||
|
mbig2 dw ? ;Factor of lesser magnitude
|
|||
|
mbig3 dw ? ;Product destination
|
|||
|
mulargs ends
|
|||
|
; When done, BIG2 will hold the sum
|
|||
|
|
|||
|
%bigmul proc far
|
|||
|
push BP ;Save BP
|
|||
|
dec SP ;Create space for multiplication carry
|
|||
|
dec SP
|
|||
|
mov BP,SP ;Point BP to args
|
|||
|
cld ;Direction forward
|
|||
|
mov SI,[BP].mbig1 ;Fetch factor pointers
|
|||
|
mov DI,[BP].mbig2
|
|||
|
lodsw ;Fetch BIG1's length
|
|||
|
mov CX,AX ;Put sum of lengths in CX
|
|||
|
add CX,[DI]
|
|||
|
scasw ;Which has greater magnitude?
|
|||
|
jae xchgskp ;Jump if BIG1 is not smaller
|
|||
|
xchg DI,SI
|
|||
|
xchgskp: lodsb ;Fetch one factor's sign
|
|||
|
xor AL,[DI] ;XOR with the other factor's sign
|
|||
|
inc DI ;Point DI to bignum proper
|
|||
|
mov BX,DI ;And store in BX
|
|||
|
mov DI,[BP].mbig3 ;Store length into product
|
|||
|
xchg AX,CX
|
|||
|
stosw
|
|||
|
push AX ;Save total length of product
|
|||
|
xchg AX,CX ;Store sign byte into product
|
|||
|
stosb
|
|||
|
push DI ;Set product to 0 over whole length
|
|||
|
xor AX,AX
|
|||
|
rep stosw
|
|||
|
pop DI
|
|||
|
xchg DI,BX ;Restore BX and DI
|
|||
|
mov CX,[DI]-3 ;Fetch length of BIG2
|
|||
|
sub BX,SI ;Point [BX+SI-2] to product
|
|||
|
dec BX
|
|||
|
dec BX
|
|||
|
mov [BP].mbig1,SI ;Store pointer to data of BIG1
|
|||
|
mullp2: push CX ;Save counter of BIG2 words
|
|||
|
;Add (BIG1*part of BIG2) to current product
|
|||
|
mov word ptr[BP].carry,0 ;Clear carry in
|
|||
|
mov SI,[BP].mbig1 ;Fetch bignum pointer
|
|||
|
mov CX,[SI]-3 ;Get number of words in bignum
|
|||
|
mullp: lodsw ;Get factor part from BIG1
|
|||
|
mul word ptr[DI] ;Multiply by factor part from BIG2
|
|||
|
add AX,[BP].carry ;Add carry in
|
|||
|
adc DX,0
|
|||
|
add [BX+SI],AX ;Add product part into BIG3
|
|||
|
adc DX,0 ;Adjust and store carry
|
|||
|
mov [BP].carry,DX
|
|||
|
loop mullp ;Continue for all BIG1
|
|||
|
mov [BX+SI+2],DX ;Store carry remaining
|
|||
|
;
|
|||
|
pop CX ;Restore BIG2 counter
|
|||
|
inc DI ;Point DI to next word in BIG2
|
|||
|
inc DI
|
|||
|
inc BX ;Point BX to next word in BIG3
|
|||
|
inc BX
|
|||
|
loop mullp2 ;Continue for all BIG2
|
|||
|
mov BX,[BP].mbig3 ;Fetch pointer to BIG3 (beginning)
|
|||
|
pop SI ;Point SI to last word of product
|
|||
|
shl SI,1
|
|||
|
inc SI
|
|||
|
add SI,BX
|
|||
|
cmp word ptr[SI],0 ;Test last word for zero
|
|||
|
jnz muldone ;Done if not zero
|
|||
|
dec word ptr[BX] ;Decrement bignum length
|
|||
|
muldone: inc SP ;Discard temporary carry variable
|
|||
|
inc SP
|
|||
|
pop BP ;Restore BP
|
|||
|
ret
|
|||
|
%bigmul endp
|
|||
|
|
|||
|
; Divide one bignum by another
|
|||
|
; Calling sequence: bigdiv(dvdnd,dvsr,quot)
|
|||
|
; Where: dvdnd ----- dividend
|
|||
|
; dvsr ------ divisor
|
|||
|
; quot ------ quotient
|
|||
|
divargs struc
|
|||
|
dw ? ;Caller's BP
|
|||
|
dvsrsz dw ? ;Size of divisor (words)
|
|||
|
bitcount dw ? ;Estimated bits in quotient
|
|||
|
align dw ? ;Alignment of dividend to divisor
|
|||
|
ldvsr dw ? ;Pointer to last word of divisor
|
|||
|
dd ? ;Return address
|
|||
|
dw ? ;Another return address
|
|||
|
dvdnd dw ? ;Dividend
|
|||
|
dvsr dw ? ;Divisor
|
|||
|
quot dw ? ;Quotient
|
|||
|
divargs ends
|
|||
|
; When done, BIG2 will hold the sum
|
|||
|
|
|||
|
%bigdiv proc far
|
|||
|
sub SP,8 ;Room for local variables
|
|||
|
push BP
|
|||
|
mov BP,SP
|
|||
|
mov DI,[BP].quot ;Get pointers to arguments
|
|||
|
mov SI,[BP].dvdnd
|
|||
|
mov BX,[BP].dvsr
|
|||
|
cld ;Direction forward
|
|||
|
lodsw ;Get dividend length
|
|||
|
mov CX,[BX] ;Fetch divisor length
|
|||
|
cmp CX,1 ;Check divisor for 0
|
|||
|
jne dvsrok
|
|||
|
cmp word ptr[BX]+3,0 ;Check divisor data word
|
|||
|
jnz dvsrok
|
|||
|
mov AX,CX ;Put nonzero value in AX
|
|||
|
pop BP
|
|||
|
add SP,8 ;Restore stack
|
|||
|
ret ;Exit
|
|||
|
dvsrok: inc BX ;Point BX+1 to divisor sign
|
|||
|
mov DX,CX ;Find & store pointer to last divisor word
|
|||
|
shl DX,1
|
|||
|
add DX,BX
|
|||
|
mov [BP].ldvsr,DX
|
|||
|
sub AX,CX ;Find dividend-divisor length difference
|
|||
|
mov DX,AX ;Save in DX for now
|
|||
|
inc AX ;Store maximum quotient length (words)
|
|||
|
stosw
|
|||
|
inc CX ;Save length of working divisor
|
|||
|
mov [BP].dvsrsz,CX
|
|||
|
dec AX ;Find and store quotient bit count
|
|||
|
shl AX,1
|
|||
|
shl AX,1
|
|||
|
shl AX,1
|
|||
|
shl AX,1
|
|||
|
inc AX
|
|||
|
mov [BP].bitcount,AX
|
|||
|
lodsb ;Get dividend sign
|
|||
|
xor AL,[BX]+1 ;Find and store quotient sign
|
|||
|
stosb
|
|||
|
mov [BP].dvdnd,SI ;Save pointer to dividend proper
|
|||
|
mov [BP].quot,DI ;Save pointer to quotient proper
|
|||
|
xor AX,AX ;Zero first two words of quotient
|
|||
|
stosw
|
|||
|
std
|
|||
|
stosw
|
|||
|
dec DX ;Account for extra divisor word
|
|||
|
shl DX,1 ;Store divisor-dividend alignment
|
|||
|
add DX,SI
|
|||
|
mov [BP].align,DX
|
|||
|
mov word ptr[BX],0 ;Put 0-word at start of divisor
|
|||
|
mov [BP].dvsr,BX ;Save pointer to working divisor
|
|||
|
bigdivlp: call divcmp ;Dividend less than aligned divisor?
|
|||
|
jb divbit0 ;Yes, perform division
|
|||
|
test word ptr[BX],8000h ;Can divisor be shifted left?
|
|||
|
jnz divbit1 ;No, perform division
|
|||
|
mov SI,[BP].dvsr ;Otherwise, shift entire divisor left
|
|||
|
mov CX,[BP].dvsrsz
|
|||
|
clc ;Start by shifting in 0
|
|||
|
shllp: rcl word ptr[SI],1 ;Shift through divisor word
|
|||
|
inc SI ;Point SI to next word
|
|||
|
inc SI
|
|||
|
loop shllp ;Do for entire divisor
|
|||
|
inc [BP].bitcount ;Increase bit count
|
|||
|
jmp bigdivlp ;See if divisor is big enough yet
|
|||
|
divlp: call divcmp ;Dividend less than aligned divisor?
|
|||
|
cld ; (Direction forward)
|
|||
|
jb divbit0 ;Yes, rotate 0 into quotient
|
|||
|
mov SI,[BP].align ;Otherwise, subtract divisor
|
|||
|
mov DI,SI
|
|||
|
mov BX,[BP].dvsr
|
|||
|
sub BX,SI
|
|||
|
dec BX
|
|||
|
dec BX
|
|||
|
mov CX,[BP].dvsrsz
|
|||
|
clc ;No carry in
|
|||
|
divsublp: lodsw
|
|||
|
sbb AX,[SI+BX]
|
|||
|
stosw
|
|||
|
loop divsublp
|
|||
|
divbit1: clc ;Clear carry (to rotate 1 in)
|
|||
|
divbit0: cmc
|
|||
|
mov SI,[BP].quot ;Fetch pointer to quotient
|
|||
|
mov CX,[SI]-3 ;Fetch quotient length
|
|||
|
quotlp: rcl word ptr[SI],1 ;Rotate bit in
|
|||
|
inc SI
|
|||
|
inc SI
|
|||
|
loop quotlp ;Rotate bits through whole quotient
|
|||
|
dec [BP].bitcount ;Last quotient bit rotated in?
|
|||
|
jz divdone ;Yes, stop
|
|||
|
mov SI,[BP].ldvsr ;Otherwise realign divisor (shr)
|
|||
|
mov CX,[BP].dvsrsz
|
|||
|
std ;Direction backward
|
|||
|
cmp word ptr[SI],0 ;Time to shift divisor words?
|
|||
|
jnz wshftskp ;No, don't bother
|
|||
|
mov BX,SI ;Save last word pointer
|
|||
|
mov DX,CX ;Save word count
|
|||
|
mov DI,SI ;Destination = source+2
|
|||
|
dec SI
|
|||
|
dec SI
|
|||
|
dec CX ;Shift significant divisor words
|
|||
|
rep movsw
|
|||
|
xor AX,AX ;Clear least significant word
|
|||
|
stosw
|
|||
|
mov SI,BX ;Restore last word pointer
|
|||
|
mov CX,DX ;Restore count
|
|||
|
sub [BP].align,2 ;Reset divisor alignment
|
|||
|
wshftskp: clc ;Shift 0 in
|
|||
|
shrlp: rcr word ptr[SI],1 ;Shift
|
|||
|
dec SI
|
|||
|
dec SI
|
|||
|
loop shrlp ;Shift entire divisor
|
|||
|
jmp divlp ;After all this, loop 'til division done
|
|||
|
divdone: mov BX,[BP].dvdnd ;Fetch dividend pointer
|
|||
|
mov DI,[BX]-3 ;Fetch former length of dividend
|
|||
|
dec DI ;Put length-1 in CX
|
|||
|
mov CX,DI
|
|||
|
shl DI,1 ;Point DI to last dividend word
|
|||
|
add DI,BX
|
|||
|
std ;Direction backward
|
|||
|
xor AX,AX ;Pack as in BIGSUB
|
|||
|
repe scasw
|
|||
|
jz smlskp2
|
|||
|
inc CX
|
|||
|
smlskp2: inc CX
|
|||
|
mov [BX]-3,CX ;Save in bignum size field
|
|||
|
mov BX,[BP].quot ;Fetch quotient pointer
|
|||
|
mov DI,[BX]-3 ;Point BX+DI to last quotient word
|
|||
|
dec DI
|
|||
|
shl DI,1
|
|||
|
cmp word ptr[BX+DI],0 ;If last word is 0, decrease length
|
|||
|
jnz divex
|
|||
|
dec word ptr[BX]-3
|
|||
|
divex: pop BP ;Restore stack
|
|||
|
add SP,8
|
|||
|
xor AX,AX ;Return 0
|
|||
|
cld ;Clear direction flag
|
|||
|
ret
|
|||
|
%bigdiv endp
|
|||
|
|
|||
|
;Compare working divisor to dividend
|
|||
|
divcmp proc near
|
|||
|
mov DI,[BP].ldvsr ;Get pointer to last divisor word
|
|||
|
mov CX,[BP].dvsrsz ;Fetch number of compares to do
|
|||
|
mov SI,[BP].align ;Get dividend pointer
|
|||
|
mov AX,CX ;Save # of wrods for pointer adjust
|
|||
|
cmp SI,[BP].dvdnd ;Dividend longer than divisor?
|
|||
|
jae adjskp ;Yes, jump
|
|||
|
dec CX ;Don't compare first divisor word
|
|||
|
adjskp: dec AX ;Adjust pointer into dividend
|
|||
|
shl AX,1
|
|||
|
add SI,AX
|
|||
|
mov BX,DI ;Save pointer to last divisor byte
|
|||
|
std ;Direction backward
|
|||
|
repz cmpsw ;Compare until unequal
|
|||
|
ret
|
|||
|
divcmp endp
|
|||
|
|
|||
|
PROGX ends
|
|||
|
|
|||
|
|
|||
|
|
|||
|
PGROUP group prog
|
|||
|
prog segment byte public 'PROG'
|
|||
|
assume CS:PGROUP
|
|||
|
|
|||
|
public big2flo
|
|||
|
big2flo proc near
|
|||
|
call %big2flo
|
|||
|
ret
|
|||
|
big2flo endp
|
|||
|
|
|||
|
public fix2big
|
|||
|
fix2big proc near
|
|||
|
call %fix2big
|
|||
|
ret
|
|||
|
fix2big endp
|
|||
|
|
|||
|
public magcomp
|
|||
|
magcomp proc near
|
|||
|
call %magcomp
|
|||
|
ret
|
|||
|
magcomp endp
|
|||
|
|
|||
|
public bigadd
|
|||
|
bigadd proc near
|
|||
|
call %bigadd
|
|||
|
ret
|
|||
|
bigadd endp
|
|||
|
|
|||
|
public bigsub
|
|||
|
bigsub proc near
|
|||
|
call %bigsub
|
|||
|
ret
|
|||
|
bigsub endp
|
|||
|
|
|||
|
public bigmul
|
|||
|
bigmul proc near
|
|||
|
call %bigmul
|
|||
|
ret
|
|||
|
bigmul endp
|
|||
|
|
|||
|
public bigdiv
|
|||
|
bigdiv proc near
|
|||
|
call %bigdiv
|
|||
|
ret
|
|||
|
bigdiv endp
|
|||
|
|
|||
|
prog ends
|
|||
|
end
|
|||
|
|