; ****************************************************************************
;
;                                 Main
;
; ****************************************************************************

#include "include.inc"

	.text

TextErr:
	.byte	CH_ENTER,'E','R','R','O','R',' '+0x80

	.balign 2	; to avoid linker error "warning: internal error: out of range error" must be at the end of unaligned tables


; ===== TEST begin

.global TestSpc
TestSpc:

	push	r31
	push	r30
	push	r27
	push	r26
	push	r25
	push	r24
	push	r23
	push	r1
	push	r0

	rcall	DispSpc

	pop	r0
	pop	r1
	pop	r23
	pop	r24
	pop	r25
	pop	r26
	pop	r27
	pop	r30
	pop	r31
	ret

.global TestNewLine
TestNewLine:

	push	r31
	push	r30
	push	r27
	push	r26
	push	r25
	push	r24
	push	r23
	push	r1
	push	r0

	rcall	DispNewLine

	pop	r0
	pop	r1
	pop	r23
	pop	r24
	pop	r25
	pop	r26
	pop	r27
	pop	r30
	pop	r31
	ret


.global TestHex
TestHex:

; INPUT: R24 = byte to display
; DESTROYS: R31, R30, R27..R23, R1, R0
; STACK: 13 bytes

	push	r31
	push	r30
	push	r27
	push	r26
	push	r25
	push	r24
	push	r23
	push	r1
	push	r0

	rcall	DispHexB
	rcall	DispSpc

	pop	r0
	pop	r1
	pop	r23
	pop	r24
	pop	r25
	pop	r26
	pop	r27
	pop	r30
	pop	r31
	ret


TestPrint:
	in	r24,_SFR_IO_ADDR(SPL)
	in	r25,_SFR_IO_ADDR(SPH)
	rcall	DispHexW
	rcall	DispSpc

	ldd	r24,Y+DATA_STKEND
	ldd	r25,Y+DATA_STKEND+1
	rcall	DispHexW
	rcall	DispSpc

	ldd	r24,Y+DATA_STKADDR
	ldd	r25,Y+DATA_STKADDR+1
	ldd	r18,Y+DATA_STKEND
	ldd	r19,Y+DATA_STKEND+1
	sub	r18,r24	
	sbc	r19,r25
	rcall	DispNum
	rcall	DispSpc

	rcall	CalcTop
	ld	r24,Z+
	ld	r11,Z+
	ld	r12,Z+
	ld	r13,Z+
	ld	r14,Z

	rcall	DispHexB
	rcall	DispSpc

	mov	r24,r11
	rcall	DispHexB
	rcall	DispSpc
	
	mov	r24,r12
	rcall	DispHexB
	rcall	DispSpc

	mov	r24,r13
	rcall	DispHexB
	rcall	DispSpc

	mov	r24,r14
	rcall	DispHexB
	rcall	DispNewLine
	ret


TestDek:
	rcall	Calc
	.byte	C_DUP
	.byte	C_END

	rcall	DecNum

	ldi	r30,lo8(OutBuf)
	ldi	r31,hi8(OutBuf)
	ldd	r22,Y+DATA_OUTBUFNUM
	tst	r22
	breq	2f
1:	ld	r24,Z+
	push	r22
	rcall	DispCh
	pop	r22
	dec	r22
	brne	1b
2: 	rcall	DispNewLine

;	rcall	TestPrint
	ret







#if 0

; display flags in SREG (5+1 characters); saves SREG, R25 and R24
TestFlags:
	push	r24
	push	r25
	push	r17
	in	r17,_SFR_IO_ADDR(SREG)
	push	r17

; B0: C carry (prenos z bitu 7, prenos z unsigned operaci - tj. byla zmena bitu 7)
; B1: Z zero (vysledek 0)
; B2: N negative (kopie bitu 7)
; B3: V Two's complement overflow (prenos ze signed operaci)
; B4: S sign = N ^ V
; B5: H half carry (prenos z bitu 3)

	ldi	r24,'-'
	sbrc	r17,5
	ldi	r24,'H'
	rcall	DispCh

	ldi	r24,'-'
	sbrc	r17,4
	ldi	r24,'S'
	rcall	DispCh

	ldi	r24,'-'
	sbrc	r17,3
	ldi	r24,'V'
	rcall	DispCh

	ldi	r24,'-'
	sbrc	r17,2
	ldi	r24,'N'
	rcall	DispCh

	ldi	r24,'-'
	sbrc	r17,1
	ldi	r24,'Z'
	rcall	DispCh

	ldi	r24,'-'
	sbrc	r17,0
	ldi	r24,'C'
	rcall	DispCh

	rcall	DispSpc

	pop	r17
	out	_SFR_IO_ADDR(SREG),r17
	pop	r17
	pop	r25
	pop	r24
	ret

