.title "EL308 HW#2"
	.sbttl "Football Results"
	.equ __24FJ256GB110, 1
	.include "p24FJ256GB110.inc"

	.global __reset          ;The label for the first line of code. 
	.global __T1Interrupt    ;Declare Timer 1 ISR name global

.bss
	LCD_line1:	.space 16
	LCD_line2:	.space 16
	LCD_ptr:	.space 2
	LCD_cmd:	.space 2
	LCD_offset: .space 2
.section .const,psv
	skor:		.ascii "KONYA 2-0 HCT, ANK 0-2 BS, DNZ 0-2 SIVAS *** "
	skor_end:

.text                             ;Start of Code section
__reset:
	mov 	#__SP_init, W15		; Initalize the Stack Pointer
	mov 	#__SPLIM_init, W0	; Initialize the Stack Pointer Limit Register
	mov 	W0, SPLIM
	nop							; Add NOP to follow SPLIM initialization
        
        ;<<insert more user code here>>

	call	init_PSV
	call	init_LED
	call	init_LCD
	call	init_keypad
	call	init_buzzer
	call	init_message

	call	init_timer
	call	init_timer2

	mov		#0, W2				; W2 used as a display index pointer

	mov		#psvoffset(skor), W0
	mov		#psvoffset(skor_end), W1

	sub		W1, W0, W3			; W3 contains the length of the message

start_over:
	mov		#16, W4				; 1 LCD line contains 16 characters
	mov		W2, W5				; start from W2 location
	mov		#LCD_line1, W6		; LCD index	
display_loop:
	mov.b	[W0+W5], [W6]		; move 1 byte of data array to display
	inc		W6, W6				; increment LCD index
	inc		W5, W5				; increment data index
	cp		W5, W3				; did we reach the end of the array?
	bra		NZ, not_end			; yes: keep up, no: goto not_end
	mov		#0, W5				; mov to the beginning of the data array
not_end:
	dec		W4, W4
	cp0		W4
	bra		NZ, display_loop	; are we finished with 1 line?

	inc		W2, W2				; increment the display index
	cp		W2, W3				; end of the array?
	bra		NZ, not_index_end
	mov		#0, W2				; start from the beginning	
not_index_end:	

wait_1:
	btss	TMR2, #13
	bra		wait_1
wait_0:
	btsc	TMR2, #13
	bra		wait_0

	bra		start_over


; -----------------------------------------------------
; !!!!!!!!!!!!!!!!!! Functions !!!!!!!!!!!!!!!!!!!!!!!!
; -----------------------------------------------------

init_timer2:
	bclr	T2CON, #TON		; turn timer1 OFF
	
	bset	T2CON, #TCKPS1
	bclr	T2CON, #TCKPS0	; set prescaler to 256

	bclr	T1CON, #TCS		; select internal clock

	mov		#0x0000, W0 
	mov		W0, TMR2		; clear TMR1 register
	mov		#15625, W0
	mov		W0, PR2			; set timer1 period to 32150 -> f=2e6/64/31250=2 Hz
	
	bset	T2CON, #TON		; turn timer1 ON
	return


init_PSV:
	mov		#psvpage(skor), W0
	mov		W0, PSVPAG		; set PSVPAG to page that contains hello
	bset.b	CORCONL,#PSV	; enable Program Space Visibility
	return

init_timer:
	bclr	T1CON, #TON		; turn timer1 OFF
	
	bset	T1CON, #TCKPS1
	bclr	T1CON, #TCKPS0	; set prescaler to 64

	bclr	T1CON, #TCS		; select internal clock

	mov		#0x0000, W0 
	mov		W0, TMR1		; clear TMR1 register
	mov		#0x0040, W0
	mov		W0, PR1			; set timer1 period to 0x0040 -> f=2e6/64/64=488 Hz

	bclr	IPC0, #14
	bclr	IPC0, #13
	bset	IPC0, #12		; set timer1 priority to 001
	bclr	IFS0, #T1IF		; clear timer1 interrupt status flag
	bset	IEC0, #T1IE		; enable timer1 interrupts
	
	bset	T1CON, #TON		; turn timer1 ON
	return

