
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;										;
;	Chopper version 1.0					;
;	by brad slattery 2008				;
;										;
;	A helicopter game for the 			;
;	8x8 game system						;
;										;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


	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 set to PC

	cblock 0x20 			;	start of general purpose registers
		counta				;	used in the delay routines
		countb 				;	used in the delay routines
		pc_green_data		;	used in the display data program counter	
		vram_green_1		;	a video ram location
		vram_green_2		;	a video ram location
		vram_green_3		;	a video ram location
		vram_green_4		;	a video ram location
		vram_green_5		;	a video ram location
		vram_green_6		;	a video ram location
		vram_green_7		;	a video ram location
		vram_green_8		;	a video ram location
		vtemp_green_1		;	a temporary video ram location
		vtemp_green_2		;	a temporary video ram location
		vtemp_green_3		;	a temporary video ram location
		vtemp_green_4		;	a temporary video ram location
		vtemp_green_5		;	a temporary video ram location
		vtemp_green_6		;	a temporary video ram location
		vtemp_green_7		;	a temporary video ram location
		repeat_frame		;	holds our data for how many times to repeat each frame
		heli_data			;	holds our helicopter data
		button_timer		;	used to help in slowing down the button repeat rate		
		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)
		level				;	holds our level data
		speed				;	holds our game speed data
		c_delay				;	used for when we have hit a wall
		collide_flag		;	if we have collided, this will set a flag so we know we have collided.
		pause_timer			;	the pause timer, pauses the screen (for a set amount of time) when we have collided
		end_delay
	endc

	org 0x0000						; org sets our start address 0000 hex


	movlw h'07'
	movwf CMCON 					; turn comparators of

	bsf STATUS, RP0 				; select bank 1 (so that we can edit some status bits)
	movlw b'00000000' 				; set PORTB all outputs
	movwf TRISB						;
	movlw b'00100000' 				; set PORTA all outputs except for bit 5
	movwf TRISA 					;
	bcf STATUS, RP0 				; select bank 0

	goto setup

green_data
	incf pc_green_data, f		;	increment pc_data by one and then
	movf pc_green_data, w		;	move it into our working register THEN
	addwf PC					;	add this number to our program counter
	nop							;	skip one step...
	retlw b'10000001'			;	now each time this routine is called, we will grab the
	retlw b'10000001'			;	next successive byte of data!
	retlw b'11000001'
	retlw b'11100001'
	retlw b'11100001'
	retlw b'11000001'
	retlw b'11000001'
	retlw b'10000001'
	retlw b'10000011'
	retlw b'10000011'
	retlw b'10000111'
	retlw b'10000011'
	retlw b'10000011'
	retlw b'10000111'
	retlw b'10000111'
	retlw b'10001111'
	retlw b'10000111'
	retlw b'10000111'
	retlw b'10000011'
	retlw b'10000011'
	retlw b'10000001'
	retlw b'10000001'
	retlw b'10000001'
	retlw b'10001001'
	retlw b'10001001'
	retlw b'10001001'
	retlw b'10001001'
	retlw b'10000101'
	retlw b'10000011'
	retlw b'10000001'
	retlw b'10000001'
	retlw b'11000001'
	retlw b'11100001'
	rlf level, 1			;	now increment the level by one
	btfsc level, 7			;	have we reached the end of the game yet?
	call end_game			;	if yes, then call end_game routine
	decf speed, 1			;	if not, then decrement our speed variable by one (this speeds up the game)
	movlw h'01'				;	and now reset our pc_data variable so that we can
	movwf pc_green_data		;	draw the track again from the start
	return					;	return to our main program