; display byte R24 (2 characters); saves SREG, R25 and R24
TestByte24:
	push	r24
	push	r25
	push	r17
	in	r17,_SFR_IO_ADDR(SREG)
	push	r17

	rcall	DispHexB

	pop	r17
	out	_SFR_IO_ADDR(SREG),r17
	pop	r17
	pop	r25
	pop	r24
	ret

; display byte R25 (2 characters); saves SREG, R25 and R24
TestByte25:
	push	r24
	push	r25
	push	r17
	in	r17,_SFR_IO_ADDR(SREG)
	push	r17

	mov	r24,r25
	rcall	DispHexB

	pop	r17
	out	_SFR_IO_ADDR(SREG),r17
	pop	r17
	pop	r25
	pop	r24
	ret

; display character in r23; saves SREG, R25 and R24
TestChar:
	push	r24
	push	r25
	push	r17
	in	r17,_SFR_IO_ADDR(SREG)
	push	r17

	mov	r24,r23
	rcall	DispCh

	pop	r17
	out	_SFR_IO_ADDR(SREG),r17
	pop	r17
	pop	r25
	pop	r24
	ret

; display space; saves SREG, R25 and R24
TestSpc:
	push	r23
	ldi	r23,CH_SPC
	rcall	TestChar
	pop	r23
	ret

#endif

; ===== TEST end


; ----- memory error

.global MemErr
MemErr:
	ldi	r24,ERR_MEM

; Error must follow

; ----------------------------------------------------------------------------
;                Report error code (and reinitialize stack)
; ----------------------------------------------------------------------------
; INPUT: R24=error code
; ----------------------------------------------------------------------------

.global Error
Error:
	mov	r12,r24		; save error code

; ----- initialize stack and restart

	cli
	ldi	r24,lo8(STACK)	; end of stack
	ldi	r25,hi8(STACK)
	out	_SFR_IO_ADDR(SPH),r25
	out	_SFR_IO_ADDR(SPL),r24
	sei

; ----- reduce edit line and calculator stack

	ldd	r24,Y+DATA_EDITADDR
	ldd	r25,Y+DATA_EDITADDR+1
	std	Y+DATA_STKADDR,r24
	std	Y+DATA_STKADDR+1,r25
	std	Y+DATA_MEMTOP,r24
	std	Y+DATA_MEMTOP+1,r25

; ----- free memory to report error

	rcall	DispReduce	; reduce memory

; ----- display error code

	ldi	r30,lo8(TextErr)
	ldi	r31,hi8(TextErr)
	rcall	DispText	; display text "ERROR"
	mov	r18,r12
	clr	r19
	rcall	DispNum		; display error code
	ldi	r24,CH_ENTER
	rcall	DispCh		; new line

	rjmp	Restart		; restart

; Reset
.global main
main:

; ----- initialize global registers

	eor	R_ZERO,R_ZERO	; register 0
	eor	R_ONE,R_ONE
	inc	R_ONE		; register 1
	eor	R_MINUS,R_MINUS
	dec	R_MINUS		; register -1	
	ldi	YL,lo8(DataStart) ; data area LOW
	ldi	YH,hi8(DataStart) ; data area HIGH

; ----- initialize status register

	out	_SFR_IO_ADDR(SREG),R_ZERO

; ----- clear whole RAM memory (initialize to 0)

	ldi	r30,lo8(RAM_BEG)
	ldi	r31,hi8(RAM_BEG)
	ldi	r25,hi8(RAM_END)
1:	st	Z+,R_ZERO
	cpi	r30,lo8(RAM_END)
	cpc	r31,r25
	brne	1b

; ----- initialize memory pointers

	ldi	r24,lo8(Board+HEIGHT+1)
	ldi	r25,hi8(Board+HEIGHT+1)
	std	Y+DATA_VARADDR,r24
	std	Y+DATA_VARADDR+1,r25
	std	Y+DATA_EDITADDR,r24
	std	Y+DATA_EDITADDR+1,r25
	std	Y+DATA_STKADDR,r24
	std	Y+DATA_STKADDR+1,r25
	std	Y+DATA_MEMTOP,r24
	std	Y+DATA_MEMTOP+1,r25

; ----- initialize stack

	ldi	r24,lo8(STACK)	; end of stack
	ldi	r25,hi8(STACK)
	out	_SFR_IO_ADDR(SPH),r25
	out	_SFR_IO_ADDR(SPL),r24

; ----- initialize port B

	ldi	r24,0			; no pull-ups
	out	_SFR_IO_ADDR(PORTB),r24	; set pull-ups of port B
	ldi	r24,B5+B3+B2+B1		; outputs: SCK, MOSI, AUDIO, SYN
	out	_SFR_IO_ADDR(DDRB),r24	; set direction of port B

