	title "HelloWorld"
	LIST	P=16F630, F=INHX8M
	#include <p16f630.inc>
	__CONFIG  _INTRC_OSC_NOCLKOUT & _CP_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _BODEN_OFF

#define	BANK1		bsf STATUS,RP0
#define	BANK0		bcf STATUS,RP0
#define	COMPCONTROL	b'00010100'		;Used to configure Comparator
#define LCDEnable 	4 ; The LCD enable pin on Port B
#define LCDRS     	5; The LCD R/S pins on Port B
#define APULLUPS    b'00110000'; The LCD E and R/S pins on Port A

; backup spots for registers during interrupt handling
w_bak		equ	0x20
status_bak	equ	0x21
fsr_bak 	equ	0x22

 ;variables
LCDAdd equ 0x23
LCDByte equ 0x24
hiByte equ 0x25
loByte equ 0x26
nibToSend equ 0x27
d1 equ 0x28
d2 equ 0x29

; startup
	org 0x0
	goto Main
; interrupt handler
	org 0x4

IntHandle
	; save registers
	movwf	w_bak
	swapf	STATUS, W
	clrf	STATUS
	movwf	status_bak
	movfw	FSR
	movwf	fsr_bak
	
	goto	IntHandle_End	; if not, finish up interrupt handling

IntHandle_End
	; restore all the backed up registers
	movfw	fsr_bak
	movwf	FSR
	swapf	status_bak, W
	movwf	STATUS
	swapf	w_bak, F
	swapf	w_bak, W
	retfie	; return from interrupt

;FUNCTIONS

LCDADD ; makes LCDAdd the current LCD Address
	nop
	BCF PORTA,LCDRS
	movf LCDAdd, 0
	movwf LCDByte
	bsf LCDByte, 7
	CALL LCDBYTE
	bsf PORTA,LCDRS
	nop
	nop 
	RETURN

LCDENT ; Entry Mode set - currently set to move cursor to right after each write
	nop
	BCF PORTA, LCDRS
	movlw b'00000110'
	movwf LCDByte
	CALL LCDBYTE
	BSF PORTA,LCDRS
	nop
	nop
	RETURN

LCDDISP ; turns on display and cursor
	nop
	BCF PORTA,LCDRS
	movlw b'00001110'
	movwf LCDByte
	CALL LCDBYTE
	BSF PORTA,LCDRS
	nop
	nop
	RETURN

LCDFUN ; sets up the LCD function byte, for 4 bit control, 2 lines, standard font
	nop
	movlw d'2'
	movwf nibToSend
	BCF PORTA, LCDRS ; we're sending a command, so R/S must be lo
	CALL SENDNIB ; due to 4 bit operation, we have to resend the first nibble
	CALL SHORTDLY	
	movlw b'00101000'
	movwf LCDByte
	CALL LCDBYTE
	BSF PORTA, LCDRS
	nop
	nop
	RETURN

LCDCLR ; clears the entire display
    clrf LCDAdd
	nop
	movlw d'1'
	movwf LCDByte 
	BCF PORTA, LCDRS ; 'cause we are doing a command, set the R/S line lo
	CALL LCDBYTE ; writes LCDByte to the LCD
	CALL LONGDLY ; Clearing the LCD takes ages, so a larger delay is needed
	bsf PORTA, LCDRS ; set the R/S line, ready for characters
	RETURN

LCDCHAR
       ;use this for displaying characters only, NOT control chars
       ;keeps track of cursor colation, and word wraps if necessary
	movf LCDAdd, 0
	sublw h'50'
	btfsc STATUS, Z
	RETURN
	CALL LCDBYTE
	incf LCDAdd, 1 ;check if we have hit the end of the top line
	movlw d'16'
	subwf LCDAdd, 0
	btfsc STATUS, Z ; skip if not zero
	GOTO LCDLINE2 ; must go to new line
	RETURN

LCDLINE2 ;here we must go to the new line
	movlw b'01000000'
	movwf LCDAdd
	CALL LCDADD
	RETURN

