; *************************************************************************** ; 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_MAGIC_LO = 0 .equ OBJECT_OFFS_MAGIC_HI = 1 .equ OBJECT_OFFS_NEXT_LO = 2 ; byte address (for LPM!) .equ OBJECT_OFFS_NEXT_HI = 3 .equ OBJECT_OFFS_PARENT_LO = 4 ; byte address (for LPM!) .equ OBJECT_OFFS_PARENT_HI = 5 .equ OBJECT_OFFS_CHILD_LO = 6 ; byte address (for LPM!) .equ OBJECT_OFFS_CHILD_HI = 7 .equ OBJECT_OFFS_TARGET_LO = 8 ; byte address (for LPM!) .equ OBJECT_OFFS_TARGET_HI = 9 .equ OBJECT_OFFS_SELECTOR = 10 .equ OBJECT_OFFS_UNUSED = 11 .equ OBJECT_OFFS_SIGNALMAP_LO = 12 ; byte address (for LPM!) .equ OBJECT_OFFS_SIGNALMAP_HI = 13 .equ OBJECT_SIZE = 14 ; 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_CREATE = 1 .equ OBJECT_SIGNAL_DESTROY = 2 .equ OBJECT_SIGNAL_TIMER = 3 .equ OBJECT_SIGNAL_RECVMSG = 4 ; X=msg .equ OBJECT_SIGNAL_NEXTFREE = 5 ; *************************************************************************** ; code .cseg ; --------------------------------------------------------------------------- ; @routine OBJ_IsObject @global ; ; @param Z byte address of object (for LPM!) ; @return CFLAG set if is widget, cleared otherwise ; @clobbers none OBJ_IsObject: push r22 push r23 mov r22, zl or r22, zh clc breq OBJ_IsObject_ret lpm r22, Z+ lpm r23, Z sbiw zh:zl, 1 cpi r22, 0x55 clc brne OBJ_IsObject_ret cpi r23, 0xaa clc brne OBJ_IsObject_ret sec OBJ_IsObject_ret: pop r23 pop r22 ret ; @end ; --------------------------------------------------------------------------- ; @routine OBJ_GetParent @global ; ; @param Z byte address of object (for LPM!) ; @return CFLAG set, if found, cleared otherwise ; @return r19:r18 resulting object (byte address for LPM!), NULL otherwise ; @clobbers none OBJ_GetParent: rcall OBJ_IsObject brcc OBJ_GetParent_ret adiw zh:zl, OBJECT_OFFS_PARENT_LO lpm r18, Z+ lpm r19, Z sbiw zh:zl, OBJECT_OFFS_PARENT_LO+1 tst r18 brne OBJ_GetParent_secRet tst r19 clc breq OBJ_GetParent_ret OBJ_GetParent_secRet: sec OBJ_GetParent_ret: ret ; @end ; --------------------------------------------------------------------------- ; @routine OBJ_GetFirstChild @global ; ; @param Z byte address of object (for LPM!) ; @return CFLAG set, if found, cleared otherwise ; @return r19:r18 resulting object (byte address for LPM!), NULL otherwise ; @clobbers none OBJ_GetFirstChild: rcall OBJ_IsObject brcc OBJ_GetFirstChild_ret adiw zh:zl, OBJECT_OFFS_CHILD_LO lpm r18, Z+ lpm r19, Z sbiw zh:zl, OBJECT_OFFS_CHILD_LO+1 tst r18 brne OBJ_GetFirstChild_secRet tst r19 clc breq OBJ_GetFirstChild_ret OBJ_GetFirstChild_secRet: sec OBJ_GetFirstChild_ret: ret ; @end ; --------------------------------------------------------------------------- ; @routine OBJ_GetNext @global ; ; @param Z byte address of object (for LPM!) ; @return CFLAG set, if found, cleared otherwise ; @return r19:r18 resulting object (byte address for LPM!), NULL otherwise ; @clobbers none OBJ_GetNext: rcall OBJ_IsObject brcc OBJ_GetNext_ret adiw zh:zl, OBJECT_OFFS_NEXT_LO lpm r18, Z+ lpm r19, Z sbiw zh:zl, OBJECT_OFFS_NEXT_LO+1 tst r18 brne OBJ_GetNext_secRet tst r19 clc breq OBJ_GetNext_ret OBJ_GetNext_secRet: sec OBJ_GetNext_ret: ret ; @end ; --------------------------------------------------------------------------- ; @routine OBJ_GetBelow @global ; ; @param Z byte address of object (for LPM!) ; @return CFLAG set, if found, cleared otherwise ; @return r19:r18 resulting object (byte address for LPM!), NULL otherwise ; @clobbers r16 OBJ_GetBelow: push zl push zh rcall OBJ_IsObject brcc OBJ_GetBelow_ret OBJ_GetBelow_get: rcall OBJ_GetFirstChild brcs OBJ_GetBelow_ret ; jmp if found rcall OBJ_GetNext brcs OBJ_GetBelow_ret ; jmp if found OBJ_GetBelow_loop: rcall OBJ_GetParent brcc OBJ_GetBelow_ret ; jmp if no parent ; use parent mov zl, r18 mov zh, r19 ; don't check for first child here, we came from there! rcall OBJ_GetNext brcs OBJ_GetBelow_ret rjmp OBJ_GetBelow_loop OBJ_GetBelow_ret: pop zh pop zl ret ; @end ; --------------------------------------------------------------------------- ; @routine OBJ_GetBelowParent @global ; ; @param Z byte address of object (for LPM!) ; @param r21:20 stay below this object ; @return CFLAG set, if found, cleared otherwise ; @return r19:r18 resulting object (byte address for LPM!), NULL otherwise ; @clobbers r16 OBJ_GetBelowParent: push zl push zh rcall OBJ_IsObject brcc OBJ_GetBelowParent_ret OBJ_GetBelowParent_get: rcall OBJ_GetFirstChild brcs OBJ_GetBelowParent_ret ; jmp if found rcall OBJ_GetNext brcs OBJ_GetBelowParent_ret ; jmp if found OBJ_GetBelowParent_loop: rcall OBJ_GetParent brcc OBJ_GetBelowParent_ret ; jmp if no parent mov zl, r18 mov zh, r19 rcall objZIsNotR21R20 brcc OBJ_GetBelowParent_ret ; Z is avoidable parent ; don't check for first child here, we came from there! rcall OBJ_GetNext brcs OBJ_GetBelowParent_ret rjmp OBJ_GetBelowParent_loop OBJ_GetBelowParent_ret: pop zh pop zl ret ; @end objZIsNotR21R20: cp zl, r20 brne objZIsNotR21R20_secRet cp zh, r21 brne objZIsNotR21R20_secRet clc rjmp objZIsNotR21R20_ret objZIsNotR21R20_secRet: sec objZIsNotR21R20_ret: ret ; --------------------------------------------------------------------------- ; @routine OBJ_GetBelowSkipChildren @global ; ; Same as @ref OBJ_GetBelow but skips children of given object. ; ; @param Z byte address of object (for LPM!) ; @return CFLAG set, if found, cleared otherwise ; @return r19:r18 resulting object (byte address for LPM!), NULL otherwise ; @clobbers r16 OBJ_GetBelowSkipChildren: push zl push zh tst zh brne OBJ_GetBelowSkipChildren_get tst zl clc breq OBJ_GetBelowSkipChildren_ret OBJ_GetBelowSkipChildren_get: rcall OBJ_GetNext brcs OBJ_GetBelowSkipChildren_ret ; jmp if found OBJ_GetBelowSkipChildren_loop: rcall OBJ_GetParent brcc OBJ_GetBelowSkipChildren_ret ; jmp if no parent ; use parent mov zl, r18 mov zh, r19 ; don't check for first child here, we came from there! rcall OBJ_GetNext brcs OBJ_GetBelowSkipChildren_ret rjmp OBJ_GetBelowSkipChildren_loop OBJ_GetBelowSkipChildren_ret: pop zh pop zl 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, !X, !Y, !Z OBJ_EmitSignal: rcall OBJ_IsObject ; (none) brcc OBJ_EmitSignal_ret push zl push zh adiw zh:zl, OBJECT_OFFS_SELECTOR lpm r17, Z sbiw zh:zl, OBJECT_OFFS_SELECTOR adiw zh:zl, OBJECT_OFFS_TARGET_LO lpm r23, Z+ lpm zh, Z mov zl, r23 rcall OBJ_HandleSignal ; (any, !X, !Y, !Z) pop zh pop zl OBJ_EmitSignal_ret: ret ; @end ; --------------------------------------------------------------------------- ; @routine OBJ_TreeHandleSignal @global ; ; @param Z 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, !R16, !R17, !X, !Z OBJ_TreeHandleSignal: rcall OBJ_IsObject ; (none) brcc OBJ_TreeHandleSignal_ret push zl push zh mov r18, zl or r18, zh clc breq OBJ_TreeHandleSignal_done rcall OBJ_HandleSignalSaveInRegs brcs OBJ_TreeHandleSignal_done rcall OBJ_GetFirstChild OBJ_TreeHandleSignal_loop: brcc OBJ_TreeHandleSignal_done mov zl, r18 mov zh, r19 rcall OBJ_TreeHandleSignal ; recursion brcs OBJ_TreeHandleSignal_done rcall OBJ_GetNext rjmp OBJ_TreeHandleSignal_loop OBJ_TreeHandleSignal_done: pop zh pop zl OBJ_TreeHandleSignal_ret: ret ; @end ; --------------------------------------------------------------------------- ; @routine OBJ_TreeAllHandleSignal @global ; ; @param Z byte address of object (for LPM!) ; @param R16 signal number ; @param R17 selector ; @param xl param1 ; @param xh param2 ; @clobbers any, !R16, !R17, !X, !Z OBJ_TreeAllHandleSignal: rcall OBJ_IsObject ; (none) brcc OBJ_TreeAllHandleSignal_ret push zl push zh OBJ_TreeAllHandleSignal_loop: rcall OBJ_HandleSignalSaveInRegs ; (any, !R16, !R17, !X, !Z) push r16 rcall OBJ_GetBelow ; (R16) pop r16 brcc OBJ_TreeAllHandleSignal_done mov zl, r18 mov zh, r19 rjmp OBJ_TreeAllHandleSignal_loop OBJ_TreeAllHandleSignal_done: pop zh pop zl OBJ_TreeAllHandleSignal_ret: ret ; @end ; --------------------------------------------------------------------------- ; @routine OBJ_HandleSignalSaveInRegs ; ; @param Z 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, !R16, !R17, !X, !Z OBJ_HandleSignalSaveInRegs: push r16 push r17 rcall OBJ_HandleSignal ; (any, !X, !Y, !Z) pop r17 pop r16 ret ; @end ; --------------------------------------------------------------------------- ; @routine OBJ_HandleSignal ; ; @param Z 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, !X, !Y, !Z OBJ_HandleSignal: rcall OBJ_IsObject ; (none) brcc OBJ_HandleSignal_ret push zl push zh rcall objGetHandlerFromSignalMap ; CF set: R19:R18=handler (r22, r23) brcc OBJ_HandleSignal_done push xl push xh push yl push yh rcall OBJ_HandleSignal_jmpR19R18 pop yh pop yl pop xh pop xl OBJ_HandleSignal_done: pop zh pop zl OBJ_HandleSignal_ret: ret OBJ_HandleSignal_jmpR19R18: ; jmp to r19:r18 via stack push r18 push r19 ret ; @end ; --------------------------------------------------------------------------- ; @routine objGetHandlerFromSignalMap ; ; @param Z byte address of object (for LPM!) ; @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 objGetHandlerFromSignalMap: push zl push zh ; z:=signal map adiw zh:zl, OBJECT_OFFS_SIGNALMAP_LO lpm r23, Z+ lpm zh, Z mov zl, r23 or r23, zh clc breq objGetHandlerFromSignalMap_done ; no 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: pop zh pop zl ret ; @end #endif