	list      p=16F84             ; list directive to define processor
	#include <p16F84.inc>         ; processor specific variable definitions

	__CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_ON & _RC_OSC

;------ All timing in this program is set for RC operation using a 4.7K and 18 pF RC circuit.  This really
;------ doesn't operate properly at the calculated frequency, so I had to change the timing for the delay
;------ loops and buzzer tones through experimentation.  Each Tcy is approximately 1.8us rather than 1.0us
;------ (at 4MHz).  If desired, a 4MHz crystal could be used with a TMR0 prescale of 1:2 and probably achieve
;------ the same overall game speed.  Maybe some of the Delay subroutine timing would have to be fixed, though,
;------ as it counts based on incrementing W, not via TMR0.

;***** VARIABLE DEFINITIONS
CBLOCK	0x0C
	w_temp		
	status_temp		; for context saving during interrupt routines
	rnd_hold		; register to hold temporary value of rnd number
	TMR_Div			; divisor for TMR0 overflow - every 64 overflows equals ONE TMR_Overflow increment
	TMR_Overflow		; counts how many times TMR0 overflows
	Delay_Count		; counter for delay loop
	LED_Number		; holds which LED should be active
	User_Number		; holds which button was pressed by user
	Move_Number		; register to hold address of EEPROM current move
	Recall_Addr		; current move number - call address for EEPROM recall routine
	speed_value		; holds the current tone delay cycle
	Tone			; register to hold flags to determine which tone to sound:
				; (if all clear, do not sound any tones)
				; bit0:	1=sound Red_Tone
				;	0=don't sound Red_Tone
				; bit1:	1=sound Yellow_Tone
				;	0=don't sound Yellow_Tone
				; bit2:	1=sound Green_Tone
				;	0=don't sound Green_Tone
				; bit3:	1=sound Blue_Tone
				;	0=don't sound Blue_Tone
				; bit4:	1=sound Error_Tone
				; 	0=don't sound Error_Tone
	Tone_Count		; register to hold the number of TMR0 overflows desired for proper tone
	flags			; register to hold generic flags
				; bit0:	1=tone output wave currently high
				;	0=tone output wave currently low
				; bit1:	1=demo mode enabled
				;	0=demo mode off - normal program operation
				; bit2:	1=reverse mode enabled - newest move displayed first
				; 	0=normal program operation - newest move displayed last
				; bit3:	1=difficult mode - two moves per round
				;	0=easy mode - normal operation
				; bit4:	1=second time through loop for difficult mode
				;	0=first time through loop - ok to repeat for second move in this round
				; bit5:	1=silent mode enabled
				;	0=not silent mode - OK to output tones
	Hold_Number		; register to hold the random number seed for next randomized number (used for demo mode)
ENDC	; 15 RAM registers allocated

;------ Initialize literal values
Timeout		EQU	0xC8	; timeout delay limit (Timeout * TMR0 overflows*64 = ~5 seconds)
easy_speed	EQU	0x14	; starting speed value - 20 loops is a nice starting speed
				; increasing this will slow the game play down by increasing the buzzer ON time, and vice versa
				; Using this value, it will take 26 moves to get down to the base_speed.
difficult_speed	EQU	0x0D	; using this value, it will take 12 moves to get to the base speed
base_speed	EQU	0x07	; upper limit for speed, be careful (0x07 is not very fast, but fast enough)
Error_Tone	EQU	0x08	; 8 loops @ 256*1.8us = 135 Hz
Red_Tone	EQU	0x05	; 5 loops @ 256*1.8us = 2.30ms per high and low bit (217Hz)
Yellow_Tone	EQU	0x04	; 4 loops @ 256*1.8us = 1.84ms per high and low bit (271Hz)
Green_Tone	EQU	0x03	; 3 loops @ 256*1.8us = 1.38ms per high and low bit (361Hz)
Blue_Tone	EQU	0x02	; 2 loops @ 256*1.8us = .920ms per high and low bit (542Hz)

