Metropoli BBS
VIEWER: nmath.asm MODE: TEXT (ASCII)
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

[ RETURN TO DIRECTORY ]