init_LED:
	bclr	TRISF, #0
	bclr	TRISF, #1
	bclr	TRISF, #2
	bclr	TRISF, #3		; LED array
	return

init_LCD:
	bclr	TRISB, #15
	bclr	PORTD, #4		; make sure LCD is disabled before port is set to output mode
	bclr	TRISD, #4
	bclr	TRISD, #5
	mov		#0xFF00, W0
	mov		W0, TRISE

	bclr	PORTD, #5		; select LCD WR mode

	mov		#0x0038, W0		; init LCD
	call	sendcomm
	call	dly
	call	dly
	call	dly

	mov		#0x000C, W0		; LCD on, cursor off
	call	sendcomm
	mov		#0x0001,W0		; clear LCD
	call 	sendcomm
	return

sendcomm:
	bclr	PORTB,#15	; select LCD command register
	mov		W0, PORTE	; output command
	bset	PORTD, #4
	call	dly
	nop
	bclr	PORTD, #4
	call	dly
	return

init_message:
	mov		#0x0000, W0
	mov		W0, LCD_ptr
	mov		W0, LCD_offset
	mov		#0x00C0, W0
	mov		W0, LCD_cmd
	mov.b	#' ', W1
	mov		#LCD_line1, W0
	repeat	#31
	mov.b	W1, [W0++]
	return

dly:
	mov 	#0x2000,W0
dlyloop:
	sub		W0, #1, W0
	bra		NZ, dlyloop
	return

init_keypad:
	bset	TRISD,#0	; DATA A
	bset	TRISD,#1	; DATA B
	bset	TRISD,#2	; DATA C
	bset	TRISD,#3	; DATA D
	bset	TRISD,#6	; DATA Available
	return

init_buzzer:
	bclr	PORTD, #13	; buzzer initially OFF
	bclr	TRISD, #13	; enable output
	return
	

;..............................................................................
;Timer 1 Interrupt Service Routine
;Example context save/restore in the ISR performed using PUSH.D/POP.D
;instruction. The instruction pushes two words W4 and W5 on to the stack on
;entry into ISR and pops the two words back into W4 and W5 on exit from the ISR
;..............................................................................
__T1Interrupt:
	push.s
	push.d	W4                  ; Save context using double-word PUSH
	
        ;<<insert user code here>>
	bclr	IFS0, #T1IF           ; Clear the Timer1 Interrupt flag Status
                                  ; bit.

	clrwdt	; !!!!!!!!!!!! Very bad practice! !!!!!!!!!!!!!!!!

	mov		LCD_ptr, W2
	mov		#0x0010, W1
	cp		W1, W2
	bra		NZ, send_LCD_data
	mov		LCD_cmd, W0
	bclr	PORTB, #15		; select LCD command register
	mov		W0, PORTE		; output command
	bset	PORTD, #4
	nop
	bclr	PORTD, #4
	btg		W0, #6
	mov		W0, LCD_cmd
	mov		#0x0000, W2
	mov		W2, LCD_ptr
	mov		LCD_offset, W0
	btg		W0, #4
	mov		W0, LCD_offset
	btg		PORTF, #2
	bra		done_T1interrupt
send_LCD_data:
	mov		LCD_offset, W3
	add		W3, W2, W3
	mov		#LCD_line1, W1
	mov.b	[W1+W3], W0
	bset	PORTB, #15		; select LCD data register
	mov		W0, PORTE		; output command
	bset	PORTD, #4
	nop
	bclr	PORTD, #4
	inc		W2, W2
	mov		W2, LCD_ptr

done_T1interrupt:
	pop.d W4                   ;Retrieve context POP-ping from Stack
	pop.s
	retfie                     ;Return from Interrupt Service routine

;--------End of All Code Sections ---------------------------------------------

.end                               ;End of program code in this file