
;Copyright 2003 Richard Cappels projects@cappels.org  http://projects.cappels.org

;You may use this for personal use only. Commercial License is available.

;You may republsih this file provided this notice is kept intact.

;Plese let me know of any bugs or (especially) improvements. Thank you.

;*********************************
;Atto Basic
;*********************************
;.nolist
;.list
.include "8515def.inc"
;//////////UART SETUP//////////////

;	.equ     clock 		= 8000000	;clock frequency	
	.equ     clock 		= 3690000	;clock frequency
	.equ     baudrate 	=  9600		;choose a baud rate
	.equ     baudconstant 	= (clock/(16*baudrate))-1
	
	
;/////////     DS Interface  ////////

	.equ	settletime	= $50	;Time for sampling, settling of data lines

	.equ	dataline= 4	;D4	Data line
	.equ	attline	= 3	;D3	Attention line


;/////////MEMORY ALLOCATION////////

;The highest memory location is designated RAMEND in the chip's definition include file.
;The use of ram, starting from RAMEND and going down is as follows:

;	uC RETURN STACK		$25F to $200	
;	DATA STACK		$1FF to $1F4
;	PROGRAM MEMORY		$1F3 to $0C9
;	LINE BUFFER		$0C8 to $08B
;	VARIABLE STORAGE	$08A to $070
;	UNASSIGNED RAM		$06F to $060


;ALLOCATE BUFFERS
	
		
	.equ	stackbot 	= $08			;Point to check for stack underflow

	.equ	dstacktop	= $FF;**		;First byte (top) of data stack
	.equ	dstackbot 	= $F4			;Last byte in data stack ;on 2313 this was stackbot
	.equ	dstackpage	= $01			;Entire dstack must be on one page

	.equ	lbufftop	= $C8			;First byte (top) of line buffer
	.equ	lbuffbot 	= $8B			;Last byte in terminal input buffer
	.equ	lbuffpage	= $00

	.equ	vartop		= $8A			;First byte in variable space
	.equ	varbot		= $70			;Last byte in varibale space
	.equ	varpage		= $00

	
	.equ	pmemtop		= $F3;*			;*First byte (top) of program memory
	.equ	pmemtopage	= $01			;Hight byte of top of program memory
	.equ	pmembot		= $C9			;Last byte in program memory	
	.equ	pmembotpage	= $00			;Hight byte of of address of bottom of memory
;	.equ	pmempage	= $03		;For now, restrict to page 2
; *Note: pmemtop cannot be $FF or address comparison in storeline will fail.	
;** Note dstack must be at the top of the same page of memory as pmemtopage	
	.equ	eeprogstortop	= $FF	;First (top) byte in EEPROM
	.equ	eepromstrotopage= $01	;MSB of highest address in EEPROM 

;/////////REGISTER ALLOCATION////////

	.def	romreg		= r0	;Used in LPM command

	.def	PClow		= r5	;Marks position in program counter for virtual machine
	.def	PChigh		= r6	;This pair points to next available space
	.def	bufferlimL	= r7	;Limit of buffer - used by parcer
	.def	bufferlimH	= r8	;Limit of buffer - used by parcer
	.def	currentcast	= r9	;Used in parsing text.
	.def	looptarget	= r10	;FOR-NEXT
	.def	loopvariable	= r11	;FOR-NEXT
	.def	loopreturnL	= r12	;FOR-NEXT
	.def	loopreturnH	= r13	;FOR-NEXT
	.def	gosubretL	= r14	;GOSUB return address Low
	.DEF	gosubretH	= r15	;GOSUB return address High
	.def	temp 		= r16	;General purpose variable
	.def	inchar 		= r17	;Char destined to go out the uart
	.def	outchar 	= r18	;Char coming in from the uart
	.def	inbytel 	= r19	;Lower byte for asci-hex conversion
	.def	inbyteh 	= r20	;Higher byte for asci-hex conversion
	.def	ecode		= r21	;Cast returned here and error code stored here
	.def	dstackpointer	= r22	;Data stack pointer.
	.def	U		= r23	;Units 
	.def	T		= r24	;Tens
	.def	H		= r25	;Hundreds
	;note   XL		= r26	;Flags register
	;note	XH		= r26	;Flags register
;Notes on XL, flag register bit useage.
;	bit	0		=1 for variabls to leave pointers on stack, =0 for values on stack
;	bit 	1		=1 to skip next line during RUN execution
;	bit	2		=1 to switch = to be part of FOR-NEXT loop
;	bit	3		=1 to activate Next as part of a loop
;	bit	4		=1 to tell runcommand to jam in loop return address next time
;	bit	5		=1 to tell runcommand to capture loop return address
;	bit	6		=1 to tell runcommand to capture GOSUB return address
;	bit	7		=1 to tell runcommand to jamb destination address

;Notes on XH, flag register bit useage.
;	bit	0		=1 to tell runcommand to jamp GOSUB return address
;	bit	1		=1 to tell runcommand to halt
;	bit	2		=1 to indicate that gosub is active
;	bit	3		=1 to indicate line no higher than linebuff encountered
;	bit	4		=1 to indicate that first line number was thrown away
;	bit	5		=1 to indicated nonnumeric char found in line
;	bit	6		=1 to indicate that suspend had been requested
	.cseg
;/////////VECTORS//////////////// 
	.org     $00
	rjmp     init		;reset handle


;////////NO INTERRUPTS USED//////

init:     
	ldi	temp,$31
	out	PORTD,temp	;Set PORTD bit 0,4 and 5 weak pullup
	ldi	temp,$00	;Port B all inputs
	out 	DDRB,temp
	ldi	temp,$00
	out	DDRD,temp	;Port D all inputs (except UART)
	ldi	temp,high(ramend) 
	out	sph,temp	
	ldi     temp,low(ramend)	
	out     spl,temp     	;Set the stack pointer

	
	ldi     temp,baudconstant     
	out     ubrr,temp     	;Load UART bard rate
	sbi	ucr,txen	;enable UART xmit
	sbi	ucr,rxen	;Enable UART receiver 
	
	
	
	rcall	newprogram	;Initialize program memory	
		
	sbic	PIND,0		;If PIND,0 is grounded then execute from EEPROM
	rjmp	readytorun
	rcall	loadcommand
	rcall   runcommand
readytorun:

	rcall	newprogramgreet	;Initialize program memory and print greeting	
	
main:	rcall	crlf
	ldi	dstackpointer,dstacktop	;Initialize data stack pointer 
	rcall	getterminalline	;Gen line from terminal (60 chars + $0D)
	rcall	Interpretelinebuffer
	rjmp	main

fetchrombyteinc:
	inc	ZL	
fetchrombyte:	;Read byte from rom, advance pointer.
		;Enter with ZH, ZL pointing to rom list.
	lpm			;Load byte from program memory into r0
	adiw	ZH:ZL,1		;Increment Z registers
    	tst	romreg		;Check if we've reached the end of the list of commands
    	breq	endoflist	;If so,return
	ret

endoflist:
	ldi	ecode,$00
	rjmp	error



getexecword:	;Find the address of the instruction that matches the three characters in H,T,and U.
		;Execute associated instruction then return.
	ldi	ZH,high(2*commandlist)	;Load high part of byte address into ZH
	ldi	ZL,low(2*commandlist)	;Load low part of byte address into ZL
tryanother:
	rcall	fetchrombyte		;See if the string matches contents of H and T
	cp	romreg,H
	brne	nomatchH
	rcall	fetchrombyte
	cp	romreg,T
	brne	nomatchT
	rcall	fetchrombyte
	cp	romreg,U
	brne	nomatchU
					;OK, A match has been found, get the address of the routine.
	adiw	ZH:ZL,1			;Increment Z registers -skip unused 4th instruction name byte
	lpm				;Get address low into r0 (romreg)
	mov	temp,romreg		;Stash low byte in temp
	adiw	ZH:ZL,1			;Increment Z registers to point to high byte
	lpm				;Get address high into r0 (romreg)
	mov	ZH,romreg		
	mov	ZL,temp	
     	icall				;Do an indirect jump
     	ret				;Then return when function is complete
     		
nomatchH:
 	adiw	ZH:ZL,1			;Increment Z registers -skip T
nomatchT:
	adiw	ZH:ZL,1			;Increment Z registers -skip U
nomatchU:
	adiw	ZH:ZL,3			;Increment Z registers -skip address (3 bytes)
 	rjmp	tryanother
	
	
formword:	;Put up to three consecutive non-delimiters in registers H,T,and U, right-justified
		;Enter with YH, YL pointing to first char in buffer to be parsed
		;Output: non-delimiters in registers T,H,and U, right-justified, count of 
		;chars in outchar. If three chars are collected, this routine advances
		;YL until the cast changes. Leaves with YH,HYL pointing to next char to be parsed.
		;Used also: temp and inbyteh.
		
	ldi	H,$F0	 	;U is always loaded, no need to ininitalize
	ldi	T,$F0		;Pre-load the others
	
	ldi	outchar,$01
	ld	temp,Y		;Get char from linebuffer into U


	rcall	Qcast		;See what type of char it is.
	cpi	ecode,$01	;If the char is a delimiter (type 1), skip
	brne	nottype1cast	; **** advancelbpointer only once, just after Qcast
	rcall	advanclbpointer	
	rjmp	formword	
nottype1cast:
	mov	U,temp 		;Store char and advance pointer
	rcall	advanclbpointer
	cpi	temp,$0D	;If its a carriage return, stop and return.
	breq	exitfromword0D
	mov	currentcast,ecode;Save cast type for reference

Getanotherhcar:
	ld	temp,Y		;Get char from linebuffer
	rcall	Qcast
	cpi	temp,$0D	;If carriage return, then return
	breq	exitfromword0D
	cp	currentcast,ecode ;If not same as cast of first char, then return.
	brne	exitfromword
	mov	H,T
	mov	T,U
	mov	U,temp  	;Store char and advance pointer
	rcall	advanclbpointer
	inc	outchar
	cpi	outchar,$03	;If third character, exit
	brne	Getanotherhcar	;Otherwise, get another
exitfromword:
				;The code below is to make sure ponter is not 
				;left pointing to the end of a word that is longer
				;than three chars long. It is not 
				;entered when the pointer is pointing to the
				;carriage return at the end of the buffer.
	ld	temp,Y		;Get char from linebuffer
	rcall	Qcast
	cp	currentcast,ecode
	breq	notclearedgroup
