; ****************************************************************************
;
;                                  Programming
;
; ****************************************************************************

; Structure of program row (length 2..32 bytes)
;  0: (1) row number HIGH + length
;	   bit 7..4: row number HIGH 4 bits
;	   bit 3..0: row length/2 (0..30 bytes), row is aligned to even length by CH_NUL
;  1: (1) row number LOW (row number 12 bits = 1..4094, 4095=stop row, 0=free row)
;  2: (0..30) row content, can by aligned with CH_NUL to even length
;
; Row number 0 = unused free row (can be rewrited by another row).
; Program is terminated by 2 bytes 0xff (=row number 4095) = default EEPROM content.

#include "include.inc"

	.text

; ----------------------------------------------------------------------------
;                Format program space in EEPROM (clear program)
; ----------------------------------------------------------------------------
; DESTROYS: R24..R22
; STACK: 8 bytes
; ----------------------------------------------------------------------------

.global ProgNew
ProgNew:

	clr	r24		; word index = 0
	ldi	r23,0xff	; stop mark, 1st byte
	ldi	r22,0xff	; stop mark, 2nd byte

; INPUT: R24 = word index
; 	 R23 = 1st byte
;	 R22 = 2nd byte
; DESTROYS: nothing
; STACK: 8 bytes

	rjmp	EEWriteW

; ----------------------------------------------------------------------------
;                 Read program row number from EEPROM
; ----------------------------------------------------------------------------
; INPUT: R24 = word index in EEPROM, pointing to row number
; OUTPUT: R25 = length of program row in words (0..15)
;	  R24 = next word index in EEPROM, pointing to row data
;	  R23:R22 = program row number (0..4095)
;	  flag Z = is set if row number is 0 (empty row)
;	  flag C = is set if row number is 0xfff (stop row)
; DESTROYS: nothing
; STACK: 7 bytes
; ----------------------------------------------------------------------------

.global ProgGetNum
ProgGetNum:

; Structure of program row (length 2..32 bytes)
;  0: (1) row number HIGH + length
;	   bit 7..4: row number HIGH 4 bits
;	   bit 3..0: row length/2 (0..30 bytes), row is aligned to even length by CH_NUL
;  1: (1) row number LOW (row number 12 bits = 1..4094, 4095=stop row, 0=free row)
;  2: (0..30) row content, can by aligned with CH_NUL to even length

; ----- read word -> R23:R22
; INPUT: R24 = word index
; OUTPUT: R23 = 1st byte
;	  R22 = 2nd byte
; DESTROYS: nothing
; STACK: 5 bytes

	rcall	EEReadW		; read 2 bytes
	inc	r24		; increase word index

; ----- row length in words -> R25

	mov	r25,r23		; R25 <- row number HIGH + length
	andi	r25,0x0f	; mask row length

; ----- row number

	swap	r23
	andi	r23,0x0f	; mask row number HIGH 4 bits

; ----- check row number to set flags (C=stop row, Z=empty row)
; 1) 0x0000 - 0x0fff = 0xf001 (empty row)
; 2) 0x0001 - 0x0fff = 0xf002 (first valid row)
; 3) 0x0ffe - 0x0fff = 0xffff (last valid row)
; 4) 0x0fff - 0x0fff = 0x0000 (stop row)

	subi	r22,lo8(ROWSTOP) ; ROWSTOP = 0x0fff
	sbci	r23,hi8(ROWSTOP)

; 1) 0xf001 - 0xf001 = 0x0000 Z- (empty row)
; 2) 0xf002 - 0xf001 = 0x0001 -- (first valid row)
; 3) 0xffff - 0xf001 = 0x0ffe -- (last valid row)
; 4) 0x0000 - 0xf001 = 0x0fff -C (stop row)

	subi	r22,lo8(-ROWSTOP) ; -ROWSTOP = 0xf001
	sbci	r23,hi8(-ROWSTOP)
	ret

; ----------------------------------------------------------------------------
;                  Find next (or equal) program row in EEPROM
; ----------------------------------------------------------------------------
; INPUT: R21:R20 = required program row 1..ROWMAX
; OUTPUT: R25 = length of program row in words (0..15)
;	  R24 = word index of program row (equal or higher), pointing to row data
;	  R23:R22 = program row number (0..4095)
;         flag Z = is set if program row is equal
;	  flag C = is set if next program row cannot be found
; DESTROYS: R27, R26, R19, R18
; STACK: 9 bytes
; ----------------------------------------------------------------------------

.global ProgFindRow
ProgFindRow:

; ----- clear best row (R19 length, R18 address, R27:R26 number 0=not found)

	clr	r27
	clr	r26

; ----- index of first row

	clr	r24
	
; ----- get next row
; INPUT: R24 = word index in EEPROM, pointing to row number
; OUTPUT: R25 = length of program row in words (0..15)
;	  R24 = next word index in EEPROM, pointing to row data
;	  R23:R22 = program row number (0..4095)
;	  flag Z = is set if row number is 0 (empty row)
;	  flag C = is set if row number is 0xfff (stop row)
; DESTROYS: nothing
; STACK: 7 bytes
ProgFind2:
	rcall	ProgGetNum	; get row number
	brcs	ProgFind6	; stop