; ----- initialize port C

	ldi	r24,B4+B5		; pull-ups: SDA, SCL
	out	_SFR_IO_ADDR(PORTC),r24	; set pull-ups of port C
	ldi	r24,0			; no output
	out	_SFR_IO_ADDR(DDRC),r24	; set direction of port C

; ----- initialize port D

	ldi	r24,B7+B6+B4+B1+B0	; pull-ups: SEL2, SEL1, KBDCLK, KBDDAT
	out	_SFR_IO_ADDR(PORTD),r24 ; set pull-ups of port D
	ldi	r24,B3			; PD3 output to LED, other bits inputs
	out	_SFR_IO_ADDR(DDRD),r24	; set direction of port D

; ----- initialize display mode

	ldi	r24,0xff
	std	Y+DATA_DISPMODE,r24	; invalidate display mode

	ldi	r24,HEIGHT
	std	Y+DATA_DISPROWS,r24	; initialize number of rows to maximum

	rcall	DispUpdate		; update display settings

; ----- set Timer1 mode

	; OC1A: start LOW pulse on TOP, stop HIGH pulse on match
	; OC1B: disconnected

	ldi	r24,BIT(COM1A1) | BIT(COM1A0) | BIT(WGM11)
#ifdef MCU8
	out	_SFR_IO_ADDR(TCCR1A),r24
#else
	sts	TCCR1A,r24
#endif

; ----- start Timer1 in fast PWM mode 14, no prescaler

	ldi	r24,BIT(WGM12) | BIT(WGM13) | BIT(CS10)
#ifdef MCU8
	out	_SFR_IO_ADDR(TCCR1B),r24
#else
	sts	TCCR1B,r24
#endif

; ----- enable interrupt on Timer1 overflow

	ldi	r24,BIT(TOIE1)
#ifdef MCU8
	out	_SFR_IO_ADDR(TIMSK),r24
#else
	sts	TIMSK1,r24
#endif

; ----- enable SPI output (MSB first, master mode, SCK data on rising edge)

	ldi	r24,SPIEN		; SPI enable, speed clk/2
	out	_SFR_IO_ADDR(SPCR),r24

; ----- clear screen

	rcall	DispClear		; clear screen

; ----- initialize keyboard
; synchronous mode, odd parity, 1 stop bit, 8 data bits, rising edge

#ifdef MCU8
	ldi	r24,BIT(URSEL) | BIT(UMSEL) | BIT(UPM1) | BIT(UPM0) | BIT(UCSZ1) | BIT(UCSZ0)
	out	_SFR_IO_ADDR(UCSRC),r24 ; set USART mode

	ldi	r24,BIT(RXEN)
	out	_SFR_IO_ADDR(UCSRB),r24 ; enable receiver
#else
	ldi	r24,BIT(UMSEL00) | BIT(UPM01) | BIT(UPM00) | BIT(UCSZ01) | BIT(UCSZ00)
	sts	UCSR0C,r24 		; set USART mode

	ldi	r24,BIT(RXEN0)
	sts	UCSR0B,r24		; enable receiver
#endif

; ----- restart after error

Restart:

; ----- enable interrupts

	sei



	; nastaveni kurzoru
	ldi	r24,0
	ldi	r25,0
	rcall	DispSetCur

	ldi	r24,lo8(NumBuf)
	ldi	r25,hi8(NumBuf)
	std	Y+DATA_MEMADDR,r24
	std	Y+DATA_MEMADDR+1,r25

	rcall	TestPrint

	rcall	Calc
	.byte	C_CONSTAB(CONST_PI2)
	.byte	C_LN
	.byte	C_END		; end
	.balign 2		; align
	rcall	TestPrint
	rcall	TestDek

	rcall	Calc
	.byte	C_DEL
	.byte	C_CONSTAB(CONST_PI2)
	.byte	C_EXP
	.byte	C_END		; end
	.balign 2		; align
	rcall	TestPrint
	rcall	TestDek

	rcall	Calc
	.byte	C_DEL
	.byte	C_CONSTAB(CONST_1)
	.byte	C_SIN
	.byte	C_END		; end
	.balign 2		; align
	rcall	TestPrint
	rcall	TestDek

	rcall	Calc
	.byte	C_DEL
	.byte	C_CONSTAB(CONST_1)
	.byte	C_COS
	.byte	C_END		; end
	.balign 2		; align
	rcall	TestPrint
	rcall	TestDek

	rcall	Calc
	.byte	C_DEL
	.byte	C_CONSTAB(CONST_1)
	.byte	C_TAN
	.byte	C_END		; end
	.balign 2		; align
	rcall	TestPrint
	rcall	TestDek