OPTIONVAL	EQU	0x98	; PORTB P/U off, TMR0 internal, RB0 falling edge, WDT prescale (1:1 for TMR0)
INTCONVAL	EQU	0xA8	; GIE & T0IE enabled, RB0 int. disabled, RBIE (port change) enabled for Tone generation only
TRISAVAL	EQU	0xFF	; direction: PORTA all input
;-- PORTA<0:3> are Red, Yellow, Green, Blue pushbuttons, respectively
TRISBVAL	EQU	0x00	; direction: PORTB all output
;-- RB1 is connected to speaker output.
;-- PORTB<2:5> are Red, Yellow, Green, Blue LEDs, respectively
;-- Note that RB0 is reserved in case RB0 interrupt is desired.

;**********************************************************************
		ORG     0x000			; processor reset vector
  		goto    Start			; go to beginning of program

;------ Interrupts below
		ORG     0x004			; interrupt vector location

		movwf	w_temp			; save off W and STATUS registers
		swapf	STATUS, 0
		movwf	status_temp
		clrf	STATUS			; select Bank0
		btfsc	flags, 5		; if silent mode...
		clrf	Tone			; ...then prevent any tones from sounding
		btfsc	INTCON, T0IF
		goto	Timer_Int
		btfsc	INTCON, RBIF		; PORTB change flag (only set to generate tone)
		goto	Generate_Tone
		movf	INTCON, 0
		andlw	0xF8			; clear all flags and ignore the interrupt if unknown
		movwf	INTCON
		goto	Reset_Interrupts

Timer_Int
;------ Note the use of TMR_Div - this achieves a dual rate for TMR0 overflow.  The straight 1:1 rate is used for
;------ the tone generation frequency count, and the 1:64 rate is used for the game speed.
		bcf	INTCON, T0IF		; clear TMR0 overflow-interrupt flag
		decfsz	TMR_Div
		goto	Continue_Tone		; always find out if a tone is sounding
		incf	TMR_Overflow		; this increments once every 64 TMR0 overflows
		movlw	0x40			; reset TMR_Div to 64 cycles through
		movwf	TMR_Div
		goto	Continue_Tone		; always check tone sound if TMR0 overflows

Generate_Tone
;------ Find out which Tone should be sounded, then begin the tone on the NEXT TMR0 interrupt
		btfsc	Tone, 0
		movlw	Red_Tone
		btfsc	Tone, 1
		movlw	Yellow_Tone
		btfsc	Tone, 2
		movlw	Green_Tone
		btfsc	Tone, 3
		movlw	Blue_Tone
		btfsc	Tone, 4
		movlw	Error_Tone
		movwf	Tone_Count
		goto	Reset_Interrupts
Continue_Tone
		movf	Tone, 1
		btfss	STATUS, Z		; if Tone register is all zeros, do not sound or continue any tones
		decfsz	Tone_Count
		goto	Reset_Interrupts
		goto	Switch_Wave
Switch_Wave
		btfss	flags, 0		; if we're currently outputting a high wave, switch to low
		goto	Set_High
		bcf	PORTB, 1
		bcf	flags, 0		; we're outputting a low wave now
		goto	Generate_Tone		; reset Tone_Count for next time
Set_High
		bsf	PORTB, 1		; otherwise set the wave high
		bsf	flags, 0		; we're outputting a high wave now
		goto	Generate_Tone

Reset_Interrupts
		bcf	INTCON, RBIF		; always keep this flag cleared
		swapf	status_temp, 0		; restore all registers
		movwf	STATUS
		swapf	w_temp, 1
		swapf	w_temp, 0
		retfie

;------ Done with interrupts.

