*************************************************
* code to compute e constant to 287273 digits
* Chris Lomont Jul 2007 www.lomont.org
*************************************************
SCREENSIZE	equ	$240			* screensize in bytes
TEMP		equ	$8000+SCREENSIZE	* 2 bytes, temp storage
CARRY		equ	TEMP+2			* 1 byte for carry amount
MODULUS		equ	CARRY+1			* 2 byte modulus
PAGEVAL		equ	MODULUS+2		* 1 byte for current memory page $30-$3F
TOPBYTE		equ	PAGEVAL+1		* 1 byte for extended 3 byte math	

	org 	16384
* program start for running mode - on entry U=Y=D=0 and S points past bytes to erase 	
app	pshs	y,d,u		* set 6 bytes
	pshs	y,d,u		* set 6 bytes
	ldy	#$8002		* Y holds next digit pos at all times
	 
* here is the digit loop - start by computing the next digit by processing all 128K of RAM
infloop	ldx	#61441		* initial modulus for 15 pages - modified by loader
	stx	MODULUS
	ldx	#0		* start past code on page $30 - modified by loader
	ldb	#$30		* start on page $30
	stb	PAGEVAL
	clr	CARRY		* start with no carry byte
	
npage	stb	#$FFA0		* next page in, X must point to start

* Compute 10 * value in ,X
xloop	clr	TOPBYTE		* 0 the high byte
	ldd	,x		* the value, need 10*X
	rolb	
	rola			* 2*X
	bcc	>		* overflow?
	inc	TOPBYTE		* if so, increment top byte
!	std	TEMP		* save this	
	rolb
	rola			* 4*X
	bcc	>
	inc	TOPBYTE	
!	rolb
	rola			* 8*X
	bcc	>
	inc	TOPBYTE
!	addd	TEMP		* 8*X + 2*X = 10*X
	bcc	>
	inc	TOPBYTE
!	std	TEMP		* now add in the carry
	clra
	ldb	CARRY
	addd	TEMP		
	bcc	timesok
	inc	TOPBYTE
timesok	clr	CARRY		* erase this, and prepare to refill it

* now D holds 10*X+CARRY, must reduce mod MODULUS
reduce	tst	TOPBYTE		* if not zero, must reduce mod M
	beq	reduce2
	inc	CARRY
	subd	MODULUS		* reduce
	bcc	reduce
	dec	TOPBYTE
	bra	reduce
reduce2	cmpd	MODULUS
	bmi	reduced
	subd	MODULUS
	inc	CARRY
	bra	reduce2
reduced	std	,x++		* the new x value
	ldd	MODULUS
	subd	#1
	std	MODULUS		* new modulus
	cmpx	#$2000		* new page?
	bne	xloop		* no, do the next pass

	inc	PAGEVAL		* get the next page to process
	ldb	PAGEVAL
	ldx	#0		* reset the pointer
	cmpb	#$40		* see if done
	blt	npage	
	
* at this point, CARRY has a value 0-9 for the next digit
	
* now write to screen
	ldb	CARRY
	addb	#$30		* value 		
!	stb	,y+
	cmpy	#$8000+256	* last digit position on screen
	blt	>		* wraparound - do a page increment		
	ldy	#$8000		* top digit
!	ldb	#$2A		* multiply * symbol	
	stb	,y		* show space

* increment digit counter
* uses registers B,X
	ldx	#$81FF-7	* last digit
!	ldb	#$3A		* overflow
	inc	,x
	cmpb	,x		* overflow test
	bgt	bound		* no overflow, done
	ldb	#$30
	stb	,x
	leax	-1,x
	cmpx	#$8200-32	* todo - check for largest digit and stop
	bgt	<

* compare to final digit, stop if hit match
bound	ldx	#$8200-6
	ldu	#$8200-13
	ldd	,x++
	cmpd	,u++
	bne	pause		
	ldd	,x++
	cmpd	,u++
	bne	pause
	ldd	,x++
	cmpd	,u++
	bne	pause
	bra	bound				

** check for pause and do 
pause	ldb	$FF00		* read output
*	comb			* reverse bits to high to see what was pressed
*	andb	#$7F		* strip unused high bit, all 0 means no keys down
	incb			* todo - may fail with joysticks?
	bne	pause		* loop if key down - 0 bit means not down


nxtpass lbra	infloop

************ The end of the main application, here is where digits start in memory
	even			* make sure aligned on even address
data	fdb 	1,1,1,1,1,1,1,1,1,1 * initialized words

