;lcd routines


	cblock	0x2A
		lcd_shadow,lcd_tmp,lcda,lcd_char
	endc


#define lcd_port	PORTB
#define lcd_enable	lcd_shadow,0
#define	lcd_rs		lcd_shadow,1
#define	lcd_rw		lcd_shadow,2



;------------------------------
lcd_uport macro
	MOV	W, lcd_shadow
	MOV	lcd_port, W
	endm



;------------------------------
;strobe lcd enable
lcd_strobe:
	MOV	W, #20
	CALL	delay
	SETB	lcd_enable
	lcd_uport
	MOV	W, #20
	CALL	delay

	MOV	W, lcd_port
	AND	W, #$F0
	MOV	lcd_tmp, W

	CLRB	lcd_enable
	lcd_uport
	MOV	W, <>lcd_tmp
	RET



;------------------------------
lcd_send_nibble:
	MOV	lcd_tmp, W
	MOV	W, #$0F
	AND	lcd_tmp, W
	AND	lcd_shadow, W

	MOV	W, <>lcd_tmp
	OR	lcd_shadow, W
	lcd_uport

	JMP	lcd_strobe




;------------------------------
lcd_read_byte:
	MOV	W, #$F0
;*** WARNING: TRIS expanded in two instructions. Check if previous instruction is a skip instruction.
;	tris	lcd_port

	SETB	lcd_rw

	lcd_uport
	CALL	lcd_strobe
	MOV	lcda, W
	SWAP	lcda
	CALL	lcd_strobe
	OR	lcda, W

	MOV	W, #0
;*** WARNING: TRIS expanded in two instructions. Check if previous instruction is a skip instruction.
;	tris	lcd_port


	CLRB	lcd_rw
	MOV	W, lcda
	RET



;------------------------------
#define	sv_addr		bit_tmp,0

lcd_putc:
	SETB	lcd_rs

lcd_send_byte:
	MOV	lcd_char, W
	CLRB	sv_addr
	SNB	lcd_rs
	SETB	sv_addr

	CLRB	lcd_rs
sb0	CALL	lcd_read_byte	;wait until not lcd busy
	AND	W, #%10000000
	SB	Z
	JMP	sb0

	CLRB	lcd_rw
	CLRB	lcd_rs
	SNB	sv_addr
	SETB	lcd_rs

	MOV	W, <>lcd_char
	CALL	lcd_send_nibble
	MOV	W, lcd_char
	JMP	lcd_send_nibble



;------------------------------
lcd_init:
	MOV	W, #0
;*** WARNING: TRIS expanded in two instructions. Check if previous instruction is a skip instruction.
;	tris	lcd_port


	CLR	lcd_shadow
	lcd_uport

	MOV	W, #50
	CALL	delay_ms

	MOV	W, #3
	MOV	lcda, W
	CLRB	lcd_rs
lcdi0	MOV	W, #3
	CALL	lcd_send_nibble
	MOV	W, #15
	CALL	delay_ms
	DECSZ	lcda
	JMP	lcdi0

	MOV	W, #2
	CALL	lcd_send_nibble

	MOV	W, #%00101000	;function set
	CALL	lcd_send_byte	;4 bit,1/6 duty,5x8

	MOV	W, #%00001000	;display off,cursor off, blink off
	CALL	lcd_send_byte

	MOV	W, #%00000001	;clear screen cursor home
	CALL	lcd_send_byte

	MOV	W, #%00000110	;Increment cursor, don't shift screen
	CALL	lcd_send_byte

	MOV	W, #%00001111	;display on,cursor on, blink on
	CALL	lcd_send_byte

	RET



;------------------------------
;lcd_gotoxy
;   input W = YYXXXXXX
;             76543210
;
;       Y    address
;      ---   -------
;       00    0
;       01    0x40
;       10    20
;       11    0x40+20

xy_loc	macro	x, y
	MOV	W, #(y <	;< 6) | (x & B'00111111')
	CALL	lcd_gotoxy
	endm

lcd_gotoxy:
	MOV	lcd_tmp, W
	AND	W, #%00111111

	SNB	lcd_tmp.6
;*** WARNING: ADDLW was expanded in three instructions! Check if previous instruction is a skip instruction. 
;	 addlw	0x40
	MOV	Hack, W
	MOV	W, #$40
	ADD	W, Hack

	SNB	lcd_tmp.7
;*** WARNING: ADDLW was expanded in three instructions! Check if previous instruction is a skip instruction. 
;	 addlw	.20
	MOV	Hack, W
	MOV	W, #20
	ADD	W, Hack

	OR	W, #%10000000
	CLRB	lcd_rs
	JMP	lcd_send_byte



;------------------------------
lcd_cursor_off:
	CLRB	lcd_rs
	MOV	W, #%00001100	;display on,cursor off, blink off
	JMP	lcd_send_byte



;------------------------------
lcd_cursor_on:
	CLRB	lcd_rs
	MOV	W, #%00001111	;display on,cursor on, blink on
	JMP	lcd_send_byte