Start
		bsf	STATUS,	RP0		; select bank 1
		movlw	OPTIONVAL
		movwf	OPTION_REG		; set options in PIC
		movlw	TRISAVAL
		movwf	TRISA			; set port A direction bits
		movlw	TRISBVAL		; set PORTB for all output
		movwf	TRISB
		bcf	STATUS, RP0		; select bank 0

		clrf	Move_Number
		clrf	Tone
		clrf	flags
		movlw	0x3C
		movwf	PORTB			; set all LEDs to turn on for power-up indication

		btfss	PORTA, 0		; Red button normally pulled high - if low, then enable demo mode
		bsf	flags, 1
		btfss	PORTA, 1		; Yellow button normally pulled high - if low, then enable reverse mode
		bsf	flags, 2
		btfss	PORTA, 2		; Green button normally pulled high - if low, then enable silent mode
		bsf	flags, 5
		btfss	PORTA, 3		; Blue button normally pulled high - if low, then enable double mode
		bsf	flags, 3

		movlw	base_speed		; base speed - absolute upper speed limit
		movwf	speed_value
		movlw	easy_speed		; default is easy speed
		btfss	PORTA, 4
		movlw	difficult_speed		; difficult switch selected (normally pulled high)
		addwf	speed_value		; add the constant to the base speed
;------ How speed_value works:
; LED will light and correct tone will sound *when generated by the program*.  (When user input generates the tone, it
; will shut off when the button is released, or if the timeout is exceeded)  A flag is set to initiate an interrupt
; to begin the tone sounding.  After TMR_Overflow increments enough to equal the speed_value, the sound will shut off.
; TMR_Overflow will increment once per (256 TMR0 counts * 64 TMR_Div) instructions @ ~1.8us each.  So, the total time for
; each TMR_Overflow is ~0.0295 seconds.  With a speed_value of 0x10, for example, this will be 16*.0295=0.47 seconds per
; move.  Note that this will keep getting faster until the base_speed is reached.
;------

;------ Delay for ~4 seconds (3 + 1 for Main delay) for user to get set up
		clrw
		clrf	Delay_Count		; set for 256 loops (~.45 seconds total)
		call	Delay
		clrw
		clrf	Delay_Count		; set for 256 loops
		call	Delay
		clrw
		clrf	Delay_Count		; set for 256 loops
		call	Delay
		clrw
		clrf	Delay_Count		; set for 256 loops
		call	Delay
		clrw
		clrf	Delay_Count		; set for 256 loops
		call	Delay
		clrw
		clrf	Delay_Count		; set for 256 loops
		call	Delay
		clrw
		clrf	Delay_Count		; set for 256 loops
		call	Delay

		movlw	INTCONVAL
		movwf	INTCON			; set interrupts
		movf	TMR0, 0
		movwf	Hold_Number		; used for demo mode
		clrf	PORTB			; turn off all LEDs after power-up sequence

Main
;------ Delay for ~1 second between sequences
		clrw
		clrf	Delay_Count		; set for 256 loops
		call	Delay
		clrw
		clrf	Delay_Count		; set for 256 loops
		call	Delay

		rrf	Move_Number, 0		; decrement once every 2 moves to increase game speed
		btfss	STATUS, C
		goto	No_Reduction

		movf	speed_value, 0
		sublw	base_speed
		btfss	STATUS, C		; if speed_value >= base speed, speed_value-- every 2 moves
		decf	speed_value

