diff --git a/avr/modules/flash/flash4p.asm b/avr/modules/flash/flash4p.asm new file mode 100644 index 0000000..24fd0cc --- /dev/null +++ b/avr/modules/flash/flash4p.asm @@ -0,0 +1,358 @@ +; *************************************************************************** +; copyright : (C) 2025 by Martin Preuss +; email : martin@libchipcard.de +; +; *************************************************************************** +; * This file is part of the project "AqHome". * +; * Please see toplevel file COPYING of that project for license details. * +; *************************************************************************** + + +.equ FLASH_PAGESIZE = (PAGESIZE*2*4) + + +; *************************************************************************** +; data + +.dseg + + flashPageNum: .byte 2 + flashPageBuffer: .byte FLASH_PAGESIZE + + + +; *************************************************************************** +; code + +.cseg + + + +; --------------------------------------------------------------------------- +; @routine Flash_Init +; +; @clobbers R16 + +Flash_Init: + ldi r16, 0xff + sts flashPageNum, r16 + sts flashPageNum+1, r16 + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine Flash_Fini +; +; @clobbers (R0, R1, R16, R18, R19, R20, R21, R24, R25, X) + +Flash_Fini: + push r15 + in r15, SREG + cli + rcall flash4pEndPage ; (R0, R1, R16, R18, R19, R20, R24, R25, X) + out SREG, r15 + pop r15 + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine Flash_WriteData +; +; @param Z destination address in FLASH memory (byte address as for LPM!) +; @param Y source address +; @param r17 number of bytes to write +; @clobbers (R0, R1, R16, R18, R19, R20, R24, R25, X) + +Flash_WriteData: + push r15 + in r15, SREG + cli +Flash_WriteData_loop: + tst r17 + breq Flash_WriteData_done + rcall flashWriteData ; (R0, R1, R16, R18, R19, R20, R24, R25, X) + rjmp Flash_WriteData_loop +Flash_WriteData_done: + out SREG, r15 + pop r15 + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine flashWriteData +; +; Interrupts must be disabled! +; +; @return Z next position +; @return R17 remainder of bytes to flash +; @param Z position to flash data to +; @param Y source pointer +; @param R17 number of bytes to flash +; @clobbers R16, R18, R24, R25, X (R0, R1, R19, R20) + +flashWriteData: + rcall flashWriteCheckPage ; (r18, r19) + brcs flashWriteData_calcPosAndLength + rcall flash4pEndPage ; (R0, R1, R16, R18, R19, R20, R24, R25, X) + rcall flash4pBeginPage ; (r16, r24, r25, X, Z) +flashWriteData_calcPosAndLength: + rcall flashCalcPosAndLength ; (r24, r25) + ; X=abs pos in buffer, r18=bytes to read, r17=bytes initially requested + ; prepare data for return + sub r17, r18 ; r17 holds remainder + add zl, r18 ; Z points to next data + adc zh, r18 ; only add carry flag + sub zh, r18 +flashWriteData_copyLoop: + ld r16, Y+ + st X+, r16 + dec r18 + brne flashWriteData_copyLoop + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine flashCalcPosAndLength +; +; @return X absolute write position inside buffer +; @return R18 bytes to write +; @param Z destination pos +; @param R17 number of bytes to write +; @clobbers r24, r25 + +flashCalcPosAndLength: + ; calc offset into buffer + mov r24, zl + andi r24, (FLASH_PAGESIZE-1) ; r24=rel pos inside buffer + ldi r25, FLASH_PAGESIZE + sub r25, r24 ; r25=bytes left inside page + mov r18, r17 + cp r25, r17 + brcc flashCalcPosAndLength_l1 + mov r18, r25 +flashCalcPosAndLength_l1: + ldi xl, LOW(flashPageBuffer) + ldi xh, HIGH(flashPageBuffer) + add xl, r24 + adc xh, r24 + sub xh, r24 + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine flashWriteCheckPage +; +; check whether the given address is inside the current page in buffer +; +; @return CFLAG set if same page, cleared otherwise +; @clobbers r18, r19 + +flashWriteCheckPage: + ; check low byte of page + mov r18, zl + andi r18, LOW(~(FLASH_PAGESIZE-1)) + lds r19, flashPageNum + cp r18, r19 + brne flashWriteCheckPage_ClcRet + ; check high byte of page + mov r18, zh + andi r18, HIGH(~(FLASH_PAGESIZE-1)) + lds r19, flashPageNum+1 + cp r18, r19 + brne flashWriteCheckPage_ClcRet + sec + ret +flashWriteCheckPage_ClcRet: + clc + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine flashCheckCurrentValid +; +; check whether the page buffer contains a valid page (e.g. flashPageNum is not 0xffff) +; +; @return CFLAG set if current page is valid, cleared otherwise +; @clobbers r18, r19 + +flashCheckCurrentValid: + lds r18, flashPageNum + lds r19, flashPageNum+1 + and r18, r19 + inc r18 + breq flashCheckCurrentValid_ClcRet + sec + ret +flashCheckCurrentValid_ClcRet: + clc + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine flash4pBeginPage +; +; Interrupts must be disabled! +; +; @param Z Address to read from (byte address as for LPM!) +; @clobbers (r16, r24, r25, X) + +flash4pBeginPage: + push zl + push zh + andi zl, LOW(~(FLASH_PAGESIZE-1)) + andi zh, HIGH(~(FLASH_PAGESIZE-1)) + sts flashPageNum, zl + sts flashPageNum+1, zh + rcall flash4pReadPagesIntoSram ; r16, r24, r25, X, Z + pop zh + pop zl + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine flash4pEndPage +; +; Interrupts must be disabled! +; +; @clobbers (R0, R1, R16, R18, R19, R20, R24, R25, X) + +flash4pEndPage: + rcall flashCheckCurrentValid ; (r18, r19) + brcs flash4pEndPage_write + ret +flash4pEndPage_write: + push zl + push zh + rcall flash4pErasePages ; (R16, R20, Z) + rcall flash4pWritePages ; (r0, r1, r20, r24, r25, X, Z) + pop zh + pop zl + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine flash4pReadPagesIntoSram +; +; Interrupts must be disabled! +; +; @param Z Address to read from (byte address as for LPM!) +; @clobbers r16, r24, X, Z + +flash4pReadPagesIntoSram: + ldi xl, LOW(flashPageBuffer) + ldi xh, HIGH(flashPageBuffer) + ldi r24, LOW(FLASH_PAGESIZE) +flash4pReadPagesIntoSram_loop: + lpm r16, Z+ + st X+, r16 + adiw ZH:ZL, 1 + dec r24 + brne flash4pReadPagesIntoSram_loop + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine flash4pErasePages +; +; Interrupts must be disabled! +; +; @clobbers R16, R20, Z + +flash4pErasePages: + lds zl, flashPageNum + lds zh, flashPageNum+1 + ldi r20, (1<