
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;										;
;	painter version 1.0					;
;	by brad slattery 2008				;
;										;
;	a paint program 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

	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 pens x_coordinate
		y_coordinate			;	used to hold the pens y_coordinate
		vram_1					;	a video ram location
		vram_2					;	a video ram location
		vram_3					;	a video ram location
		vram_4					;	a video ram location
		vram_5					;	a video ram location
		vram_6					;	a video ram location
		vram_7					;	a video ram location
		vram_8					;	a video ram location
		button_timer			;	used to help in slowing down the button repeat rate 
		button_adjust			;	used to help in slowing down the button repeat rate 
		stop_repeat				;	used to help in slowing down the button repeat rate 
	endc

	org 0x0000						;	org sets the start address to 0000 hex


	movlw h'07'						;	turn off comparators
	movwf CMCON 					;	make 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 - PORTA, bit 5 cannot be an output!
	bcf STATUS, RP0 				;	select bank 0
	goto setup




setup
	movlw b'11011010'		;	This disables all 74373 outputs, and closes
	movwf PORTA				;	all 74373 latches.
	movlw b'00010000'		;	This will setup our start point for our dot	
	movwf x_coordinate		;	when we first turn the game board on
	movwf y_coordinate		;	It's basically the middle of the screen
	clrf vram_1				;	These next 8 lines clear the screen
	clrf vram_2				;	on startup by clearing all video ram locations
	clrf vram_3				;
	clrf vram_4				;
	clrf vram_5				;
	clrf vram_6				;
	clrf vram_7				;
	clrf vram_8				;
	clrf stop_repeat		;	clear our stop repeat flag (used in our button response routine)
	movlw d'08'				;	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						;	This is our main program
	call joystick			;	call the joystick routine (see if any buttons have been pressed)
	call draw_pen			;	call the draw_pen routine (to draw our pen on the screen)
	call draw_picture		;	call the draw picture (to draw our picture!)
	goto begin				;	do it all again!


draw_pen						;	This will draw our pen on the screen
	movf y_coordinate, w		;	copy the data from the y_coordinate variable into w
	movwf PORTB					;	then output that to PORTB
	bsf PORTA, 2				;	now that its in PORTB, we want to latch that data to the green 74373
	bcf PORTA, 2				;	close the latches and now that data will be held there
	movf x_coordinate, w		;	Now copy the x_coordinate to the w register and
	movwf PORTB					;	then place it on PORTB
	bsf PORTA, 4				;	now latch that data to the row data 74373
	bcf PORTA, 4				;	close the latches and the data will now be held there
	bcf PORTA, 3				;	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 row data output
	call delay					;	call the delay, to hold this data on the screen for a split second
	bsf PORTA, 3				;	now disable both the green 74373 output and also
	bsf PORTA, 6				;	the row data 74373 output
	return						;	then return from where we came from