No_Reduction
;------ This section reads the current value of TMR0 (unpredictable because of user input on switches) and loads
;------ it into LED_Number to be randomized.  If demo mode is enabled, don't use TMR0 each time, only use the first
;------ one as a seed, then recycle each randomized value as a seed for the next move.
;------ Once the move is randomized, it's stored in EEPROM memory, then the recall address is set (to the first move
;------ if normal operation, or to the last move if reverse mode is enabled) and each move is recalled and displayed
;------ at a speed determined by the speed_value.
		movf	TMR0, 0			; use unknown state of TMR0 as seed for random number
		btfsc	flags, 1		; if demo mode, load random number
		movf	Hold_Number, 0
		movwf	LED_Number
		call	Randomize		; returns LED number to illuminate next
		incf	Move_Number		; create next move - do not use location 0x00 (start at 0x01)
		call	Store_Number		; add this number to stored values
		clrf	Recall_Addr
		incf	Recall_Addr		; begin at 0x01 for move recall for normal operation mode
		movf	Move_Number, 0
		btfsc	flags, 2		; if reverse mode, begin recall address at maximum move number
		movwf	Recall_Addr		; start recalling moves at the current max. move number
						; This register is decreased to zero to provide the move sequence
						; while the Move_Number register holds the current latest move number
		sublw	0x40
		btfsc	STATUS, Z		; 64 moves max. (really 63 since we started at 0x01)
		goto	Game_Finished		; if we get to this point, game is over

		btfsc	flags, 3		; if we're in difficult mode, then check flag bit 4
		btfsc	flags, 4		; if this is the first time through (bit=clear)...
		goto	Recall_Loop		; if bit3 clear or if bit4 set, skip the second move
		bsf	flags, 4
		goto	Main			; ...then set flag and create another move for difficult mode
Recall_Loop
		bcf	flags, 4		; as default, clear flag
		movlw	0xAA			; set for 170 loops to add a small break between moves
		movwf	Delay_Count
		clrw
		call	Delay
		call	Recall_Number		; read the current Recall_Addr and return the move into LED_Number

		movlw	LED_Number		; treat as literal to load address pointer into FSR
		movwf	FSR			; load FSR with LED_Number address pointer
		call	Switch_LED		; determines which LED to illuminate, does so and selects tone
		call	SoundTone		; begin sounding correct tone

		btfsc	flags, 2		; if reverse mode is set, skip to proper display method
		goto	Reverse_Method
		movf	Move_Number, 0
		subwf	Recall_Addr, 0
		btfsc	STATUS, C
		goto	Test_Mode		; if equal or greater, we're done recalling moves
		incf	Recall_Addr		; otherwise display next move
		goto	Recall_Loop

Reverse_Method
		decfsz	Recall_Addr		; output next move (note that 0x01 is the lowest move)
		goto	Recall_Loop

Test_Mode
		btfsc	flags, 1		; if demo mode, skip user input...
		goto	Main			; ...and loop directly back to generate the next move
;------ This next section of the program recalls each move and waits for user input before comparing them.  After
;------ each move is recalled, we wait for user input by polling the switches.  Once one is pressed, the corresponding
;------ tone is sounded as long as the button is depressed.  Once released (if within the timeout period), the
;------ user input move is compared with the expected (recalled) move.  If they match, the next move is recalled
;------ until all moves are finished.  Then we loop back again to generate the next move.  Once we hit 63 moves,
;------ we're done.
		clrf	Recall_Addr
		incf	Recall_Addr		; begin at 0x01 for move recall for normal operation mode
		movf	Move_Number, 0
		btfsc	flags, 2		; if reverse mode, start at maximum move number
		movwf	Recall_Addr		; reset address register to top position
GetUserInput
		call	Recall_Number		; get current "move" to match with user input
		movlw	0x40
		movwf	TMR_Div			; reset divisor and overflow registers
		clrf	TMR_Overflow		; holds total timeout counts for user input
		call	WaitForButton		; waits for user input, W register holds button pressed on return
		movwf	User_Number		; dump off which button was pressed
		movlw	0x0C
		movwf	Delay_Count
		clrw
		call	Delay			; debounce switch to 20ms

		movlw	User_Number		; treat as literal to load address pointer into FSR
		movwf	FSR			; load FSR with LED_Number address pointer
		call	Switch_LED		; indicate which LED the user pressed