exitfromword0D:
	ret
	
	
notclearedgroup:
	rcall	advanclbpointer
	rjmp	exitfromword
	

advanclbpointer:
		;Decrements YL, Jumps to error routine if fetch is requester after 
		;pointer is moved past the end of the buffer. Enter with buffer limits 
		;in bufferlimH,bufferlimL
	cp	YH,bufferlimH
	brne	nohitend
	cp	YL,bufferlimL
	brne	nohitend
	ldi	ecode,$04
	rjmp	error
	ret
nohitend:
	sbiw	YH:YL,1
	ret


Interpretelinebuffer:		;Interpret line
	ldi	YH,lbuffpage		;Initialize line buffer pointer to lbufftop 
	ldi	YL,lbufftop
	ldi	temp,lbuffbot-1	;Set buffer limits to those of line buffer.
	mov	bufferlimL,temp
	ldi	temp,lbuffpage
	mov	bufferlimH,temp
	ld	temp,Y		;Get first char from linebuffer
	rcall	Qcast
	cpi	ecode,$02
	brne	dotheline	;First char is not a numeral so interpret line
	rjmp	storeline	;If it's a number, then it's a line number -store it.
dotheline:
	rcall	crlf
	ori	XL,$01		;Flag variable ponters to be left on stack
	rjmp	interpretline	
	

interpretlinev:
	andi	XL,$FE		;Flag to leave value of variables on stack
interpretline:	;Interpret line. Enter with YH, YL pointing to first char to be interpreted
	in	inbytel,spl	
	cpi	inbytel,stackbot
	brsh	stacknotexceeded
;	brpl	stacknotexceeded
	ldi	ecode,$08
	rjmp	error
stacknotexceeded:

	rcall	formword 
	cpi	U,$0D
	breq	endofline

	mov	temp,currentcast ; Check to see if its a number	
	cpi	temp,$02
	brne	dontmakenumber	
	andi	H,$0F		;Its a number so make binary and push on stack
	andi	T,$0F
	andi	U,$0F
	rcall	decimaltobinary	;change from 3 BCD bytes to one binary vaue
	rcall	pushU
	rjmp	interpretline	;Keep going until CR is found
dontmakenumber:
	
	andi 	H,$5F		;Upper-case H,T,U
	andi	T,$5F
	andi	U,$5F	

	cpi	outchar,$01	;If its a type 3 (letter) and 1 char long its a variable.
	brne	notavar		;(If outchar = 1 and ecode = 3 its a variable)
	mov	temp,currentcast
	cpi	temp,$03
	brne 	notavar
	rcall	processvariable
	rjmp	interpretline

notavar:
	rcall	getexecword	;Check for CR after coming back from routine
	cpi	U,$0d
	breq	endofline
	ret
					
endofline:
	ori	XL,$01		;Flag variable ponters to be left on stack next line
	ret
	
	
processvariable:	;Make variable in A into a pointer and
			;if XL bit 0 is 1, put pointer on stack (assignment to variable), or
			;if XL bit 0 is 0 put the value of variable on stack.
	
	subi	U,$41		;Make into an offset		
	cpi	U,(vartop-varbot);Test for range
	brmi	variableok
	ldi	ecode,$05
	rjmp	error
variableok:
	subi	U,-varbot	;Make into a pointer
	sbrs	XL,$00	
	brne	notcodezero	
	rcall	pushU		;Put pointer on stack (ecode = $00)
	ret
notcodezero:		
	ldi	ZH,varpage		
	mov	ZL,U		;Put contents of variable on stack
	ld	U,Z	
	rcall	pushU
	ret


pushU:		;Push contents of U on datastack

	ldi	ZH,dstackpage	
	mov	ZL,dstackpointer
	st	Z,U
	dec	dstackpointer
	cpi	dstackpointer,dstackbot-1 ;If no stack undrflow, return.
;	brpl	nopusherror
	brsh	nopusherror
	ldi	ecode,$06
	rjmp	error
nopusherror:
	ret
	
	
popU:		;Pop contents of U from datastack

	inc	dstackpointer	;
	cpi	dstackpointer,dstacktop+1
	brmi	nopoperror
	ldi 	ecode,$07
	rjmp	error
nopoperror:
	ldi	ZH,dstackpage	
	mov	ZL,dstackpointer
	ld	U,Z
	ret
	
	
;///////////////INSERT LINE ROUTINES//////////////////////////////


linenotoolong:
	ldi	ecode,$0B	;Error: Line number has too many characters.
	rjmp	error


		
Countlinehcars:		;Count total chars and number of non-numeric, non-delimiter chars
				;If not empty, there will be more than zero non-numeric
				;and non-delimiter characters in the line before the 
				;carriage return.Retruns count in temp. The number of numerals
				;in the line number is contained in U.

	ldi	YH,lbuffpage		;Initialize line buffer pointer to lbufftop 
	ldi	YL,lbufftop
	clr	gosubretH
	clr	gosubretL
	clr	U
	andi	XH,$DF			;Clear nonnumeric char found flag
morchars: 			
	ld	temp,Y
	dec	YL
	inc	gosubretL
	cpi	temp,$0D
	breq	donecounting
	rcall	Qcast
	cpi	ecode,$02
	breq	anothernum
	ori	XH,$20
	cpi	ecode,$01 
	breq	morchars
	inc	gosubretH
	rjmp	morchars	
donecounting:

	mov	temp,gosubretH  	;Return with non-numeric, non-delimer count in temp
	ret				;Return with char total count in gusubretL

anothernum:
	sbrs	XH,5
	inc	U
	rjmp	morchars


buffendhit:
	ldi	ecode,$04
	rjmp	error
	
memoryfull:
	ldi	ecode,$02
	rjmp	error	
	


makeHTUdecimal:			;Make decimal digits in H,T,and U into a binary number in U.
	andi	H,$0F		;Its a number so make binary and push on stack
	andi	T,$0F
	andi	U,$0F
	rcall	decimaltobinary	
	ret

storelbufatZ:
	ldi	YH,lbuffpage	;Initialize line buffer pointer to first char 
	ldi	YL,lbufftop
anotherlinchar:
	cpi	ZL,pmembot 
	breq	memoryfull
	ld	temp,Y		;Put contents of line buffer into temp
	st	Z,temp		;Put temp into the program memory
	sbiw	ZH:ZL,1
	sbiw	YH:YL,1
	cpi	temp,$0D
	brne	anotherlinchar
	mov	PClow,ZL
	mov	PChigh,ZH 
	ret
	
	
storeline:	;Store line in appropriate place.
	
	rcall	Countlinehcars	;Reject line if line number contains more than three numerals.
	cpi 	U,4
	brsh	linenotoolong
	
	mov	temp,PChigh
	cpi	temp,pmemtopage
	brne	pcnotattop
	mov	temp,PClow
	cpi	temp,pmemtop
	brne	pcnotattop
	rjmp	storelineatend
pcnotattop:
	
		
	ldi	YH,lbuffpage	;Initialize line buffer pointer to first char 
	ldi	YL,lbufftop
	
				;Find out what line number in line buffer is and put in looptarget
	clr	U
	clr	T
	clr	H
				
fetchanothernum1:	
	cp	YL,bufferlimL	;Error if past end of buffer
	brmi	buffendhit
	ld	temp,Y
	rcall	qcast		;Find out what kind of char this is
	cpi	ecode,$02	;Type $02 - a numeral
	brne	notanumeral1
	mov	H,T		;Ita a numeral so shift it in
	mov	T,U
	mov	U,temp
	sbiw	YH:YL,1	
	rjmp	fetchanothernum1
notanumeral1:			;The pointer is not poiting to a numeral, so test the number.
	rcall	makeHTUdecimal
	mov	looptarget,U	;Put number of line in linebuffer into looptarget

		;//GOT LINE BUFFER LINE NUMBER///
	
		;////SCAN PROGRAM MEMORY////
scanpmem:		;Scan from lowest to top of program memory to find the place to
			;insert the input line.
	mov	ZH,PChigh	;Get current program memory location from PC high and PC low
	mov	ZL,PClow
	andi	XH,$F7		;Clear higherthan flag
	andi	XH,$EF		;Clear first line no thrown out flag
newnumber:
	clr	H		;Clear digits buffer
	clr	T
	clr	U
	clr	loopvariable	;Clear count of number of digits
nextchar:
	adiw	ZH:ZL,$01	
	cpi	ZH,pmemtopage
	brne	notattop 
	cpi	ZL,pmemtop+1
	breq 	justifynumber	;If Z exceeds top of buffer, its the end of the line number
notattop:
	ld	temp,Z
   	rcall	Qcast		;Find out what kind of character Z is pointing to
	cpi	ecode,$04	;If its a carriage return, then its the end of the line number
	breq 	justifynumber
	cpi	ecode,$02
	brne	newnumber	;If its not a numeral, then dump numeral registers and start over.
	inc	loopvariable	;Increment count of numerals shifted in
	

	mov	U,T		;Shift current char in
	mov	T,H
	mov	H,temp	
	rjmp	nextchar	;Get next char
	
justifynumber:			;Right justify the number in HTU
	mov	temp,loopvariable
	cpi	temp,3		;There are three registers: H,T,and U.	
	breq	nowjustified
	inc	loopvariable
	mov	U,T
	mov	T,H
	ldi	H,0
	rjmp	justifynumber
nowjustified:

	sbrc	XH,4		;If this is the first line number, skip it (only responding to last CR in pmem).
	rjmp	notfirstlineno
	ori	XH,$10
	rjmp	newnumber
notfirstlineno:

   
	rcall	makeHTUdecimal	;Put value of HTU into U.

	cp	looptarget,U	;DIVERT IF EQUAL
	breq	deleteandgo	;If current line no is equal to target, then delete and/or replace the line
	brsh	nothigher	;If current line no is higher than target, set flag XH,3
	ori	XH,$08	
	mov	loopreturnH,ZH	;and save address of CR following higher line number
	mov	loopreturnL,ZL
nothigher:

				
	cpi	ZH,pmemtopage	;DIVERT IF BUFFER SCANNED AND NO HIGHER
	brne	notattop2	;Test for Z being past end of memory
	cpi	ZL,pmemtop+1
	brne	notattop2	;If not past end of memory, test to see if line higher than in line buffer,
	sbrs	XH,3		;and if no higher number found, store line at end of buffer
	rjmp	storelineatend 	;If at end and no higher found, store at end.
notattop2:
	
	
	
	
	
			;DIVERT IF HIGHER PRVIOUSLY FOUND AND (HIGHER OR END)
	
	sbrs	XH,3		;Was a higher line number found?
	rjmp	noisnertlowerline
	
	cp	U,looptarget	;Is current line number lower than target?
	brsh	notlowerline
	rjmp	insertinmiddle	
notlowerline:
			

	cpi	ZH,pmemtopage	;Test for Z being past end of memory		
	brne	notattop3	
	cpi	ZL,pmemtop+1
	brne	notattop3 	;If not past end of memory, test to see if line higher than in line buffer,
	rjmp	insertinmiddle
notattop3:



noisnertlowerline:		;Don't insert a line in the midst of pmem -keep scanning

;	
	
	;(DEFAULT LOOP BACK)


	cpi	ZH,pmemtopage
	brne	newnumber
	cpi	ZL,pmemtop+1	
	brne	newnumber
	ret		
	


storelineatend:	;Store line in next available locatoin in program memory from first char to $0D
		;Enter with YH, YL pointing to first char of line


	rcall	Countlinehcars		;If its a zero length line, don't store it.
	cpi	temp,$00
	brne	writelineatend
	ret	
writelineatend:
	ldi	YH,lbuffpage	;Initialize line buffer pointer to first char 
	ldi	YL,lbufftop	
	
	
	mov	ZH,PChigh	;Get current program memory location from PC high and PC low
	mov	ZL,PClow
anotherlinchar2:		;Check to see if ponter is past end of program memory
	cpi	ZH,pmembotpage
	brne	pmemnotfull
	cpi	ZL,pmembot 
	brne	pmemnotfull
	rjmp	memoryfull2
pmemnotfull:
	ld	temp,Y		;Put contents of line buffer into temp
	st	Z,temp		;Put temp into the program memory
	sbiw	ZH:ZL,$01
	sbiw	YH:YL,$01
	cpi	temp,$0D
	brne	anotherlinchar2
	mov	PClow,ZL
	mov	PChigh,ZH 
	ret

memoryfull2:
	ldi	temp,$02
	mov	ecode,temp   	; **** ecode is now a high register
	rjmp	error


;itsanemptylineRELAY: rjmp itsanemptyline 	;can this be displosed of? ****
	
deleteandgo:	;Delete a line in prorgam memory. Enter with ZL pointing to
		;first char in line to be deleated (first char of line number).
		;Moves everything from the first char of the line following the 
		;line to be deleted to the  end of the program memory to 
		;overwrite the deleted line. ZH must be set to the correct page
	
	sbiw	ZH:ZL,1	
	mov	YH,ZH		;Copy Z into Y
	mov	YL,ZL
	
				;Scan Y down the pgrogam memory until either end ofmemory
continuescan:			;or CR is encountered. If end of memory, claim error.

	cpi	YH,pmembotpage
	brne	Nothitpmembot
	cpi	YL,pmembot
	brne	Nothitpmembot
	rjmp	buffendhit
Nothitpmembot:
		
	ld	temp,Y
	sbiw	YH:YL,1
	cpi	temp,$0D
	brne	continuescan

	mov	temp,ZL		;The difference between ZL and YL is the size of the line being
	sub	temp,YL		;deleted. Adjust PClow accodingly.

	add	PClow,temp
	brcc	noinc
	inc	PChigh
noinc:


keepoverwriting:
	cpi	YH,pmembotpage
	brne	skip9
	cpi	YL,pmembot	;Copy memory(Y) to memory (Z) until end of memory is reached.	
	breq	finishedoverwrite
skip9:
	ld	temp,Y
	st	Z,temp
	sbiw	YH:YL,1
	sbiw	ZH:ZL,1
	rjmp	keepoverwriting
finishedoverwrite:

	rcall	Countlinehcars
	cpi	temp,$00
	breq	dontwriteline

	rjmp	storeline
;	rjmp	scanpmem		;**** changed to storeline from scanpmem - seems to have fixed reluctance to try and re-write line after deleting it.
dontwriteline:
	ret		
	
	
	
	

insertinmiddle:	;MAKE ROOM FOR LINE IN MIDST OF TEXT AND INSERT


	rcall	Countlinehcars 
	cpi	temp,$00		;If its a zero length line, don't store it.
	breq	itsanemptyline
;	breq	itsanemptylineRELAY


	
	mov	temp,PChigh	 ;But first, check to see if there is enough memory				
	cpi	temp,pmembotpage ;PC in same page as bottom of program memory?
	brne	cantbefull

	mov	temp,pclow	
	subi	temp,pmembot	;Temp has remaining memory bytes (in last page of memory)	
	cp	temp,gosubretL	;Compare bytes remaining with line size
	brlo	memoryfull2
cantbefull:

				;Make room to insert line
				
	mov	ZH,PChigh	;Point Z to bottom of program [the source]
	mov	ZL,PClow
	
	mov	YH,ZH		;Set Y = Z - size of line buffer content) [the destination]		
	mov	YL,ZL
	sub	YL,gosubretL
	sbci	YH,$00

	mov	temp,YL		;Adjust PC (pointer to end of program)
;	subi	temp,2		
	mov	PClow,temp	;**** clean this up by simplifying 
	mov	temp,YH
;	sbci	temp,0	
	mov	Pchigh,temp
	
	
movemore:
	cp	ZH,loopreturnH
	brne	notfinishedmoving
	cp	ZL,loopreturnL
	brne	notfinishedmoving
	rjmp	movingfinished
notfinishedmoving:

	
	ld	temp,Z
	st	Y,temp
	adiw	YH:YL,1
	adiw	ZH:ZL,1
	rjmp	movemore
	
movingfinished:			;The text has been moved to make room for line buffer contents

	
		;Insert contents of line buffer into program memory
		
	ldi	YH,lbuffpage	;Initialize line buffer pointer to first char 
	ldi	YL,lbufftop	
	mov	ZH,loopreturnH	;Get address of CR after higher line
	mov	ZL,loopreturnL			
	sbiw	ZH:ZL,$01		;Move pointer to first char of line to be moved	
	
	
fillmore:
	ld	temp,Y
	st	Z,temp
	cpi	temp,$0D
	breq	finishedfilling
	sbiw	ZH:ZL,1
	sbiw	YH:YL,1
	rjmp	fillmore
finishedfilling:	 	
	   	
	   	
itsanemptyline:   	
	   ret
	
	
;/////////////////END OF INSERT LINE ROUTINES///////////////		
		