; ===== TEST begin

#if 0
	ldi	r16,-8
	ldi	r17,0
	ldi	r18,0
	sub	r15,r15
	in	r15,_SFR_IO_ADDR(SREG)
loop2:

	; nastaveni kurzoru
	ldi	r24,0
	ldi	r25,0
	rcall	DispSetCur

	; pocet radku k zobrazeni
	push	r16
	push	r17
	push	r18
	ldi	r19,HEIGHT-1
aaaa1:
	; nastaveni a zobrazeni pocatecnich flagu
	out	_SFR_IO_ADDR(SREG),r15
	rcall	TestFlags

	; zobrazeni operandu R18:R17:R16
	mov	r24,r18
	rcall	TestByte24
;	ldi	r23,':'
;	rcall	TestChar
	mov	r24,r17
	rcall	TestByte24
;	ldi	r23,':'
;	rcall	TestChar
	mov	r24,r16
	rcall	TestByte24

	; oddelovac vysledku
	ldi	r23,'>'
	rcall	TestChar

	; vypocet
	mov	r24,r16
	mov	r25,r17
	mov	r26,r18
	com	r26
	com	r25
	neg	r24		; carry will be set if number was NOT 0 (R_M5 = 0 - R_M5, CARRY <- (R_M5 != 0))
	sbci	r25,0xff	; increment if lower byte was 0, set carry if result is NOT 0 (R_M4 = R_M4 - (0xFF + CARRY))
	sbci	r26,0xff

	; zobrazeni vysledku
	push	r24
	push	r25
	mov	r24,r26
	rcall	TestByte24
;	ldi	r23,':'
;	rcall	TestChar
	pop	r24
	rcall	TestByte24
;	ldi	r23,':'
;	rcall	TestChar
	pop	r24
	rcall	TestByte24
	rcall	TestSpc

	; zobrazeni koncovych flagu
	rcall	TestFlags

	; novy radek
	rcall	DispNewLine

	; zvyseni registru a citac radku
	subi	r16,-1
	sbci	r17,-1
	sbci	r18,-1
	dec	r19
	brne	aaaa1
	pop	r18
	pop	r17
	pop	r16

aaa2:
	; cekani na klavesu s blikanim kurzoru
	rcall	DispCurBlink
	rcall	KeyIn

	; UP - snizeni R16 o 16
	cpi	r24,CH_UP
	brne	aaa3
	subi	r16,16
	sbci	r17,0
	sbci	r18,0
	rjmp	loop2

	; DOWN - zvyseni R16 o 16
aaa3:	cpi	r24,CH_DOWN
	brne	aaa4
	subi	r16,-16
	sbci	r17,-1
	sbci	r18,-1
	rjmp	loop2

	; LEFT - snizeni R17 o 1
aaa4:	cpi	r24,CH_LEFT
	brne	aaa5
	subi	r17,1
	sbci	r18,0
	rjmp	loop2

	; RIGHT - zvyseni R17 o 1
aaa5:	cpi	r24,CH_RIGHT
	brne	aaa6
	subi	r17,-1
	sbci	r18,-1
	rjmp	loop2

	; SPACE - zmena C flagu
aaa6:	cpi	r24,CH_SPC
	brne	aaa7
	eor	r15,R_ONE
	rjmp	loop2

	; ENTER - zmena Z flagu
aaa7:	cpi	r24,CH_ENTER
	brne	aaa8
	ldi	r24,B1
	eor	r15,r24
	rjmp	loop2

	; PageUp - snizeni R18 o 1
aaa8:	cpi	r24,CH_PGUP
	brne	aaa9
	dec	r18
	rjmp	loop2

	; PageDown - zvyseni R18 o 1
aaa9:	cpi	r24,CH_PGDN
	brne	aaa2
	inc	r18
	rjmp	loop2
#endif

; ===== TEST end






; ==== key input begin

#if 1

loop2:
	rcall	DispReduce


	rcall	KeyIn
	cpi	r24,0
	breq	loop6

	cpi	r24,CH_A
	brne	loop3
	rjmp	MemErr

loop3:

	rcall	DispCh
;	rcall	DispHexB
;	rcall	DispSpc

loop4:

	ldd	r16,Y+DATA_CURX
	ldd	r17,Y+DATA_CURY

	ldi	r24,0
	ldi	r25,HEIGHT-1
	rcall	DispSetCur

	rcall	MemFree
	movw	r18,r24
	rcall	DispNum
	rcall	DispSpc

	mov	r24,r16
	mov	r25,r17
	rcall	DispSetCur

loop6:

	; cursor blinking service
	rcall	DispCurBlink

#endif

; ==== key input end



	rjmp	loop2

