
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;										;
;	pong version 1.0					;
;	by brad slattery 2008				;
;										;
;	a pong game for the 8x8 game board	;
;										;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


	LIST p=16f648a 					;	tell assembler what chip we are using
	include "P16f648a.inc"			;	include the defaults for the chip
	__config 0x3f18					;	sets the configuration settings (oscillator type etc.)

PC equ 0x02						;	The program counter is now refered to as PC

	cblock 0x20 				;	start of general purpose registers
		counta					;	used in the delay routine
		countb 					;	used in the delay routine
		x_coordinate			;	used to hold the dots x_coordinate
		y_coordinate			;	used to hold the dots y_coordinate
		player_1_paddle			;	holds the players paddle data
		ball_x					;	holds the balls x co-ordinate
		ball_y					;	holds the balls y co-ordinate
		ball_up					;	holds the ball up data
		ball_down				;	holds the ball down data
		ball_left				;	holds the ball left data
		ball_right				;	holds the ball right data
		ball_refresh			;	holds the ball refresh data
		button_timer			;	used to help in slowing down the button repeat rate (it prevents the car from moving many times for one button press)
		button_adjust			;	used to help in slowing down the button repeat rate (it prevents the car from moving many times for one button press)
		stop_repeat				;	used to help in slowing down the button repeat rate (it prevents the car from moving many times for one button press)
		endc

	org 0x0000						;	org sets the start address of our program to 0000 hex


	movlw h'07'						;	turn comparators off
	movwf CMCON 					;	this makes all Ports digital

	bsf STATUS, RP0 				;	select bank 1
	movlw b'00000000' 				;	set PORTB all outputs
	movwf TRISB						;
	movlw b'00100000' 				;	set PORTA all outputs except for bit 5
	movwf TRISA 					;	remember bit 5 cannot be made an output!
	bcf STATUS, RP0 				;	select bank 0




