;*************************************************************
;ELECTRONIC PING-PONG!
;This program drives the electronic ping-pong game, 
;fixed speed, single mode of play.
;TJW 21.6.01. Rev. 14.3.05. 				Retested 15.4.05
;*************************************************************
;
;Clock freq 800kHz approx (RC osc.)
;Port A 4  	right paddle (ip)
;	  3	left paddle (ip)
;	  2	"out of play" led (op)
;	  1	"Score Left" led (op)
;	  0	"Score Right" led (op)
;Port B 7-0	"play" leds (all op)
;
;Config Word: 	RC oscillator, WDT off, 
;		power-up timer on, code protect off
;No Interrupts used
;
	list 	p=16F84A
;specify SFRs
status  equ     	03
porta   equ     	05
trisa   equ     	05
portb   equ     	06
trisb   equ     	06
;
;specify a constant
led_durn equ    	20   ;no. of time inner loop is iterated, hence
  				          ;time duration each led is lit.
;
;specify RAM locations
delcntr1 equ	10	;used in 5ms delay SR
delcntr2 equ	11	;used in 500ms delay SR
led_posn equ	12	;holds current ball led posn.
loop_cntr equ	13	;preloaded with value led_durn for every 
;led illumination, and counts down to 0 before 
;ball moves on
;
	org 	00
	goto	start
;
; **“Initialise” State**
; Initialise
	org	0010
start	bsf	status,5 ;select memory bank 1
	movlw	B'00011000'
	movwf	trisa	;port A according to above pattern 
	movlw	00
	movwf	trisb	;all port B bits op
	bcf	status,5 ;select bank 0
;
;**”Wait”** State
;set up initial led patterns
wait movlw	04
	movwf	porta	;switch on "out of play" led
	movlw	00
	movwf	portb	;all play leds off
;
;check that both paddles are clear before allowing play to commence
	btfss	porta,4 ;right paddle pressed?
	goto	wait	  ;yes, so wait
	btfss	porta,3 ;left paddle pressed?
	goto	wait    ;yes, so wait
;
;now ready for action, now wait until paddle pressed
wait1 btfss	porta,4 ;right paddle pressed?
	goto	r_to_l  ;yes, so start play
	btfss	porta,3 ;left paddle pressed?
	goto	l_to_r  ;yes, so start play
	goto	wait1
;
;**”Right-to-Left” State**
;play has started
r_to_l movlw 00	 ;switch off "out of play"
	movwf	porta
	movlw	80	 ;define ball start posn.
	movwf	led_posn
;loop to here every time led is to change
rtl_0 movlw	led_durn
	movwf	loop_cntr   ;preset length of led illumination
	movf	led_posn,w  ;output new ball posn
	movwf	portb
;loop to here n times for every led, where n = led_durn. 
;Check for rule violations. Special conditions apply if
;ball is at start or end.
rtl_1	btfss led_posn,7  ;is ball at start (ie posn 7)?
	goto	rtl_2 	;no, so move on
	;yes, it’s OK if right paddle still pressed, so don't test
	btfss	porta,3	;left paddle pressed?
	goto	rt_myscore  ;yes, so score
	goto	rtlend
rtl_2	btfss	led_posn,0  ;is ball at end (ie posn 0)?
	goto	rtl_3 	;no, so move on
;here if ball at end, left paddle can force direction change
	btfss	porta,3	;left paddle pressed?
	goto 	l_to_r	;yes, so change direction - **state exit**
	btfss	porta,4     ;right paddle pressed?
	goto	rt_yrscore  ;yes, so left scores
	goto	rtlend
;here if neither start nor end posn.
rtl_3	btfss	porta,4     ;right paddle pressed?
	goto	score_left  ; yes, so score
	btfss	porta,3     ;left paddle pressed?
	goto	rt_myscore  ;yes, so score
;at then end of each loop call a delay
rtlend call	delay5
	decfsz loop_cntr  ;decrement loop counter, check if led is to move
	goto	rtl_1
;here if ball moving on
	bcf	status,0
	rrf	led_posn,1
	btfsc	status,0 	;ball off end?
	goto	rt_myscore  ;yes, right's point
	goto	rtl_0
;**state exit**
rt_myscore	goto score_right
rt_yrscore 	goto score_left
;
;**”Left-to-Right” State**
l_to_r movlw 00	     ;switch off "out of play"
	movwf	porta
	movlw	01	     ;define ball start posn.
	movwf	led_posn
ltr_0	movlw	led_durn
	movwf	loop_cntr  ;determine length of led illumination
;go round this loop “duration” times, for every ball position
ltr_1	movf	led_posn,w ;output new ball posn
	movwf	portb
	btfss	led_posn,0 ;is ball at start (ie posn 0)?
	goto	ltr_2      ;no, so move on
	;yes, OK if left paddle still pressed (so only test rt paddle)
	btfss	porta,4    ;right paddle pressed?
	goto	lft_myscore	;yes, so score
	goto	ltrend
ltr_2	btfss	led_posn,7 ;is ball at end (ie posn 7)?
	goto	ltr_3      ;no, so move on
;here if ball at end, right paddle will change dirn, score right if left paddle
	btfss	porta,4    ;right paddle pressed?
	goto 	r_to_l     ;yes, so change direction
	btfss	porta,3    ;left paddle pressed?
	goto	lft_yrscore ;yes, so right score
	goto	ltrend
;here if neither start nor end posn.
ltr_3	btfss	porta,4    ;right paddle pressed?
	goto	lft_myscore ;yes, so score
	btfss	porta,3    ;left paddle pressed?
	goto	lft_yrscore ;yes, so score
ltrend call	delay5
	decfsz loop_cntr ;decrement loop counter, check if led is to move
	goto	ltr_1
;here if ball moving on
	bcf	status,0   ;Clear Carry, as rlf rotates through it
	rlf	led_posn,1
	btfsc	status,0  ;ball off end?
	goto	lft_myscore ;yes, left's point
	goto	ltr_0
;**state exit**
lft_myscore	goto score_left
lft_yrscore goto score_right
;	
;**”Score” State**
;here if Left has scored
score_left
	movlw	00
	movwf	portb	;all play leds off
	bsf		porta,1	;activate "score" led
	call	delay500
	bcf		porta,1	;clear "score" led
	goto	wait
;here if Right has scored
score_right
	movlw	00
	movwf	portb	;all play leds off
	bsf		porta,0	;activate "score" led
	call	delay500
	bcf		porta,0 ;clear "score" led
	goto	wait
;
;**********************************************
;SUBROUTINES
;**********************************************
;
;Delay of 5ms approx. Instruction cycle time is 5us.
delay5  movlw 	D'200' ;200 cycles called, 
							;each taking 5x5=25us
        movwf  	delcntr1
del1    nop			;5 inst cycles in this loop
        nop
        decfsz 	delcntr1,1
        goto 	del1
        return
; 
; Delay of 500ms (approx) - 100 calls to delay5
delay500  movlw D'100'
        movwf  	delcntr2
del2    call 	delay5
        decfsz  delcntr2,1
        goto 	del2
        return  
;
	end