draw_picture
	movf vram_1, w				;	copy the data from the y_coordinate variable into w
	movwf PORTB					;	then output that to PORTB
	bsf PORTA, 0				;	now that its in PORTB, we want to latch that data to the green 74373
	bcf PORTA, 0				;	close the latches and now that data will be held there
	movlw b'00000001'			;	this will enable one column at a time (it will be enabled where there is a 1)
	movwf PORTB					;	then place it on PORTB
	bsf PORTA, 4				;	now latch that data to the row 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 row 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 row data 74373 output

	movf vram_2, w				;	copy the data from the y_coordinate variable into w
	movwf PORTB					;	then output that to PORTB
	bsf PORTA, 0				;	now that its in PORTB, we want to latch that data to the green 74373
	bcf PORTA, 0				;	close the latches and now that data will be held there
	movlw b'00000010'			;	this will enable one column at a time (it will be enabled where there is a 1)
	movwf PORTB					;	then place it on PORTB
	bsf PORTA, 4				;	now latch that data to the row 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 row 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 row data 74373 output
	
	movf vram_3, w				;	copy the data from the y_coordinate variable into w
	movwf PORTB					;	then output that to PORTB
	bsf PORTA, 0				;	now that its in PORTB, we want to latch that data to the green 74373
	bcf PORTA, 0				;	close the latches and now that data will be held there
	movlw b'00000100'			;	this will enable one column at a time (it will be enabled where there is a 1)
	movwf PORTB					;	then place it on PORTB
	bsf PORTA, 4				;	now latch that data to the row 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 row 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 row data 74373 output

	movf vram_4, w				;	copy the data from the y_coordinate variable into w
	movwf PORTB					;	then output that to PORTB
	bsf PORTA, 0				;	now that its in PORTB, we want to latch that data to the green 74373
	bcf PORTA, 0				;	close the latches and now that data will be held there
	movlw b'00001000'			;	this will enable one column at a time (it will be enabled where there is a 1)
	movwf PORTB					;	then place it on PORTB
	bsf PORTA, 4				;	now latch that data to the row 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 row 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 row data 74373 output

	movf vram_5, w				;	copy the data from the y_coordinate variable into w
	movwf PORTB					;	then output that to PORTB
	bsf PORTA, 0				;	now that its in PORTB, we want to latch that data to the green 74373
	bcf PORTA, 0				;	close the latches and now that data will be held there
	movlw b'00010000'			;	this will enable one column at a time (it will be enabled where there is a 1)
	movwf PORTB					;	then place it on PORTB
	bsf PORTA, 4				;	now latch that data to the row 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 row 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 row data 74373 output

	movf vram_6, w				;	copy the data from the y_coordinate variable into w
	movwf PORTB					;	then output that to PORTB
	bsf PORTA, 0				;	now that its in PORTB, we want to latch that data to the green 74373
	bcf PORTA, 0				;	close the latches and now that data will be held there
	movlw b'00100000'			;	this will enable one column at a time (it will be enabled where there is a 1)
	movwf PORTB					;	then place it on PORTB
	bsf PORTA, 4				;	now latch that data to the row 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 row 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 row data 74373 output

	movf vram_7, w				;	copy the data from the y_coordinate variable into w
	movwf PORTB					;	then output that to PORTB
	bsf PORTA, 0				;	now that its in PORTB, we want to latch that data to the green 74373
	bcf PORTA, 0				;	close the latches and now that data will be held there
	movlw b'01000000'			;	this will enable one column at a time (it will be enabled where there is a 1)
	movwf PORTB					;	then place it on PORTB
	bsf PORTA, 4				;	now latch that data to the row 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 row 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 row data 74373 output

	movf vram_8, w				;	copy the data from the y_coordinate variable into w
	movwf PORTB					;	then output that to PORTB
	bsf PORTA, 0				;	now that its in PORTB, we want to latch that data to the green 74373
	bcf PORTA, 0				;	close the latches and now that data will be held there
	movlw b'10000000'			;	this will enable one column at a time (it will be enabled where there is a 1)
	movwf PORTB					;	then place it on PORTB
	bsf PORTA, 4				;	now latch that data to the row 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 row 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 row data 74373 output
	btfsc stop_repeat, 1		;	Check to see if the stop repeat bit 1 has been set,
	call button_time			;	call the button time routine to help with our button repeat rate
	return						;	then return from where we came from


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						;	and 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 resistor 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 is 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 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 down				;	if it has been pressed (logic 0) then call the down routine
	btfss PORTB, 2			;	check the left button, if it has not been pressed (logic 1) then skip this next line,
	call left				;	if it has been pressed (logic 0) then call the left routine
	btfss PORTB, 3			;	check the right button, if it has not been pressed (logic 1) then skip this next line,
	call right				;	if it has been pressed (logic 0) then call the right routine
	btfss PORTB, 5			;	check the draw button, if it has not been pressed (logic 1) then skip this next line,
	call paint_dot			;	if it has been pressed (logic 0) then call the paint_dot routine
	btfss PORTB, 6			;	check the reset button, if it has not been pressed (logic 1) then skip this next line,
	goto setup				;	if it has been pressed (logic 0) then reset the program!
	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...


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;																	;
;	NOTE: you may notice that to move up in this next routine, we	;
;	rotate the data left - and to rotate down we rotate the data	;
;	right, which all sounds pretty easy enough. But have a look at	;
;	the left and right routines. To move the led left, we actually	;
;	rotate the data to the right, and to move the led to right we	;
;	actually rorate the data to the left. So as you can see it is	;
;	actually connected back to front. This has to do with the way	;
;	I have connected the hardware, I found it was a bit hard to		;
;	get it connected the proper way when I was routing all my		;
;	tracks. So in an effort to keep the board small and keep costs	;
;	down, I had to connect it up in this way. But i found it is		;
;	a minor flaw that is easily worked around.						;
;																	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


