; *************************************************************************** ; 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_GetNextObject @global ; @param Y pointer to object ; @return X pointer to parent 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_GetLastObject_haveIt List_GetPredecessorFor_next: mov xl, r16 mov xh, r17 rjmp List_GetPredecessorFor List_GetPredecessorFor_haveIt: sbiw xh:xl, 1 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 st X+, yl ; WID_OFFS_WNEXT_LO st X+, yh ; WID_OFFS_WNEXT_HI 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 #endif ; AQH_AVR_COMMON_LIST_H