******* initial screen **********************************
*****************12345678901234567890123456789012********
msg	fcc	"2.                              "  * 1	
	fcc	"                                "  * 2 
	fcc	"                                "  * 3 
	fcc	"                                "  * 4 
	fcc	"                                "  * 5 
	fcc	"                                "  * 6 
	fcc	"                                "  * 7 
	fcc	"                                "  * 8 
	fcc	"--------------------------------"  * 9	
	fcc	"Computing Euler's natural base e"  * 10 
	fcc	"to 287273 digits,by Chris Lomont"  * 11
	fcc	"      WWW.LOMONT.ORG, 2007      "  * 12
	fcc	"    A CoCo3 record for e!!!     "  * 13
	fcc	" Press and hold a key to pause. "  * 14
	fcc	"Check out my site for more items"  * 15
	fcc	"Digits completed   000001/287300"  * 16
	fcc	"e is approx 2.718281828459045..."  * 17  
	fcc	"--------------------------------"  * 18	
		

* Steps:
*    1. start initialization - speed, interrupts, mem page, video
*    2. copy program to high memory and jump there
*    3. erase uneeded part of program
*    4. jump to running mode

* entry point for Step 1 and EXEC
entrypt	orcc	#$50		* turn off interrupts
	sta	$FFD9		* high speed poke

	lda	#$68		* 0b0110 1000 = 0x40
	sta	$FF90		* enable MMU, disable GIME interrupts

	lda	#$30		* GIME page $30 - bottom 128K page
	sta	$FFA4		* map to CPU $8000

* copy prog to after video ram and jump there
	ldx	#$8000+SCREENSIZE
	leay	app,pcr
!	lda	,y+
	sta	,x+
	cmpx	#$A000		* plenty of size copied - todo dynamic sized?
	blt	<
	lbra	#begin-app+$8000+SCREENSIZE * jump to start in $8000 block

begin	nop			* after prog copied, jump here, todo - make useful


* prepare keyboard for reading keys
	clr	$FF01		* clear control register A
	clr	$FF03		* clear control register B
	clr	$FF00		* set side PIA0 side A to input
	ldd	#$FF34
	sta	$FF02		* set PIA0 side B to output
	stb	$FF01	
	stb	$FF03
	
	clrb			* ground all bits
	stb	$FF02		* set column strobe
	

* load screen
	ldx	#$8000		* new screen location
	leay	msg,pcr		* get initial screen
msgloop	lda	,y+
!	sta	,x+	
	cmpx	#$8000+SCREENSIZE
	bne	msgloop

* set videopage to $8000
*	sta	$FFC6		* set text screen start to CPU $8000
*	sta	$FFC8		* todo - do after screen drawn there
*	sta	$FFCA
*	sta	$FFCC
*	sta	$FFCE
*	sta	$FFD0
*	sta	$FFD3

* set CoCo3 video mode and text start to $8000 - page $30


* set CoCo3 video mode and text start to $8000 - page $30
	lda	#$26		* 0b0010 0110 - text, color, 12 lines per char 	
	sta	$FF98		* set video mode
	lda	#0		* 0b00000000
	sta	$FF99		* video resolution
	lda	#$00
	sta	$FF9C		* Vertical scroll to 0
	ldd	#$C000		* $60000/8
	std	$FF9D
	
* set white letters on black screen?
	clra			* black
	sta	$FFB0		* background black
	lda	#48		* 48 for CMP, 63 for RGB todo
	sta	$FFB8		* foreground
		

*** initialize GIME memory pages $31 through $3F
	lda	#$31		* pages $31-$3F
	ldy	#1
clrmem	sta	$FFA0		* map to addresses $0000-$1FFF
	ldx	#0
!	sty	,x++
	cmpx	#$2000
	blt 	<
	inca	
	cmpa	#$40
	blt	clrmem

	lda	#$80	
	tfr	a,dp		* set DP for smaller, faster code - todo - use well

* initialize page $30 except for vidmem and program in use, page $30 at $8000 right now
* this has to be aligned to word, and above code needs set
	leas	final,pcr	* prepare for cleaning with PSHS, even aligned
	tfr	s,d
	andb	#1		* see if even
	beq	>		* was even, nothing to do
	leas	1,s		* bump one place
	
!	tfr	s,d		* compute initial modulus, overwrite code
	ldd	#8192		* bytes per page
	subd	#SCREENSIZE+data-app * bytes left to work with
	addd	#1		* round up
	rora	
	rorb			* divide by two - number of words free	
	addd	#61440+1	* # of words in other pages + offset of 1
	std	TEMP+9		* overwrite modulus code

	ldd	#SCREENSIZE+data-app	
	std	TEMP+15		* overwrite memory start
	
	ldd	#$0001		* initial value for some registers
	tfr	d,y		* store 1 in each word
	tfr	d,u		*
	
	leax	final,pcr	* clear rest of page
!	std	,x++
	cmpx	#$A000		
	blt	<	
	
	
	leax	data,pcr	* start clearing here
clrstop	nop
!	std	,x++		* must store 2 bytes at a time
	cmpx	#$8000+SCREENSIZE+clrstop-app
	blt	<
		
	lbra	app		* 3 bytes run the main application
	
	even
final	end	entrypt		* set BASIC exec address


*************************************************
* End of file
*************************************************


