SUB2   ;		* * * * * * * * * * * * *
 ;		*  PROGRAM BY KIM WATT  *
 ;		* BREEZE COMPUTING INC. *
 ;		*     P.O. BOX  1013    *
 ;		* BERKLEY, MICH.  48072 *
 ;		*    (313)  288-9422    *
 ;		* * * * * * * * * * * * *											
 ;	=====  SUBROUTINES # 2  =====												
 ;  THIS IS A SUBROUTINE SECTON FOR LIBRARY USAGE										
 ;	FLOATING POINT ROUTINES													
 	ORG	5000H		;RESIDENT ROUTINE AREA
 ;  FIRST TO DEFINE THE WORKING STORAGE AREAS
 FMPNT	DEFW	0		;FROM POINTER
 TOPNT	DEFW	0		;TO POINTER
 CNTR	DEFB	0		;COUNTER
 TSIGN	DEFB	0		;SIGN INDICATOR
 SIGNS	DEFB	0		;MULTIPLY/DIVIDE IND.
 FPLSWE	DEFB	0		;FPACC EXTENSION
 FPLSW	DEFB	0		;FPACC LSB
 FPNSW	DEFB	0		;FPACC NEXT MSB
 FPMSW	DEFB	0		;FPACC MSB
 FPACCE	DEFB	0		;FPACC EXPONENT
 ;  MULTIPLICATION WORK AREA
 MCAND0	DEFB	0
 MCAND1	DEFB	0
 MCAND2	DEFB	0
 FOLSWE	DEFB	0		;FPOP EXTENSION
 FOPLSW	DEFB	0		;FPOP LSB
 FOPNSW	DEFB	0		;FPOP NEXT MSB
 FOPMSW	DEFB	0		;FPOP MSB
 FOPEXP	DEFB	0		;FPOP EXPONENT
 ;  WORKING STORAGE
 WORK0	DEFB	0
 WORK1	DEFB	0
 WORK2	DEFB	0
 WORK3	DEFB	0
 WORK4	DEFB	0
 WORK5	DEFB	0
 WORK6	DEFB	0
 WORK7	DEFB	0
 WORK8	DEFB	0
 WORK9	DEFB	0
 ;
 ;  FIRST THE GENERAL PURPOSE SUBROUTINES
 ;
 ;	CLEAR A BUFFER
 ZERMEM	LD	A,0		;BYTE TO CLEAR
 CLRMEM	LD	(IX),A		;PUT INTO BUFFER
 	INC	IX		;POINT TO NEXT
 	DJNZ	CLRMEM		;KEEP GOING
 	RET			;DONE
 ;	MOVE VALUES BETWEEN BUFFERS
 MOVIND	LD	A,(IX)		;FROM BYTE
 	LD	(IY),A		;TO BYTE
 	INC	IX
 	INC	IY
 	DJNZ	MOVIND		;COUNTER
 	RET
 ;	ROTATE MULTIPLE PRECISION
 ROTATL	OR	A		;CLEAR CARRY FLAG
 ROTL	RLC	(IX)		;ROTATE LEFT
 	DJNZ	MORRTL		;MORE ROTATES
 	RET			;DONE
 MORRTL	INC	IX		;INCREMENT POINTER
 	JR	ROTL		;CONTINUE TO ROTATE
 ;	INCREMENT MULTIPLE PRECISION
 INCMEM	INC	(IX)		;INCREMENT CONTENTS
 	RET	NZ		;RETURN IF NOT ZERO
 	INC	IX		;ADVANCE POINTER
 	DJNZ	INCMEM		;CONTINUE INCREMENTING
 	RET			;DONE
 ;	DECREMENT MULTIPLE PRECISION
 DCRMEM	LD	A,(IX)		;GET A BYTE
 	SUB	1		;DECREMENT
 	LD	(IX),A		;RESTORE IT
 	INC	IX		;ADVANCE POINTER
 	DJNZ	DCRET		;LAST BYTE DONE
 	JR	C,DCRMEM	;NEXT BYTE SHOULD BE DONE
 DCRET	RET			;DONE
 ;	ROTATE MULTIPLE PRECISION RIGHT
 ROTATR	OR	A		;CLEAR CARRY FLAG
 ROTR	RRC	(IX)		;ROTATE RIGHT
 	DJNZ	MORRTR		;NOT ZERO, CONTINUE
 	RET			;DONE
 MORRTR	DEC	IX		;DECREMENT INDEX
 	JR	ROTR		;CONTINUE
 ;	COMPLEMENT MULTIPLE PRECISION
 COMPLM	SCF			;SET CARRY FOR 2'S COMPL.
 COMPL	LD	A,0FFH		;ALL BITS ON
 	XOR	(IX)		;COMPLEMENT THE BYTE
 	ADC	A,0		;IF CARRY, 2'S COMPLEMENT
 	LD	(IX),A		;STORE THE BYTE
 	INC	IX		;BUMP POINTER
 	DJNZ	COMPL		;NOT ZERO, CONTINUE
 	RET			;DONE
 ;	MULTIPLE PRECISION ADDER
 ADDER	OR	A		;CLEAR CARRY FLAG
 ADDR1	LD	A,(IY)		;FETCH ONE BYTE
 	ADC	A,(IX)		;ADD TO NEXT BYTE
 	LD	(IY),A		;SAVE IN DEST.
 	INC	IX
 	INC	IY
 	DJNZ	ADDR1		;NEXT BYTE
 	RET			;ADDITION DONE
 ;	MULTIPLE PRECISION SUBTRACTER
 SUBBER	SCF			;SET CARRY FLAG
 SUBB1	LD	A,(IY)		;GET A BYTE
 	SBC	A,(IX)		;SUBTRACT FROM OTHER
 	LD	(IY),A		;SAVE HERE
 	INC	IY
 	INC	IX
 	DJNZ	SUBB1
 	RET
 ;	NOW FOR FLOATING POINT NORMALIZATION
 FPNORM	LD	IX,TSIGN	;POINT TO SIGN FLAG
 	LD	A,(FPMSW)	;FPACC MSB
 	OR	A		;SET FLAGS
 	JP	M,ACCMIN
 	LD	C,0		;IF POS, CLEAR SIGN REG
 	LD	(IX),C
 	JR	ACZERT		;TEST IF FPACC=0
 ACCMIN	LD	(IX),A		;SET SIGN INDICATOR
 	LD	B,4		;PRECISION COUNTER
 	LD	IX,FPLSWE	;FPACC LSB-1
 	CALL	COMPLM		;TWO'S COMPLEMENT
 ACZERT	LD	IY,FPMSW	;FPACC MSB
 	LD	B,4		;PRECISION
 	LD	HL,FPACCE	;FPACC EXPONENT
 LOOKO	LD	A,(IY)		;SEE IF FPACC=0
 	OR	A		;SET FLAGS
 	JR	NZ,ACNONZ	;GO IF NONZERO
 	DEC	IY		;DECREMENT POINTER
 	DJNZ	LOOKO		;CONTINUE
 	LD	(HL),B		;CLEAR EXPONENT TOO
 NORMEX	RET			;EXIT NORMALIZATION
 ACNONZ	LD	IX,FPLSWE	;FPACC LSB-1
 	LD	B,4		;PRECISION
 	CALL	ROTATL		;ROTATE LEFT
 	LD	A,(IX)		;SEE IF ONE IN MS BIT
 	OR	A		;SET FLAGS
 	JP	M,ACCSET	;PROPERLY JUSTIFIED IF M
 	DEC	(HL)		;IF POS, DEC EXPONENT
 	JR	ACNONZ		;CONTINUE ROTATING
 ACCSET	LD	IX,FPMSW	;FPACC MSB
 	LD	B,3		;PRECISION
 	CALL	ROTATR		;COMPENSATING ROTATE
 	LD	A,(TSIGN)	;IS ORIGINAL POSITIVE ?
 	OR	A		;SET FLAGS
 	JR	Z,NORMEX	;YES, RETURN
 	LD	B,3		;POINTER AT LSB, SET PREC
 	JP	COMPLM		;RESTORE TO NEG. AND RET.
 ;	FLOATING POINT ADDITION
 FPADD	LD	A,(FPMSW)	;SEE IF FPACC MSB =0
 	OR	A		;SET FLAGS
 	JR	NZ,NONZAC	;GO IF NOT ZERO
 MOVOP	LD	IX,FOPLSW	;FPOP LSB
 	LD	IY,FPLSW	;FPACC LSB
 	LD	B,4		;PRECISION
 	JP	MOVIND		;MOVE FPOP TO FPACC
 NONZAC	LD	A,(FOPMSW)	;SEE IF FPOP MSB =0
 	OR	A
 	JR	NZ,CKEQEX	;NO, CHECK EXPONENTS
 	RET			;YES, RESULT = FPACC
 CKEQEX	LD	IX,FPACCE	;FPACC EXPONENT
 	LD	A,(IX)		;FETCH IT
 	LD	HL,FOPEXP	;FPOP EXPONENT
 	CP	(HL)		;ARE THEY EQUAL ?
 	JR	Z,SHACOP	;Z=YES
 	SCF	;IF NOT EQUAL, DETERMINE WHICH IS LARGER
 	LD	A,0		;ZERO, BUT NOT FLAGS
 	SBC	A,(IX)		;THE FPACC EXPONENT
 	ADC	A,(HL)		;ADD IN FPOP EXPONENT
 	JP	P,SKPNEG	;SKIP IF NEGATIVE
 	SCF			;IF -, FORM 2'S COMPL.
 	LD	D,A		;SAVE TEMPORARILY
 	LD	A,0		;TO TEST THE MAGINTUDE
 	SBC	A,D		;	OF DIFF OF EXP
 SKPNEG	CP	18H		;IS DIFF < 18H ?
 	JP	M,LINEUP	;ALIGN MANTISSA
 	SCF
 	LD	A,(FOPEXP)	;EXPONENT
 	SBC	A,(IX)		;	COMPARE
 	JP	P,MOVOP		;FPOP LARGER, MOVE IT
 	RET			;DONE
 LINEUP	LD	A,(FOPEXP)	;FETCH EXPONENT
 	SCF			;SET FOR SUBTRACTION
 	SBC	A,(IX)		;FPOP-FPACC EXPONENTS
 	LD	B,A		;SAVE COUNTER
 	JP	M,SHIFTO	;IF NEG,FPACC>,SHIFT FPOP
 MORACC	LD	IX,FPACCE	;EXPONENT
 	CALL	SHLOOP		;SHIFT FPACC RIGHT 1 BIT
 	DJNZ	MORACC		;CONTINUE TILL DONE
 	JP	SHACOP		;WHEN 0, SET FOR ADDITION
 SHIFTO	LD	IX,FOPEXP	;FPOP EXPONENT
 	CALL	SHLOOP		;SHIFT FPOP RIGHT 1 BIT
 	INC	B		;INCREMENT COUNTER
 	JR	NZ,SHIFTO	;NOT ZERO, CONTINUE
 SHACOP	LD	A,0		;PREPARE FOR ADDITION
 	LD	(FPLSWE),A	;CLEAR FPACC LSB-1
 	LD	(FOLSWE),A	;CLEAR FPOP LSB-1
 	LD	IX,FPACCE	;POINT TO EXPONENT
 	CALL	SHLOOP		;ROTATE RIGHT 1 BIT
 	LD	IX,FOPEXP
 	CALL	SHLOOP		;BOTH EXPONENTS SHIFTED
 	LD	IX,FOLSWE	;FPOP LSB-1
 	LD	IY,FPLSWE	;FPACC LSB-1
 	LD	B,4		;PRECISION COUNTER
 	CALL	ADDER		;ADD FPOP TO FPACC
 	JP	FPNORM		;NORMALIZE RESULT
 SHLOOP	INC	(IX)		;INCREMENT EXPONENT
 	DEC	IX		;NEXT ONE
 	LD	A,B		;SAVE COUNTER
 	LD	B,4		;PRECISION
 FSHIFT	PUSH	AF		;SAVE ON STACK
 	LD	A,(IX)		;FETCH MSB
 	OR	A
 	JP	M,BRING1	;IF NEG, ROTATE 1 IN MSB
 	CALL	ROTATR		;POS, ROTATE RIGHT
 	JR	RESCNT		;RETURN TO CALLER
 BRING1	SCF			;SET CARRY TO MAINTAIN -
 	CALL	ROTR		;RIGHT ONE BIT
 RESCNT	POP	AF		;RESTORE STACK
 	LD	B,A		;RESTORE COUNT
 	RET			;DONE
 ;	FLOATING POINT SUBTRACTION
 FPSUB	LD	IX,FPLSW	;FPACC LSB
 	LD	B,3		;PRECISION
 	CALL	COMPLM		;COMPLEMENT FPACC
 	JP	FPADD		;SUBTRACT BY ADDING NEG.
 ;	FLOATING POINT MULTIPLICATION
 FPMULT	CALL	CKSIGN		;CHECK SIGN OF MANTISSA
 	LD	A,(FOPEXP)	;FPOP EXPONENT
 	OR	A		;CLEAR CARRY FLAG
 	LD	HL,FPACCE	;FPACC EXPONENT
 	ADC	A,(HL)		;COMPARE
 	LD	(HL),A		;SAVE IN FPACC EXPONENT
 	INC	(HL)		;ADD FOR ALGORITHM COMP.
 SETMCT	LD	A,17H		;SET BIT COUNTER
 	LD	E,A		;SAVE IN COUNTER
 MULTIP	LD	IX,FPMSW	;FPACC MSB
 	LD	B,3		;PRECISION COUNTER
 	CALL	ROTATR		;ROTATE FPACC RIGHT
 	JR	NC,NADOPP	;DON'T ADD PARTIAL PROD.
 ADOPP	LD	IX,MCAND1	;LSB OF MULTIPLICAND
 	LD	IY,WORK1	;LSB OF PARTIAL PRODUCT
 	LD	B,6		;PRECISION COUNTER
 	CALL	ADDER		;ADD MULT TO PARTIAL PROD
 NADOPP	LD	IX,WORK6	;MSB OF PARTIAL PROD
 	LD	B,6
 	CALL	ROTATR		;ROTATE RIGHT
 	DEC	E		;DECREMENT COUNTER
 	JR	NZ,MULTIP	;CONTINUE MULTIPLYING
 	LD	IX,WORK6	;SET POINTER TO PARTIAL
 	LD	B,6
 	CALL	ROTATR		;MAKE ROOM FOR ROUNDING
 	LD	IX,WORK3	;24'TH BIT OF PARTIAL
 	LD	A,(IX)		;FETCH THE BYTE
 	RLCA			;24'TH BIT TO SIGN
 	JP	P,PREXFR	;IF BIT=0, BRANCH AHEAD
 	OR	A		;CLEAR CARRY FLAG
 	LD	B,3
 	LD	A,40H		;ADD 1 TO 23'RD BIT
 	ADC	A,(IX)		;TO ROUND OFF RESULT
 	LD	(WORK3),A	;SAVE SUM
 CROUND	LD	A,0		;CLEAR A, BUT NOT CARRY
 	ADC	A,(IX)		;ADD WITH CARRY
 	LD	(IX),A		;SAVE IT
 	INC	IX		;NEXT ONE
 	DJNZ	CROUND		;NZ, ADD NEXT BYTE
 PREXFR	LD	IY,FPLSWE	;FPACC LSB-1
 	LD	IX,WORK3	;PARTIAL PROD LSB-1
 	LD	B,4		;PRECISION
 EXMLDV	CALL	MOVIND		;MOVE TO FPACC
 	CALL	FPNORM		;NORMALIZE RESULT
 	LD	A,(SIGNS)	;GET SIGN STORAGE
 	OR	A		;FLAGS SET
 	JR	NZ,MULTEX	;SIGN IS POSITIVE
 	LD	IX,FPLSW	;FPACC LSB
 	LD	B,3
 	CALL	COMPLM		;COMPLEMENT RESULT
 MULTEX	RET			;EXIT MULTIPLICATION
 CKSIGN	LD	IX,WORK0	;POINT TO WORK AREA
 	LD	B,8		;PRECISION
 	CALL	ZERMEM		;ZERO BUFFER
 	LD	IX,MCAND0	;MULTIPLICAND STORAGE
 	LD	B,4
 	CALL	ZERMEM		;CLEAR STORAGE
 	LD	A,1		;INITIALIZE
 	LD	(SIGNS),A	;	SIGNS INDICATOR
 	LD	A,(FPMSW)	;FPACC MSB
 	OR	A		;SET FLAGS
 	JP	P,OPSGNT	;IF NEG, DEC. SIGNS
 NEGFPA	LD	HL,SIGNS	;POINT TO IT
 	DEC	(HL)		;ONE LESS
 	LD	IX,FPLSW	;FPACC LSB
 	LD	B,3
 	CALL	COMPLM		;MAKE IT POSITIVE
 OPSGNT	LD	A,(FOPMSW)	;IS FPOP NEGATIVE ?
 	OR	A
 	JP	M,NEGOP		;YES, COMPLEMENT
 	RET			;ELSE RETURN
 NEGOP	LD	HL,SIGNS
 	DEC	(HL)
 	LD	IX,FOPLSW	;FPOP LSB
 	LD	B,3
 	JP	COMPLM		;COMPLEMENT FPOP AND RET
 ;	FLOATING POINT DIVISION
 FPDIV	CALL	CKSIGN		;CLEAR WORK AREA
 	LD	A,(FPMSW)	;CHECK FOR DIVIDE BY 0
 	OR	A
 	JR	Z,ERRORD	;DIVIDE ERROR
 SUBEXP	LD	A,(FOPEXP)	;DIVIDEND EXPONENT
 	SCF
 	LD	HL,FPACCE	;DIVISOR
 	SBC	A,(HL)		;SUBTRACT EXPONENT
 	LD	(HL),A		;SAVE INTO EXPONENT
 	INC	(HL)		;COMPENSATE FOR DIVIDE
 SETDCT	LD	A,17H		;BIT COUNTER STORAGE
 	LD	E,A		;SAVE HERE
 DIVIDE	CALL	SETSUB		;DIVIDEND MINUS DIVISOR
 	JP	M,NOGO		;ROTATE 0 IN QUOTIENT
 	LD	IY,FOPLSW	;POINT TO DIVIDEND
 	LD	IX,WORK0	;POINT TO QUOTIENT
 	LD	B,3
 	CALL	MOVIND		;MOVE QUOTIENT TO DIVIDEN
 	SCF
 	JP	QUOROT		;ROTATE INTO QUOTIENT
 ERRORD	LD	HL,ERRMES	;ERROR MESSAGE
 	LD	A,99		;BAD FLAG
 	RET			;RETURN IN ERROR
 NOGO	OR	A		;CLEAR CARRY FLAG
 QUOROT	LD	IX,WORK4	;QUOTIENT LSB
 	LD	B,3
 	CALL	ROTL		;CARRY INTO LSB OF QUOT.
 	LD	IX,FOPLSW	;DIVIDEND LSB
 	LD	B,3
 	CALL	ROTATL		;ROTATE DIVIDEND
 	DEC	E		;DECREMENT COUNTER
 	JR	NZ,DIVIDE	;CONTINUE IF NOT DONE
 	CALL	SETSUB		;ONE MORE FOR ROUNDING
 	JP	M,DVEXIT	;IF MINUS, NO ROUNDING
 	LD	A,1		;ADD TO 23'RD BIT
 	OR	A		;CLEAR CARRY FLAG
 	LD	HL,WORK4	;LSB OF QUOTIENT
 	ADC	A,(HL)		;ROUND OFF BYTE
 	LD	(HL),A		;SAVE IT
 	LD	A,0		;CLEAR A, NOT CARRY
 	INC	HL		;POINT TO WORK5
 	ADC	A,(HL)		;ADD TO BYTE
 	LD	(HL),A		;SAVE IT
 	LD	A,0		;CLEAR A, NOT CARRY
 	INC	HL		;POINT TO WORK6
 	ADC	A,(HL)		;ADD TO MSB
 	LD	(HL),A		;SAVE IT
 	OR	A		;FLAGS
 	JP	P,DVEXIT	;IF MSB=0, EXIT
 	LD	IX,WORK6	;ELSE PREPARE TO
 	LD	B,3		;	ROTATE RIGHT
 	CALL	ROTATR
 	LD	HL,FPACCE	;COMPENSATE EXPONENT
 	INC	(HL)		;	FOR ROTATE
 DVEXIT	LD	IY,FPLSWE	;FPACC
 	LD	IX,WORK3	;QUOTIENT
 	LD	B,4		;PRECISION
 	JP	EXMLDV		;MOVE QUOTIENT TO FPACC
 SETSUB	LD	IY,WORK0	;POINT TO WORK AREA
 	LD	IX,FPLSW	;FPACC
 	LD	B,3
 	CALL	MOVIND		;MOVE FPACC TO WORK AREA
 	LD	IY,WORK0	;PREPARE FOR SUBTRACTION
 	LD	IX,FOPLSW	;FPOP LSB-1
 	LD	D,0		;INITIALIZE INDEX
 	LD	B,3		;PRECISION
 	SCF
 SUBR1	LD	A,(IX)		;GET FPOP BYTE
 	SBC	A,(IY)		;SUBTRACT FPACC BYTE
 	LD	(IY),A		;SAVE IN PLACE OF DIVISOR
 	INC	IX
 	INC	IY
 	DEC	D		;COUNTER
 	JR	NZ,SUBR1	;CONTINUE SUBTRACTION
 	LD	A,(WORK2)	;SET SIGN BIT RESULT
 	OR	A		;SET FLAGS
 	RET			;FLAG IS CONDITIONED
 ERRMES	DEFB	0DH
 	DEFM	'BAD INPUT TO FLOATING POINT DIVISION.'
 	DEFB	3		;TERMINATOR
 ;	FLOATING POINT OUTPUT
 ;	DATA STORAGE
 INMTAS	DEFB	0		;I/O MANTISSA SIGN
 INEXPS	DEFB	0		;I/O EXPONENT SIGN
 INPRDI	DEFB	0		;I/O PERIOD INDICATOR
 IOLSW	DEFB	0		;I/O WORK AREAS LSB
 IONSW	DEFB	0		;NEXT MSB
 IOMSW	DEFB	0		;WORK AREAD MSB
 IOEXP	DEFB	0		;I/O WORK AREA EXPONENT
 IOSTR	DEFB	0		;I/O STORAGE
 IOSTR1	DEFB	0
 IOSTR2	DEFB	0
 IOSTR3	DEFB	0
 IOEXPD	DEFB	0		;I/O EXPONENT STORAGE
 TPLSW	DEFB	0		;TEMPORARY INPUT LSB
 TPNSW	DEFB	0		;NEXT MSB
 TPMSW	DEFB	0		;TEMPORARY INPUT MSB
 TPEXP	DEFB	0		;EXPONENT
 TEMP1	DEFB	0		;RESIDE ON PAGES
 ;	TO OUTPUT A FLOATING POINT NUMBER
 ;	NUMBER IS IN FPACC
 ;	DE => WHERE TO DISPLAY ON VIDEO
 FPOUT	XOR	A		;CLEAR ALL FLAGS
 	LD	(IOEXPD),A	;CLEAR EXPONENT