; ----- compare row number with required row number

	cp	r22,r20
	cpc	r23,r21
	breq	ProgFind8	; equal row has been found
	brcs	ProgFind4	; row number is less than required row number

; ----- check if it is first best row (number = 0)

	adiw	r26,1
	sbiw	r26,1
	breq	ProgFind3	; it is first row

; ----- compare with best row

	cp	r22,r26
	cpc	r23,r27
	brcc	ProgFind4	; it is not better row number

; ----- save new best row

ProgFind3:
	movw	r18,r24		; save best row length and address
	movw	r26,r22		; save best row number

; ----- shift to next row

ProgFind4:
	add	r24,r25		; shift to next row
	brcc	ProgFind2

; ----- return best program row

ProgFind6:
	movw	r24,r18		; address and length of best row
	movw	r22,r26		; number of best row
	cp	r22,r20		; compare row number (C is set if best = 0, Z is set if best = required)
	cpc	r23,r21
	
ProgFind8:
	ret

; ----------------------------------------------------------------------------
;               Clear program row in EEPROM (mark it as empty)
; ----------------------------------------------------------------------------
; INPUT: R21:R20 = required program row 1..ROWMAX
; DESTROYS: R27..R22, R19, R18
; STACK: 11 bytes
; ----------------------------------------------------------------------------

.global ProgClrRow
ProgClrRow:

; ----- find row
; INPUT: R21:R20 = required program row 1..ROWMAX
; OUTPUT: R25 = length of program row in words (0..15)
;	  R24 = word index of program row (equal or higher), pointing to row data
;	  R23:R22 = program row number (0..4095)
;         flag Z = is set if program row is equal
;	  flag C = is set if next program row cannot be found
; DESTROYS: R27, R26, R19, R18
; STACK: 9 bytes

	rcall	ProgFindRow
	brne	ProgFind8	; not found

; ----- write row number = 0 (= empty row)
; INPUT: R24 = word index
; 	 R23 = 1st byte
;	 R22 = 2nd byte
; DESTROYS: nothing
; STACK: 8 bytes

	dec	r24		; return start address
	mov	r23,r25		; 1st byte = length/2
	clr	r22		; 2nd byte = row number LOW = 0
	rjmp	EEWriteW	; write row number

; ----------------------------------------------------------------------------
;                  Write program row into EEPROM
; ----------------------------------------------------------------------------
; INPUT: R31:R30 (Z) = source address i RAM
;	 R15 = length in words 0..15
;	 R21:R20 = program row 1..ROWMAX
; DESTROYS: R27..R22, R19, R18
; STACK: 8 bytes
; ----------------------------------------------------------------------------

#if 0
.global ProgWriteRow
ProgWriteRow:

; ----- first, clear existing row
; INPUT: R21:R20 = required program row 1..ROWMAX
; DESTROYS: R27..R22, R19, R18
; STACK: 11 bytes

	rcall	ProgClrRow

; ----- prepare address -> R24, R17 best row length (255 not found), R16 best row address

	clr	r24
	ldi	r17,255

; ----- read row number

ProgWriteRow2:
; INPUT: R24 = word index in EEPROM, pointing to row number
; OUTPUT: R25 = length of program row in words (0..15)
;	  R24 = next word index in EEPROM, pointing to row data
;	  R23:R22 = program row number (0..4095)
;	  flag Z = is set if row number is 0 (empty row)
;	  flag C = is set if row number is 0xfff (stop row)
; DESTROYS: nothing
; STACK: 7 bytes
	rcall	ProgGetNum
	brcs	ProwWriteRow5	; stop mark
	brne	ProgWriteRow3	; not empty row

; ----- check best row

	cp	r25,r15		; check required length
	brcs	ProwWriteRow3	; row is too short

	cp	r25,r17		; check best row length
	brcc	ProgWriteRow3	; not better

	movw	r16,r24		; save best row length and address	

; ----- next row

ProgWriteRow3:
	add	r24,r25		; shift to next row
	brcc	ProgWriteRow2

; ----- overflow

	cpi	r17,255		; check best row
	brcs	ProgWriteRow6	; found OK

; ----- memory overflow

ProgWriteRow4:
	ldi	r24,ERR_PROGMEM	; out of program memory
	rjmp	Error

; ----- check if empty row has been found

ProgWriteRow5:
	cpi	r17,255		; check best row
	brcs	ProgWriteRow6	; found OK

; ----- check remaining space





; ----- write program row

ProgWriteRow6:


#endif




;                           Write EEPROM data
; ----------------------------------------------------------------------------
; INPUT: R31:R30 = source address in RAM
;	 R25:R24 = destination address in EEPROM
;	 R20 = number of bytes
; OUTPUT: R31:R30 = shifted source address
;	  R25:R24 = shifted destination address
; DESTROYS: R23, R22
; STACK: 6 bytes
; ----------------------------------------------------------------------------
;.global EEWriteData
;EEWriteData:
