




;--------- UTILITY ROUTINES! -----------

; return user address input in X
;

***
;get_address: "util.asm"
;	used to get user input of an address. Could definitely use some help, as it does not
;	allow for backspaces or anything else. I'm not really sure why this code is in here.
;	Reg Input:
;		None
;	Reg Output:
;		X = user entered address
***

get_address:
	pshb					; saves state of B
	bsr		get_number		; gets a number input from the user
	lsla					; shifts the number over 4 bits since it
	lsla					; is the upper nibble of the byte
	lsla
	lsla
	psha					; stores what was entered
	bsr		get_number		; gets another number
	pulb					; puts the first value in B
	aba					; Adds B to A, forming the first byte of the address
	psha					; stores the address
	bsr		get_number		; gets another number
	lsla					; shifts the number over 4 bits since it
	lsla					; is the upper nibble of the byte
	lsla
	lsla
	psha					; stores what was entered
	bsr		get_number		; gets the lower nibble
	pulb					; puts upper nibble in B
	aba					; adds them together. put in A

*						* can be made more efficient
	psha					; saves the byte in A
	pulb					; so it can be put in B
	pula					; then pull the upper byte and put in A
	xgdx					; put address that is in D into X
	pulb					; restores the state of B
	rts					; returns with the address in X

***
;skip_wspace: "util.asm"
;	skips over whitespace characters in the command buffer
;	Reg Input:
;		Y = character buffer pointer
;	Reg output:
;		Y = character buffer pointer not pointing to whitespace
***


						; skips over whitespace chars in buffer pointed to by Y
						; returns an error code in B if we skip too much!
skip_wspace:
	ldab		#5			; we'll skip a max of 5 chars. error if more.
sw_loop1:
	ldaa		0,y			; loads the first character in the y buffer

*						* kind of a weird way of doing the space?
	cmpa		#'+'-1			; compares it with the value for a space
	ble		is_wspace		; if it is wspace, don't return -- keep going
	rts					; if not, return -- we've found good stuff
is_wspace:
	iny					; increment buffer to the next character
	decb					; decrement the whitespace counter
	beq		ret_error		; if the whitespace counter reaches 0, there is an error
	bra		sw_loop1		; keep skipping wspace until it finds good stuff
ret_error:
	ldab		#$ff			; loads error code
	rts					; then returns

***
;parse_byte: "util.asm"
;	parses an 8-bit byte from the command buffer
;	Reg Input:
;		Y = pointer to place in the command buffer
;	Reg Output:
;		Y = pointer after byte
;		A = value of the parsed byte 
***

						; parse_byte parses command buffer in Y for a two-char 
						; (and only two-char) byte which
						; is returned in A; error returned in B (if one)
parse_byte:
	jsr		skip_wspace		; skips the whitespace
	cmpb		#$ff			; check for error!	
	beq		pb_error		; if error, just return!
*						* no message is printed, wonder why not?
*						* this error occurs if too much whitespace is found

	pshb					; state of B is stored
	bsr		parse_number		; parses a number in the command buffer pointed to by Y
	lsla					; this is the upper nibble shifts it up
	lsla	
	lsla
	lsla	
	psha					; stores the upper nibble
	bsr		parse_number		; gets the lower nibble
	pulb					; loads the upper nibble
	aba					; combines the nibbles to form the byte
	pulb					; restores the state of B
pb_error:
	rts					; returns




***
;parse_address: "util.asm"
;	parses a 16-bit address from the command buffer
;	Reg Input:
;		Y = pointer to place in command buffer
;	Reg Output:
;		Y = pointer after address
;		X = address that was parsed
***
						; parse_address just parses out an address
						; (4 bytes) from the command buffer

parse_address:
	jsr		skip_wspace		; skips the whitespace
	cmpb		#$ff			; if there is an error( too much whitespace )
	beq		pa_error		; then leave

	bsr		parse_byte		; returns the first byte in A
	psha					; stores the first byte
	bsr		parse_byte		; returns the second byte in A

*						* use tab here
	psha					; moves the lower byte
	pulb					; into B
	pula					; puts the upper byte in A
						; D is now the number we want to return in X
	xgdx					; so we put D into X then return
pa_error:
	rts					; returns


***
;parse_number: "util.asm"
;	takes a single character from the command buffer and turns
;	it into the real value of the hex digit.
;	Reg Input:
;		Y = command buffer address pointer
;	Reg Output:
;		Y = incremented command buffer address
;		A = value of parsed byte
***

						; like get_number, this one gets a byte 
						; from the command buffer (Y)
						; and converts it to binary from ascii. returns in A
parse_number:
	ldaa		0,y			; loads in first value of command buffer
	cmpa		#$39			; checks if it is a number
	bgt		pn_alpha		; if not, it must be a letter so move on
	suba		#$30			; it is a number, so subtract $30 and you have
	bra		pn_overalpha		; your value to return in A
pn_alpha:
	anda		#$0f			; gets rid of the upper nibble
	adda		#9			; adds $9 to the number to get the real value of the
						; hex digit in the command buffer
pn_overalpha:
	iny					; move to next char
	rts					; return

***
;get_number: "util.asm"
;	gets user input of one single hex digit from the user, 0-15
;	Reg Input:
;		None
;	Reg Output:
;		A = value entered
***

						; this subroutine is used when loading s19 files
						; Now this get_number subroutine actually returns a
						; single hex number 0-15. It does not do a hex
						; double -- that is the get_byte subroutine.
get_number:					; the number is returned in A
	jsr		get_char_wait_noecho		; waits for a character to be entered
	cmpa	#$39				; checks to see if the character is a letter
	bgt		alpha_			; if it is a letter, go to the alpha_ routine
	suba	#$30				; subtract $30 if it is a number
	bra		over_alpha_		; then return number in A
alpha_:
	anda	#$0f				; cuts off the first 4 bits. A starts at $41, so that makes
	adda	#9				; A into $01, then add $9 and you have the right value. Same
over_alpha_:					; works for the rest of the letter digits.
	rts					; returns 

***
;print_splash: "util.asm"
;	used to print the splash screen at monitor reset
;	Reg Input:
;		None
;	Reg Output:
;		none
***


print_splash:					; very simple. prints the splash screen
	ldy		#newline		; loads a new line string
	jsr		print_string		; prints it. see "serial.asm"
	ldy		#msg_1			; loads the message address
	jsr		print_string		; prints it. see "serial.asm"
	ldy		#newline		; loads a new line string
	jsr		print_string		; prints it. see "serial.asm"
	rts					; returns to the stack



***
;get_byte: "util.asm"
;	gets user input of a byte. Does not allow for backspaces
;	Reg Input:
;		None
;	Reg Output:
;		A = byte input
***
						; get_byte
						; waits for two numbers (in hex)
						; to be entered and returns the
						; result in A
get_byte:
	pshb					; saves the state of B
	bsr		get_number		; returns a number entered by the user into A
	lsla					; shifts this number left, because it is the upper
	lsla					; nibble of the byte
	lsla		
	lsla	
	psha					; stores the upper nibble
	bsr		get_number		; gets the lower nibble
	pulb					; loads the upper nibble
	aba					; combines the nibbles to form a byte
	pulb					; restores the state of B
	rts					; returns
	

***
;get_line: "util.asm"
;	command prompt, gets whatever is typed and puts in a buffer
;	at the address of the command buffer. The buffer is 20 bytes
;	Reg Input:
;		X = command buffer address
;		B = size of command buffer
;	Reg Output:
;		none
***


						; get_line subroutine gets a line 
						; of text from the serial port
						; and puts it in a buffer starting 
						; at the address in X. The
						; "end of line" is a CRLF (13,10). 
						; You can prevent buffer overflows
						; by making B = # of chars that, if 
						; the user enters that many, will
						; automatically cause this sub to return
get_line:

	pshx					; lets push X to keep it unchanged so you could print it
	pshb					; keep B unchanged


*added						; this is used for repeating the previous command
	clr		tempw			; makes a counter in the temporary variable
	inc		tempw			; increments the counter to one
*endadd

gl_loop1:
	jsr		get_char_wait		; returns the character in A

*added

						; this section of code is for repeating the
						; previous command
	dec		tempw			; decrements the counter
	bne		gl_skip			; if the counter is not zero, then it is
						; not the first time it has been decremented
	cmpa		#13			; if it is the first time, check and see if the
	beq		gl_repeat		; character is a linefeed. if it is, then repeat
						; the previous command
	jsr		clear_cmd_buffer	; if not, then clear the command buffer and
						; carry on as usual
gl_skip:
	
*endadd


	cmpa		#8			; check to see if it is a backspace character
	beq		gl_backspace		; if it is, go to a different spot for handling backspaces

	staa		0,x			; otherwise store it in X
	inx					; increment X


	cmpa		#13			; only check for a 13 (LF) (if you hit enter)
	beq		gl_done			; if its a 13, return, because command is entered


	decb					; decrement B -- the line-length counter
	beq		gl_done			; if its zero, it means the user has entered enough. done.
	bra		gl_loop1		; continue getting characters

gl_done:
	inx					; increments X
	clra					; clears the value of A
*						* i think this can be done quicker
	staa		0,x			; put a zero at the end of the line to indicate eol
	pulb					; restore B
	pulx					; restore X
	rts					; returns

gl_repeat:
	pulb
	pulx
	rts


gl_backspace:					; handles the backspace
	clr		0,x			; clears the value rather than having a backspace char
	cmpb		#cmd_buffer_size	; compares B to 20. that is the max length of char buffer
	beq		gl_loop1		; if it is 20, then nothing should be done because it is
						; at the beginning of the buffer
	dex					; otherwise, decrement X
	incb					; and increment B
	bra		gl_loop1		; then look for another character



***
;clear_cmd_buffer: "util.asm"
;	zeroes out the command buffer
;	Reg Input:
;		None
;	Reg Output:
;		None
***

						; we need to clear the command buffer before 
						; each command input. I think.
clear_cmd_buffer:
	pshx					; saves state of X
	pshd					; saves state of X
	ldx		#cmd_buffer		; loads pointer to beginning of command buffer
	clrb					; clears content of B
	ldaa		#cmd_buffer_size	; loads A with the size of the command buffer
ccb_loop1:
	stab		0,x			; stores zero into the first spot
	inx					; increments pointer to next location
	deca					; decrements counter
	beq		ccb_done		; if the counter is zero, return
	bra		ccb_loop1		; else, continue zeroing the buffer
ccb_done:
	puld					; restores state of D
	pulx					; restores state of X
	rts					; returns
