Files
aqhomecontrol/avr/common/utils.asm
2025-05-17 10:50:09 +02:00

567 lines
12 KiB
NASM

; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
; ***************************************************************************
; data
.dseg
utilsDataBegin:
utilsSeed: .byte 2
utilsDataEnd:
; ***************************************************************************
; code
.cseg
UTILS_BEGIN:
utilsDateString: .db "%YEAR%-%MONTH%-%DAY%-%HOUR%:%MINUTE%", 0, 0
; ---------------------------------------------------------------------------
; Utils_Init
;
; IN:
; OUT:
; - CFLAG: set if okay, clear on error
; USED: R16, R17, R18, R19, X, (R20, R21, R24, R25, X, Z)
Utils_Init:
rcall utilsSetupSeed ; (R16, R18, R19, R20, R21, R24, R25, X, Z)
; preset SRAM data area
ldi xh, HIGH(utilsDataBegin)
ldi xl, LOW(utilsDataBegin)
clr r16
ldi r17, (utilsDataEnd-utilsDataBegin)
rcall Utils_FillSram ; (r17, x)
sts utilsSeed, r18
sts utilsSeed+1, r19
sec
ret
; ---------------------------------------------------------------------------
; setup seed
;
; IN:
; OUT:
; REGS: R16, R18, R19, R20, R21, R24, R25, X, Z
utilsSetupSeed:
rcall Utils_ReadSeed
mov r20, r18
mov r21, r19
; default initial seed
ldi r18, 0xe1
ldi r19, 0xac
; work stored seed into it
mov r16, r20
rcall utilsWorkByteIntoSeed
mov r16, r21
rcall utilsWorkByteIntoSeed
; work date string into seed
ldi zl, LOW(utilsDateString*2)
ldi zh, HIGH(utilsDateString*2)
rcall utilsWorkProgStringIntoSeed ; (R16, Z)
; work sram content into seed
rcall utilsWorkSramContentIntoSeed ; (R16, R24, R25, X)
; store seed in EEPROM
rcall Utils_WriteSeed ; (R16, R17, X)
ret
; ---------------------------------------------------------------------------
; utilsWorkProgStringIntoSeed
;
; IN:
; - Z : pointer to string to work into seed
; - R18: low byte of current seed
; - R19: high byte of current seed
; OUT:
; - R18: low byte of updated seed
; - R19: high byte of updated seed
; USED: R16, Z
utilsWorkProgStringIntoSeed:
lpm r16, Z+
tst r16
breq utilsWorkProgStringIntoSeed_done
rcall utilsWorkByteIntoSeed
rjmp utilsWorkProgStringIntoSeed
utilsWorkProgStringIntoSeed_done:
ret
; ---------------------------------------------------------------------------
; utilsWorkSramContentIntoSeed
; IN:
; - Z : pointer to string to work into seed
; - R18: low byte of current seed
; - R19: high byte of current seed
; OUT:
; - R18: low byte of updated seed
; - R19: high byte of updated seed
; USED: R16, R24, R25, X
utilsWorkSramContentIntoSeed:
ldi xl, LOW(SRAM_START)
ldi xh, HIGH(SRAM_START)
ldi r24, LOW(RAMEND-SRAM_START)
ldi r25, HIGH(RAMEND-SRAM_START)
utilsWorkSramContentIntoSeed_loop:
ld r16, X+
rcall utilsWorkByteIntoSeed
sbiw r25:r24, 1
brne utilsWorkSramContentIntoSeed_loop
ret
; ---------------------------------------------------------------------------
; utilsWorkByteIntoSeed
;
; IN:
; - R16: byte to work into the seed
; - R18: low byte of current seed
; - R19: high byte of current seed
; OUT:
; - R18: low byte of updated seed
; - R19: high byte of updated seed
; USED:
utilsWorkByteIntoSeed:
eor r18, r16
clc
sbrc r19, 7
sec ; only executed if bit 7 is set in r19
rol r18
rol r19
ret
; ---------------------------------------------------------------------------
; Utils_Fini
;
; IN:
; OUT:
; - CFLAG: set if okay, clear on error
; USED: R16, R17, R18, X, Y
Utils_Fini:
sec
ret
; ---------------------------------------------------------------------------
; @routine Utils_FillSram @global
;
; @return X points directly behind filled memory
; @param X pointer to SRAM to fill
; @param r16 value to fill the SRAM with
; @param r17 size of area to fill
; @clobbers r17, X
Utils_FillSram:
tst r17
breq Utils_FillSram_end
Utils_FillSram_loop:
st x+, r16
dec r17
brne Utils_FillSram_loop
Utils_FillSram_end:
ret
; @end
; ---------------------------------------------------------------------------
; Increment a 32 bit counter at the address given by X.
; IN:
; - X: Address of the 4 byte counter (1. byte is LSB)
; OUT:
; - nothing
; MODIFIED REGISTERS: r18, r19, r20, r21, 22
Utils_IncrementCounter32:
ld r18, x+
ld r19, x+
ld r20, x+
ld r21, x
ldi r22, 1
add r18, r22
clr r22 ; doesn't affect carry flag
adc r19, r22
adc r20, r22
adc r21, r22
st x, r21
st -x, r20
st -x, r19
st -x, r18
ret
; ---------------------------------------------------------------------------
; Increment a 16 bit counter at the address given by X.
; IN:
; - X: Address of the 2 byte counter (1. byte is LSB)
; OUT:
; - nothing
; MODIFIED REGISTERS: r18, r19, 22
Utils_IncrementCounter16:
ld r18, x+
ld r19, x
ldi r22, 1
add r18, r22
clr r22 ; doesn't affect carry flag
adc r19, r22
st x, r19
st -x, r18
ret
; ---------------------------------------------------------------------------
; Utils_ReadEepromIncr
;
; Read a byte from EEPROM (see example in ATtiny24/44/84 manual p.19).
;
; IN:
; - X: EEPROM Address to read from
; OUT:
; - R16: byte read
; - X: EEPROM Address incremented
; MODIFIED REGISTERS: R16
Utils_ReadEepromIncr:
.ifdef EEPE
sbic EECR, EEPE ; wait for previous write to complete (if any)
.else
sbic EECR, EEWE ; wait for previous write to complete (if any)
.endif
rjmp Utils_ReadEepromIncr
out EEARH, xh ; set EEPROM address
out EEARL, xl
sbi EECR, EERE ; start EEPROM read by writing EERE
in r16, EEDR ; read data from data register
adiw xh:xl, 1
ret
; ---------------------------------------------------------------------------
; Utils_WriteEepromIncr
;
; Write a byte to EEPROM (see example in ATtiny24/44/84 manual p.18).
;
; IN:
; - R16: byte to write
; - X: EEPROM Address to write to
; OUT:
; - X: EEPROM Address incremented
; MODIFIED REGISTERS: R17
Utils_WriteEepromIncr:
.ifdef EEPE
sbic EECR, EEPE ; wait for previous write to complete (if any)
.else
sbic EECR, EEWE ; wait for previous write to complete (if any)
.endif
rjmp Utils_WriteEepromIncr
.ifdef EEPM1
ldi r17, (0<<EEPM1) | (0<<EEPM0) ; set programming mode
.endif
out EECR, r17
out EEARH, xh ; set EEPROM address
out EEARL, xl
out EEDR, r16 ; write data to data register
.ifdef EEMPE
sbi EECR, EEMPE ; write logical one to EEMPE
.else
sbi EECR, EEMWE ; write logical one to EEMWE
.endif
.ifdef EEPE
sbi EECR, EEPE ; start EEPROM write by setting EEPE
.else
sbi EECR, EEWE ; start EEPROM write by setting EEWE
.endif
adiw xh:xl, 1
ret
; ---------------------------------------------------------------------------
; Utils_PseudoRandom
;
; Generate a pseudo random number.
; (see https://www.avrfreaks.net/s/topic/a5C3l000000URNfEAO/t119045?comment=P-1021038)
;
; IN:
; OUT:
; - R16: 8 bit pseudo random number
; REGS: R16, R17, R18, R19
Utils_PseudoRandom:
lds r16, utilsSeed
lds r17, utilsSeed+1
ldi r18, 0x9c
ldi r19, 8
Utils_PseudoRandom_step:
lsr r17
ror r16
brcc Utils_PseudoRandom_nomask
eor r17, r18
Utils_PseudoRandom_nomask:
dec r19
brne Utils_PseudoRandom_step
sts utilsSeed, r16
sts utilsSeed+1, r17
ret ; result in r16
; ---------------------------------------------------------------------------
; Update seed in EEPROM.
;
; IN:
; OUT:
; REGS: R18, R19, (R16, R17, X)
Utils_UpdateSeedInEeprom:
lds r18, utilsSeed
lds r19, utilsSeed+1
rcall Utils_WriteSeed ; (R16, R17, X)
ret
; ---------------------------------------------------------------------------
; Utils_ReadUid
;
; Read UID from EEPROM.
;
; IN:
; - nothing
; OUT:
; - R18:R19:R20:R21: UID
; REGS: R16, X
Utils_ReadUid:
push r15
in r15, SREG
cli
ldi xl, LOW(EEPROM_OFFS_UUID)
ldi xh, HIGH(EEPROM_OFFS_UUID)
rcall Utils_ReadEepromIncr ; (R16)
mov r18, r16
rcall Utils_ReadEepromIncr ; (R16)
mov r19, r16
rcall Utils_ReadEepromIncr ; (R16)
mov r20, r16
rcall Utils_ReadEepromIncr ; (R16)
mov r21, r16
out SREG, r15
pop r15
ret
; ---------------------------------------------------------------------------
; Utils_SetupUid
;
; Reads UID from EEPROM. If not set generate a new one and store it in EEPROM.
;
; IN:
; OUT:
; - CFLAG set if new generated, cleared if there already was one.
; REGS: R15, R16, R18, R19, R20, R21, X (R17)
Utils_SetupUid:
in r15, SREG
cli
rcall Utils_ReadUid ; (R16, X)
cp r18, r19 ; all the same?
brne Utils_SetupUid_uidOkay ; different, jmp
cp r18, r20
brne Utils_SetupUid_uidOkay ; different, jmp
cp r18, r21
brne Utils_SetupUid_uidOkay ; different, jmp
ldi xl, LOW(EEPROM_OFFS_UUID) ; all the same, generate new uid
ldi xh, HIGH(EEPROM_OFFS_UUID)
rcall Utils_PseudoRandom ; byte 0 (R16, R17, R18, R19)
inc r16
rcall Utils_WriteEepromIncr ; (R17)
rcall Utils_PseudoRandom ; byte 1
rcall Utils_WriteEepromIncr ; (R17)
rcall Utils_PseudoRandom ; byte 2
rcall Utils_WriteEepromIncr ; (R17)
rcall Utils_PseudoRandom ; byte 3
rcall Utils_WriteEepromIncr ; (R17)
rcall Utils_UpdateSeedInEeprom ; (R16, R17, R18, R19, X)
Utils_SetupUid_uidOkay:
out SREG, r15
sec
ret
; ---------------------------------------------------------------------------
; Utils_ReadSeed
;
; Read seed from EEPROM.
;
; IN:
; OUT:
; - R18:R19: seed read
; REGS: R16, X
Utils_ReadSeed:
in r15, SREG
push r15
cli
ldi xl, LOW(EEPROM_OFFS_SEED)
ldi xh, HIGH(EEPROM_OFFS_SEED)
rcall Utils_ReadEepromIncr ; (R16)
mov r18, r16
rcall Utils_ReadEepromIncr ; (R16)
mov r19, r16
pop r15
out SREG, r15
ret
; ---------------------------------------------------------------------------
; Utils_WriteSeed
;
; Read seed from EEPROM.
;
; IN:
; - R18:R19: seed to write
; OUT:
; REGS: R16, X, (R17)
Utils_WriteSeed:
in r15, SREG
push r15
cli
ldi xl, LOW(EEPROM_OFFS_SEED)
ldi xh, HIGH(EEPROM_OFFS_SEED)
mov r16, r18
rcall Utils_WriteEepromIncr ; (R17)
mov r16, r19
rcall Utils_WriteEepromIncr ; (R17)
pop r15
out SREG, r15
ret
; ---------------------------------------------------------------------------
; Utils_TableJump
;
; Jump to a routine using a jump table.
; IN:
; - r16: position to jump to
; - r17: number of entries in table
; - Z : pointer to table
; OUT:
; - depends on called function
; REGS: depends on called function
Utils_TableJump:
cp r16, r17
brcc Utils_TableJump_ret
clr r17
add zl, r16
adc zh, r17
lsl zl ; shift z left for LPM instruction
rol zh
lpm r16, z+ ; read pointer from table
lpm r17, z
tst r16
brne Utils_TableJump_jmp
tst r17
brne Utils_TableJump_jmp
Utils_TableJump_ret:
ret
Utils_TableJump_jmp:
push r16 ; jump via stack
push r17
ret
; ---------------------------------------------------------------------------
; Find position of a given code in a table.
;
; IN:
; - r16: value to translate
; - r17: number of entries
; - Z : pointer to table
; OUT:
; - CFLAG: set if translation found, cleared otherwise
; - r16: translated value
Utils_FindBytePositionInTable:
lsl zl ; shift z left for LPM instruction
rol zh
clr r19
Utils_TranslateByTable_loop:
lpm r18, z+
cp r18, r16
breq Utils_TranslateByTable_found
inc r19
dec r17
brne Utils_TranslateByTable_loop
clc
ret
Utils_TranslateByTable_found:
mov r16, r19
sec
ret
UTILS_END:
.equ MODULE_SIZE_UTILS = UTILS_END-UTILS_BEGIN