; *************************************************************************** ; copyright : (C) 2026 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_GUI2_OBJECT_ASM #define AQH_AVR_GUI2_OBJECT_ASM ; *************************************************************************** ; defines ; Object in flash .equ OBJECT_OFFS_NEXT_LO = 0 .equ OBJECT_OFFS_NEXT_HI = 1 .equ OBJECT_OFFS_PARENT_LO = 2 .equ OBJECT_OFFS_PARENT_HI = 3 .equ OBJECT_OFFS_CHILD_LO = 4 .equ OBJECT_OFFS_CHILD_HI = 5 .equ OBJECT_OFFS_FLAGS = 6 .equ OBJECT_OFFS_SELECTOR = 7 .equ OBJECT_OFFS_TARGET_LO = 8 .equ OBJECT_OFFS_TARGET_HI = 9 .equ OBJECT_OFFS_OPTS_LO = 10 .equ OBJECT_OFFS_OPTS_HI = 11 .equ OBJECT_OFFS_SIGNALMAP_LO = 12 ; byte address (for LPM!) .equ OBJECT_OFFS_SIGNALMAP_HI = 13 .equ OBJECT_SIZE = 14 ; object opts_lo .equ OBJECT_OPTSLO_TIMER_BIT = 7 .equ OBJECT_OPTSLO_MSGRECV_BIT = 6 ; SignalMap entries .equ OBJECT_SIGNALMAP_OFFS_SELECTOR = 0 .equ OBJECT_SIGNALMAP_OFFS_SIGNAL = 1 ; end if 0 .equ OBJECT_SIGNALMAP_OFFS_HANDLER_LO = 2 .equ OBJECT_SIGNALMAP_OFFS_HANDLER_HI = 3 ; signals .equ OBJECT_SIGNAL_NONE = 0 .equ OBJECT_SIGNAL_DESTROY = 1 .equ OBJECT_SIGNAL_TIMER = 2 .equ OBJECT_SIGNAL_RECVMSG = 3 ; X=msg .equ OBJECT_SIGNAL_NEXTFREE = 4 ; *************************************************************************** ; code .cseg ; --------------------------------------------------------------------------- ; @routine Object_Alloc @global ; ; @return CFLAG set if object created, cleared otherwise ; @return Y address of created object in SDRAM (if CFLAG set) ; @param r25:r24 size of object to allocate ; @clobbers !r16, !r17 Object_Alloc: push r16 push r17 bigcall Heap_Alloc ; X=mem allocated (r16, r17, r18, r19, r24, r25, X) pop r17 pop r16 brcc Object_Alloc_ret mov yl, xl mov yh, xh sec Object_Alloc_ret: ret ; @end ; --------------------------------------------------------------------------- ; @routine OBJ_Init @global ; ; @param Y address of object in SDRAM ; @param r16 value for OBJECT_OFFS_OPTS_LO ; @param r17 value for OBJECT_OFFS_OPTS_HI ; @clobbers r16, r17, X OBJ_Init: push r16 push r17 mov xl, yl mov xh, yh clr r16 ldi r17, OBJECT_SIZE bigcall Utils_FillSram ; (r17, X) pop r17 pop r16 ; set opts std Y+OBJECT_OFFS_OPTS_LO, r16 std Y+OBJECT_OFFS_OPTS_HI, r17 ; set default signal map ldi r16, LOW(Object_DefaultSignalmap*2) std Y+OBJECT_OFFS_SIGNALMAP_LO, r16 ldi r16, HIGH(Object_DefaultSignalmap*2) std Y+OBJECT_OFFS_SIGNALMAP_HI, r16 ret ; @end ; --------------------------------------------------------------------------- ; @routine OBJ_Fini @global ; ; @param Y address of object in SDRAM ; @clobbers none OBJ_Fini: ret ; @end ; --------------------------------------------------------------------------- ; @routine OBJ_Free @global ; ; Sends a OBJECT_SIGNAL_DESTROY signal to all children and to the given ; object which frees all objects from the Heap. ; CAVEAT: Y is invalid after return! ; ; @param Y address of object in SDRAM ; @clobbers none OBJ_Free: tst yl brne OBJ_Free_notNull tst yh brne OBJ_Free_notNull rjmp OBJ_Free_ret OBJ_Free_notNull: ldi r16, OBJECT_SIGNAL_DESTROY clr r17 rcall OBJ_TreeHandleSignalChildenFirst ; (any, !R16, !R17, !X, !Y) OBJ_Free_ret: ret ; @end ; --------------------------------------------------------------------------- ; @routine OBJ_OnDestroy @global ; ; Releases given object from heap. ; CAVEAT: Y is invalid after return! ; ; @param Y address of object in SDRAM ; @return CFLAG set if signal handled ; @clobbers r16, r17, r18, r19, r20, r21, r24, r25, X OBJ_OnDestroy: rcall OBJ_Unlink ; (r16, r17, r18, r19, r20, r21, X) mov xl, yl mov xh, yh bigcall Heap_Free ; (r16, r17, r24, r25, X) sec ret ; @end ; --------------------------------------------------------------------------- ; @routine OBJ_GetNext @global ; ; @param Y address of object ; @return CFLAG set, if found, cleared otherwise ; @return r19:r18 resulting object ; @clobbers none OBJ_GetNext: tst yl brne OBJ_GetNext_notNull tst yh brne OBJ_GetNext_notNull rjmp OBJ_GetNext_clcRet OBJ_GetNext_notNull: ldd r18, Y+OBJECT_OFFS_NEXT_LO ldd r19, Y+OBJECT_OFFS_NEXT_HI tst r18 brne OBJ_GetNext_secRet tst r19 brne OBJ_GetNext_secRet OBJ_GetNext_clcRet: clc rjmp OBJ_GetNext_ret OBJ_GetNext_secRet: sec OBJ_GetNext_ret: ret ; @end ; --------------------------------------------------------------------------- ; @routine OBJ_GetParent @global ; ; @param Y address of object ; @return CFLAG set, if found, cleared otherwise ; @return r19:r18 resulting object ; @clobbers none OBJ_GetParent: tst yl brne OBJ_GetParent_notNull tst yh brne OBJ_GetParent_notNull rjmp OBJ_GetParent_clcRet OBJ_GetParent_notNull: ldd r18, Y+OBJECT_OFFS_PARENT_LO ldd r19, Y+OBJECT_OFFS_PARENT_HI tst r18 brne OBJ_GetParent_secRet tst r19 brne OBJ_GetParent_secRet OBJ_GetParent_clcRet: clc rjmp OBJ_GetParent_ret OBJ_GetParent_secRet: sec OBJ_GetParent_ret: ret ; @end ; --------------------------------------------------------------------------- ; @routine OBJ_GetFirstChild @global ; ; @param Y address of object ; @return CFLAG set, if found, cleared otherwise ; @return r19:r18 resulting object ; @clobbers none OBJ_GetFirstChild: tst yl brne OBJ_GetFirstChild_notNull tst yh brne OBJ_GetFirstChild_notNull rjmp OBJ_GetFirstChild_clcRet OBJ_GetFirstChild_notNull: ldd r18, Y+OBJECT_OFFS_PARENT_LO ldd r19, Y+OBJECT_OFFS_PARENT_HI tst r18 brne OBJ_GetFirstChild_secRet tst r19 brne OBJ_GetFirstChild_secRet OBJ_GetFirstChild_clcRet: clc rjmp OBJ_GetFirstChild_ret OBJ_GetFirstChild_secRet: sec OBJ_GetFirstChild_ret: ret ; @end ; --------------------------------------------------------------------------- ; @routine OBJ_GetLastChild @global ; ; @param Y address of object ; @return CFLAG set, if found, cleared otherwise ; @return r19:r18 resulting object ; @clobbers none OBJ_GetLastChild: push yl push yh rcall OBJ_GetFirstChild ; R19:R18=obj (none) brcc OBJ_GetLastChild_ret OBJ_GetLastChild_loop: mov yl, r18 mov yh, r19 rcall OBJ_GetNext ; R19:R18=obj (none) brcs OBJ_GetLastChild_loop mov r18, yl mov r19, yh sec OBJ_GetLastChild_ret: pop yh pop yl ret ; @end ; --------------------------------------------------------------------------- ; @routine OBJ_GetChildAt @global ; ; @param Y address of object ; @param R16 idx of child to get (starting at 0) ; @return CFLAG set, if found, cleared otherwise ; @return r19:r18 resulting object ; @clobbers none OBJ_GetChildAt: push yl push yh rcall OBJ_GetFirstChild ; R19:R18=obj (none) brcc OBJ_GetChildAt_ret OBJ_GetChildAt_loop: tst r16 breq OBJ_GetChildAt_secRet mov yl, r18 mov yh, r19 rcall OBJ_GetNext ; R19:R18=obj (none) brcs OBJ_GetChildAt_loop rjmp OBJ_GetChildAt_ret ; idx too high, not found OBJ_GetChildAt_secRet: sec OBJ_GetChildAt_ret: pop yh pop yl ret ; @end ; --------------------------------------------------------------------------- ; @routine OBJ_AddChild @global ; ; @param Y object to add to ; @param X object to add ; @clobbers r18, r19 OBJ_AddChild: rcall OBJ_GetLastChild ; r19:r18=last child (r18, r19) brcc OBJ_AddChild_setAsFirstChild ; append to last child push yl push yh mov yl, r18 mov yh, r19 std Y+OBJECT_OFFS_NEXT_LO, xl std Y+OBJECT_OFFS_NEXT_HI, xh pop yh pop yl rjmp OBJ_AddChild_setParent OBJ_AddChild_setAsFirstChild: std Y+OBJECT_OFFS_CHILD_LO, xl std Y+OBJECT_OFFS_CHILD_HI, xh OBJ_AddChild_setParent: adiw xh:xl, OBJECT_OFFS_PARENT_LO st X+, yl st X, yh sbiw xh:xl, (OBJECT_OFFS_PARENT_LO+1) ret ; @end ; --------------------------------------------------------------------------- ; @routine OBJ_Unlink @global ; ; @param Y object to unlink ; @clobbers r16, r17, r18, r19, r20, r21, X OBJ_Unlink: mov xl, yl mov xh, yh adiw xh:xl, OBJECT_OFFS_NEXT_LO ; r21:r20=next ld r20, X+ ld r21, X sbiw xh:xl, (OBJECT_OFFS_NEXT_LO+1) push yl push yh rcall objGetPredecessor ; Y=predecessor (r16, r17, Y) brcc OBJ_Unlink_l1 ; unlink from predecessor std Y+OBJECT_OFFS_NEXT_LO, r20 ; copy NEXT to predecessor std Y+OBJECT_OFFS_NEXT_HI, r21 rjmp OBJ_Unlink_l2 OBJ_Unlink_l1: ; no predecessor, unlink from parent pop yh pop yl rcall OBJ_GetParent brcc OBJ_Unlink_clearTreePtrs push yl push yh mov yl, r18 mov yh, r19 std Y+OBJECT_OFFS_CHILD_LO, r20 std Y+OBJECT_OFFS_CHILD_HI, r21 OBJ_Unlink_l2: pop yh pop yl OBJ_Unlink_clearTreePtrs: clr r16 std Y+OBJECT_OFFS_NEXT_LO, r16 std Y+OBJECT_OFFS_NEXT_HI, r16 std Y+OBJECT_OFFS_PARENT_LO, r16 std Y+OBJECT_OFFS_PARENT_HI, r16 OBJ_Unlink_ret: ret ; @end ; --------------------------------------------------------------------------- ; @routine OBJ_GetRoot @global ; ; @param Y address of object ; @return Y address pointer to root object ; @clobbers r18, r19 OBJ_GetRoot: OBJ_GetRoot_loop: rcall OBJ_GetParent ; (none) brcc OBJ_GetRoot_found ; no parent, return current Y mov yl, r18 mov yh, r19 rjmp OBJ_GetRoot_loop OBJ_GetRoot_found: sec OBJ_GetRoot_end: ret ; @end ; --------------------------------------------------------------------------- ; @routine OBJ_EmitSignal @global ; ; @param Z byte address of object (for LPM!) ; @param R16 signal number ; @param xl param1 ; @param xh param2 ; @clobbers any, !Y OBJ_EmitSignal: push yl push yh ldd r17, Y+OBJECT_OFFS_SELECTOR ldd r23, Y+OBJECT_OFFS_TARGET_LO ldd yh, Y+OBJECT_OFFS_TARGET_HI mov yl, r23 rcall OBJ_HandleSignal ; (any, !Y) pop yh pop yl ret ; @end ; --------------------------------------------------------------------------- ; @routine OBJ_HandleSignal @global ; ; @param Y byte address of object (for LPM!) ; @param R16 signal number ; @param R17 selector ; @param xl param1 ; @param xh param2 ; @return CFLAG set if handled, cleared otherwise ; @clobbers any, !Y OBJ_HandleSignal: push yl push yh rcall objGetHandlerFromSignalMap ; r19:r18=handler (r22, r23, Z) brcc OBJ_HandleSignal_done rcall OBJ_HandleSignal_jmpR19R18 OBJ_HandleSignal_done: pop yh pop yl ret OBJ_HandleSignal_jmpR19R18: ; jmp to r19:r18 via stack push r18 push r19 ret ; @end ; --------------------------------------------------------------------------- ; @routine OBJ_TreeHandleSignal @global @recursive ; ; @param Y address of object ; @param R16 signal number ; @param R17 selector ; @param xl param1 ; @param xh param2 ; @return CFLAG set if handled, cleared otherwise ; @clobbers any, !R16, !R17, !X, !Y OBJ_TreeHandleSignal: push yl push yh ; call signal handler push r16 push r17 push xl push xh rcall OBJ_HandleSignal ; (any, !Y) pop xh pop xl pop r17 pop r16 ; handle children rcall OBJ_GetFirstChild ; r19:r18=object (none) OBJ_TreeHandleSignal_loop: brcc OBJ_TreeHandleSignal_done mov yl, r18 mov yh, r19 rcall OBJ_TreeHandleSignal ; recursion! rcall OBJ_GetNext ; r19:r18=object (none) rjmp OBJ_TreeHandleSignal_loop OBJ_TreeHandleSignal_done: pop yh pop yl ret ; @end ; --------------------------------------------------------------------------- ; @routine OBJ_TreeHandleSignalChildenFirst @global @recursive ; ; Sends a given signal to a tree of objects, handling children first. ; After sending a signal to a child object that object is no longer accessed ; from within this routine, so it can be used to send a DESTROY signal which ; frees the object from the memory heap. ; ; @param Y address of object ; @param R16 signal number ; @param R17 selector ; @param xl param1 ; @param xh param2 ; @return CFLAG set if handled, cleared otherwise ; @clobbers any, !R16, !R17, !X, !Y OBJ_TreeHandleSignalChildenFirst: push yl push yh ; handle children first rcall OBJ_GetFirstChild ; r19:r18=object (none) brcc OBJ_TreeHandleSignalChildenFirst_done OBJ_TreeHandleSignalChildenFirst_loop: mov yl, r18 mov yh, r19 rcall OBJ_GetNext ; r19:r18=object (none) ldi r20, 0 sbci r20, 0 push r18 push r19 push r20 rcall OBJ_TreeHandleSignalChildenFirst ; recursion! pop r20 pop r19 pop r18 tst r20 ; result of OBJ_GetNext (0=no next) brne OBJ_TreeHandleSignalChildenFirst_loop OBJ_TreeHandleSignalChildenFirst_done: pop yh pop yl ; call signal handler on self push r16 push r17 push xl push xh rcall OBJ_HandleSignal ; (any, !Y) pop xh pop xl pop r17 pop r16 ret ; @end ; --------------------------------------------------------------------------- ; @routine OBJ_AddFlagsDown @global ; ; @param Y address of object ; @param R16 flags to add ; @clobbers r17, r18, r19 OBJ_AddFlagsDown: push yl push yh ldd r17, Y+OBJECT_OFFS_FLAGS or r17, r16 std Y+OBJECT_OFFS_FLAGS, r17 ; handle children rcall OBJ_GetFirstChild ; r19:r18=object (none) OBJ_AddFlagsDown_loop: brcc OBJ_AddFlagsDown_done mov yl, r18 mov yh, r19 rcall OBJ_AddFlagsDown ; recursion! rcall OBJ_GetNext ; r19:r18=object (none) rjmp OBJ_AddFlagsDown_loop OBJ_AddFlagsDown_done: pop yh pop yl ret ; @end ; --------------------------------------------------------------------------- ; @routine OBJ_SubFlagsDown @global ; ; @param Y address of object ; @param R16 flags to subtract ; @clobbers r17, r18, r19 OBJ_SubFlagsDown: push yl push yh ldd r17, Y+OBJECT_OFFS_FLAGS com r16 and r17, r16 com r16 std Y+OBJECT_OFFS_FLAGS, r17 ; handle children rcall OBJ_GetFirstChild ; r19:r18=object (none) OBJ_SubFlagsDown_loop: brcc OBJ_SubFlagsDown_done mov yl, r18 mov yh, r19 rcall OBJ_SubFlagsDown ; recursion! rcall OBJ_GetNext ; r19:r18=object (none) rjmp OBJ_SubFlagsDown_loop OBJ_SubFlagsDown_done: pop yh pop yl ret ; @end ; --------------------------------------------------------------------------- ; @routine objGetHandlerFromSignalMap ; ; @param Y address of object ; @param R16 signal number ; @param R17 selector ; @param xl param1 ; @param xh param2 ; @return CFLAG set if found, cleared otherwise ; @return R19:R18 handler found ; @clobbers r22, r23, Z objGetHandlerFromSignalMap: ldd zl, Y+OBJECT_OFFS_SIGNALMAP_LO ldd zh, Y+OBJECT_OFFS_SIGNALMAP_HI mov r23, zl or r23, zh clc breq objGetHandlerFromSignalMap_done ; Z=signal map objGetHandlerFromSignalMap_loop: lpm r22, Z+ ; selector lpm r23, Z+ ; signal (0=end of table) lpm r18, Z+ ; handler LOW lpm r19, Z+ ; handler HIGH tst r23 ; end of table? clc breq objGetHandlerFromSignalMap_done ; yes, jmp cp r16, r23 ; signal match? brne objGetHandlerFromSignalMap_next ; no, next tst r22 breq objGetHandlerFromSignalMap_checkHandler ; accept any selector if it is 0 in table cp r17, r22 ; selector match? brne objGetHandlerFromSignalMap_next ; no, next objGetHandlerFromSignalMap_checkHandler: mov r23, r18 ; handler==NULL? or r23, r19 clc breq objGetHandlerFromSignalMap_done ; yes, done sec ; found handler, return in r19:r18 rjmp objGetHandlerFromSignalMap_done objGetHandlerFromSignalMap_next: rjmp objGetHandlerFromSignalMap_loop objGetHandlerFromSignalMap_done: ret ; @end ; --------------------------------------------------------------------------- ; @routine objGetPredecessor ; ; @param Y address of object whose predecessor is to be found ; @return CFLAG set if predecessor found, cleared otherwise ; @return Y pointer to predecessor (if CFLAG set) ; @clobbers r16, r17, Y objGetPredecessor: rcall OBJ_GetParent brcc objGetPredecessor_ret mov r16, yl mov r17, yh rcall OBJ_GetFirstChild ; R19:R18=obj brcc objGetPredecessor_ret mov yl, r18 mov yh, r19 objGetPredecessor_loop: rcall OBJ_GetNext brcc objGetPredecessor_ret cp r18, r16 brne objGetPredecessor_next cp r19, r17 brne objGetPredecessor_next sec rjmp objGetPredecessor_ret objGetPredecessor_next: mov yl, r18 mov yh, r19 rjmp objGetPredecessor_loop objGetPredecessor_ret: ret ; @end ; *************************************************************************** ; data in FLASH Object_DefaultSignalmap: .db 0, OBJECT_SIGNAL_DESTROY, LOW(OBJ_OnDestroy), HIGH(OBJ_OnDestroy) .db 0, 0, 0, 0 ; end of table #endif