.equ    locat, 0xF100           ;Location for this program

; LCD memory mapped locations:
;.equ	lcd_command_wr, 0xFF80
;.equ	lcd_status_rd, 0xFF81
;.equ	lcd_data_wr, 0xFF82
;.equ	lcd_data_rd, 0xFF83

.equ	lcd_command_wr, 0xFE00
.equ	lcd_status_rd, 0xFE01
.equ	lcd_data_wr, 0xFE02
.equ	lcd_data_rd, 0xFE03

.equ	esc, 0x003E		;paulmon2's check for esc key

.org    locat
.db     0xA5,0xE5,0xE0,0xA5     ;signiture bytes
.db     35,255,0,0              ;id (35=prog)
.db     0,0,0,0                 ;prompt code vector
.db     0,0,0,0                 ;reserved
.db     0,0,0,0                 ;reserved
.db     0,0,0,0                 ;reserved
.db     0,0,0,0                 ;user defined
.db     255,255,255,255         ;length and checksum (255=unused)
.db     "LCD Test",0            ;max 31 characters, plus the zero
.org    locat+64                ;executable code begins here

startup:


.equ	cout, 0x0030
.equ	cin, 0x0032
.equ	phex, 0x0034
.equ	phex16, 0x0036
.equ	pstr, 0x0038
.equ	newline, 0x0048


.equ	lcd_clear_cmd, 0x01		;clears display
.equ	lcd_home_cmd, 0x02		;put cursor at home position
.equ	lcd_on_cmd, 0x0C		;turn on display (cursor off)
.equ	lcd_left_move_cmd, 0x10
.equ	lcd_right_move_cmd, 0x14
.equ	lcd_left_shift_cmd, 0x18
.equ	lcd_right_shift_cmd, 0x1C
.equ	lcd_config_cmd, 0x38		;configure, 8 bit interface, 2 lines, 5x7 digits

.equ	lcd_horiz_size, 16
.equ	lcd_vert_size, 2
.equ	lcd_bytes_per_line, 80 / lcd_vert_size

begin:
	mov	dptr, #mesg_start
	lcall	pstr

main_loop:

lcd_init:
	lcall	lcd_busy
	mov	dptr, #lcd_command_wr
	mov	a, #lcd_config_cmd
	movx	@dptr, a

	lcall	lcd_busy
	mov	dptr, #lcd_command_wr
	mov	a, #lcd_clear_cmd
	movx	@dptr, a

	lcall	lcd_busy
	mov	dptr, #lcd_command_wr
	mov	a, #lcd_on_cmd
	movx	@dptr, a

	lcall	lcd_busy
	mov	dptr, #lcd_command_wr
	mov	a, #lcd_left_shift_cmd
	movx	@dptr, a

	lcall	lcd_busy
	mov	dptr, #lcd_command_wr
	mov	a, #0x81
	movx	@dptr, a


	mov	r0, #0
	mov	r1, #0
	acall	lcd_set_xy

	mov	dptr, #mesg1
	acall	lcd_pstr

	mov	r0, #0
	mov	r1, #1
	acall	lcd_set_xy

	mov	dptr, #mesg2
	acall	lcd_pstr

	lcall	cin
	add	a, #256 - 27
	jz	quit


	mov	r0, #0
	mov	r1, #0
	acall	lcd_set_xy

	mov	dptr, #mesg3
	acall	lcd_pstr

	mov	r0, #0
	mov	r1, #1
	acall	lcd_set_xy

	mov	dptr, #mesg4
	acall	lcd_pstr

	lcall	cin
	add	a, #256 - 27
	jnz	main_loop

quit:
	ljmp	0

mesg_start:
	.db	"LCD Test Program... press a key to toggle",13,10
	.db	"between two messages, or ESC to exit",13,10,13,10,0

mesg1:	.db	"LCD 2x16 Display",0
mesg2:	.db	"y* www.pjrc.com *",0

mesg3:	.db	255,255,255,255,255,255,255,255
	.db	255,255,255,255,255,255,255,255,0
mesg4:	.db	255,255,255,255,255,255,255,255,255
	.db	255,255,255,255,255,255,255,255,0



lcd_pstr:
	clr	a
	movc	a, @a+dptr
	inc	dptr
	jz	lcd_pstr_end
	push	dpl
	push	dph
	acall	lcd_cout
	pop	dph
	pop	dpl
	sjmp	lcd_pstr
lcd_pstr_end:
	ret


lcd_cout:
	push	acc
	acall	lcd_busy
	mov	dptr, #lcd_data_wr
	pop	acc
	movx	@dptr, a
	ret


lcd_busy:
	mov	dptr, #lcd_status_rd
	movx	a, @dptr
	jb	acc.7, lcd_busy
	ret


	;R0 = X position (0 to 15), R1 = Y position (0 to 1)
lcd_set_xy:
	;check X is within display size
	mov	a, r0
	add	a, #256 - lcd_horiz_size
	jnc	lcd_set_xok
	mov	r0, #lcd_horiz_size - 1
lcd_set_xok:
	;check Y is within display size
	mov	a, r1
	add	a, #256 - lcd_vert_size
	jnc	lcd_set_yok
	mov	r1, #lcd_vert_size - 1
lcd_set_yok:
	acall	lcd_busy
	;compute address within data display ram in LCD controller chip
	mov	a, r1
	mov	b, #lcd_bytes_per_line
	mul	ab
	add	a, r0
	inc	a
	orl	a, #0x80	;msb set for set DD RAM address
	mov	dptr, #lcd_command_wr
	movx	@dptr, a
	ret