setup
	movlw b'11011010'		;	This basically disables all 74373 outputs, and closes
	movwf PORTA				;	all 74373 latches.	
	movlw b'10000001'		;	These next 9 lines setup all vram locations	
	movwf vram_green_1		;	so that when we first turn on the game
	movwf vram_green_2		;	we get lines up the top and bottom of the
	movwf vram_green_3		;	screen rather than just random junk.
	movwf vram_green_4		;	
	movwf vram_green_5		;
	movwf vram_green_6		;
	movwf vram_green_7		;
	movwf vram_green_8		;
	clrf pc_green_data		;	reset the pc_green_data 
	movlw b'01000000'		;	setup our start position for the
	movwf heli_data			;	helicopter 
	movlw d'14'				;	setup our button_adjust variable to 14
	movwf button_adjust		;	(this is used to slow the button repeat rate)
	clrf stop_repeat		;	clear stop_repeat (this is used to slow the button repeat rate)
	movlw d'01'				;	start at level number 1
	movwf level				;
	movlw d'15'				;	set the start speed of the game
	movwf speed				;	(the higher the number, the sower the game speed
	clrf collide_flag		;	clear the collide_flag variable


begin							;	Now lets begin the main program...
	call display				;	run the display routine
	btfss collide_flag, 0		;	checks to see if we have collided (it wont draw the car if we have hit a wall)
	call fill_ram_green			;	run the fill_ram_green routine
	goto begin					;	and do it all again!

								
display									;	this takes care of drawing the display	
			movf speed, w				;	copy our speed data
			movwf repeat_frame			;	into w and then from w to repeat_frame (this determines our speed)
loop		btfss collide_flag, 0		;	have we hit a wall? if we have then DONT draw the helicopter
			call helicopter				;	call the helicopter routine to draw our chopper
			call show_level				;	call the show_level routine to show what level we are on
			movf vram_green_1, w		;	Now we grab the first COLUMN of data from vram_green_1.	
			movwf PORTB					;	then we copy it to PORTB
			bsf PORTA, 2				;	now that its in PORTB we need to latch it to the green memory.
			bcf PORTA, 2				;	so the latch was opened, now we need to close it (the data will now stay there)
				movlw b'10000000'		;	This now activates the right-most column of anodes by moving
				movwf PORTB				;	'10000000' to PORTB, 
				bsf PORTA, 4			;	then latching it onto the column data latch
				bcf PORTA, 4			;	then closing the latch (the data is now held there)
			bcf PORTA, 6				;	Now that all our data is ready, we can enable our 74373 outputs.
			bcf PORTA, 3				;	PORTA, 6 is the COLUMN data enable - PORTA, 3 is the green data enable
			call delay					;	Call the delay (to hold that one column ON for a split second)
			bsf PORTA, 6				;	Now disable both outputs (remember PORTA, 6 is the COLUMN data
			bsf PORTA, 3				;	and PORTA, 3 is the green data)

			movf vram_green_2, w		;	Now we grab the first COLUMN of data from vram_green_2.	
			movwf PORTB					;	then we copy it to PORTB
			bsf PORTA, 2				;	now that its in PORTB we need to latch it to the green memory.
			bcf PORTA, 2				;	so the latch was opened, now we need to close it (the data will now stay there)
				movlw b'01000000'		;	This now activates the right-most column of anodes by moving
				movwf PORTB				;	'10000000' to PORTB, 
				bsf PORTA, 4			;	then latching it onto the column data latch
				bcf PORTA, 4			;	then closing the latch (the data is now held there)
			bcf PORTA, 6				;	Now that all our data is ready, we can enable our 74373 outputs.
			bcf PORTA, 3				;	PORTA, 6 is the COLUMN data enable - PORTA, 3 is the green data enable
			call delay					;	Call the delay (to hold that one column ON for a split second)
			bsf PORTA, 6				;	Now disable both outputs (remember PORTA, 6 is the COLUMN data
			bsf PORTA, 3				;	and PORTA, 3 is the green data)

			movf vram_green_3, w		;	Now we grab the first COLUMN of data from vram_green_3.	
			movwf PORTB					;	then we copy it to PORTB
			bsf PORTA, 2				;	now that its in PORTB we need to latch it to the green memory.
			bcf PORTA, 2				;	so the latch was opened, now we need to close it (the data will now stay there)
				movlw b'00100000'		;	This now activates the right-most column of anodes by moving
				movwf PORTB				;	'10000000' to PORTB, 
				bsf PORTA, 4			;	then latching it onto the column data latch
				bcf PORTA, 4			;	then closing the latch (the data is now held there)
			bcf PORTA, 6				;	Now that all our data is ready, we can enable our 74373 outputs.
			bcf PORTA, 3				;	PORTA, 6 is the COLUMN data enable - PORTA, 3 is the green data enable
			call delay					;	Call the delay (to hold that one column ON for a split second)
			bsf PORTA, 6				;	Now disable both outputs (remember PORTA, 6 is the COLUMN data
			bsf PORTA, 3				;	and PORTA, 3 is the green data)

			movf vram_green_4, w		;	Now we grab the first COLUMN of data from vram_green_4.	
			movwf PORTB					;	then we copy it to PORTB
			bsf PORTA, 2				;	now that its in PORTB we need to latch it to the green memory.
			bcf PORTA, 2				;	so the latch was opened, now we need to close it (the data will now stay there)
				movlw b'00010000'		;	This now activates the right-most column of anodes by moving
				movwf PORTB				;	'10000000' to PORTB, 
				bsf PORTA, 4			;	then latching it onto the column data latch
				bcf PORTA, 4			;	then closing the latch (the data is now held there)
			bcf PORTA, 6				;	Now that all our data is ready, we can enable our 74373 outputs.
			bcf PORTA, 3				;	PORTA, 6 is the COLUMN data enable - PORTA, 3 is the green data enable
			call delay					;	Call the delay (to hold that one column ON for a split second)
			bsf PORTA, 6				;	Now disable both outputs (remember PORTA, 6 is the COLUMN data
			bsf PORTA, 3				;	and PORTA, 3 is the green data)

			movf vram_green_5, w		;	Now we grab the first COLUMN of data from vram_green_5.	
			movwf PORTB					;	then we copy it to PORTB
			bsf PORTA, 2				;	now that its in PORTB we need to latch it to the green memory.
			bcf PORTA, 2				;	so the latch was opened, now we need to close it (the data will now stay there)
				movlw b'00001000'		;	This now activates the right-most column of anodes by moving
				movwf PORTB				;	'10000000' to PORTB, 
				bsf PORTA, 4			;	then latching it onto the column data latch
				bcf PORTA, 4			;	then closing the latch (the data is now held there)
			bcf PORTA, 6				;	Now that all our data is ready, we can enable our 74373 outputs.
			bcf PORTA, 3				;	PORTA, 6 is the COLUMN data enable - PORTA, 3 is the green data enable
			call delay					;	Call the delay (to hold that one column ON for a split second)
			bsf PORTA, 6				;	Now disable both outputs (remember PORTA, 6 is the COLUMN data
			bsf PORTA, 3				;	and PORTA, 3 is the green data)

			movf vram_green_6, w		;	Now we grab the first COLUMN of data from vram_green_6.	
			movwf PORTB					;	then we copy it to PORTB
			bsf PORTA, 2				;	now that its in PORTB we need to latch it to the green memory.
			bcf PORTA, 2				;	so the latch was opened, now we need to close it (the data will now stay there)
				movlw b'00000100'		;	This now activates the right-most column of anodes by moving
				movwf PORTB				;	'10000000' to PORTB, 
				bsf PORTA, 4			;	then latching it onto the column data latch
				bcf PORTA, 4			;	then closing the latch (the data is now held there)
			bcf PORTA, 6				;	Now that all our data is ready, we can enable our 74373 outputs.
			bcf PORTA, 3				;	PORTA, 6 is the COLUMN data enable - PORTA, 3 is the green data enable
			call delay					;	Call the delay (to hold that one column ON for a split second)
			bsf PORTA, 6				;	Now disable both outputs (remember PORTA, 6 is the COLUMN data
			bsf PORTA, 3				;	and PORTA, 3 is the green data)

			movf vram_green_7, w		;	Now we grab the first COLUMN of data from vram_green_7.	
			movwf PORTB					;	then we copy it to PORTB
			bsf PORTA, 2				;	now that its in PORTB we need to latch it to the green memory.
			bcf PORTA, 2				;	so the latch was opened, now we need to close it (the data will now stay there)
				movlw b'00000010'		;	This now activates the right-most column of anodes by moving
				movwf PORTB				;	'10000000' to PORTB, 
				bsf PORTA, 4			;	then latching it onto the column data latch
				bcf PORTA, 4			;	then closing the latch (the data is now held there)
			bcf PORTA, 6				;	Now that all our data is ready, we can enable our 74373 outputs.
			bcf PORTA, 3				;	PORTA, 6 is the COLUMN data enable - PORTA, 3 is the green data enable
			call delay					;	Call the delay (to hold that one column ON for a split second)
			bsf PORTA, 6				;	Now disable both outputs (remember PORTA, 6 is the COLUMN data
			bsf PORTA, 3				;	and PORTA, 3 is the green data)

			movf vram_green_8, w		;	Now we grab the first COLUMN of data from vram_green_8.	
			movwf PORTB					;	then we copy it to PORTB
			bsf PORTA, 2				;	now that its in PORTB we need to latch it to the green memory.
			bcf PORTA, 2				;	so the latch was opened, now we need to close it (the data will now stay there)
				movlw b'00000001'		;	This now activates the right-most column of anodes by moving
				movwf PORTB				;	'10000000' to PORTB, 
				bsf PORTA, 4			;	then latching it onto the column data latch
				bcf PORTA, 4			;	then closing the latch (the data is now held there)
			bcf PORTA, 6				;	Now that all our data is ready, we can enable our 74373 outputs.
			bcf PORTA, 3				;	PORTA, 6 is the COLUMN data enable - PORTA, 3 is the green data enable
			call delay					;	Call the delay (to hold that one column ON for a split second)
			bsf PORTA, 6				;	Now disable both outputs (remember PORTA, 6 is the COLUMN data
			bsf PORTA, 3				;	and PORTA, 3 is the green data)
				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)
				call check_collision		;	if it has not been set, then keep going here and call the check_collision routine
			decfsz repeat_frame				;	then decrease repeat_frame by one, 
		goto loop							;	if its not zero then draw it all again!
	return									;	if it is zero, then go back to where we came from...


