; *************************************************************************** ; 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. ; Registers that can be used by the given function are all ; except R16, R18 and R19 (those are used by this routine). ; ; @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 clr r16 std Y+LIST_OFFS_NEXT_LO, r16 std Y+LIST_OFFS_NEXT_HI, r16 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