996 lines
24 KiB
NASM
996 lines
24 KiB
NASM
; ***************************************************************************
|
|
; 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
|
|
|
|
|
|
; ***************************************************************************
|
|
; @module OBJECT
|
|
;
|
|
; Central to this module is the signal handler (@ref OBJ_HandleSignal).
|
|
;
|
|
; Inputs:
|
|
; - Y: Pointer to the object to handle a signal
|
|
; - R16: Signal number (e.g. @ref OBJECT_SIGNAL_DESTROY)
|
|
; - R17: Selector
|
|
; Normally this comes from the object var OBJECT_OFFS_SELECTOR but it can
|
|
; have different meanings for different signals.
|
|
; For signals WIDGET_SIGNAL_SETVALUE and WIDGET_SIGNAL_GETVALUE from the
|
|
; @ref WIDGET module this contains the id of the value to reference, e.g.
|
|
; to set the X position of a widget R17 has the value WIDGET_VALUE_X.
|
|
; - X: Parameter for the signal (either as 16-bit value or as two 8-bit values
|
|
; in xl and xh). E.g. for signal WIDGET_SIGNAL_SETVALUE this would contain
|
|
; the value to assign
|
|
;
|
|
; Outputs:
|
|
; - CFLAG: Set if signal handled.
|
|
; - R19:R18: Response from the signal handler. Most signals do not have return values, but
|
|
; especially the signal WIDGET_SIGNAL_GETVALUE is expected to return a result.
|
|
;
|
|
|
|
|
|
|
|
; ***************************************************************************
|
|
; 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_SIGNALMAP_LO = 10 ; byte address (for LPM!)
|
|
.equ OBJECT_OFFS_SIGNALMAP_HI = 11
|
|
.equ OBJECT_OFFS_OPTS = 12
|
|
.equ OBJECT_SIZE = 13
|
|
|
|
; object opts_lo
|
|
.equ OBJECT_OPTS_TIMER_BIT = 7
|
|
.equ OBJECT_OPTS_MSGRECV_BIT = 6
|
|
|
|
; SignalMap entries
|
|
.equ OBJECT_SIGNALMAP_OFFS_HEADER = 0
|
|
.equ OBJECT_SIGNALMAP_OFFS_ENTRIES = 2
|
|
|
|
.equ OBJECT_SIGNALMAPENTRY_OFFS_SELECTOR = 0
|
|
.equ OBJECT_SIGNALMAPENTRY_OFFS_SIGNAL = 1 ; end if 0
|
|
.equ OBJECT_SIGNALMAPENTRY_OFFS_HANDLER_LO = 2
|
|
.equ OBJECT_SIGNALMAPENTRY_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, !X
|
|
|
|
Object_Alloc:
|
|
push xl
|
|
push xh
|
|
push r16
|
|
push r17
|
|
push r24
|
|
push r25
|
|
bigcall Heap_Alloc ; X=mem allocated (r16, r17, r18, r19, r24, r25, X)
|
|
pop r25
|
|
pop r24
|
|
pop r17
|
|
pop r16
|
|
brcc Object_Alloc_ret
|
|
mov yl, xl
|
|
mov yh, xh
|
|
clr r18
|
|
Object_Alloc_loop:
|
|
st X+, r18
|
|
sbiw r25:r24, 1
|
|
brne Object_Alloc_loop
|
|
sec
|
|
Object_Alloc_ret:
|
|
pop xh
|
|
pop xl
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine OBJ_Init @global
|
|
;
|
|
; @param Y address of object in SDRAM
|
|
; @param r16 value for OBJECT_OFFS_OPTS
|
|
; @clobbers r16, r17, X
|
|
|
|
OBJ_Init:
|
|
; set opts
|
|
std Y+OBJECT_OFFS_OPTS, r16
|
|
|
|
; 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_CHILD_LO
|
|
ldd r19, Y+OBJECT_OFFS_CHILD_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 r16
|
|
|
|
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
|
|
dec r16
|
|
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
|
|
; @param X object to add to
|
|
; @clobbers r18, r19
|
|
|
|
OBJ_AddChild:
|
|
mov r18, yl ; switch X/Y
|
|
mov yl, xl
|
|
mov xl, r18
|
|
mov r18, yh
|
|
mov yh, xh
|
|
mov xh, r18
|
|
rcall objAddObjXAsChildToY
|
|
mov r18, yl ; switch X/Y
|
|
mov yl, xl
|
|
mov xl, r18
|
|
mov r18, yh
|
|
mov yh, xh
|
|
mov xh, r18
|
|
ret
|
|
; @end
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine objAddObjXAsChildToY
|
|
;
|
|
; @param Y designated parent
|
|
; @param X object to add
|
|
; @clobbers r18, r19
|
|
|
|
objAddObjXAsChildToY:
|
|
rcall OBJ_GetLastChild ; r19:r18=last child (r18, r19)
|
|
brcc objAddObjXAsChildToY_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 objAddObjXAsChildToY_setParent
|
|
objAddObjXAsChildToY_setAsFirstChild:
|
|
std Y+OBJECT_OFFS_CHILD_LO, xl
|
|
std Y+OBJECT_OFFS_CHILD_HI, xh
|
|
objAddObjXAsChildToY_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_GetRootToY @global
|
|
;
|
|
; @param Y address of object
|
|
; @return Y address pointer to root object
|
|
; @clobbers r18, r19
|
|
|
|
OBJ_GetRootToY:
|
|
OBJ_GetRootToY_loop:
|
|
rcall OBJ_GetParent ; (none)
|
|
brcc OBJ_GetRootToY_found ; no parent, return current Y
|
|
mov yl, r18
|
|
mov yh, r19
|
|
rjmp OBJ_GetRootToY_loop
|
|
OBJ_GetRootToY_found:
|
|
sec
|
|
OBJ_GetRootToY_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 address of object
|
|
; @param R16 signal number
|
|
; @param R17 selector
|
|
; @param xl param1
|
|
; @param xh param2
|
|
; @return CFLAG set if handled, cleared otherwise
|
|
; @return r19:r18 return value from signal handler
|
|
; @clobbers any, !Y
|
|
|
|
OBJ_HandleSignal:
|
|
; check pointer
|
|
mov r18, yl
|
|
or r18, yh
|
|
clc
|
|
breq OBJ_HandleSignal_ret
|
|
|
|
; start with objects signal map
|
|
ldd zl, Y+OBJECT_OFFS_SIGNALMAP_LO
|
|
ldd zh, Y+OBJECT_OFFS_SIGNALMAP_HI
|
|
|
|
OBJ_HandleSignal_loop:
|
|
; test table validity
|
|
mov r18, zl
|
|
or r18, zh
|
|
clc
|
|
breq OBJ_HandleSignal_ret
|
|
; try this table
|
|
push zl
|
|
push zh
|
|
push r16
|
|
push r17
|
|
push xl
|
|
push xh
|
|
rcall objHandleSignalWithMap ; (any, !Y)
|
|
pop xh
|
|
pop xl
|
|
pop r17
|
|
pop r16
|
|
pop zh
|
|
pop zl
|
|
brcs OBJ_HandleSignal_ret
|
|
; get next table
|
|
lpm r18, Z+
|
|
lpm zh, Z
|
|
mov zl, r18
|
|
rjmp OBJ_HandleSignal_loop ; try next table
|
|
OBJ_HandleSignal_ret:
|
|
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)
|
|
brcc OBJ_TreeHandleSignal_done
|
|
OBJ_TreeHandleSignal_loop:
|
|
mov yl, r18
|
|
mov yh, r19
|
|
rcall OBJ_TreeHandleSignal ; recursion!
|
|
rcall OBJ_GetNext ; r19:r18=object (none)
|
|
brcs OBJ_TreeHandleSignal_loop
|
|
OBJ_TreeHandleSignal_done:
|
|
pop yh
|
|
pop yl
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine OBJ_TreeHandleSignalIfMatchingOpts @global @recursive
|
|
;
|
|
; @param Y address of object
|
|
; @param R16 signal number
|
|
; @param R17 selector
|
|
; @param xl param1
|
|
; @param xh param2
|
|
; @param r20 mask for OBJECT_OFFS_OPTS
|
|
; @param r21 value for OBJECT_OFFS_OPTS to match
|
|
; @clobbers any, !R16, !R17, !X, !Y
|
|
|
|
OBJ_TreeHandleSignalIfMatchingOpts:
|
|
push yl
|
|
push yh
|
|
; call signal handler
|
|
push r16
|
|
push r17
|
|
push xl
|
|
push xh
|
|
ldd r18, Y+OBJECT_OFFS_OPTS
|
|
eor r18, r21
|
|
and r18, r20
|
|
brne OBJ_TreeHandleSignalIfMatchingOpts_l1
|
|
push r20
|
|
push r21
|
|
rcall OBJ_HandleSignal ; (any, !Y)
|
|
pop r21
|
|
pop r20
|
|
OBJ_TreeHandleSignalIfMatchingOpts_l1:
|
|
pop xh
|
|
pop xl
|
|
pop r17
|
|
pop r16
|
|
; handle children
|
|
rcall OBJ_GetFirstChild ; r19:r18=object (none)
|
|
OBJ_TreeHandleSignalIfMatchingOpts_loop:
|
|
brcc OBJ_TreeHandleSignalIfMatchingOpts_done
|
|
mov yl, r18
|
|
mov yh, r19
|
|
rcall OBJ_TreeHandleSignalIfMatchingOpts ; recursion!
|
|
rcall OBJ_GetNext ; r19:r18=object (none)
|
|
rjmp OBJ_TreeHandleSignalIfMatchingOpts_loop
|
|
OBJ_TreeHandleSignalIfMatchingOpts_done:
|
|
pop yh
|
|
pop yl
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine OBJ_TreeHandleSignalIfFlagsSet @global @recursive
|
|
;
|
|
; @param Y address of object
|
|
; @param R16 signal number
|
|
; @param R17 selector
|
|
; @param xl param1
|
|
; @param xh param2
|
|
; @param r20 flags to match
|
|
; @clobbers any, !R16, !R17, !X, !Y
|
|
|
|
OBJ_TreeHandleSignalIfFlagsSet:
|
|
push yl
|
|
push yh
|
|
; call signal handler
|
|
push r16
|
|
push r17
|
|
push xl
|
|
push xh
|
|
ldd r18, Y+OBJECT_OFFS_FLAGS
|
|
eor r18, r20
|
|
and r18, r20
|
|
brne OBJ_TreeHandleSignalIfFlagsSet_l1
|
|
push r20
|
|
rcall OBJ_HandleSignal ; (any, !Y)
|
|
pop r20
|
|
OBJ_TreeHandleSignalIfFlagsSet_l1:
|
|
pop xh
|
|
pop xl
|
|
pop r17
|
|
pop r16
|
|
; handle children
|
|
rcall OBJ_GetFirstChild ; r19:r18=object (none)
|
|
OBJ_TreeHandleSignalIfFlagsSet_loop:
|
|
brcc OBJ_TreeHandleSignalIfFlagsSet_done
|
|
mov yl, r18
|
|
mov yh, r19
|
|
rcall OBJ_TreeHandleSignalIfFlagsSet ; recursion!
|
|
rcall OBJ_GetNext ; r19:r18=object (none)
|
|
rjmp OBJ_TreeHandleSignalIfFlagsSet_loop
|
|
OBJ_TreeHandleSignalIfFlagsSet_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
|
|
; @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 OBJ_AddFlagsUp @global @recursive
|
|
;
|
|
; @param Y address of object
|
|
; @param R16 flags to add
|
|
; @clobbers r17, r18, r19
|
|
|
|
OBJ_AddFlagsUp:
|
|
push yl
|
|
push yh
|
|
ldd r17, Y+OBJECT_OFFS_FLAGS
|
|
or r17, r16
|
|
std Y+OBJECT_OFFS_FLAGS, r17
|
|
; handle parents
|
|
OBJ_AddFlagsUp_loop:
|
|
rcall OBJ_GetParent ; r19:r18=object (none)
|
|
brcc OBJ_AddFlagsUp_done
|
|
mov yl, r18
|
|
mov yh, r19
|
|
rcall OBJ_AddFlagsUp ; recursion!
|
|
rjmp OBJ_AddFlagsUp_loop
|
|
OBJ_AddFlagsUp_done:
|
|
pop yh
|
|
pop yl
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine objHandleSignalWithMap
|
|
;
|
|
; @param Y byte address of object (for LPM!)
|
|
; @param Z signal map to use
|
|
; @param R16 signal number
|
|
; @param R17 selector
|
|
; @param xl param1
|
|
; @param xh param2
|
|
; @return CFLAG set if handled, cleared otherwise
|
|
; @return r19:r18 return value from signal handler
|
|
; @clobbers any, !Y
|
|
|
|
objHandleSignalWithMap:
|
|
push yl
|
|
push yh
|
|
rcall objGetHandlerFromSignalMap ; r19:r18=handler (r22, r23, Z)
|
|
brcc objHandleSignalWithMap_done
|
|
rcall objHandleSignalWithMap_jmpR19R18
|
|
objHandleSignalWithMap_done:
|
|
pop yh
|
|
pop yl
|
|
ret
|
|
objHandleSignalWithMap_jmpR19R18:
|
|
; jmp to r19:r18 via stack
|
|
push r18
|
|
push r19
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine objGetHandlerFromSignalMap
|
|
;
|
|
; @param Y address of object
|
|
; @param Z signal map to use (byte address 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, Z
|
|
|
|
objGetHandlerFromSignalMap:
|
|
mov r23, zl
|
|
or r23, zh
|
|
clc
|
|
breq objGetHandlerFromSignalMap_done
|
|
adiw zh:zl, OBJECT_SIGNALMAP_OFFS_ENTRIES ; go straight to entries
|
|
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:
|
|
; header
|
|
.dw 0 ; next table to use (none here)
|
|
; entries
|
|
.db 0, OBJECT_SIGNAL_DESTROY, LOW(OBJ_OnDestroy), HIGH(OBJ_OnDestroy)
|
|
.db 0, 0, 0, 0 ; end of table
|
|
|
|
|
|
|
|
|
|
; @endmodule
|
|
|
|
|
|
#endif
|
|
|