;------ Wait for button to be released - user can't cheat by holding down the button due to timeout.
;------ We will use User_Number to determine which button to wait for, rather than check ALL buttons, since
;------ the user could press another button and, due to the bounce, effectively "release" a button, thus throwing
;------ off the timing.
		movlw	0x40
		movwf	TMR_Div
		clrf	TMR_Overflow
		bsf	INTCON, RBIF		; use flag to begin generating tone

		call	WaitForRelease		; if timeout occurs, Failed_Input will be called from WaitForRelease
		clrf	PORTB			; turn off LEDs (and buzzer if still on)
		clrf	Tone			; reset the tone register to stop generating tone

		movlw	0x0C
		movwf	Delay_Count
		clrw
		call	Delay			; debounce switch to 20ms

		movf	LED_Number, 0		; compare LED and User numbers
		subwf	User_Number, 0
		btfss	STATUS, Z
		goto	Failed_Input		; if current move and User inputs don't match, abort

		btfsc	flags, 2		; if reverse mode is set, skip to proper display method
		goto	Reverse_Compare
		movf	Move_Number, 0
		subwf	Recall_Addr, 0
		btfsc	STATUS, C
		goto	Main			; if equal or greater, we're done recalling moves
		incf	Recall_Addr		; otherwise display next move
		goto	GetUserInput

Reverse_Compare
		decfsz	Recall_Addr		; output next move (note that 0x01 is the lowest move)
		goto	GetUserInput

		goto	Main			; continuous loop - find the next number in the cycle

;------------------------------------------- Win/Loss Endgame routines listed below --------------------------------
Failed_Input
;------ Turn on LED that was SUPPOSED to be entered and sound error tone.
		clrf	PORTB			; reset LEDs and buzzer in preparation for Error indication
		movlw	LED_Number		; treat as literal to load address pointer into FSR
		movwf	FSR			; load FSR with LED_Number address pointer
		call	Switch_LED		; will sound correct tone with LED in addition to the error_tone
		movlw	0x40			; long tone delay
		movwf	speed_value
		clrf	Tone
		bsf	Tone, 4			; error tone to be sounded
		call	SoundTone
		clrw
		clrf	Delay_Count
		call	Delay
		clrw
		clrf	Delay_Count		; set for 256 loops
		call	Delay			; wait for 1 second before sounding completed move count
;------ Divide Move_Number by 10 to identify to the user the maximum move number achieved.  Store multiplier in Recall_Addr
;------ and remainder in Move_Number.  Sound out total count with 10s as long low tones and 1s as short high tones.
;------ Also, light up Red LED for 10s and Yellow LED for 1s.
;------ We're not doing anything fancy here - we're just using successive subtraction for the division since it
;------ would be such a small number.  Alternately, some real division bit-shifting code could be substituted.
		clrf	Recall_Addr
Div_By_10
		movlw	0x0A			; successive subtraction by 10
		subwf	Move_Number, 0
		btfss	STATUS, C		; if carry=0, we overflowed, so begin sounding tones
		goto	Sound_Tens
		incf	Recall_Addr
		movwf	Move_Number		; move remainder into Move_Number register for next subtraction
		goto	Div_By_10
Sound_Tens
		movf	Recall_Addr, 1		; move file to itself to test for zero
		btfsc	STATUS, Z
		goto	Sound_Ones		; if Recall_Addr = 0, skip to Ones
		movlw	0x20			; longer time duration for 10s
		movwf	speed_value
		clrf	Tone
		bsf	PORTB, 2		; turn Red LED on
		bsf	Tone, 0			; Red tone counts number of 10s
		call	SoundTone		; shuts off buzzer and LED
		clrw
		clrf	Delay_Count		; set for 256 loops
		call	Delay			; wait for 0.5 seconds between tones
		decfsz	Recall_Addr
		goto	Sound_Tens
Sound_Ones
		movf	Move_Number, 1
		btfsc	STATUS, Z
		sleep				; if no Ones, then end game
		movlw	0x10			; shorter tone duration for 1s
		movwf	speed_value
		clrf	Tone
		bsf	PORTB, 3		; turn Yellow LED on
		bsf	Tone, 3			; Blue tone counts number of 1s
		call	SoundTone		; shuts off buzzer and LED
		clrw
		clrf	Delay_Count		; set for 256 loops
		call	Delay			; wait for 0.5 seconds between tones
		decfsz	Move_Number
		goto	Sound_Ones
		sleep				; power-down to save battery after game over