Qcast:		;Determine whether character is a letter, numeral, delimiter, or other (operator).
		;Input: temp. Output: ecode. Uses: inchar
		;Value in ecode = cast
		;0 = Operator (not one of the other casts
		;1 = Delimiter -space ($20) or comman ($2C)
		;2 = Numeral 0..9 ($30 through $39)
		;3 = Letter -A..Z uppercase ($41 throught $5A)
		;4 = Carriage return
		;Tests are made after anding the input byte with $5F
		
	clr	ecode		;Default is type 0
	mov	inchar,temp	;Copy to inchar for modification
	
	cpi	inchar,$0D	;Is it a carriage return? -check this before uppercasing
	brne	not0D
	rjmp	makecast4
not0D:
	
	andi	inchar,$5F	;Make upper-case
	

	cpi	inchar,00	;Is it a space?
	brne	notspacecode
	rjmp	makecast1
notspacecode:
	cpi	inchar,$0C	;Is it a comma?
	brne	notaspacecode	
makecast1:
	ldi	ecode,$01
	ret	
notaspacecode:
	cpi	inchar,$10
	brpl	notunder10	
	ret
notunder10:
	cpi	inchar,$5B
	brmi	notover5B	
	ret	
notover5B:
	cpi	inchar,$40
	brmi	notover40
	ldi	ecode,$03
	ret
notover40:	
	cpi	inchar,$1A	
	brpl	notunder1A
	ldi	ecode,$02
notunder1A:
	ret
makecast4:
	ldi	ecode,$04
	ret
	
	
deletekey:			;Backup up cursor -destructive backspace
	cpi 	YL,lbufftop
	brne	notexceededbuftop
	ldi	outchar,$07	;If not CR at last position, ring the bell
	rcall	emitchar
	rjmp	anothertermchar
notexceededbuftop:
	mov	outchar,inchar
	rcall	emitchar0d
	inc 	YL
	ldi	inchar,$0D
	st	Y,inchar	;Put in line buffer
	rjmp	anothertermchar
	
	

	
getterminalline: 	;Get characters from terminal into linebuffer. Stop accepting chars except
			;0D when end of buffer is reached.
	ldi	outchar,$3E
	rcall	emitchar
	ldi	YH,lbuffpage		;Initialize line buffer pointer to lbufftop 
	ldi	YL,lbufftop
anothertermchar:
	rcall	recvchar	;Get char from terminal
	cpi	inchar,$08	;Is it backspace/delet character?
	breq	deletekey
	st	Y,inchar	;Put in line buffer
	cpi	inchar,$0D
	breq	CRreceived	;If char was CR,then return
	cpi	YL,lbuffbot	;If buffer is at last byte, don't store char but beep.
	brne	notlbuffend	
	ldi	outchar,$07	;If not CR at last position, ring the bell
	rcall	emitchar
	rjmp	anothertermchar
notlbuffend:
	dec	YL		;Not end of buffer and not CR, so emit and go another
echoandgo:
	mov	outchar,inchar
	rcall	emitchar0d
	rjmp	anothertermchar
CRreceived:			;Last char in line received
	ret
	
	
Error:
	rcall	crlf
	cpi	ecode,$00
	brne	notzero
	ldi	ZH,high(2*emessage0)	;Load high part of byte address into ZH
	ldi	ZL,low(2*emessage0)	;Load low part of byte address into ZL
	rcall	sendromstring		;sent it.
	rjmp	errorend
notzero:


	cpi	ecode,$01
	brne	not1
	ldi	ZH,high(2*emessage1)	;Load high part of byte address into ZH
	ldi	ZL,low(2*emessage1)	;Load low part of byte address into ZL
	rcall	sendromstring		;sent it.
	rjmp	errorend
not1:


	cpi	ecode,$02
	brne	not2
	ldi	ZH,high(2*emessage2)	;Load high part of byte address into ZH
	ldi	ZL,low(2*emessage2)	;Load low part of byte address into ZL
	rcall	sendromstring		;sent it.
	rjmp	errorend
not2:


	cpi	ecode,$03
	brne	not3
	ldi	ZH,high(2*emessage3)	;Load high part of byte address into ZH
	ldi	ZL,low(2*emessage3)	;Load low part of byte address into ZL
	rcall	sendromstring		;sent it.
	rjmp	errorend
not3:


	cpi	ecode,$04
	brne	not4
	ldi	ZH,high(2*emessage4)	;Load high part of byte address into ZH
	ldi	ZL,low(2*emessage4)	;Load low part of byte address into ZL
	rcall	sendromstring		;sent it.
	rjmp	errorend
not4:


	cpi	ecode,$05
	brne	not5
	ldi	ZH,high(2*emessage5)	;Load high part of byte address into ZH
	ldi	ZL,low(2*emessage5)	;Load low part of byte address into ZL
	rcall	sendromstring		;sent it.
	rjmp	errorend
not5:


	cpi	ecode,$06
	brne	not6
	ldi	ZH,high(2*emessage6)	;Load high part of byte address into ZH
	ldi	ZL,low(2*emessage6)	;Load low part of byte address into ZL
	rcall	sendromstring		;sent it.
	rjmp	errorend
not6:


	cpi	ecode,$07
	brne	not7
	ldi	ZH,high(2*emessage7)	;Load high part of byte address into ZH
	ldi	ZL,low(2*emessage7)	;Load low part of byte address into ZL
	rcall	sendromstring		;sent it.
	rjmp	errorend
not7:


	cpi	ecode,$08
	brne	not8
	ldi	ZH,high(2*emessage8)	;Load high part of byte address into ZH
	ldi	ZL,low(2*emessage8)	;Load low part of byte address into ZL
	rcall	sendromstring		;sent it.
	rjmp	errorend
not8:


	cpi	ecode,$09
	brne	not9
	ldi	ZH,high(2*emessage9)	;Load high part of byte address into ZH
	ldi	ZL,low(2*emessage9)	;Load low part of byte address into ZL
	rcall	sendromstring		;sent it.
	rjmp	errorend
not9:


	cpi	ecode,$0A
	brne	notA
	ldi	ZH,high(2*emessageA)	;Load high part of byte address into ZH
	ldi	ZL,low(2*emessageA)	;Load low part of byte address into ZL
	rcall	sendromstring		;sent it.
	rjmp	errorend
notA:


	cpi	ecode,$0B
	brne	notB
	ldi	ZH,high(2*emessageB)	;Load high part of byte address into ZH
	ldi	ZL,low(2*emessageB)	;Load low part of byte address into ZL
	rcall	sendromstring		;sent it.
	rjmp	errorend
notB:



errorend: 
	ldi     temp,ramend 		;low(ramend)
	ldi	temp,high(ramend) 
	out	sph,temp
	ldi     temp,low(ramend) 	
	out     spl,temp     	
	ldi	dstackpointer,dstacktop	;Initialize data stack pointer
	ldi	XL,$00			;Clear interpreter mode flags
	ldi	XH,$00
	rcall	crlf
	rjmp	main

sendbyte:      ;Send byte contained in inbytel to terminal
	rcall 	byte_to_asciihex	
     	mov     outchar,inbyteh
     	rcall 	emitchar
     	mov     outchar,inbytel
     	rcall  	emitchar
	ret	

emitchar0:			;emit char in r0
	mov	outchar,temp	
emitchar:
	sbis	usr,udre	;wait until the register is cleared
	rjmp	emitchar     
	rcall	Checkkeybd 	;Xsee if control-c or control-s is pressed

	sbrs	XH,6		;is XH,6 is clear, don't wait for key
	rjmp	waitdone
waitforkey:	
	sbis	usr,rxc		
	rjmp 	waitforkey	;wait for a key before continuing
	andi	XH,$BF		;clear the flag
waitdone:


	out	udr,outchar	;send the byte
	ret			;go back
	

crlf:   ldi	outchar,$0D	;Send carriage return and line feed to terminal
	rcall	emitchar
	ldi	outchar,$0A
	rcall 	emitchar
	ret


emitchar0D:			;Send outchar to terminal. Add line feed to carriage return.

	cpi	outchar,$0D	;Its a carraiage return, send a linefeed also
	brne	notareturn
	rcall	crlf
	ret
notareturn:   
	rjmp	emitchar


recvchar:     	;Receive a byte from the terminal         
	sbis	usr,rxc		;Wait for byte to be received
	rjmp 	recvchar
	in	inchar,udr	;Read byte
	ret			


sendromstring:			;call with location of string in Z
     	lpm			;Load byte from program memory into r0
    	tst	r0		;Check if we've reached the end of the message
    	breq	finishsendstering;If so, return
     	mov	outchar,r0
     	rcall	emitchar
     	adiw	ZH:ZL,1		;Increment Z registers
     	rjmp	sendromstring
finishsendstering:
     	ret


sendlromline:			;Send a string terminated in cariage return and line feed
				;Call with location of start of string in Z               
	rcall	sendromstring
	rcall	crlf
	ret

;/////////////START DATA FORMAT CONVERSION ROTINES//////////////////

bitpositiontoormask:	;Convert bit position (0..7) to OR mask value
			;Enter with bit position on top of dstack, exit with
			;mask on top of stack
			
	rcall	popU		;Get bit position
	ldi	temp,$07
	cp	temp,U
	brmi	toomanybits			
	ldi	temp,$01	;Put 0000 0001 pattern into temp for shifting
rotatesomemore:
	cpi	U,$00
	breq	finishedshifting
	lsl	temp
	dec	U
	rjmp	rotatesomemore
finishedshifting:
	mov	U,temp
	rcall	pushU
	ret

toomanybits:
	ldi	ecode,$0A
	rcall	error



sendHTUasdecimal:	;Send decimal number in H,T,U registers (hundreds,tens,units)
			;As numerals.
	cpi	H,0
	breq	dontsendh
	subi	H,-48
	mov	outchar,H
	rcall	emitchar
	cpi	t,0
	brne	dontsendh
	ldi	outchar,$30	;If U=0 then don't emit this zero
	rcall	emitchar
dontsendh:	
	cpi	t,0
	breq	dontsendt
	subi	T,-48
	mov	outchar,T
	rcall	emitchar
dontsendt:
	subi	U,-48	
	mov	outchar,U
	rcall	emitchar
	ret
	
	
binarytodecimal:	;Enter with 8 bit value in U, Exits with numerals in H,T,U
			;with Hundreds, Tens, and Units.
	clr	H
	clr	T
anotherh:
	subi 	U,100	;Find out how many hundreds in U
	brcs	hdone
	inc	H
	rjmp	anotherh
hdone:
	subi	U,-100	;Subtracted one too many -add back.
anothert:
	subi	U,10
	brcs	tdone
	inc	T
	rjmp	anotherT
tdone:
	subi	U,-10
	ret
	

byte_to_asciihex:     ;convert byte in inbytel to ascii in inbyteh,nbytel
	mov	inbyteh,inbytel
	lsr	inbyteh 	;convert the high nybble to ascii byte
	lsr	inbyteh
	lsr	inbyteh
	lsr	inbyteh
	subi	inbyteh,$D0	;add $30
	cpi	inbyteh,$3A    
	brlo	PC+2 		;If less than 9 skip next instruction
	subi	inbyteh,$F9	;add 8 to ASCII (if data greater than 9)
     ; byte in inbyteh represents upper nybble that was in inbytel at start

	andi	inbytel,0b00001111;convert the lower nybble to ascii byte
	subi	inbytel,$D0	;add $30
	cpi	inbytel,$3A     
	brlo	PC+2		;If less than 9 skip next instruction
	subi	inbytel,$F9 	;add 8 to ASCII (if data greater than 9)
     ; byte in inbyteh represents upper nybble that was in inbytel at start
	ret


asciihex_to_byte:     	;convert ascii in inbyteh,inbytel to byte in inbytel
	sbrc	inbyteh,6	;convert high byte
	subi	inbyteh,$f7	;add     inbyte,temp     ;if bit 6 is set, add $09
	andi	inbyteh,$0F

	sbrc	inbytel,6	;convert low byte
	subi	inbytel,$f7	;add     inbyte,temp     ;if bit 6 is set, add $09
	andi	inbytel,$0F

	lsl	inbyteh		;combine them
	lsl	inbyteh
	lsl	inbyteh
	lsl	inbyteh     
	or	inbytel,inbyteh
	ret
	
decimaltobinary:	;Convert decimal number in H,T,U registers (hundreds,tens,units) to 
			;binary value in U register.
			;But first check to see if nummber exceeds 255 decimal.


	cpi	H,3
	brpl	exceeded255
	cpi	H,2
	brmi	numisok
	cpi	T,6
	brpl	exceeded255
	cpi	T,5
	brmi	numisok
	cpi	U,6
	brpl	exceeded255
numisok:
	tst	T		;Accumulate the number of tens
	breq	moreh
	ldi	temp,10
	add	U,temp		;Add  10
	dec	T	
	brne	decimaltobinary
moreh:
	tst	H		;Accumulate the number of hundreds
	brne	notdoneconv
	ret			;When hundreds = zero, return
notdoneconv:
	ldi	temp,100
	clc	
	add	U,temp		;Add 100	
	dec	H
	brcc	moreh		;If carry is not set, continue
exceeded255:
	ldi	ecode,$01	; **** ecode is now a high register
	rjmp	Error	


;/////////////////END DATA FORMAT CONVERSION ROTINES/////////////////

TypeGreeting:				;Type greeting
	rcall	crlf			; **** consider combinng with sendromline if sendromline is not used elsewhere
	rcall	crlf
	ldi	ZH,high(2*hellomessage)	;Load high part of byte address into ZH
	ldi	ZL,low(2*hellomessage)	;Load low part of byte address into ZL
	rcall	sendlromline		;sent it.
	ret


hellomessage:
	.db     "      ATTOBASIC version 8515-021115C. Not for commercial use. "
	.db	$0A,$0D
	.db     "      Copyright 2002 by Richard Cappels all rights reserved." 
	.db	$0A,$0D
	.db     "      http://projects.cappels.org       projects@cappels.org" 
	.db	$0A,$0D
	.db     $00,$00

freeword:
	.db	"Free  pages:"
	.db      $00,$00
	

pageword:
	.db	"  chars:"
	.db      $00,$00
	

emessage0:
	.db	"Error 0: Unknown command or operator. "
	.db      $00,$00

emessage1:
	.db	"Error 1: Encountered a value that is not between 0 and 255. "
	.db      $00,$00
emessage2:
	.db	"Error 2: Program memory is full."
	.db      $00,$00

emessage3:
	.db	"Error 3: Encountered a character that is not a recognized type. "
	.db      $00,$00

emessage4:
	.db	"Error 4:(internal error -buffer limit exceeded) "
	.db      $00,$00

emessage5:
	.db	"Error 5: Inappropriate variable name encountered. "
	.db      $00,$00

emessage6:
	.db	"Error 6: Data stack push error -too many arguments on one line. "
	.db      $00,$00

emessage7:
	.db	"Error 7: Data stack pop error."
	.db	$0A,$0D
	.db	"         Function tried to use a value that was not available." 
	.db      $00,$00
	
emessage8:
	.db	"Error 8: Machine stack error"
	.db	$0A,$0D
	.db	"         Functions and/or calls nested too deeply or too complex"
	.db      $00,$00
	
emessage9:
	.db	"Error 9: GOTO or GOSUB destination line was not found."
	.db      $00,$00


emessageA:
	.db	"Error A: Specified bit position range of 0..7 exceeded"
	.db      $00,$00


emessageB:
	.db	"Error B: Line number has more than three numerals "
	.db      $00,$00




;//////////BEGIN COMMANDS//////////

;Note about command routines: Clear XL bit 0 to have variables leave their value
;on the stack. This flag is set again at the start of each line.

;Format for command list:
	;1. A .db line with three characters which are the first 
	;three leters of the command plus a fourth to fill out the word.
	;Commands less than three bytes need to be righ-justfied, with 
	;blank leading bytes having the value $50. Compare values are 
	;anded with $5F.
	;2. A .dw line that is the label for the routine to be executed.

commandlist:
	.db	"LIS "
	.dw	listcommand
	.db	"SIZ "		;SIZE	bytes or ram remaining
	.dw	sizecommand
	
	.db	"NEW "		;NEW	clear progam space, start over
	.dw	newprogramgreet
		
	.db	$50,$50,$0B,$20	; +
	.dw	addcommand

	.db	$50,$50,$0D,$20	; -
	.dw	subtractcommand

	.db	"PRIN"		;PRINT
	.dw	printcommand

	.db	"PRX "		;PRX -Print in hexidecimal
	.dw	printhexcommand

	.db	"PRB "		;PRB -Print in binary
	.dw	prbcommand

	.db	"PWM8"		;PWM8  send value to 8 bit pwm channel, set DDRB,3 to 1
	.dw	pwm8command

	.db	"PWE "		;PWE  send value to 10 bit pwm channel, set DDRB,3 to 1
	.dw	pwecommand

	.db	"PWO "		;PWO   turn off pulse-width modulation. Do not change DDRB
	.dw	pwocommand

	.db	"EMIT"		;EMIT -send byte on stack as ascii to terminal. 
	.dw	emitcommand	

	.db	$50,$1A,$1D,$20	; :=
	.dw	setequalscommand
	
	.db	$50,$50,$1D,$20	;  =	eual sign. Evaluate expression
	.dw	evaluatecommand
	
	.db	"FOR "
	.dw	forcommand
	
	.db	"NEXT"
	.dw	nextcommand
	
	.db	$50,$1C,$1E,$20	; <>
	.dw	notequalcommand
	
	.db	$50,$50,$1E,$20	; >
	.dw	greaterthancommand
	
	.db	$50,$50,$1C,$20	; <
	.dw	lessthancommand
	
	.db	$50,$49,$46,$20	; IF
	.dw	ifcommand
	
	.db	$50,$54,$4F,$20	; TO
	.dw	tocommand

	.db	$50,$50,$04,$20	; $ -Hex command - interpret following as hexidecimal.
	.dw	hexcommand

	.db	"RUN "
	.dw	runcommand
	
	.db	"END "
	.dw	endcommand
	
	.db	"AND "
	.dw	andcommand
	
	.db	"LSR "
	.dw	lsrcommand
	
	.db	"LSL "
	.dw	lslcommand
	
	.db	$50,$4F,$52,$20	;OR -Logical OR
	.dw	orcommand
	
	.db	"XOR "
	.dw	eorcommand
	
	.db	"DUMP"
	.dw	dumppmembuffer

	.db	"GOTO"
	.dw	gotocommand
	
	.db	"GOSU"		;GOSUB
	.dw	gosubcommand
			
	.db	"RETU"		;RETURN
	.dw	returncommand
	
	.db	"THEN"		;THEN
	.dw	thencommand
		
	.db	"KEY "		;WAIT -pause execution until char received from terminal. Halt if control-C received
	.dw	keycommand
		
	.db	"ACO "		;ACO -Put analog comparitor output on the stack
	.dw	acocommand
		
	.db	"SAVE"		;SAVE	-Save contents of variable space and program memory to EEPROM
	.dw	savecommand

	.db	"LOAD"		;LOAD	-Load variable space and program memory from EEPROM
	.dw	loadcommand
			
	.db	"PEEK"		;PEEK -return data pointed to by parameter
	.dw	peekcommand
	
	.db	"POKE"		;POKE - "POKE data, address"
	.dw	pokecommand
		
	.db	"ODA "		;ODA -Out Data Direction A
	.dw	outdAcommand

	.db	"ODB "		;ODB -Out Data Direction A
	.dw	outdBcommand
	
	.db	"ODC "		;ODC -Out Data Direction C
	.dw	outdCcommand

	.db	"ODD "		;ODD -Out Data Direction D
	.dw	outdDcommand
	
	.db	"OPA "		;OPA -Out Port A
	.dw	outpAcommand
		
	.db	"OPB "		;OPB -Out Port B
	.dw	outpBcommand
			
	.db	"OPC "		;OPC -Out Port C
	.dw	outpCcommand
				
	.db	"OPD "		;OPD -Out Port D
	.dw	outpDcommand	
	
	.db	"INA "		;INA -Input data from port A
	.dw	inAcommand
	
	.db	"INB "		;INB -Input data from port B
	.dw	inBcommand	
		
	.db	"INC "		;INC -Input data from port C
	.dw	inCcommand	

	.db	"IND "		;IND -Input data from port D
	.dw	inDcommand	

	.db	"SBA "		;SBA -Set bit in A register
	.dw	setbitinA
		
	.db	"CBA "		;CBA -Clear bit in A register
	.dw	clearbitinA
			
	.db	"SBB "		;SBD -Set bit in B register
	.dw	setbitinB
		
	.db	"CBB "		;CBD -Clear bit in B register
	.dw	clearbitinB
				
	.db	"SBC "		;SBD -Set bit in C register
	.dw	setbitinC	
		
	.db	"CBC "		;CBD -Clear bit in C register
	.dw	clearbitinC
					
	.db	"SBD "		;SBD -Set bit in D register
	.dw	setbitinD
			
	.db	"CBD "		;CBD -Clear bit in D register
	.dw	clearbitinD
						
	.db	"SDA "		;SDA -Set direction bit in A 
	.dw	setdirectionA
			
	.db	"CDA "		;CDA -Clear direction bit in A
	.dw	cleardirectionA
				
	.db	"SDB "		;SDA -Set direction bit in B 
	.dw	setdirectionB	
		
	.db	"CDB "		;CDA -Clear direction bit in B
	.dw	cleardirectionB
					
	.db	"SDC "		;SDA -Set direction bit in C
	.dw	setdirectionC
			
	.db	"CDC "		;CDA -Clear direction bit in C
	.dw	cleardirectionC

	.db	"SDD "		;SDA -Set direction bit in D 
	.dw	setdirectionD		
		
	.db	"CDD "		;CDA -Clear direction bit in D
	.dw	cleardirectionD
		
	.db	"IBA "		;IBA -Test bit in A
	.dw	testbitinA
								
	.db	"IBB "		;IBA -Test bit in B
	.dw	testbitinB
	
	.db	"IBC "		;IBA -Test bit in C
	.dw	testbitinC
	
	.db	"IBD "		;IBA -Test bit in D
	.dw	testbitinD
						
	.db	"DELA"		;DELAY -DELAY approx. 50 ms per count at 4 MHz
	.dw	DELAYcommand		
			
	.db	"DSRE"		;DSRECIVE - recieve by to TOS from DS Interface
	.dw	dsrcommand		
					
	.db	"DSCO"		;DSCOMMAND - Send TOS via DS Interface as command
	.dw	dsccommand		
					
	.db	"DSDE"		;DSDATA - Send TOS via DS Interface as data
	.dw	dsdcommand		
									
	.db	$00,$00

	
listcommand:	;lists program memory buffer to screen..
	rcall	crlf
	ldi	ZH,pmemtopage	;Initialize PC position inidcator
	ldi 	ZL,pmemtop
anotherchar:
	cp	ZH,PChigh
	brne	skip1
	cp	ZL,PClow	;Was cpi pmembot
	breq	endofpmem
skip1:
	ld	outchar,Z	;Put contents of line buffer into outchar;	
	rcall	emitchar0D
	sbiw	ZH:ZL,1
	rjmp	anotherchar
endofpmem:
	rcall	crlf
	;(listcommand flows into sizecommand)

sizecommand:	;Find remaining program memory space. Uses U.
	rcall	crlf

	ldi	ZH,high(2*freeword)	;Load high part of byte address into ZH
	ldi	ZL,low(2*freeword)	;Load low part of byte address into ZL
	rcall	sendromstring		;sent it.
	
	
	mov	U,PClow	
	mov	H,PChigh	
	subi	U,pmembot
	sbci	H,pmembotpage
	rcall	pushU
	mov	U,H
	rcall	binarytodecimal
	rcall	sendHTUasdecimal
	
	
	ldi	ZH,high(2*pageword)	;Load high part of byte address into ZH
	ldi	ZL,low(2*pageword)	;Load low part of byte address into ZL
	rcall	sendromstring		;sent it.
	rcall	popU
	rcall	binarytodecimal
	rcall	sendHTUasdecimal
	rcall	crlf
	ret




printcommand:			;Print TOS after call, to screen
	andi	XL,$FE		;Flag to leave value of variables on stack
	rcall	interpretline
	rcall	popU
	rcall	binarytodecimal
	rcall	sendHTUasdecimal	
	rcall 	crlf
	ret


printhexcommand:			;Print TOS in hex, after call, to screen
	rcall	interpretlinev
	ldi	outchar,$24
	rcall	emitchar
	rcall	popU
	mov	inbytel,U
	rcall	sendbyte	
	rcall 	crlf
	ret
	
	
setequalscommand:		;Get value at TOS after call to variable on stack when 
				;equals command is called.
	andi	XL,$FE	;cbr	XL,0		;Flag to leave value of variables on stack
	rcall	interpretline	;**** can be made into single call to interpretlinev
	rcall	popU
	mov	temp,U
	rcall	popU
	ldi	ZH,varpage	
	mov	ZL,U
	st	Z,temp
	ret



evaluatecommand:;Euqal sign	;If XL,2 = 0, perform subtract command. 
				;If XL,2 = 1, set up FOR-NEXT loop
	sbrs	XL,$02
	rjmp	subtractcommand	;Its functionally identical to subtract.
				;Set up FOR-NEXT loop
	andi	XL,$FE		;Flag variable values to be left on stack next line	
	rcall	interpretline	;Get the rest of the loop parameters on the stack

	rcall	popU		;Pop loop target
	mov	looptarget,U	;Store loop target
	
	rcall	popU		;Pop initial counter value
	mov	T,U		;Put in T for now

	rcall	popU		;Pop pointer to counter
	
	mov	loopvariable,U	;Copy variable pointer into loopvariable register

	ldi	ZH,varpage	
	mov	ZL,U		;Copy  variable pointer into ZL as index
	st	Z,t		;Store initial counter value into counter
	
	ori	XL,$20		;Set flag asking runcommand to capture loop address

	
	ori	XL,$08		;Set flag activating NEXT
	andi	XL,$FA
	ret
	
	
nextcommand:			;The distant end of the FOR-NEXT loop
				;Tests the loop variable to see its equal target.
				;If its equal to target, go to next line
				;If not equal target, increment variable and 
				;Signal RUNCOMMAND to jump to loop return
						
	ldi	ZH,varpage	;This is fetching the the loop variable from variable space
	mov	ZL,loopvariable
	ld	temp,Z		;Get loop variable value into temp
	cp	temp,looptarget
	breq	finishedfnloop	;If they are equal, the loop's done
	inc	temp
	st	Z,temp		;Increment loop variable and put it back into the register			
	ori	XL,$10		;Set XL,4 to flag run command to jump to return address next time
finishedfnloop:
;	andi	XL,$F7		;Make sure that next flags is cleared 
	ret

	
notequalcommand:		; <> command -Returns opposite result of subtractcommand
	rcall	interpretlinev	
	rcall	popU
	mov	temp,U
	rcall	popU
	cp	U,temp
	breq	makeff
	clr	U
	rcall	pushU		
	ret
makeff:	ser	U
	rcall	pushU
	ret
	

acocommand:			;Put inverse of analog comparitor output on stack (0 for high)
	rcall	interpretlinev	
	ldi	U,0
	sbis	ACSR,ACO
	ldi	U,1
	rcall	pushU
	ret
	
peekcommand:			;Replace value on TOS (Top Of Stack) with contents of memory
				;at that location.
	rcall	interpretlinev
	rcall	popU
	mov	ZL,U
	ldi	ZH,0		;Peek is limited to page zero 
	ld	U,Z
	rcall 	pushU
	ret
;
pokecommand:			;Store data at one down from TOS at location pointed to by TOS

	rcall	interpretlinev

	rcall	popU
	mov	temp,U		;Pop uses Z register, so initialize after all the popping is done.
	rcall	popU
	ldi	ZH,0		;Poke is limited to page zero
	mov	ZL,temp
	st	Z,U
	ret
	
	
	
addcommand:
	rcall	interpretlinev
	rcall	popU
	mov	temp,U
	rcall	popU
	add	U,temp
	rcall	pushU
	ret


subtractcommand:
	rcall	interpretlinev
	rcall	popU
	mov	temp,U
	rcall	popU
	sub	U,temp
	rcall	pushU
	ret
	

andcommand:
	rcall	interpretlinev
	rcall	popU
	mov	temp,U
	rcall	popU
	and	U,temp
	rcall	pushU
	ret


lsrcommand:
	rcall	interpretlinev
	rcall	popU
	lsr	U
	rcall	pushU
	ret
	

lslcommand:
	rcall	interpretlinev
	rcall	popU
	lsl	U
	rcall	pushU
	ret
	

orcommand:
	rcall	interpretlinev
	rcall	popU
	mov	temp,U
	rcall	popU
	or	U,temp
	rcall	pushU
	ret


eorcommand:
	rcall	interpretlinev
	rcall	popU
	mov	temp,U
	rcall	popU
	eor	U,temp
	rcall	pushU
	ret


makeU1:
	ldi	U,1
	rcall	pushU
	ret

lessthancommand:
	rcall	interpretlinev
	rcall	popU
	mov	temp,U
	rcall	popU
	cp	U,temp
	rjmp	evaldiff
	
pwm8command:
	rcall	interpretlinev
	ldi	temp,$81
	out	TCCR1A,temp 		; 8 bit PWM
	out	TCCR1B,temp 		; prescaler = 1
	sbi	DDRD,5
	rcall	popU
	ldi	temp,$00
	out 	OCR1AH,temp
	out	OCR1AL,U
	ret



pwecommand:
	rcall	interpretlinev
	ldi	temp,$83		;set timer1 PWM mode
	out	TCCR1A,temp 		; 10 bit PWM not reverse (Fck/510)
	ldi	temp,$01
	out	TCCR1B,temp 		; prescaler = 1
	sbi	DDRB,5
	rcall	popU
	mov	temp,U
	rcall	popU
	out 	OCR1AH,U
	out	OCR1AL,temp
	ret


	
	
pwocommand:				;Pulse Width Modulation OFF	
	ldi	temp,$00		;set timer1 PWM mode
	out	TCCR1A,temp 
	ret
	
greaterthancommand:
	rcall	interpretlinev
	rcall	popU
	mov	temp,U
	rcall	popU
	cp	temp,U
evaldiff:
	ldi	U,0
	brpl	makeU1		;**** suspicious brpl command
	breq	makeU1
	rcall	pushU
	ret

	
ifcommand:	;Set falg to skip next line if number on TOS returned from rest 
		;of line is not zero
	rcall	interpretlinev
	rcall	popU	;Pop value off data stack
	tst	U		;
	breq	itszero
	ori	XL,$02
itszero:
	ret
	


thencommand:			;Return to previous calling routine using a	
	in	temp,spl	;skanky trick with stack pointer. Get pointer
	subi	temp,$FE	;Add 02 to value (undo one return address)
	out	spl,temp	;Put value back in stack pointer
	ret			;Pop up to previous call. Don't try this at home.


forcommand:			;Initial statement in FOR-NEXT structure
				;Sets flag to switch "=" routine to set up the
				;FOR-NEXT loop
	ori	XL,$04		;Set bit 3
	ret


tocommand:			;To in FOR-NEXT structure. This is a dummy command
	rcall	interpretlinev
	ret


endcommand:			;Stop execution by setting flag
	ori	XH,$02		;Set flag telling runcommand to stop.
	ret
		
	
	
	
hexcommand:			;Nasty and dangerous - get two following chars as hex put on stack.
	ld	inbyteh,Y
	rcall	advanclbpointer
	ld	inbytel,Y
	rcall	asciihex_to_byte
	mov	U,inbytel
	rcall	pushU
	rcall	advanclbpointer
	rcall	interpretlinev
	ret 	
	
	
	
getlineno:			;Search buffer for line number, set up for runcommand to jump to it.
				;Can use Y because will will be modified by this routine
				;before runcommand uses it again anyway.
	rcall	interpretlinev	;Get target line number to TOS (Top Of Stack)
	rcall	popU
	mov	inbyteh,U	;Put target line number into inbytel
	ldi	ZH,pmemtopage	;Could preserve ZH?
	ldi 	ZL,pmemtop	;Initialize PC position inidcator
	rjmp	pufistln	;Jump in the middle so first line no. can be found
	
searchCR:
	cp	ZH,PChigh
	brne	skip2
	cp	PClow,ZL	;Error if past end of buffer
	brsh	gotonotfound
skip2:
	ld	temp,Z
	cpi	temp,$0D
	breq	checkforlinumb	;Take the branch if CR is found
	sbiw	ZH:ZL,1
	rjmp	searchCR	;Else continue to look for CR

checkforlinumb:			;Found a CR now make line number
	sbiw	ZH:ZL,1		;Move pointer past CR
pufistln:
	clr	U
	clr	T
	clr	H
		
fetchanothernum:
	cp	ZH,PChigh
	brne	skip3
	cp	PClow,ZL	;Error if past end of buffer
;	brpl	gotonotfound
	brsh	gotonotfound
skip3:
	ld	temp,Z
	rcall	qcast		;Find out what kind of char this is
	cpi	ecode,$02	;$02 is a numeral
	brne	notanumeral
	mov	H,T		;Ita a numeral so shift it in
	mov	T,U
	mov	U,temp
	sbiw	ZH:ZL,1	
	rjmp	fetchanothernum
notanumeral:			;The pointer is not poiting to a numeral, so test the number.
	
	andi	H,$0F		;Its a number so make binary and push on stack
	andi	T,$0F
	andi	U,$0F
	rcall	decimaltobinary	;Change from 3 BCD bytes to one binary vaue	
	cp	inbyteh,U
	brne	searchCR	;No the current line number is in binary form
	ret
	

gotonotfound:
	ldi	ecode,$09	;Claim error - goto line not found
	rjmp	error

	
gotocommand:
	rcall	getlineno
	mov	YH,ZH
	mov	YL,ZL
	ret


gosubcommand:			;Do a gosub
				
	rcall	getlineno	;Get destination address in ZH and ZL	
	ori	XL,$C0		;Set flags to capture return address and jam destination address
	ret
	
	
returncommand:			;Return from gosub
	sbrs	XH,2
	rjmp	returnnotactive
	ori	XH,$01		;Set flag calling for jaming of return address	
	ret
returnnotactive:
	ori	XH,$02		;Set flag calling for program halt
	ret	
	
	

Savecommand:		;Save contents of memory from dstacktop to pmembot to EEPROM eepromtop down.
			;Values of PChigh and PClow to be stored in top two bytes of dstack.
	ldi	dstackpointer,dstacktop	;Initialize data stack pointer
	mov	U,PClow
	rcall	pushU
	mov	U,PChigh
	rcall	pushU			;dstack in the same page as the top of pmem, so saving pemem from
	ldi	YH,pmemtopage		;the top down will also save dstack
	ldi	YL,dstacktop		;dstack top is at the top of the page so use this of LSByte
	ldi	ZL,eeprogstortop
	ldi	ZH,eepromstrotopage

storeanotherchar:
	ld	temp,Y			;Put contents of program memory into temp
wrat1:	sbic	eecr,eewe		;Wait for EEPROM write to not be busy
	rjmp	wrat1
	out	eearH,ZH
	out	eearL,ZL		
	out	eedr,temp		;Set up the  write data
	sbi	eecr,eemwe
	sbi	eecr,eewe		;Trigger the write
	cpi	YH,pmembotpage
	brne	skip7
	cpi	YL,pmembot
	breq	finishedsaving
skip7:
	sbiw	ZH:ZL,1
	sbiw	YH:YL,1
	rjmp	storeanotherchar
finishedsaving:
	ret



Loadcommand:		;Save contents of memoru from dstacktop to pmembot to EEPROM eepromtop down.
			;Vales of PChight and PCLow to be read from top two bytes of dstack.
	ldi	YH,pmemtopage	
	ldi	YL,dstacktop
	ldi	ZL,eeprogstortop
	ldi	ZH,eepromstrotopage
loadanotherchar:
wratz1:	sbic	eecr,eewe		;Wait for EEPROM write to not be busy
	rjmp	wratz1
	out	eearH,ZH
	out	eearl,ZL		;move to EEPROM address register
	sbi	eecr,eere		;Trigger the read
	in	temp,eedr		;Get the data into temp
	st	Y,temp
	cpi	YH,pmembotpage
	brne	skip8
	cpi	YL,pmembot
	breq	finishedloading
skip8:
	sbiw	ZH:ZL,1
	sbiw	YH:YL,1
	rjmp	loadanotherchar
finishedloading:

	ldi	dstackpointer,dstacktop-2 ;Initialize data stack pointer
	rcall	popU
	mov	PChigh,U
	rcall	popU
	mov	PClow,U
	ret


emitcommand:
	rcall	interpretlinev
	rcall	popU
	mov	outchar,U
	rcall	emitchar
	ret


keycommand:		;Receive a byte from the terminal     
	sbis	usr,rxc		;Wait for byte to be received
	rjmp 	keycommand
	in	U,udr	;Read byte
	cpi	U,$03	;Is it control-C?
	brne	notermhalt1
	ori	XH,$02		;set flag to halt program
notermhalt1:
	rcall	pushU
	ret 



     
prbcommand:	;print in binary format
	rcall	interpretlinev
	rcall	popU
	ldi	temp,$08
stillsendingbinary:	
	ldi	outchar,$30
	rol	U
	brcc	dontsendone
	ldi	outchar,$31
dontsendone:
     	rcall  	emitchar
     	dec 	temp
     	brne	stillsendingbinary 
     	rcall	crlf   	
	ret		




setbitinA:				;Set bit in position inidicated at top of stack.
	rcall	interpretlinev
	rcall	bitpositiontoormask
	rcall	popU
	in	temp,PORTA
	or	temp,U
	out	PORTD,temp
	ret



clearbitinA:				;Clear bit in position inidicated at top of stack.
	rcall	interpretlinev
	rcall	bitpositiontoormask
	rcall	popU
	com	U
	in	temp,PORTA
	and	temp,U
	out	PORTD,temp
	ret


setbitinB:				;Set bit in position inidicated at top of stack.
	rcall	interpretlinev
	rcall	bitpositiontoormask
	rcall	popU
	in	temp,PORTB
	or	temp,U
	out	PORTD,temp
	ret



clearbitinB:				;Clear bit in position inidicated at top of stack.
	rcall	interpretlinev
	rcall	bitpositiontoormask
	rcall	popU
	com	U
	in	temp,PORTB
	and	temp,U
	out	PORTD,temp
	ret


setbitinC:				;Set bit in position inidicated at top of stack.
	rcall	interpretlinev
	rcall	bitpositiontoormask
	rcall	popU
	in	temp,PORTC
	or	temp,U
	out	PORTD,temp
	ret



clearbitinC:				;Clear bit in position inidicated at top of stack.
	rcall	interpretlinev
	rcall	bitpositiontoormask
	rcall	popU
	com	U
	in	temp,PORTC
	and	temp,U
	out	PORTD,temp
	ret




setbitinD:				;Set bit in position inidicated at top of stack.
	rcall	interpretlinev
	rcall	bitpositiontoormask
	rcall	popU
	in	temp,PORTD
	or	temp,U
	out	PORTD,temp
	ret



clearbitinD:				;Clear bit in position inidicated at top of stack.
	rcall	interpretlinev
	rcall	bitpositiontoormask
	rcall	popU
	com	U
	in	temp,PORTD
	and	temp,U
	out	PORTD,temp
	ret


setdirectionA:				;Set bit in position inidicated at top of stack.
	rcall	interpretlinev
	rcall	bitpositiontoormask
	rcall	popU
	in	temp,DDRA
	or	temp,U
	out	DDRA,temp
	ret



cleardirectionA:				;Clear bit in position inidicated at top of stack.
	rcall	interpretlinev
	rcall	bitpositiontoormask
	rcall	popU
	com	U
	in	temp,DDRA
	and	temp,U
	out	DDRA,temp
	ret


setdirectionB:				;Set bit in position inidicated at top of stack.
	rcall	interpretlinev
	rcall	bitpositiontoormask
	rcall	popU
	in	temp,DDRB
	or	temp,U
	out	DDRB,temp
	ret



cleardirectionB:				;Clear bit in position inidicated at top of stack.
	rcall	interpretlinev
	rcall	bitpositiontoormask
	rcall	popU
	com	U
	in	temp,DDRB
	and	temp,U
	out	DDRB,temp
	ret

setdirectionC:				;Set bit in position inidicated at top of stack.
	rcall	interpretlinev
	rcall	bitpositiontoormask
	rcall	popU
	in	temp,DDRC
	or	temp,U
	out	DDRC,temp
	ret



cleardirectionC:				;Clear bit in position inidicated at top of stack.
	rcall	interpretlinev
	rcall	bitpositiontoormask
	rcall	popU
	com	U
	in	temp,DDRC
	and	temp,U
	out	DDRC,temp
	ret
	
	
setdirectionD:				;Set bit in position inidicated at top of stack.
	rcall	interpretlinev
	rcall	bitpositiontoormask
	rcall	popU
	in	temp,DDRD
	or	temp,U
	out	DDRD,temp
	ret



cleardirectionD:				;Clear bit in position inidicated at top of stack.
	rcall	interpretlinev
	rcall	bitpositiontoormask
	rcall	popU
	com	U
	in	temp,DDRD
	and	temp,U
	out	DDRA,temp
	ret


testbitinA:				;Test bit in specified position indicated at top of stack.
	rcall	interpretlinev
	rcall	bitpositiontoormask
	rcall	popU
	in	temp,PINA
	and	temp,U
	ldi	U,0
	tst	temp
	brne	JA
	ldi	U,1
JA:	rcall	pushU
	ret


testbitinB:				;Test bit in specified position indicated at top of stack.
	rcall	interpretlinev
	rcall	bitpositiontoormask
	rcall	popU
	in	temp,PINB
	and	temp,U
	ldi	U,0
	tst	temp
	brne	JB
	ldi	U,1
JB:	rcall	pushU
	ret


testbitinC:				;Test bit in specified position indicated at top of stack.
	rcall	interpretlinev
	rcall	bitpositiontoormask
	rcall	popU
	in	temp,PINC
	and	temp,U
	ldi	U,0
	tst	temp
	brne	JC
	ldi	U,1
JC:	rcall	pushU
	ret


testbitinD:				;Test bit in specified position indicated at top of stack.
	rcall	interpretlinev
	rcall	bitpositiontoormask
	rcall	popU
	in	temp,PIND
	and	temp,U
	ldi	U,0
	tst	temp
	brne	JD
	ldi	U,1
JD:	rcall	pushU
	ret



outpAcommand:			;Output to PORTA
	rcall	interpretlinev	;Get target line number to TOS (Top Of Stack)
	rcall	popU
	out	PORTA,U
	ret
	
outpBcommand:			;Output to PORTB
	rcall	interpretlinev	;Get target line number to TOS (Top Of Stack)
	rcall	popU
	out	PORTB,U
	ret
	
outpCcommand:			;Output to PORTC
	rcall	interpretlinev	;Get target line number to TOS (Top Of Stack)
	rcall	popU
	out	PORTC,U
	ret
	
	
outpDcommand:			;Output to PORTD
	rcall	interpretlinev	;Get target line number to TOS (Top Of Stack)
	rcall	popU
	out	PORTD,U
	ret
		
	

outdAcommand:			;Output to DDRA
	rcall	interpretlinev	;Get target line number to TOS (Top Of Stack)
	rcall	popU
	out	DDRA,U
	ret



outdBcommand:			;Output to DDRB
	rcall	interpretlinev	;Get target line number to TOS (Top Of Stack)
	rcall	popU
	out	DDRB,U
	ret

	
	

outdCcommand:			;Output to DDRC
	rcall	interpretlinev	;Get target line number to TOS (Top Of Stack)
	rcall	popU
	out	DDRC,U
	ret


outdDcommand:			;Output to DDRD
	rcall	interpretlinev	;Get target line number to TOS (Top Of Stack)
	rcall	popU
	out	DDRD,U
	ret

inAcommand:
	in	U,PINA
	rcall	pushU
	ret

inBcommand:
	in	U,PINB
	andi	U,$FC
	rcall	pushU
	ret

inCcommand:
	in	U,PINC
	rcall	pushU
	ret

inDcommand:
	in	U,PIND
	andi	U,$FC
	rcall	pushU
	ret


breakmsgtxt:
	.db	"Break "
	.db	$0A,$0D
	.db     $00,$00
	


;//////////RUN COMMAND/////////////////
	
runcommand:			
	ldi	YH,pmemtopage		;Initialize PC position inidcator
	ldi 	YL,pmemtop	
checkandrunline:
	ldi	dstackpointer,dstacktop	;Initialize data stack pointer
					;Parameters may be passed on the stack within a line
					;but not between lines.
					
	ori	XL,$01		;Flag variable ponters to be left on stack

	rcall	Checkkeybd	;See if Control-C key was received
		

	sbrs	XL,$05		;FOR-NEXT management. Capture F-N return adddress
	rjmp	nocaploopad
	mov	loopreturnL,YL	;Copy return address (in interpreter p. space) to registers
	mov	loopreturnH,YH
	andi	XL,$DF		;Turn off flag -address captured.
nocaploopad:

	sbrs	XL,$04		;FOR-NEXT management. If XL,4 is set, jam in new address
	rjmp	noaddressjam
	mov	YH,loopreturnH 
	mov	YL,loopreturnL
	andi	XL,$EF		;Flip jaming flag off
noaddressjam:

	sbrs	XL,$06		;GOSUB-RETURN management: Capture GOSUB return address
	rjmp	nocapgosubret
	mov	gosubretL,YL
	mov	gosubretH,YH
	andi	XL,$BF		;Flip flag off
nocapgosubret:


	sbrs	XL,$07		;GOSUB-RETURN management:jamb destination address
	rjmp	nodestaddjam
	mov	YH,ZH 
	mov	YL,ZL
	ori	XH,$04		;Set flag indicating that gosub is active
	andi	XL,$7F		;Flip flag off
nodestaddjam:


	sbrs	XH,$00		;GOSUB-RETURN management: Jamb return address
	rjmp	noretjam
	mov	YH,gosubretH 
	mov	YL,gosubretL
	andi	XH,$FA		;Flip flags off (including gosub active flag)
noretjam:


	sbrs	XH,$01		;Halt flag -if set, halt
	rjmp	nostop
	rcall	breakmessage
	mov	YH,PChigh
	mov	YL,PClow	
	andi	XH,$FD		;Clear the halt flag
nostop:
	cp	YH,PChigh
	brne	skip4		
	cp	PClow,YL	;See if the end of the buffer has been reached
;	brpl	endofprogram	;**** changed to BRSH now works past about 127 bytes
	brsh	endofprogram
skip4:
	ld	temp,Y		;Get char from buffer into temp
	rcall	Qcast		;See what type of char it is.
	
	sbrs	XL,$01		;If XL bit 1 is clear, skip this line- move cursor
	rjmp	noskipline	;to next carriage return
	cpi	ecode,$04
	breq	noskipline
	sbiw	YH:YL,1	
	rjmp	checkandrunline

	
noskipline:
	andi	XL,$FD		;Make sure that skip line flag is cleared for next time around
	; **** does clearing this flag now actuall do anyting?
;	Code below uses Qcast call several lines above.
	cpi	ecode,$02	;See if its a numeral
	brne	notonlinenumber	
	sbiw	YH:YL,1		;If numeral, move pointer past it
	rjmp	checkandrunline
notonlinenumber:

	rcall	interpretline			
	rjmp 	checkandrunline
endofprogram:
	ret
	
	

newprogramgreet:
	rcall	TypeGreeting		
newprogram:		;Ready program space and interpreter for new program
	ldi	temp,pmemtopage
	mov	PChigh,temp		;Initialize PC position inidcator
	ldi 	temp,pmemtop
	mov	PClow,temp
	mov	ZH,PChigh		;Initialize program memory pointer to top of program memory
	mov	ZL,PClow	
	ldi	dstackpointer,dstacktop	;Initialize data stack pointer

	ldi	XL,$00			;Clear interpreter mode flags
	ldi	XH,$00
	
	ldi	temp,$00	
doanotherone:
	cpi	ZH,pmembotpage
	brne	skip6
	cpi	ZL,pmembot	
	breq	endofpmem1
skip6:
	st	Z,temp			;fill memory with nulls ($00)
	sbiw	ZH:ZL,1
	rjmp	doanotherone
endofpmem1:
	ret



dumppmembuffer:	;dumps pmem buffer for debug only.

	ldi	ZH,pmemtopage		;Initialize PC position inidcator
	ldi 	ZL,pmemtop
anotherchar2:
	cpi	ZH,pmembotpage
	brne	skip5
	cpi	ZL,pmembot
	breq	endofpmem2
skip5:
	ld	inbytel,Z	;Put contents of line buffer into outchar;	
	rcall	sendbyte
	ldi	outchar,$20
	rcall	emitchar
	ldi	outchar,$20
	rcall	emitchar
	sbiw	ZH:ZL,1
	rjmp	anotherchar2
endofpmem2:
	rcall	crlf		;dump XL, looptarget,loopvariable,loopreturnL
	rcall	crlf
	
	
	mov	inbytel,PChigh	
	rcall	sendbyte
	
	ldi	outchar,$20
	rcall 	emitchar
	mov	inbytel,PClow
	rcall	sendbyte
	
	
	rcall	crlf
	rcall 	crlf
	ret
	
	
breakmessage:
	ldi	ZH,high(2*breakmsgtxt)	;Load high part of byte address into ZH
	ldi	ZL,low(2*breakmsgtxt)	;Load low part of byte address into ZL
	rcall	sendromstring		;sent it.
	ret



DELAYcommand:		;wait for (tos) times 2^16 times around the loop.
	rcall	interpretlinev	;Get target line number to TOS (Top Of Stack)
	rcall	popU
	clr	H
	clr	T
	clr	ecode
	clr	temp
decu:
	tst	U
	breq	delaydone
dech:
	dec	H
dect:
	dec	T
dececode:	
	dec	ecode
dectemp:
decinbyteh:
	dec	inbyteh
	brne	decinbyteh
	dec	temp
	brne	dectemp	
	brne	dececode
	brne	dect
	brne	dech
	dec	U
	rjmp	decu

delaydone:
	ret
	
	
dsdcommand:		;Send byte (top of stack) via DS port
	rcall	interpretlinev	;Get target line number to TOS (Top Of Stack)
	rcall	popU
	mov	inchar,U
	clc
	rcall	SendDSByte	
	ret
	
	
dsccommand:		;Send byte (top of stack) via DS port
	rcall	interpretlinev	;Get target line number to TOS (Top Of Stack)
	rcall	popU
	mov	inchar,U
	sec
	rcall	SendDSByte	
	ret
	
	
	
dsrcommand:		;Receive a byte vai DS port	
	rcall	ReceiveDSByte
	mov	U,inchar
	rcall	pushU
	ret
	
;/////////////////// DS INTERFACE BYTE SEND AND RECEIVE ROUTINES////////////////

;	Registers used:
;	inchar 	;byte to be sent
;	temp 	;scratch
;	inbytel,inbyteh	;counter used for timing delay
;	H ;counter for number of bits transfered



;//////////SEND A BYTE
; Send carry bit as first bit, then send inchar bit-by-bit. inchar destroyed.
SendDSByte:

	in	temp,DDRD	;assure that PORT D is set up to be compatible with DS Interface
	andi	temp,$E7
	out	DDRD,temp
	in	temp,PORTD
	ori	temp,$18
	out	PORTD,temp
	
	ldi	H,$09

S1:
	
	sbis	PIND,attline		;Wait for Attention line to go high =--SEND A BIT
	rjmp	S1
	

	sbi	PORTD,dataline		;Put data on data line
	cbi	DDRD,dataline
	brcs	R1	
	cbi	PORTD,dataline
	sbi	DDRD,dataline
R1:	
	cbi	PORTD,attline		;Set Attention line low
	sbi	DDRD, attline

	rcall	shortdelay		;Wait a short time so other chip can see Attnetion line is low
	cbi	DDRD,attline		;Release Attention line for a peak
	sbi	PORTD,attline
	rcall	shortdelay		;Short delay to allow settling of lines
	sbic	PIND,attline		;If Attention line isn't low, go back and put it low again, else continue
	rjmp	R1
	
	brcs	szero			;Invert data line
	sbi	PORTD,dataline
	cbi	DDRD,dataline
	rjmp	R3
szero:	cbi	PORTD,dataline
	sbi	DDRD,dataline
R3:
	
	sbis	PIND,attline		;Wait for Attention line to go high
	rjmp	R3
	
	cbi	DDRD,dataline		;Let data line float
	sbi	PORTD,dataline
					;-finished sending a bit

	rol	inchar			;Shift inchar through carry

	dec	H
	brne	S1			;Continue until all bits sent
ret




ReceiveDSByte: ;Get a byte into inchar, and "start bit" into carry bit.

	in	temp,DDRD	;assure that PORT D is set up to be compatible with DS Interface
	andi	temp,$D7
	out	DDRD,temp
	in	temp,PORTD
	ori	temp,$18
	out	PORTD,temp
	ldi	H,$09

W3:					;Get a bit from the input into the carry
	sbic	PIND,attline		;Wait for Attention line to go low
	rjmp	w3
	
	clc				;Latch dataline into carry bit
	sbis	PIND,dataline
	rjmp	NotaOne
	sec	
	
	cbi	PORTD,attline		;ACK by pulling attention line low
	sbi	DDRD, attline
	
W1:					;Wait for data line to go low
	sbic	PIND,dataline
	rjmp	W1
	rjmp	RelesaseAttLineAndGo
		
	
NotaOne:
	
	cbi	PORTD,attline		;ACK by pulling attention line low
	sbi	DDRD, attline
	
	
W2:					;Wait for data line to go high
	sbis	PIND,dataline
	rjmp	W2

RelesaseAttLineAndGo:			;Release attention line
	cbi	DDRD, attline
 	sbi	PORTD,attline		
					;DONE RECEIVING BIT
	rol	inchar		;Shift inchar through carry

	dec	H
	brne	W3			;Continue until all bits received
ret



shortdelay:
	ldi	inbytel,settletime
outerloop:
	ldi	inbyteh,settletime	
innerloop:
	dec	inbyteh
	brne	innerloop
	dec	inbytel
	brne	outerloop	
	ret


Checkkeybd:		;See if there is any reason to stop output or stop program execution
			;If control-s is found in keyboard buffer and if XH bit 6 is set, wait until
			;another key is pressed. This routine assures that XH,6 is cleared at exit.
			;If control-C then stop program execution before executing
			;the next line.

	sbis	usr,rxc		;if byte received, from termnial, get it
	rjmp	nokeydown
	in	temp,udr	;Read byte
	cpi	temp,$13	;Is it control-S?
	brne	noterstop
	ori	XH,$40		;Set the flag indicating that suspend was requested
	rjmp	notermhalt
		
noterstop:

	in	temp,udr	;Read byte
	cpi	temp,$03	;Is it control-C?
	brne	notermhalt
	ori	XH,$02		;set flag to halt program.

notermhalt:
nokeydown:
	ret