LCDBYTE	;sends a byte to the LCD, in 4bit fashion
        ;responsible for breaking up the byte to send into high and low nibbles
		;and dumps them to LCD
		;NOT responsible for the status of the LCDRS line, nor the major delays
		;IN: LCDByte  - distructive OUT: hiByte, loByte
	clrf hiByte ; clears the vars, to prevent bugs
	clrf loByte
	bcf STATUS,0 ; get rif of any carry which could screw up the bitshifts
	rlf LCDByte, 1
	rlf hiByte
	rlf LCDByte, 1
	rlf hiByte
	rlf LCDByte, 1
	rlf hiByte
	rlf LCDByte, 1
	rlf hiByte
	movf LCDByte, 0
	movwf loByte
	swapf loByte, 1
	movf hiByte,0
	movwf nibToSend
	CALL SENDNIB
	movf loByte,0
	movwf nibToSend
	CALL SENDNIB
	CALL SHORTDLY ; blocks until most instructions are done
	RETURN


SENDNIB; responsible for sending nibble commands to the LCD. ;IN: nibToSend - non-distructive
	clrf W ; clears W
	movf nibToSend, 0
    movwf PORTC
	nop
	bsf PORTA, LCDEnable; pulse the LCD Enable high
	nop
	nop
	bcf PORTA, LCDEnable ; lower LCD Enable
	nop
	nop
	RETURN
	

SHORTDLY	;around 50us ;46 cycles
	movlw	0x0F
	movwf	d1
SHORTDLY_0
	decfsz	d1, f
	goto	SHORTDLY_0	;4 cycles (including call)
	return


LONGDLY ;25ms ;24993 cycles
	movlw	0x86
	movwf	d1
	movlw	0x14
	movwf	d2
LONGDLY_0
	decfsz	d1, f
	goto	$+2
	decfsz	d2, f
	goto	LONGDLY_0;3 cycles
	goto	$+1
	nop		;4 cycles (including call)
	return


LCDBACKSPACE ; acts like a backspace
	movf LCDAdd,0
	andlw b'11111111'
	btfsc STATUS, Z ; skip if not zero
	RETURN ; already at end, so ignore backspace
	sublw h'40'
	btfsc STATUS, Z ; skip if at start of 2nd line
	GOTO LCDBSTARTBOTLINE ; correct for moveing up to new line
	decf LCDAdd, 1;
	CALL LCDADD ;         move back one
	movlw d'32' ;         wipe the current char
	movwf LCDByte
	CALL LCDBYTE
	CALL LCDADD
	RETURN

LCDBSTARTBOTLINE ; correct for moveing up to new line
	movlw d'15'
	movwf LCDAdd
	CALL LCDADD ; put us at 15
	movlw d'32'
	movwf LCDByte
	CALL LCDBYTE
	RETURN

Main

	BANK1
	call 	3ffh
	movwf 	OSCCAL
	clrf	TRISA	;set all to output
	clrf	TRISC	;set all to output
	movlw	APULLUPS
	movwf	WPUA

	BANK0
	clrf	PORTA	;set all output latches to zero
	clrf	PORTC	;set all output latches to zero


	CALL LONGDLY
	CALL LCDFUN ; sets the LCD's function to 4 bit, 2 line, 5x7 font
	CALL LONGDLY 	
	CALL LCDDISP ; Turns on the display and cursor
	CALL LONGDLY
	CALL LCDENT ; sets auto increment right after write (like a typewriter)
	CALL LCDCLR
	movlw "H"
	movwf LCDByte
	CALL LCDCHAR
	movlw "E"
	movwf LCDByte
	CALL LCDCHAR
	movlw "L"
	movwf LCDByte
	CALL LCDCHAR
	movlw "L"
	movwf LCDByte
	CALL LCDCHAR
	movlw "O"
	movwf LCDByte
	CALL LCDCHAR
	movlw " "
	movwf LCDByte
	CALL LCDCHAR
	movlw "W"
	movwf LCDByte
	CALL LCDCHAR
	movlw "O"
	movwf LCDByte
	CALL LCDCHAR
	movlw "R"
	movwf LCDByte
	CALL LCDCHAR
	movlw "L"
	movwf LCDByte
	CALL LCDCHAR
	movlw "D"
	movwf LCDByte
	CALL LCDCHAR
	END