Game_Finished
;------ Cycle speaker tones to indicate game won.
		movlw	0x07
		movwf	speed_value		; preset quick cycle time for tones in this routine
		movlw	0x05
		movwf	Delay_Count		; just re-use Delay_Count as a loop counter
		clrf	Tone
GF_Loop
		bsf	Tone, 0
		call	SoundTone
		bsf	Tone, 1
		call	SoundTone
		bsf	Tone, 2
		call	SoundTone
		bsf	Tone, 3
		call	SoundTone
		decfsz	Delay_Count		; 4 times through this routine
		goto	GF_Loop
		sleep

;------------------------------------------- Subroutines listed below ----------------------------------------------
Store_Number
;------ Stores value of LED_Number into EEPROM address "Move_Number"
		movf	Move_Number, 0
		movwf	EEADR
		movf	LED_Number, 0
		movwf	EEDATA
		bsf	STATUS, RP0		; select Bank1 for EECON access
		bcf	INTCON, GIE		; disable interrupts temporarily
		bsf	EECON1, WREN		; enable EEPROM write
		movlw	0x55
		movwf	EECON2
		movlw	0xAA
		movwf	EECON2
		bsf	EECON1, WR		; write values to EE
		bsf	INTCON, GIE		; reenable interrupts
		bcf	EECON1, WREN		; disable EEPROM write
Waitforflag
		btfss	EECON1, EEIF		; poll flag bit for write cycle completion
		goto	Waitforflag
		bcf	EECON1, EEIF		; reset flag - write cycle complete
		bcf	STATUS, RP0		; leave Bank0 active by default
		return

Recall_Number
;------ Recalls the value located at Recall_Addr from EEPROM into LED_Number
		movf	Recall_Addr, 0
		movwf	EEADR
		bsf	STATUS, RP0		; select Bank1 for EECON access
		bsf	EECON1, RD		; enable read
		bcf	STATUS, RP0		; select Bank0 for EEDATA access
		movf	EEDATA, 0
		movwf	LED_Number
		return

Randomize
;Rnew = Rold * 221 + 53
;221 = 256 - 32 - 4 + 1
;256 can be eliminated
;so we need to calculate Rnew = Rold * (1 - 32 - 4) + 53 using
;truncating arithmetic
;or Rnew = Rold * (-32 - 3) + 53
		clrc
		rlf	LED_Number, 1
		swapf	LED_Number, 0
		andlw	0xE0
		rrf	LED_Number, 1
		addwf	LED_Number, 0
		addwf	LED_Number, 0
		addwf	LED_Number, 0
		sublw	0x35
		movwf	LED_Number
		movwf	Hold_Number		; used for demo mode only

;Then divide by 64 to get a result from 0-3 (4 values):
;shift LED_Number right 6 times
		rlf	LED_Number, 1
		clrf	rnd_hold
		rlf	rnd_hold, 1
		rlf	LED_Number, 1
		rlf	rnd_hold, 1
		movf	rnd_hold, 0
		movwf	LED_Number
		return

Switch_LED
;------ Find out which LED should be turned on, then do it and select appropriate tone
;------ Indirect addressing is used due to 2 different sources to switch (user or program)
;------ Leave LED on when finished - must clear PORTB after this routine to turn off LEDs
;------ (This is done so when button is pressed by user input, the LED remains on)
		btfsc	INDF, 1			; test bit 1
		goto	GT_2			; number is either 2 or 3
		btfsc	INDF, 0			; test bit 0
		goto	Yellow
		bsf	PORTB, 2		; must be zero (Red)
		bsf	Tone, 0			; set flag to turn on Low tone
		return
Yellow
		bsf	PORTB, 3		; number is 1 (Yellow)
		bsf	Tone, 1
		return
GT_2
		btfsc	INDF, 0
		goto	Blue
		bsf	PORTB, 4		; must be 2 (Green)
		bsf	Tone, 2
		return
