Files
aqhomecontrol/avr/common/list.asm
2026-04-20 23:56:52 +02:00

249 lines
5.7 KiB
NASM

; ***************************************************************************
; 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. *
; ***************************************************************************
#ifndef AQH_AVR_COMMON_LIST_H
#define AQH_AVR_COMMON_LIST_H
; ---------------------------------------------------------------------------
; This code implements a simple single-linked list.
; It assumes that the first 2 bytes of an object managed by this code contain
; a 2 byte pointer to the next object.
; ---------------------------------------------------------------------------
; ***************************************************************************
; defs
.equ LIST_OFFS_NEXT_LO = 0
.equ LIST_OFFS_NEXT_HI = 1
.equ LIST_SIZE = 2
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; @routine List_InitObject @global
;
; Reset list object fields.
; @param Y pointer to object
; @clobbers r16
List_InitObject:
clr r16 ; set this->NEXT to NULL
std Y+LIST_OFFS_NEXT_LO, r16
std Y+LIST_OFFS_NEXT_HI, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine List_FiniObject @global
;
; @param Y pointer to object
; @clobbers r16
List_FiniObject:
clr r16 ; set this->NEXT to NULL
std Y+LIST_OFFS_NEXT_LO, r16
std Y+LIST_OFFS_NEXT_HI, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine List_GetNextObject @global
; @param Y pointer to object
; @return X pointer to successor object
; @clobbers none
List_GetNextObject:
ldd xl, Y+LIST_OFFS_NEXT_LO
ldd xh, Y+LIST_OFFS_NEXT_HI
ret
; @end
; ---------------------------------------------------------------------------
; @routine List_GetLastObject
; @param X pointer to one object in a list
; @return X pointer to last object which has an empty NEXT pointer
; @clobbers r16, r17, X, Y
List_GetLastObject:
clr yl
clr yh
rjmp List_GetPredecessorFor
; @end
; ---------------------------------------------------------------------------
; @routine List_GetPredecessorFor
; @param Y pointer to this object
; @param X pointer to first object in a list
; @return X pointer to object whose NEXT pointer points to the given object (or NULL)
; @clobbers r16, r17, X
List_GetPredecessorFor:
mov r16, xl
or r16, xh
breq List_GetPredecessorFor_ret
ld r16, X+
ld r17, X+
cp r16, yl
brne List_GetPredecessorFor_next
cp r17, yh
breq List_GetPredecessorFor_haveIt
List_GetPredecessorFor_next:
mov xl, r16
mov xh, r17
rjmp List_GetPredecessorFor
List_GetPredecessorFor_haveIt:
sbiw xh:xl, 2
List_GetPredecessorFor_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine List_AddObject
; @param X pointer to first object in a list
; @param Y pointer to object to add
; @clobbers r16, r17, x
List_AddObject:
push yl
push yh
rcall List_GetLastObject ; (r16, r17, X, Y)
pop yh
pop yl
mov r16, xl
or r16, xh
clc
breq List_AddObject_ret
st X+, yl ; LIST_OFFS_NEXT_LO
st X+, yh ; LIST_OFFS_NEXT_HI
sec
List_AddObject_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine List_UnlinkObject
; @param X pointer to first object in a list
; @param Y pointer to object to remove
; @clobbers r16, r17, x
List_UnlinkObject:
push yl
push yh
rcall List_GetPredecessorFor ; (r16, r17, X)
pop yh
pop yl
mov r16, xl
or r16, xh
breq List_UnlinkObject_ret
ldd r16, Y+LIST_OFFS_NEXT_LO ; get this->NEXT
ldd r17, Y+LIST_OFFS_NEXT_HI
st X+, r16 ; store as NEXT in predecessor
st X, r17
clr r16 ; set this->NEXT to NULL
std Y+LIST_OFFS_NEXT_LO, r16
std Y+LIST_OFFS_NEXT_HI, r16
List_UnlinkObject_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine List_UnlinkAllObjects
; @param Y pointer to first object in a list
; @clobbers r16, r17, r18, Y
List_UnlinkAllObjects:
clr r18
List_UnlinkAllObjects_loop:
ldd r16, Y+LIST_OFFS_NEXT_LO
ldd r17, Y+LIST_OFFS_NEXT_HI
std Y+LIST_OFFS_NEXT_LO, r18
std Y+LIST_OFFS_NEXT_HI, r18
mov yl, r16
mov yh, r17
or r16, r17
brne List_UnlinkAllObjects_loop
ret
; @end
; ---------------------------------------------------------------------------
; @routine List_ForEveryObject
;
; Calls the given function for every object until it
; returns with a set carry flag or until the full list
; is handled.
; All registers that can be used by the given function, however
; R16, R18, R19 and Y are modified between function calls.
;
; @param Y pointer to first object in a list
; @param Z routine to call for every object
; @clobbers r16, r17, r18, r19, X, Y (r24, r25)
List_ForEveryObject:
List_ForEveryObject_loop:
ldd r18, Y+LIST_OFFS_NEXT_LO ; next
ldd r19, Y+LIST_OFFS_NEXT_HI ; next
push r18 ; next
push r19 ; next
rcall List_ForEveryObject_callZ
pop r19 ; next
pop r18 ; next
brcs List_ForEveryObject_ret
mov yl, r18
mov yh, r19
or r18, r19
brne List_ForEveryObject_loop
List_ForEveryObject_ret:
ret
List_ForEveryObject_callZ:
ijmp
; @end
#endif ; AQH_AVR_COMMON_LIST_H