;/* Title	: Butterfly LCD display experiments */
;/* Author	: Jan Skalicky, 2005 */


.equ	ASC_FIRST 	=	' '					;offset of first descibed character in <znaky.inc>
.equ	ASC_ZERO 	=	'0'					;offset of zero character in <znaky.inc>

.equ	DIGIT_LEFT	=	2					; left-most digit index
.equ	DIGIT_RIGHT	=	8					;right-most digit index

.cseg
asctable:
.include	"znaky.inc"

/* print Decadic value (r16) to LCD position (r19), left adjusted, maximum of (r20) digits printed */
printDec:	
	push	r16
	push	r17
	push	r18
	push	r19
	push	r20

	ldi		r18, ASC_ZERO					;offset for zero character (internal constant)

printDec_loop:	
	ldi		r17, 10							;decadic constant used for BIN->DEC
	call	div8x8
	push	r16
	mov		r16, r17
	add		r16, r18
	mov		r17, r19
	rcall	printChar
	pop		r16
	dec		r19
	cpi		r19, DIGIT_LEFT					;last possible digit index to print to is left-most
	brlo	printDec_exit
	dec		r20
	breq	printDec_exit
	rjmp	printDec_loop
printDec_exit:
	pop		r20
	pop		r19
	pop		r18
	pop		r17
	pop		r16
	ret

/* print ASCIIZ String (pointer in X) to LCD position (r17), maximum of (r20) digits printed */
printStr:
	push	r16
	push	r17
	push	r20
	push	XL
	push	XH
printStr_loop:
	tst		r20								;maximum of required digits used?
	breq	printStr_exit
	ld		r16, X+
	tst		r16								;end of string?
	breq	printStr_exit
	rcall	printChar
	inc		r17
	cpi		r17, DIGIT_RIGHT				;last possible digit index to print to is right-most
	brsh	printStr_exit
	dec		r20
	rjmp	printStr_loop
printStr_exit:	
	pop		XH
	pop		XL
	pop		r20
	pop		r17
	pop		r16
	ret

/* display initialization */
init_disp:
	push	r16
	ldi		r16, 0xB7
	sts		LCDCRB, r16
	ldi		r16, 0x10
	sts		LCDFRR,	r16
	ldi		r16, 0x0F
	sts		LCDCCR,	r16
	ldi		r16, 0x80
	sts		LCDCRA,	r16
	pop		r16
	ret

/* display clear screen */
disp_clear:
	push	r0
	clr		r0
	sts		LCDDR0, r0
	sts		LCDDR1, r0
	sts		LCDDR2, r0
	sts		LCDDR3, r0
	sts		LCDDR5, r0
	sts		LCDDR6, r0
	sts		LCDDR7, r0
	sts		LCDDR8, r0
	sts		LCDDR10, r0
	sts		LCDDR11, r0
	sts		LCDDR12, r0
	sts		LCDDR13, r0
	sts		LCDDR15, r0
	sts		LCDDR16, r0
	sts		LCDDR17, r0
	sts		LCDDR18, r0
	pop		r0
	ret

/* print ASCII char (r16) to LCD position (r17); r16={42..95}, r17={2..7} */
printChar:
	push	r0
	push	r1
	push	r16
	push	r17
	push	r18
	push	r19
	push	r20
	push	r21
	push	XL
	push	XH
	push	ZL
	push	ZH

	ldi		r18, ASC_FIRST				;first valid ASCII char here (space)
	ldi		r20, 5						;space between videomemory registers for one 14segment
	sub		r16, r18
	lsl		r16
	lsl		r16							;each char is coded in 4 bytes
	dec		r17
	dec		r17							;first position in display is char #2
	mov		r19, r17
	lsr		r19							;two 14segments are coded in one byte of videomemory
	ldi		XH, high(LCDDR0)
	ldi		XL, low (LCDDR0)
	add		XL, r19
	ldi		ZH, high(asctable<<1)
	ldi		ZL, low (asctable<<1)
	add		ZL, r16						;base+offset points to asctable
	clr		r0
	adc		ZH, r0						;bypass for asctable located upper than 0x100 in flash
	ldi		r19, 4						;4 group of segmets is to be processed

printChar_loop:	
	lpm
	sbrc	r17, 0
	swap	r0							;first nibble = even segments, second = odd ones
	ldi		r21, 0b11110000				;mask for merging 2 nibbles
	sbrc	r17, 0
	swap	r21
	ld		r1, X
	and		r1, r21	
	or		r0, r1						;let the segments next to our remain unchanged
	st		X, r0
	dec		r19
	breq	printChar_exit
	inc		ZL
	brne	PC+2
	inc		ZH							;bypass for asctable located upper than 0x100 in flash
	add		XL, r20
	rjmp	printChar_loop

printChar_exit:
	pop		ZH
	pop		ZL
	pop		XH
	pop		XL
	pop		r21
	pop		r20
	pop		r19
	pop		r18
	pop		r17
	pop		r16
	pop		r1
	pop		r0
	ret