Blue
		bsf	PORTB, 5		; number is 3 (Blue)
		bsf	Tone, 3
		return

WaitForButton
;------ Continually poll PORTA switches to determine which was pressed (grounded).  Rather than using
;------ PORTB pin interrupt on change, polling is just as quick and I don't have to worry about reading
;------ other PORTB pins causing trouble or disabling/enabling interrupts at the proper times, etc.
;------ If TMR_Overflow equals allowed delay time (Timeout register), then abort due to timeout.
		btfss	PORTA, 0		; normally pulled-up
		retlw	0x00			; Red button depressed (RA0)
		btfss	PORTA, 1
		retlw	0x01			; Yellow (RA1)
		btfss	PORTA, 2
		retlw	0x02			; Green (RA2)
		btfss	PORTA, 3
		retlw	0x03			; Blue (RA3)
		movf	TMR_Overflow, 0
		sublw	Timeout
		btfsc	STATUS, Z
		goto	Failed_Input
		goto	WaitForButton

WaitForRelease
;------ Continually poll PORTA switches to determine if User_Number pin was released.
;------ If TMR_Overflow equals allowed delay time (Timeout register), then abort due to timeout.
		btfsc	User_Number, 1		; test bit 1
		goto	Pin2_3			; number is either 2 or 3
		btfsc	User_Number, 0		; test bit 0
		goto	Pin1Loop
Pin0Loop
		btfsc	PORTA, 0		; when pin is pulled up again, return
		return
		movf	TMR_Overflow, 0
		sublw	Timeout
		btfsc	STATUS, Z
		goto	Failed_Input		; exceeded timeout allowance
		goto	Pin0Loop
Pin1Loop
		btfsc	PORTA, 1
		return
		movf	TMR_Overflow, 0
		sublw	Timeout
		btfsc	STATUS, Z
		goto	Failed_Input
		goto	Pin1Loop
Pin2_3
		btfsc	User_Number, 0
		goto	Pin3Loop
Pin2Loop
		btfsc	PORTA, 2
		return
		movf	TMR_Overflow, 0
		sublw	Timeout
		btfsc	STATUS, Z
		goto	Failed_Input
		goto	Pin2Loop
Pin3Loop
		btfsc	PORTA, 3
		return
		movf	TMR_Overflow, 0
		sublw	Timeout
		btfsc	STATUS, Z
		goto	Failed_Input
		goto	Pin3Loop

SoundTone
;---Set flag to start interrupt moving which starts tone sounding, clear flag inside interrupt.
;---At every TMR0 overflow, we will check to see if tone is still sounding and also to see if we have
;---to change the wave bit from high to low.  The "Tone" register bits being set will determine if
;---the PORTB, 1 output continues, since the flag is cleared after the first time through.
		movlw	0x40
		movwf	TMR_Div			; reset divisor and overflow registers
		clrf	TMR_Overflow
		bsf	INTCON, RBIF		; use flag to begin generating tone
SoundToneLoop
		movf	speed_value, 0
		subwf	TMR_Overflow, 0
		btfss	STATUS, Z
		goto	SoundToneLoop
		clrf	PORTB			; turn off LEDs (and buzzer if still on)
		clrf	Tone			; reset the tone register to stop generating tone
		return

Delay
;------ Note that W register must be cleared before calling this routine to obtain the proper delay.
;------ Delay_Count is predefined with the multiplier (Delay_Count*256 loops*4Tcy) gives total delay.
;------ Delay is approximately .45 seconds with Delay_Count=0xFF.
;------ Note that if W register is preloaded with higher values, the total delay time can be fine tuned.
;------ Alternately, another constant can be defined and preloaded prior to entering this routine, then
;------ copying it to W and proceding normally.  Another inner loop would need to be defined, with the
;------ constant value being held outside the inner loop.
		addlw	0x01
		btfss	STATUS, Z
		goto	Delay
		decfsz	Delay_Count
		goto	Delay
		return

		END                     ; directive 'end of program'