up								;	We come here when we have pushed the up button
	btfsc stop_repeat, 0		;	check to see if we are allowed to move...
	return						;	if not - then return, but if we can then continue on...
	rlf y_coordinate, 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			;	pen 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 pen would move too fast
	return						;	now return to where we came from	


down							;	We come here when we have pushed the down button
	btfsc stop_repeat, 0		;	check to see if we are allowed to move...
	return						;	if not - then return, but if we can then continue on...
	rrf y_coordinate, 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			;	pen 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 pen would move too fast
	return						;	now return to where we came from

left							;	We come here when we have pushed the left button
	btfsc stop_repeat, 0		;	check to see if we are allowed to move...
	return						;	if not - then return, but if we can then continue on...
	rrf x_coordinate, 1			;	shift the data in x_coordinate right (this moves the led left)
	bsf stop_repeat, 1			;	Now that we have moved one space we want to prevent our
	bsf stop_repeat, 0			;	pen 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 pen
	return						;	now return to where we came from

right							;	We come here when we have pushed the right button
	btfsc stop_repeat, 0		;	check to see if we are allowed to move...
	return						;	if not - then return, but if we can then continue on...
	rlf x_coordinate, 1			;	shift the data in x_coordinate left (this moves the led right)
	bsf stop_repeat, 1			;	Now that we have moved one space we want to prevent our
	bsf stop_repeat, 0			;	pen 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 pen
	return						;	now return to where we came from


paint_dot						;	This will now paint a dot in the specified place.
	btfsc x_coordinate, 0		;	check to see where the pen is when we pushed the draw button
	call load_a					;	then draw a dot at that specified co-ordinate
	btfsc x_coordinate, 1		;	check to see where the pen is when we pushed the draw button
	call load_b					;	then draw a dot at that specified co-ordinate
	btfsc x_coordinate, 2		;	check to see where the pen is when we pushed the draw button
	call load_c					;	then draw a dot at that specified co-ordinate
	btfsc x_coordinate, 3		;	check to see where the pen is when we pushed the draw button
	call load_d					;	then draw a dot at that specified co-ordinate
	btfsc x_coordinate, 4		;	check to see where the pen is when we pushed the draw button
	call load_e					;	then draw a dot at that specified co-ordinate
	btfsc x_coordinate, 5		;	check to see where the pen is when we pushed the draw button
	call load_f					;	then draw a dot at that specified co-ordinate
	btfsc x_coordinate, 6		;	check to see where the pen is when we pushed the draw button
	call load_g					;	then draw a dot at that specified co-ordinate
	btfsc x_coordinate, 7		;	check to see where the pen is when we pushed the draw button
	call load_h					;	then draw a dot at that specified co-ordinate
	return						;	and now return to where we came from


load_a							;	
	movf y_coordinate, w		;	inclusive OR our data with vram_1	
	iorwf vram_1, f				;	this will add our new dot while also leaving
	return						;	our old data on the screen

load_b
	movf y_coordinate, w		;	inclusive OR our data with vram_2	
	iorwf vram_2, f				;	this will add our new dot while also leaving
	return						;	our old data on the screen

load_c
	movf y_coordinate, w		;	inclusive OR our data with vram_3	
	iorwf vram_2, f				;	this will add our new dot while also leaving
	return						;	our old data on the screen

load_d
	movf y_coordinate, w		;	inclusive OR our data with vram_4	
	iorwf vram_4, f				;	this will add our new dot while also leaving
	return						;	our old data on the screen

load_e
	movf y_coordinate, w		;	inclusive OR our data with vram_5	
	iorwf vram_5, f				;	this will add our new dot while also leaving
	return						;	our old data on the screen

load_f
	movf y_coordinate, w		;	inclusive OR our data with vram_6	
	iorwf vram_6, f				;	this will add our new dot while also leaving
	return						;	our old data on the screen

load_g
	movf y_coordinate, w		;	inclusive OR our data with vram_7	
	iorwf vram_7, f				;	this will add our new dot while also leaving
	return						;	our old data on the screen

load_h
	movf y_coordinate, w		;	inclusive OR our data with vram_8	
	iorwf vram_8, f				;	this will add our new dot while also leaving
	return						;	our old data on the screen




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!