show_level					;	This next routine shows us a running commentary of what level we are on.
	movf level, w			;	copy our level data into the w register.
	movwf PORTB				;	then copy this data to PORTB.
	bsf PORTA, 0			;	open up the red 74373 latch
	bcf PORTA, 0			;	now close the latch (our 8 bits of data will now be held on our output.)
	bsf PORTA, 2			;	open up the green 74373 latch	
	bcf PORTA, 2			;	now close the latch (our 8 bits of data will now be held on our output.)
	movlw b'10000000'		;	this 8 bits of data basically activates the very right hand column
	movwf PORTB				;	of our screen (which means our level dot will be displayed here)
	bsf PORTA, 4			;	open up the COLUMN 74373 latch
	bcf PORTA, 4			;	now close the latch (our 8 bits of data will now be held on our output.)
	bcf PORTA, 1			;	Now that all screen memory latches have their info, we can then enable
	bcf PORTA, 3			;	all outputs, which means our screen will actually display something!
	bcf PORTA, 6			;	1=red output, 3=green output and 6=COLUMN output
	call delay				;	now call the delay, which will hold that data on screen for a split second.
	bsf PORTA, 1			;	alright, now the screen has displayed what we want,
	bsf PORTA, 3			;	we then disable all outputs.
	bsf PORTA, 6			;	and,
	return					;	then return to our main program...


