diff basic/fbasic.asm @ 57:2088fd998865

sbc09 directry clean up
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 23 Jul 2018 16:07:12 +0900
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/basic/fbasic.asm	Mon Jul 23 16:07:12 2018 +0900
@@ -0,0 +1,1344 @@
+	;FBASIC, Floating point BASIC.
+
+	;This is not a BASIC interpreter, but a simple RPN calculator
+	;to test the floating point routines. As such it is not a finished
+	;application.
+	;Written in 1996 by Lennart Benschoo.
+	;
+	;2014-07-26: Added welcome message, a few more comments.
+	
+		;Configuration info, change this for different apps.
+ROM		equ 0		;Flag to indicate that BASIC is in ROM
+ROMSTART	equ $8000	;First ROM address.
+RAMSTART	equ $400	;First RAM address.
+RAMTOP		equ $8000	;Last RAM address +1.				
+
+PROGORG		equ ROM*ROMSTART+(1-ROM)*RAMSTART
+
+		;First the O.S. vectors in the zero page.		
+		org $0000
+* First the I/O routine vectors.
+getchar		rmb 3		;Jump to getchar routine.
+putchar		rmb 3		;Jump to putchar routine.
+getline		rmb 3		;Jump to getline routine.
+putline		rmb 3		;Jump to putline routine.
+putcr		rmb 3		;Jump to putcr routine.
+getpoll         rmb 3           ;Jump to getpoll routine.
+xopenin		rmb 3		;Jump to xopenin routine.
+xopenout	rmb 3		;Jump to xopenout routine.
+xabortin	rmb 3           ;Jump to xabortin routine.
+xclosein	rmb 3		;Jump to xclosein routine.
+xcloseout	rmb 3		;Jump to xcloseout routine.
+delay		rmb 3		;Jump to delay routine.
+
+timer 		equ *+6		;3-byte timer.
+linebuf		equ $200	;Input line buffer
+xerrvec		equ $280+6*3	;Error vector.
+
+* Now BASIC's own zero-page allocations.
+		org $40
+startprog	rmb 2		;Start of BASIC program.
+endprog		rmb 2		;End of BASIC program.
+endvar		rmb 2		;End of variable area.
+fpsp		rmb 2		;Floating point stack pointer (grows up).
+endmem		rmb 2
+
+intbuf		rmb 4		;Buffer to store integer.
+intbuf2		rmb 4
+bcdbuf		rmb 5		;Buffer for BCD conversion.
+
+endstr		rmb 2		;End address of string.
+dpl		rmb 1		;Decimal point location.
+
+* The BASIC interpreter starts here.
+		org PROGORG
+cold		jmp docold
+warm		bra noboot
+
+* Cold start routine.
+docold		ldx #RAMTOP
+		stx endmem
+		tfr x,s	
+		ldu #FREEMEM
+		stu startprog
+		clr ,u+
+		clr ,u+
+		stu endprog
+		ldx PROGEND
+		leax 1,x
+		beq noboot	;Test for autoboot program.
+		ldx #PROGEND
+		stx startprog
+		jmp dorun
+noboot		jsr doclear
+	;; Print a welcome message first.
+		ldx #nbmesg
+		ldb #nbmend-nbmesg
+		jsr putline
+		jsr putcr
+		ldd #$4000
+		std fpsp
+		ldu fpsp
+	;; Main loop. This is a simple RPN calculator that treat
+nbloop		ldx #$5000
+		ldb #20
+		jsr getline
+		clr b,x
+		cmpb #1
+		lbne donum	; All commands are single-character, everything
+	; else is treated as a number. Also the single-character lines that
+	; are not commands are later parsed as numbers.
+		ldb ,x
+		cmpb #'+'	; Add
+		bne nb1
+		jsr fpadd
+		lbra doprint
+nb1		cmpb #'-'	; Subtract
+		bne nb2
+		jsr fpsub
+		lbra doprint
+nb2		cmpb #'*'	; Multiply
+		bne nb3	
+		jsr fpmul
+		lbra doprint
+nb3		cmpb #'/'	; Divide
+		bne nb4
+		jsr fpdiv
+		lbra doprint		
+nb4		cmpb #'q'	; Square root.
+		bne nb5
+		jsr fpsqrt
+		lbra doprint
+nb5		cmpb #'i'	; Round to -Inf INT() in BASIC.
+		bne nb6
+		jsr fpfloor
+		lbra doprint
+nb6		cmpb #'s'	; SIN() function
+		bne nb7
+		jsr fpsin
+		lbra doprint
+nb7		cmpb #'='	; Compare top two numbers Show < = or >
+		bne nb8
+		jsr fpcmp
+		beq nbeq
+		bcc nbgt
+		ldb #'<'
+		bra nbcmp
+nbeq		ldb #'='
+		bra nbcmp
+nbgt		ldb #'>'	
+nbcmp		leau -10,u
+		jsr putchar
+		jsr putcr
+		bra nbloop
+nb8		cmpb #'c'	; COS() function.
+		bne nb9
+		jsr fpcos
+		bra doprint
+nb9		cmpb #'t'	; TAN() function.
+		bne nb10
+		jsr fptan
+		bra doprint
+nb10		cmpb #'a'  	; ATAN() function.
+		bne nb11
+		jsr fpatan
+		bra doprint
+nb11		cmpb #'e'	; EXP() function.
+		bne nb12
+		jsr fpexp
+		bra doprint
+nb12		cmpb #'l'	; LN() function.
+		bne nb13
+		jsr fln
+		bra doprint
+nb13		cmpb #'d'	; Duplicate top number on stack.
+		bne nb14
+		jsr fpdup
+		bra doprint  	; Exchange top two numbers on stack.
+nb14		cmpb #'x'
+		bne nb15
+		jsr fpexg
+		bra doprint
+nb15		cmpb #'r'  	; Drop top from stack.
+		bne nb16
+		leau -5,u
+		bra doprint
+nb16
+donum		ldy #$5000
+		jsr scannum
+		lbra nbloop
+doprint		ldy #$5000
+		jsr fpdup
+		jsr fpscient
+		ldx #$5000
+		ldb ,x+
+		jsr putline
+		jsr putcr
+		lbra nbloop
+nbmesg		fcc "Welcome to RPN calculator"
+nbmend		
+	
+doclear 	rts
+dorun		swi
+makefree	rts		
+
+* Floating point primitives.
+
+* U is the floating point stack pointer and points to the first free
+* location. Each number occupies 5 bytes, 
+* Format: byte0: binary exponent  $00-$FF $80 means number in range 1..2.
+*         byte1-byte4 binary fraction between 1.0 and 2.0, msb would
+*	  always be set, but replaced by sign.
+*	  Special case: all bytes zero, number=0.
+
+* Exchange top two numbers on stack.
+fpexg		ldx -2,u
+		ldd -7,u
+		stx -7,u
+		std -2,u
+		ldx -4,u
+		ldd -9,u
+		stx -9,u
+		std -4,u
+		lda -5,u
+		ldb -10,u
+		sta -10,u
+		stb -5,u
+		rts
+
+fpdup		leax -5,u
+* Load fp number from address X and push onto stack.
+fplod		ldd ,x++
+		std ,u++
+		ldd ,x++
+		std ,u++
+		lda ,x+
+		sta ,u+
+fckmem		tfr s,d
+		stu fpsp
+		subd fpsp
+		subd #40	
+		lbcs makefree	;Test for sufficient free space.
+		rts 
+		
+* Pop fp number from stack and store into address X.
+fpsto		lda -5,u
+		sta ,x+
+		ldd -4,u
+		std ,x++
+		ldd -2,u
+		std ,x++
+		leau -5,u
+		rts
+
+* Compare magnitude (second-top).
+fpcmpmag	lda -10,u
+		cmpa -5,u	;Compare exponents.
+		bne cmpend
+		ldd -4,u
+		anda #$7F	;Eliminate sign bit.
+		std ,--s
+		ldd -9,u
+		anda #$7F	;Eliminate sign bit.
+		subd ,s++	;Compare msb of mantissa.
+		bne cmpend
+		ldd -7,u
+		subd -2,u
+		bne cmpend
+cmpend		rts
+
+* Test a top number for 0.
+fptest0		tst -5,u
+		bne cmpend
+		ldd -4,u
+		bne cmpend
+		ldd -2,u
+		rts
+
+* Floating point subtraction.
+fpsub		jsr fpneg
+
+* Floating point addition.
+fpadd		bsr fpcmpmag	;First compare magnitudes.
+		bcc fpadd1
+		jsr fpexg	;Put the biggest one second.
+fpadd1		bsr fptest0		
+		beq fpaddend	;Done if smallest number is 0.
+		lda -10,u
+		suba -5,u	;Determine exponent difference.
+		cmpa #32
+		bhi fpaddend	;Done if difference too big.
+		ldb -9,u
+		andb #$80
+		stb ,-s		;Store sign of biggest number.
+		eorb -4,u
+		stb ,-s		;Store difference of signs.
+		ldb -9,u
+		orb #$80
+		stb -9,u
+		ldb -4,u
+		orb #$80
+		stb -4,u	;Put the hidden msbs back in.
+		clr ,u		;Make extra mantissa byte.
+		tsta
+		beq fpadd2b	;Skip the alignment phase.
+fpalign		lsr -4,u
+		ror -3,u
+		ror -2,u
+		ror -1,u	;Shift the smaller number right to align
+		ror ,u
+		deca
+		bne fpalign
+fpadd2b		tst ,s+
+		bmi dosub	;Did signs differ? Then subtract.
+		ldd -7,u	;Add the mantissas.
+		addd -2,u
+		std -7,u
+		ldd -9,u
+		adcb -3,u
+		adca -4,u
+		std -9,u
+		bcc fpadd2
+fpadd2a		inc -10,u	;Sum overflowed, inc exp, shift mant.
+		lbeq fpovf	;If exponent overflowed, too bad.
+		ror -9,u
+		ror -8,u
+		ror -7,u
+		ror -6,u
+		ror ,u
+fpadd2		tst ,u
+		bpl fpadd3	;test msb of extra mantissa byte.		
+		ldd -7,u	;Add 1 to mantissa if this is set
+		addd #1         
+		std -7,u	
+		bcc fpadd3
+		ldd -9,u
+		clr ,u
+		addd #1
+		std -9,u
+		bcs fpadd2a	
+fpadd3		ldb -9,u
+		andb #$7F
+		eorb ,s+
+		stb -9,u	;Put original sign back in.		
+fpaddend 	leau -5,u
+		rts		
+dosub		ldb ,u
+		negb
+		stb ,u
+		ldd -7,u	;Signs differed, so sbutract.
+		sbcb -1,u
+		sbca -2,u
+		std -7,u
+		ldd -9,u
+		sbcb -3,u
+		sbca -4,u
+		std -9,u
+		bmi fpadd2	;Number still normalized, then done.
+		ldd -9,u
+		bne fpnorm
+		ldd -7,u
+		bne fpnorm
+		tst ,u
+		beq fpundf	;If mantissa exactly zero, underflow.
+fpnorm		tst -10,u	;dec exp, shift mant left
+		beq fpundf	;Underflow, put a zero in. 
+		dec -10,u
+		asl ,u
+		rol -6,u
+		rol -7,u
+		rol -8,u
+		rol -9,u
+		bpl fpnorm	;Until number is normalized.
+		bra fpadd2
+		
+fpundf		clr -10,u	;Underflow, substitute zero.
+		clr -9,u
+		clr -8,u
+		clr -7,u
+		clr -6,u
+		leas 1,s	;Discard the sign on stack.
+		bra fpaddend
+
+* Compare Floating Point Numbers, flags as with unsigned comparison.
+fpcmp		lda -9,u
+		anda #$80
+		sta ,-s
+		lda -4,u
+		anda #$80
+		suba ,s+	;Subtract the signs, subtraction is reversed.
+		bne fpcmpend
+		tst -9,u
+		bmi fpcmpneg	;Are numbers negative?	
+		jmp fpcmpmag
+fpcmpneg	jsr fpcmpmag
+		beq fpcmpend	
+		tfr cc,a
+		eora #$1
+		tfr a,cc	;Reverse the carry flag.
+fpcmpend	rts
+
+* Multiply floating point numbers.
+fpmul		lda -9,u
+		eora -4,u
+		anda #$80
+		sta ,-s		;Sign difference to stack.
+		jsr fptest0	;Test one operand for 0
+		beq fpundf	
+		ldd -7,u
+		bne fpmula		
+		ldd -9,u
+		bne fpmula	;And the other one.
+		ldb -10,u
+		beq fpundf
+fpmula		ldb -9,u
+		orb #$80
+		stb -9,u
+		ldb -4,u
+		orb #$80
+		stb -4,u	;Put hidden msb back in.
+		lda -10,u
+		suba #$80	;Make unbiased signed num of exponents.
+		sta ,-s
+		lda -5,u
+		suba #$80
+		adda ,s+	;add exponents.
+		bvc fpmul1	;Check over/underflow
+		lbmi fpovf
+		bra fpundf
+fpmul1		adda #$80	;Make exponent biased again.
+		sta -10,u	;Store result exponent.
+* Now perform multiplication of mantissas to 40-bit product.
+* 0,u--4,u product. 5,u--9,u added term
+* Having a mul instruction is nice, but using it for an efficient 
+* multiprecision multiplicaton is hard. This routine has 13 mul instructions.
+		lda -1,u
+		ldb -8,u
+		mul		;b4*a2
+		sta 4,u
+		lda -1,u
+		ldb -9,u
+		mul		;b4*a1
+		addb 4,u
+		adca #0
+		std 3,u
+		lda -2,u
+		ldb -7,u
+		mul		;b3*a3
+		sta 9,u
+		lda -2,u
+		ldb -8,u
+		mul		;b3*a2
+		addb 9,u
+		adca #0
+		std 8,u
+		lda -2,u
+		ldb -9,u
+		mul		;b3*a1
+		addb 8,u
+		adca #0
+		std 7,u
+		ldd 8,u
+		addd 3,u
+		std 3,u
+		ldb 7,u
+		adcb #0
+		stb 2,u		;Add b4*a and b3*a partial products.
+		lda -3,u
+		ldb -6,u
+		mul		;b2*a4
+		sta 9,u
+		lda -3,u
+		ldb -7,u
+		mul		;b2*a3
+		addb 9,u
+		adca #0
+		std 8,u
+		lda -3,u
+		ldb -8,u
+		mul		;b2*a2
+		addb 8,u
+		adca #0
+		std 7,u
+		lda -3,u
+		ldb -9,u	;b2*a1
+		mul	
+		addb 7,u
+		adca #0
+		std 6,u
+		ldd 8,u
+		addd 3,u
+		std 3,u
+		ldd 6,u
+		adcb 2,u
+		adca #0
+		std 1,u		;Add b2*a partial product in.
+		lda -4,u
+		ldb -6,u
+		mul		;b1*a4
+		std 8,u
+		lda -4,u
+		ldb -7,u
+		mul		;b1*a3
+		addb 8,u
+		adca #0
+		std 7,u
+		lda -4,u
+		ldb -8,u
+		mul		;b1*a2
+		addb 7,u
+		adca #0
+		std 6,u
+		lda -4,u
+		ldb -9,u
+		mul		;b1*a1
+		addb 6,u
+		adca #0
+		std 5,u
+		ldd 8,u
+		addd 3,u
+		std -6,u
+		ldd 6,u
+		adcb 2,u
+		adca 1,u
+		std -8,u	
+		ldb 5,u
+		adcb #0
+		stb -9,u	;Add product term b1*a in, result to dest.
+		bmi fpmul2	
+		asl -5,u
+		rol -6,u
+		rol -7,u
+		rol -8,u
+		rol -9,u	;Normalize by shifting mantissa left.
+		bra fpmul3
+fpmul2		inc -10,u	;increment exponent.
+		lbeq fpovf	;Test for overflow.
+fpmul3		tst -5,u	
+		lbpl fpadd3
+		ldd -7,u	;Add 1 if msb of 5th nibble is set.
+		addd #1
+		std -7,u
+		lbcc fpadd3
+		ldd -9,u
+		addd #1
+		std -9,u
+		bcs fpmul4	;It could overflow.
+		lbra fpadd3
+fpmul4		clr -5,u
+		bra fpmul2
+
+* Divide floating point numbers.
+fpdiv		lda -9,u
+		eora -4,u
+		anda #$80
+		sta ,-s		;Sign difference to stack.
+		jsr fptest0	;Test divisor for 0
+		lbeq fpovf	
+		ldd -7,u
+		bne fpdiva		
+		ldd -9,u
+		bne fpdiva	;And the other one.
+		ldb -10,u
+		lbeq fpundf
+fpdiva		ldb -9,u
+		orb #$80
+		stb -9,u
+		ldb -4,u
+		orb #$80
+		stb -4,u	;Put hidden msb back in.
+		lda -5,u
+		suba #$80	;Make unbiased signed difference of exponents.
+		sta ,-s
+		lda -10,u
+		suba #$80
+		suba ,s+	;subtract exponents.
+		bvc fpdiv1	;Check over/underflow
+		lbmi fpovf
+		lbra fpundf
+fpdiv1		adda #$80	;Make exponent biased again.
+		sta -10,u	;Store result exponent.
+* Now start the division of mantissas. Temprorary 34-bit quotient in 0,u--4,u
+* -5,u is extra byte of dividend.
+		lda #34
+		sta ,-s
+		clr ,u
+		clr 1,u
+		clr 2,u
+		clr 3,u
+		clr 4,u
+		clr -5,u
+fpdivloop	asl 4,u		;Shift quotient left.
+		rol 3,u
+		rol 2,u
+		rol 1,u
+		rol ,u		
+		ldd -7,u	;Perform trial subtraction.
+		subd -2,u	
+		std -7,u
+		ldd -9,u
+		sbcb -3,u
+		sbca -4,u
+		std -9,u
+		ldb -5,u
+		sbcb #0
+		bcc fpdiv2
+		ldd -7,u	;Undo the trial subtraction.		
+		addd -2,u	
+		std -7,u
+		ldd -9,u
+		adcb -3,u
+		adca -4,u
+		std -9,u
+		bra fpdiv4
+fpdiv2		stb -5,u	;Store new msb of quotient.
+		lda 4,u		;Add 1 to quotient.
+		adda #$40
+		sta 4,u
+fpdiv4		asl -6,u	;Shift dividend left.
+		rol -7,u
+		rol -8,u
+		rol -9,u
+		rol -5,u
+		dec ,s
+		bne fpdivloop
+		leas 1,s
+		ldd 3,u
+		std -6,u
+		ldd 1,u
+		std -8,u
+		ldb ,u
+		stb -9,u	;Move quotient to final location.
+		bmi fpdiv3	
+fpdiv5		asl -5,u
+		rol -6,u
+		rol -7,u
+		rol -8,u
+		rol -9,u	;Normalize by shifting mantissa left.
+		ldb -10,u	;decrement exponent.
+		lbeq fpundf	;Test for underflow.
+		decb
+		stb -10,u
+fpdiv3		tst -5,u	
+		lbpl fpadd3
+		ldd -7,u	;Add 1 if msb of 5th nibble is set.
+		addd #1
+		std -7,u
+		lbcc fpadd3
+		ldd -9,u
+		addd #1
+		std -9,u
+		lbcs fpmul4	;This addition could overflow.
+		lbra fpadd3				
+
+* Floating point negation.
+fpneg		jsr fptest0
+		beq fpnegend	;Do nothing if number equals zero.
+		lda -4,u
+		eora #$80
+		sta -4,u	;Invert the sign bit.	
+fpnegend	rts
+
+* Convert unsigned double number at X to float.
+ufloat		leau 5,u	;Make room for extra number on stack.
+		ldd ,x
+		std -4,u
+		ldd 2,x
+		clr -5,u
+uf16		std -2,u	;Transfer integer to FP number.	
+		jsr fptest0
+		beq ufzero
+		ldb #$9f	;Number is not zero.		
+		stb -5,u
+		tst -4,u
+		bmi ufdone
+ufloop		dec -5,u	;Decrement exponent.
+		asl -1,u
+		rol -2,u
+		rol -3,u
+		rol -4,u	;Shift mantissa.
+		bpl ufloop	;until normalized.
+ufdone		ldb -4,u
+		andb #$7f
+		stb -4,u	;Remove the hidden msb.
+ufend		jmp fckmem 	;Check that fp stack does not overflow
+ufzero		clr -5,u	;Make exponent zero as well.
+		bra ufend
+
+* Convert unsigned 16-bit integer in D to floating point.
+unint2fp	clr ,-s
+		bra i2fp2
+* Convert signed 16-bit integer in D to floating point.
+int2fp		sta ,-s		;Store sign byte.
+		bpl i2fp2
+		comb
+		coma
+		addd #1		;Negate D if negative.
+i2fp2		leau 5,u
+		clr -4,u
+		clr -5,u
+		clr -3,u	;Clear msb	
+		jsr uf16	
+		tst ,s+
+		bmi fpneg
+		rts		;Negate number if it was negative.
+
+* Convert float to unsigned 32-bit integer at X.
+* A is nonzero if number was not integer or zero.
+uint		ldd -4,u
+		ora #$80	;Put the hidden msb back in.
+		std ,x
+		ldd -2,u
+		std 2,x		;Transfer mantissa.
+		clra
+		ldb -5,u
+		cmpb #$80	;If less than 1, it's 0		
+		blo uizero
+		cmpb #$9f
+		lbhi intrange	;2^32 or higher, that's too bad. 		
+		beq uidone
+uiloop		lsr ,x
+		ror 1,x
+		ror 2,x
+		ror 3,x		;Adjust integer by shifting to right
+		adca #0		;Add any shifted out bit into A.
+		incb				
+		cmpb #$9f
+		blo uiloop 
+uidone		leau -5,u
+		rts
+uizero		inca		; Indicate non-integer.
+		clr ,x		; Number is zero
+		clr 1,x
+		clr 2,x
+		clr 3,x
+		leau -5,u
+	        rts   
+
+* Convert fp number to signed or unsigned 16-bit number in D.
+* Acceptable values are -65535..65535.
+fp2uint		ldb -5,u
+		stb ,-s		;Store sign.
+		ldx #intbuf	
+		bsr uint
+		ldx ,x
+		lbne intrange	;Integer must be in 16-bit range.
+		ldd intbuf+2
+		tst ,s+
+		bpl fp2iend
+		comb
+		coma
+		addd #1		;Negate number if negative.
+fp2iend		rts
+* Convert fp number to signed 16-bit number in D. 
+fp2int		ldb -5,u
+		stb ,-s		;Store sign of FP number.
+		bsr fp2uint
+		pshs d
+		eora ,s+
+		lbmi intrange	;Compare sign to what it should be. 
+		puls d,pc
+
+* Scan a number at address Y and convert to integer or floating point
+scannum		jsr skipspace
+		clr ,-s		;Store sign on stack.
+		cmpb #'-'	;Test for minus sign.
+		bne sn1
+		inc ,s		;Set sign on stack
+		ldb ,y+
+sn1		jsr scanint	;First scan the number as an integer.
+		ldx #intbuf
+		jsr ufloat	;Convert to float.
+		ldb -1,y
+sn1loop		cmpb #'.'
+		bne sn1c
+		tst dpl		;If dpl already set, accept no other point.
+		bne sn1d
+		inc dpl
+		ldb ,y+
+		bra sn1loop
+sn1c		subb #'0'
+		blo sn1d
+		cmpb #9
+		bhi sn1d
+		clra
+		jsr int2fp	;Convert digit to fp
+		jsr fpexg
+		ldx #fpten
+		jsr fplod
+		jsr fpmul	;Multiply original number by 10.
+		jsr fpadd	;Add digit to it.
+		tst dpl
+		beq sn1k
+		inc dpl		;Adjust dpl (one more digit after .)
+sn1k		ldb ,y+
+		bra sn1loop		
+sn1d		tst ,s+
+		beq sn1a
+		jsr fpneg	;Negate the number if negative.
+sn1a		clr ,-s
+		clr ,-s		;Prepare exponent part on stack.
+		ldb -1,y
+		cmpb #'e'
+		beq sn1e
+		cmpb #'E'
+		bne sn1f	;Test for exponent part.
+sn1e		ldb ,y+
+		clr ,-s		;Prepare exponent sign on stack.
+		cmpb #'+'
+		beq sn1g
+		cmpb #'-'
+		bne sn1h
+		inc ,s		;Set sign to negative.
+sn1g		ldb ,y+
+sn1h		lda dpl
+		pshs a
+		clr dpl
+		inc dpl
+		jsr scanint	;Scan the exponent part.
+		puls a
+		sta dpl		;Restore dpl.
+		lda intbuf
+		ora intbuf+1
+		ora intbuf+2
+		lbne fpovf	;Exponent may not be greater than 255.
+		ldb intbuf+3
+		lbmi fpovf	;Not even greater than 127.
+		tst ,s+
+		beq sn1i
+		negb
+sn1i		sex
+		std ,s
+sn1f		ldb dpl
+		beq sn1j
+		decb
+sn1j		negb
+		sex
+		addd ,s++	;Add exponent part as well
+		pshs d
+		ldx #fpten
+		jsr fplod
+		puls d
+		jsr fpipower
+		jsr fpmul
+sn1b		rts		
+
+* Scan integer number below 1e9 at address Y, first digit in B.
+scanint		clr dpl
+scanint1	clr intbuf
+		clr intbuf+1
+		clr intbuf+2
+		clr intbuf+3	;Initialize number
+snloop		cmpb #'.'	
+		bne sn2a	;Test for decimal point.
+		tst dpl
+		bne sndone	;Done if second point found.
+		inc dpl		;Set dpl to indicate decimal point.
+		bra sn3
+sn2a		subb #'0'
+		blo sndone
+		cmpb #9
+		bhi sndone	;Check that character is a digit.
+		tst dpl
+		beq sn2b
+		inc dpl		;Incremend deecimal point loc if set.
+sn2b		pshs b
+		ldd intbuf+2
+		aslb
+		rola
+		std intbuf+2
+		std intbuf2+2
+		ldd intbuf
+		rolb
+		rola
+		std intbuf
+		std intbuf2
+		asl intbuf+3
+		rol intbuf+2
+		rol intbuf+1
+		rol intbuf
+		asl intbuf+3
+		rol intbuf+2
+		rol intbuf+1
+		rol intbuf
+		ldd intbuf+2
+		addd intbuf2+2
+		std intbuf +2
+		ldd intbuf
+		adcb intbuf2+1
+		adca intbuf2
+		std intbuf	;Multiply the integer by 10
+		ldd intbuf+2
+		addb ,s+	;Add the digit in.
+		adca #0
+		std intbuf+2
+		bcc sn2
+		ldd intbuf
+		addd #1
+		std intbuf
+sn2		ldd intbuf
+		cmpd #$5f5      
+		blo sn3
+		bhi snovf
+		ldd intbuf+2	;note $5f5e100 is 100 million
+		cmpd #$e100	;Compare result to 100 million 
+		bhs snovf
+sn3		ldb ,y+		;get next digit.
+		bra snloop		
+snovf		ldb ,y+		;get next digit.
+sndone		ldb -1,y
+		rts
+
+*Convert integer at X to BCD.
+int2bcd		clr bcdbuf
+		clr bcdbuf+1
+		clr bcdbuf+2
+		clr bcdbuf+3
+		clr bcdbuf+4
+		ldb #4
+tstzero		tst ,x+
+		bne bcd1
+		decb
+		bne tstzero	;Skip bytes that are zero.
+		bra sndone	;Done if number already zero.	
+bcd1		stb ,-s		;Store number of bytes.
+		leax -1,x
+bcdloop		ldb #8
+bcdloop1	rol ,x		;Get next bit of binary nunber
+		lda bcdbuf+4
+		adca bcdbuf+4
+		daa
+		sta bcdbuf+4
+		lda bcdbuf+3
+		adca bcdbuf+3
+		daa
+		sta bcdbuf+3
+		lda bcdbuf+2
+		adca bcdbuf+2
+		daa
+		sta bcdbuf+2
+		lda bcdbuf+1
+		adca bcdbuf+1
+		daa
+		sta bcdbuf+1
+		lda bcdbuf
+		adca bcdbuf
+		daa
+		sta bcdbuf	;Add BCD number to itself plus the extra bit.
+		decb
+		bne bcdloop1		
+		leax 1,x
+		dec ,s
+		bne bcdloop
+		leas 1,s	;Remove counter from stack.
+		rts
+
+* Raise fp number to an integer power contained in D. 
+fpipower	sta ,-s		;Store sign of exponent.
+		bpl fppow1	;Is exponent negative.
+		coma
+		comb
+		addd #1		;Take absolute value of exponent.
+fppow1		std ,--s	;Store the exponent.
+		ldx #fpone
+		jsr fplod	;Start with number one.
+fppowloop	lsr ,s
+		ror 1,s		;Divide exponent by 2.
+		bcc fppow2	;Test if it was odd.
+		leax -10,u
+		jsr fplod
+		jsr fpmul	;Multiply result by factor.
+fppow2		ldd ,s
+		beq fppowdone	;Is exponent zero?
+		leax -10,u
+		jsr fplod
+		jsr fpdup
+		jsr fpmul	;Sqaure the factor.
+		leax -15,u
+		jsr fpsto	;Store it in its place on stack.
+		bra fppowloop				
+fppowdone	leas 2,s	;Remove exponent.
+		tst ,s+
+		bpl fppow3	;Was exponent negative?
+		ldx #fpone
+		jsr fplod
+		jsr fpexg
+		jsr fpdiv	:compute 1/result.
+fppow3		jsr fpexg
+		leau -5,u	;Remove factor from stack.
+		rts								
+
+
+* Convert fp number to string at address Y in scientific notation.
+fpscient	ldb #15
+		stb ,y+		;Store the string length.
+		lda #' '
+		ldb -4,u
+		bpl fpsc1
+		lda #'-'
+fpsc1		sta ,y+		;Store - or space depending on sign.
+		andb #$7f
+		stb -4,u	;Make number positive.
+		clr ,-s		;Store decimal exponent (default 0)
+		jsr fptest0		
+		beq fpsc2	;Test for zero
+		lda -5,u
+		suba #$80
+		suba #$1D	;Adjust exponent.
+		bvc fpsc11a
+		lda #-128
+fpsc11a		sta ,-s		;store it to recover sign later.
+		bpl posexp
+		nega		;Take absolute value.
+posexp		ldb #5
+		mul
+		lsra
+		rorb
+		lsra
+		rorb
+		lsra
+		rorb
+		lsra
+		rorb		;multiply by 5/16 approx 10log 2
+		cmpb #37
+		bls expmax
+		ldb #37	;Maximum decimal exponent=37
+expmax		tst ,s+
+		bpl posexp1
+		negb
+posexp1		stb ,s		;Store approximate decimal exponent.
+		negb
+		sex		;Approximate (negated) decimal exponent in D.
+		pshs d
+		ldx #fpten
+		jsr fplod
+		puls d
+		jsr fpipower	;Take 10^-exp
+		jsr fpmul
+fpsc1a		ldx #fplolim
+		jsr fplod
+		jsr fpcmpmag	;Compare number to 100 million
+		leau -5,u
+		bhs fpsc1c
+		dec ,s		;Decrement approximate exponent.
+		ldx #fpten
+		jsr fplod
+		jsr fpmul	;Multiply by ten.
+		bra fpsc1a
+fpsc1c		ldx #fphilim
+		jsr fplod
+		jsr fpcmpmag	;Compare number to 1 billion
+		leau -5,u
+		blo fpsc1d
+		inc ,s		;Increment approximate exponent.
+		ldx #fpten
+		jsr fplod
+		jsr fpdiv	;Divide by ten.
+		bra fpsc1c
+fpsc1d		ldb ,s
+		addb #8
+		stb ,s		;Adjust decimal exponent (8 decimals)
+		ldx #fphalf
+		jsr fplod
+		jsr fpadd	;Add 0.5 for the final round to integer.		
+* Number is either zero or between 100 million and 1 billion.
+fpsc2		ldx #intbuf
+		jsr uint	;Convert decimal mantissa to integer.
+		jsr int2bcd	;Convert to bcd.
+		ldb bcdbuf
+		addb #'0'
+		stb ,y+		;Store digit before decimal point
+		ldb #'.'
+		stb ,y+		;Store decimal point.
+		lda #4
+		sta ,-s
+		ldx #bcdbuf+1
+fpscloop	lda ,x+
+		tfr a,b
+		lsrb
+		lsrb
+		lsrb
+		lsrb
+		addb #'0'	
+		stb ,y+
+		anda #$0f
+		adda #'0	
+		sta ,y+
+		dec ,s		;Convert the other 8 digits to ASCII
+		bne fpscloop
+		leas 1,s	;Remove loop counter.
+		ldb #'E'
+		stb ,y+		;Store the E character.
+		lda #'+'
+		ldb ,s+		;Get decimal exponent.
+		bpl fpsc3	;Test sign of exponent.
+		lda #'-'
+		negb		;Take absolute value of exponent.
+fpsc3		sta ,y+		;Store sign of exponent.
+		stb intbuf+3
+		clr intbuf+2
+		clr intbuf+1
+		clr intbuf
+		ldx #intbuf
+		jsr int2bcd	;Convert decimal exponent to bcd.
+		lda bcdbuf+4
+		tfr a,b
+		lsrb
+		lsrb
+		lsrb
+		lsrb
+		addb #'0'	
+		stb ,y+		;Convert first exp digit to ascii
+		anda #$0f
+		adda #'0'
+		sta ,y+		;And the second one.
+		rts
+
+
+		include "floatnum.inc"
+
+fpovf		swi
+intrange	swi
+inval		swi
+
+* This routine takes the square root of an FP number.
+* Uses Newton's algorithm.
+fpsqrt		tst -4,u
+		lbmi inval	;Negative arguments are invalid.
+		jsr fptest0
+		beq sqdone	;Sqaure root of 0 is 0.
+		jsr fpdup
+		ldb -5,u
+		subb #$80	;Unbias the exponent.
+		bpl sq1
+		addb #1
+sq1		asrb		;Divide exponent by 2.
+		addb #$80	;Make it biased again.
+		stb -5,u	;This is the initial guess for the root.
+		ldb #4		;Do the loop 4 times.
+		stb ,-s
+sqloop		leax -10,u
+		jsr fplod
+		leax -10,u
+		jsr fplod
+		jsr fpdiv	;Divide argument by guess.
+		jsr fpadd	;Add to guess.
+		dec -5,u	;Divide this by two, giving new guess.
+		dec ,s
+		bne sqloop
+		leas 1,s
+		jsr fpexg	
+		leau -5,u	;Remove argument, leave final guess.
+sqdone		rts	
+			
+* Compute the floor of an fp number (result is still fp.
+fpfloor		ldb -5,u
+		cmpb #$9f
+		bhs sqdone	;If abs value >=2^31, then already integer.
+		ldb -4,u
+		stb ,-s		;Stroe sign of number
+		andb #$7f
+		stb -4,u	;Take absolute value of number.
+		ldx #intbuf
+		jsr uint	;Convert to int (truncation)
+		sta ,-s		;Store number of fraction bits.
+		ldx #intbuf
+		jsr ufloat	;Convert back to float
+		ldd ,s++
+		tstb
+		bpl sqdone
+		sta ,-s
+		jsr fpneg	;Negate number if it was negative
+		lda ,s+
+		beq sqdone
+		ldx #fpone
+		jsr fplod
+		jmp fpsub	;Subtract 1 if negative & not integer.
+		
+* Floating point modulo operation (floored modulo).
+* Integer part of quotient is still left in intbuf
+fpmod		leax -10,u
+		jsr fplod
+		leax -10,u
+		jsr fplod
+		jsr fpdiv	;Perform division.
+		jsr fpfloor
+		jsr fpmul	;Multiply Quotient and Divisor
+		leax -10,u
+		jmp fpsub	;Dividend - quotient*divisor = modulus.		
+		
+
+* Now the transcendental functions follow.
+* They use approximation polynomials as defined in the
+* Handbook of Mathematical Functions by Abramowitz & Stegun.
+
+* Compute polynomial, number of terms in B, coefficients start at Y
+fppoly		stb ,-s
+		ldx #fpzero
+		jsr fplod	;Start with zero.
+polyloop	leax ,y
+		jsr fplod
+		jsr fpadd	;Add next coefficient.
+		leay 5,y	
+		leax -10,u		
+		jsr fplod
+		jsr fpmul	;Multiply by x.
+		dec ,s
+		bne polyloop
+		leas 1,s
+		jsr fpexg
+		leau -5,u	;Remove x from stack.
+		rts
+
+add1		ldx #fpone
+		jsr fplod
+		jsr fpadd
+		rts
+
+halfpi		ldx #fpi
+		jsr fplod
+		dec -5,u
+		rts
+
+* sin(x)
+fpsin		ldx #fpi
+		jsr fplod
+		inc -5,u	;Load 2*pi
+		jsr fpmod	;Modulo 2pi
+		bsr halfpi
+		jsr fpcmp	;Compare x to pi/2
+		bls sin2
+		inc -5,u	;Change pi/2 to pi
+		jsr fpsub
+		jsr fpneg	;x := pi-x if x>pi/2
+		bsr halfpi
+		jsr fpneg
+		jsr fpcmp	;Compare x to -pi/2
+		bhs sin2
+		inc -5,u	;Change -pi/2 to -pi
+		jsr fpsub
+		jsr fpneg
+		bra sin3
+sin2		leau -5,u	;Drop the compare limit pi/2 or -pi/2
+sin3		jsr fpdup
+		jsr fpdup
+		jsr fpmul	;On stack: x, x*x
+		ldy #sincoeff
+		ldb #5
+		jsr fppoly	;Do the sine polynomial with x*x as argument
+		jsr add1	;Add 1 to the result.
+		jmp fpmul	;multiply the polynomial result with x.				
+* cos(x)
+fpcos		jsr halfpi
+		jsr fpsub
+		jsr fpneg
+		bra fpsin	;Compute sin(pi/2-x)
+
+* tan(x)	
+fptan		jsr fpdup
+		jsr fpsin
+		jsr fpexg
+		jsr fpcos
+		jmp fpdiv	;Compute sin(x)/cos(x)
+
+* atan(x)
+fpatan		clr ,-s		;Make flag on stack
+		ldb -5,u
+		cmpb #$80	;Compare magnitude to 1.
+		blo atn1
+		inc ,s		;Set flag on stack.
+		ldx #fpone	;if x>1 then compute 1/x
+		jsr fplod
+		jsr fpexg
+		jsr fpdiv
+atn1		jsr fpdup
+		jsr fpdup
+		jsr fpmul	;On stack: x, x*x
+		ldb #8
+		ldy #atancoeff
+		jsr fppoly	;Doe the arctan polynomyal, x*x as argument.
+		jsr add1	;Add 1 to result
+		jsr fpmul	;multiply result by x.
+		tst ,s+
+		beq atndone		
+		jsr halfpi
+		jsr fpsub
+		jsr fpneg	;Compute pi/2 - result when x was >1
+atndone		rts
+
+* exp(x)
+fpexp		ldb -4,u
+		stb ,-s		;Store sign of x.
+		andb #$7f
+		stb -4,u	;Take absolute value.
+		ldx #fln2
+		jsr fplod
+		jsr fpmod	;modulo ln2.
+		ldb #7
+		ldy #expcoeff
+		jsr fppoly	;Do the exp(-x) polynomial.
+		jsr add1
+		tst ,s+
+		bpl exppos
+		ldb -5,u	;Number was negative.
+		subb intbuf+3	;Subtract the integer quotient of the modln2	
+		bcs expund	
+		lda intbuf
+		ora intbuf+1
+		ora intbuf+2
+		bne expund	;Underflow also if quotient >255
+		stb -5,u	;Store exponent.
+		rts
+exppos		ldx #fpone
+		jsr fplod
+		jsr fpexg
+		jsr fpdiv	;x was postitive, compute 1/exp(-x)
+		ldb intbuf
+		orb intbuf+1
+		orb intbuf+2	;Check int part is less than 255
+		lbne fpovf
+		ldb -5,u
+		addb intbuf+3	;Add integer part to exponent.
+		lbcs fpovf	;Check for overflow.	
+		stb -5,u
+		rts
+expund		leau -5,u
+		ldx #fpzero
+		jmp fplod	;underflow, result is zero.
+
+* ln(x) Natural logarithm
+fln		jsr fptest0
+		lbeq inval	;Don't accept zero as argument.
+		tst -4,u
+		lbmi inval	;No negative numbers either.
+		ldb -5,u
+		stb ,-s		;Save the binary exponent.
+		ldb #$80
+		stb -5,u	;Replace exponent with 1.
+		ldx #fpone	;Argument is now in range 1..2
+		jsr fplod
+		jsr fpsub	;Subtract 1.
+		ldy #lncoeff
+		ldb #8
+		jsr fppoly	;Do the ln(1+x) polynomial.
+		ldb ,s+		;Get original exponent.
+		subb #$80	;Unbias it.
+		sex
+		jsr int2fp	;Convert to fp.
+		ldx #fln2
+		jsr fplod
+		jsr fpmul	;Multiply it by ln2.
+		jmp fpadd	;Add that to result.
+
+skipspace	ldb ,y+
+		cmpb #' ' 
+		beq skipspace
+		rts
+
+PROGEND		fdb $FFFF	;Indicate there is no AUTOBOOT app.
+				;Flag can be overwritten by it.
+FREEMEM		equ ROM*RAMSTART+(1-ROM)*(PROGEND+2)
+
+
+		end
+