setup
	movlw b'11011010'		;	This disables all 74373 outputs, and closes
	movwf PORTA				;	all 74373 latches.
	movlw b'11000000'		;	player paddle start position
	movwf player_1_paddle	;	(starts up the top of the screen
	movlw b'10000000'		;	sets the balls start position
	movwf ball_x			;	which is the the top right
	movwf ball_y			;	hand corner of the screen
	clrf ball_up			;	clear the ball up flag
	clrf ball_down			;	clear the ball down flag
	clrf ball_left			;	clear the ball left flag
	clrf ball_right			;	clear the ball right flag
	bsf ball_down, 0		;	lets start the game off by making the
	bsf ball_left, 0		;	ball move down and to the left
	movlw d'50'				;	this sets the ball speed
	movwf ball_refresh		;	(the higher the number, the slower the ball speed.)
	clrf stop_repeat		;	clear the stop repeat flag (used in the button repeat rate routine
	movlw d'30'				;	set our button response delay (the higher the number,
	movwf button_adjust		;	the longer you have to wait to be able to push the button again)


begin								;	lets begin our program!
	call check_ball					;	call the check ball routine
	call draw_ball					;	call the draw ball routine
	call joystick					;	call the joystick routine (see if any buttons have been pressed)
	call draw_paddle				;	call the draw_dot routine (to place the x and y coordinates on the display)
	call move_ball					;	call the draw ball routine
	btfsc stop_repeat, 1			;	Check to see if the stop repeat bit 1 has been set,
	call button_time				;	if it has, then call the button_time routine (which will decrement the timer by one)
	goto begin						;	do it all again!


check_ball							;
	btfss ball_x, 1					;	first we need to see if the ball is next to our paddle column
	goto check_next					; 	if it is NOT then goto check_next, but if it is - 
	movf player_1_paddle, w			;	then check if the ball is going to hit the paddle
	andwf ball_y, w					;	if it is going to hit the paddle then
	btfss STATUS, Z					;	make the ball go to the right
	call set_right					;	(to the right) if not, then continue 
check_next	btfsc ball_y, 7			;	now check to see if the ball has hit the screen top
	call set_down					;	if it has then call set down, otherwise - 
	btfsc ball_y, 0					;	check to see if we have hit the screen bottom		
	call set_up						;	if it has then call set up, otherwise - 
	btfsc ball_x, 0					;	check to see if the ball has gone past our paddle
	goto setup						;	if it has then goto setup otherwise - 
	btfsc ball_x, 7					;	check to see if we have hit the right hand wall
	call set_left					;	if we have then call set left.
	return							;	and now return to our main program


move_ball						;	This routine takes care of actually moving the ball
	decfsz ball_refresh, f		;	decrement ball refresh by one, if it is zero
	return						;	then return (dont let the ball move) otherwise - 
	movlw d'50'					;	now reset our ball refresh data
	movwf ball_refresh			;	this defines how fast our ball will move.
	btfsc ball_up, 0			;	is the ball up flag set?
	rlf ball_y, f				;	if yes then move the ball up one space, otherwise
	btfsc ball_down, 0			;	is the ball down flag set?
	rrf ball_y, f				;	if yes then move the ball down one space, otherwise
	btfsc ball_left, 0			;	is the ball left flag set?
	rrf ball_x, f				;	if yes then move the ball left one space, otherwise
	btfsc ball_right, 0			;	is the ball right flag set?
	rlf ball_x, f				;	if yes then move the ball right one space, otherwise
	return						;	now return to where we came from

set_up						;	this routine sets our up flag
	bcf ball_down, 0		;	clear the down flag
	bsf ball_up, 0			;	set the up flag
	return					;	and return

set_down					;	this routine sets our down flag
	bcf ball_up, 0			;	clear the up flag
	bsf ball_down, 0		;	set the down flag
	return					;	and return

set_left					;	this routine sets our left flag
	bcf ball_right, 0		;	clear the right flag
	bsf ball_left, 0		;	set the left flag
	return					;	and return

set_right					;	this routine sets our right flag
	bcf ball_left, 0		;	clear the left flag	
	bsf ball_right, 0		;	set the right flag
	return					;	and return


draw_ball				;	this routine draws the ball on the screen
	movf ball_y, w		;	copy our ball_y co-ordinate to w
	movwf PORTB			;	and then to portb (our data bus)
	bsf PORTA, 2		;	now latch this 8-bits to the green 74373
	bcf PORTA, 2		;	and now close the latches
	movf ball_x, w		;	copy ball_x co-ordinate to w
	movwf PORTB			;	then to port b (our data bus)
	bsf PORTA, 4		;	now latch this 8-bits to the COLUMN data 74373
	bcf PORTA, 4		;	and close the latches
	bcf PORTA, 3		;	enable both the green and column 74373 outputs
	bcf PORTA, 6		;	3 is green and 6 is column data
	call delay			;	hold this data on the screen for a split second
	bsf PORTA, 3		;	close both green and column outputs
	bsf PORTA, 6		;	3 is green and 6 is column data
	return				;	and return to the main program


draw_paddle						;	This will draw our paddle on the screen
	movf player_1_paddle, w		;	copy the data from player_1_paddle
	movwf PORTB					;	then output that to PORTB
	bsf PORTA, 0				;	now that its in PORTB, we want to latch that data to the red 74373
	bcf PORTA, 0				;	close the latches and now that data will be held there
	movlw b'00000001'			;	This just activates the 
	movwf PORTB					;	then place it on PORTB
	bsf PORTA, 4				;	now latch that data to the COLUMN data 74373
	bcf PORTA, 4				;	close the latches and the data will now be held there
	bcf PORTA, 1				;	now that all our data is ready, we need to enable the outputs
	bcf PORTA, 6				;	PORTA, 3 is the green 74373 output, and PORTA, 6 is the COLUMN data output
	call delay					;	call the delay, to hold this data on the screen for a split second
	bsf PORTA, 1				;	now disable both the green 74373 output and also
	bsf PORTA, 6				;	the COLUMN data 74373 output
	return						;	then return from where we came from


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;																	;
;	If you recall the way the buttons are working I.E they are		;
;	constantly being pulled upto a logic 1 (+5v) but when we		;
;	press a button, we now connect that resistor to ground which	;
;	means the resitor will drop +5v, but since our output is		;
;	connected to the bottom (ground) lead of the resistor, we will	;
;	now output a logic 0. So a logic 1 means the button has not		;
;	pressed, and a logic 0 means the button has been pressed.		;
;																	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


joystick					;	The joystick routine.	
	call port_b_input		;	First we need PORTB to be an input before we can read data from the joystick
	bcf PORTA, 7			;	Now open up the joystick 74373 latches (to allow data through from the buttons)
	btfss PORTB, 0			;	check the up button, if it has not been pressed (logic 1) then skip this next line,
	call p1_up					;	if it has been pressed (logic 0) then call the up routine
	btfss PORTB, 1			;	check the down button, if it has not been pressed (logic 1) then skip this next line,
	call p1_down				;	if it has been pressed (logic 0) then call the down routine
	bsf PORTA, 7			;	Now close the joystick 74373 latches
	call port_b_output		;	Make PORTB an output again so we can then output our data to the screen
	return					;	And return to where we came from...



port_b_input				;	This routine makes all of PORTB into inputs
   	bsf 	STATUS,	RP0		;	which allows us to then read from the
	movlw	b'11111111'		;	Joystick.
	movwf	TRISB			;
	bcf		STATUS,	RP0		;
	return					;	Now return to where we can from...

port_b_output				;	This routine makes all of PORTB outputs again
   	bsf 	STATUS,	RP0		;	If we didnt make PORTB an output again, then
	movlw	b'00000000'		;	we could never display any data on our screen!
	movwf	TRISB			;
	bcf		STATUS,	RP0		;
	return					;	Now return to where we can from...



p1_up
	btfsc player_1_paddle, 7	;	this prevents the paddle from moving
	return						;	off the screen
	btfsc stop_repeat, 0		;	First we check if the stop_repeat bit is set
	return						;	if it is then return, otherwise - 
	rlf player_1_paddle, 1		;	shift the data in y_coordinate left (this moves the led up)
	bsf stop_repeat, 1			;	Now that we have moved one space we want to prevent our
	bsf stop_repeat, 0			;	paddle from moving another space straight away. so we set
	movf button_adjust, w		;	the stop_repeat bits which will remain set untill the
	movwf button_timer			;	specified time period is complete. Without this, the paddle
	return						;	would move way to fast for us to be able to play the game

p1_down
	btfsc player_1_paddle, 0	;	this prevents the paddle from moving
	return						;	off the screen
	btfsc stop_repeat, 0		;	First we check if the stop_repeat bit is set
	return						;	if it is then return, otherwise - 
	rrf player_1_paddle, 1		;	shift the data in y_coordinate right (this moves the led down)
	bsf stop_repeat, 1			;	Now that we have moved one space we want to prevent our
	bsf stop_repeat, 0			;	paddle from moving another space straight away. so we set
	movf button_adjust, w		;	the stop_repeat bits which will remain set untill the
	movwf button_timer			;	specified time period is complete. Without this, the paddle
	return						;	would move way to fast for us to be able to play the game


button_time						;	This routine decrements the button_timer by one
	decfsz button_timer, 1		;	(we can change the value of button_timer in the setup routine)
	return						;	If the timer has not yet reached zero, then it returns to the main program
	bcf stop_repeat ,0			;	If the timer has reached zero, then we clear the stop_repeat bits
	bcf stop_repeat, 1			;	this then allows us to press a button again!
	return	


delay
		movlw d'03'				;	You can make the delay longer by
		movwf counta			;	increasing the decimal value. Or you
		movwf countb			;	can make the delay shorter by decreasing
again	decfsz counta, 1		;	the decimal value.
	goto again					;
		decfsz countb, 1		;
	goto again					;	once counta and countb have reached zero
	return						;	it will return to the main program



	end		;	thats it!