check_collision					;	a routine to see if we have hit anything
	movf heli_data, w			;	copy heli_data to w register
	andwf vram_green_8, w		;	and this number with vram_green_8
	btfss STATUS, Z				;	have we hit a wall?
	goto collided				;	yes - then call the collided routine
	return						;	no - then just return to our main program


collided						;	The only time we come here is if weve hit a wall!
	bsf collide_flag, 0			;	set bit 0 of the collide_flag variable (make it a '1')
	decfsz pause_timer, 1		;	decrement the pause timer by 1, 
	return						;	if it is not yet zero, then go back to where we came from
	goto setup					;	if it is zero, then reset the game (back to setup)


helicopter					;	this takes care of moving our helicopter
	call port_b_input		;	before we can read from the joystick - we need to make PORTB and input
	bcf PORTA, 7			;	now open up the latches
	btfss PORTB, 0			;	has the up button been pressed?
	call go_up				;	yes! then call go_up routine
	btfsc PORTB, 0			;	has the up button been pressed?
	call go_down			;	no! then call the go_down routine
	bsf PORTA, 7			;	close the latches
	call port_b_output		;	make portb an output again (so we can display data on the display)
	movf heli_data, w		;	copy our helicopter data
	movwf PORTB				;	to portb
	bsf PORTA, 0			;	now latch onto this data into the red data latch
	bcf PORTA, 0			;	and close the latch
	movlw b'00000001'		;	now enable the left most column of led anodes
	movwf PORTB				;	by sending this data to portb
	bsf PORTA, 4			;	then latching onto it in the column data 74373
	bcf PORTA, 4			;	then close the latch
	bcf PORTA, 1			;	open up both the red output and the column data output
	bcf PORTA, 6			;	(1 is red 6 is column data)
	call delay				;	hold that info on the screen for a split second
	bsf PORTA, 1			;	then disable the outputs 
	bsf PORTA, 6			;	both red and column data
	return					;	and return to our main program


port_b_input
   	bsf 	STATUS,	RP0		;	this allows us to now modify status bits
	movlw	b'11111111'		;	set all PORTB to inputs
	movwf	TRISB			;
	bcf		STATUS,	RP0		;	and now go back to bank 0 and continue our program!
	return

port_b_output
   	bsf 	STATUS,	RP0		;	this allows us to modify status bits
	movlw	b'00000000'		;	set all PORTB to outputs
	movwf	TRISB			;
	bcf		STATUS,	RP0		;	and now go back to bank 0 and continue our program!
	return


go_up
	btfsc stop_repeat, 0		;	check stop repeat bit 0 - if it is set
	return						;	then don't allow our chopper to move! if it's not set then...
	rlf heli_data, 1			;	move our chopper one space right
	bsf stop_repeat, 1			;	set stop_repeat bit 1 (this is a flag for so we know the button has been pressed)
	bsf stop_repeat, 0			;	set stop_repeat bit 0 (this is a flag for so we know the button has been pressed)
	movf button_adjust, w		;	copy the contents of button adjust to
	movwf button_timer			;	button timer
	return						;	and now return

go_down
	btfsc stop_repeat, 0		;	Even though we havent actually 
	return						;	pressed a button
	rrf heli_data, 1			;	we can still use basically the 	
	bsf stop_repeat, 1			;	same technique here as we did above
	bsf stop_repeat, 0			;	to prevent the chopper from moving too
	movf button_adjust, w		;	fast.	
	movwf button_timer			;
	return						;	return to our main program

button_time						;	
	decfsz button_timer, 1		;	decrement button_timer by one
	return						;	its not zero then just return
	bcf stop_repeat ,0			;	if it is then clear our flags
	bcf stop_repeat, 1			;	so that we are able to push a
	return						;	button again. - then return


end_game
	; what could you add here to tell you that you have completed the game?
	goto setup



fill_ram_green						;	this routine saves all video ram
		movf vram_green_1, 0		;	to a temp location and then
		movwf vtemp_green_1			;	shifts all data to the next
		movf vram_green_2, 0		;	video ram location and also
		movwf vtemp_green_2			;	loads in the next byte of data 
		movf vram_green_3, 0		;	to vram_1
		movwf vtemp_green_3			;
		movf vram_green_4, 0		;
		movwf vtemp_green_4			;
		movf vram_green_5, 0		;
		movwf vtemp_green_5			;
		movf vram_green_6, 0		;
		movwf vtemp_green_6			;
		movf vram_green_7, 0		;
		movwf vtemp_green_7			;
	call green_data		;
	movwf vram_green_1				;
	movf vtemp_green_1, 0			;
	movwf vram_green_2				;
	movf vtemp_green_2, 0			;
	movwf vram_green_3				;
	movf vtemp_green_3, 0			;
	movwf vram_green_4				;
	movf vtemp_green_4, 0			;
	movwf vram_green_5				;
	movf vtemp_green_5, 0			;
	movwf vram_green_6				;
	movf vtemp_green_6, 0			;
	movwf vram_green_7				;
	movf vtemp_green_7, 0			;
	movwf vram_green_8				;
	return							;






delay									;	This first delay is a rather fast one.
			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
