Files
aqhomecontrol/avr/modules/lcd2/gui2/object.asm
Martin Preuss 55292bddf1 avr: simplify handling of object tree
- set CFLAG if pointer valid, cleared otherwise
- check for inbound NULL pointer
2026-01-15 17:26:54 +01:00

408 lines
9.3 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
; ***************************************************************************
; defines
; Object in flash
.equ OBJECT_OFFS_NEXT_LO = 0 ; byte address (for LPM!)
.equ OBJECT_OFFS_NEXT_HI = 1
.equ OBJECT_OFFS_PARENT_LO = 2 ; byte address (for LPM!)
.equ OBJECT_OFFS_PARENT_HI = 3
.equ OBJECT_OFFS_CHILD_LO = 4 ; byte address (for LPM!)
.equ OBJECT_OFFS_CHILD_HI = 5
.equ OBJECT_OFFS_TARGET_LO = 6 ; byte address (for LPM!)
.equ OBJECT_OFFS_TARGET_HI = 7
.equ OBJECT_OFFS_SELECTOR = 8
.equ OBJECT_OFFS_UNUSED = 9
.equ OBJECT_OFFS_SIGNALMAP_LO = 10 ; byte address (for LPM!)
.equ OBJECT_OFFS_SIGNALMAP_HI = 11
.equ OBJECT_SIZE = 12
; 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_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:
tst zh
brne OBJ_GetParent_get
tst zl
brne OBJ_GetParent_get
clc
rjmp OBJ_GetParent_ret
OBJ_GetParent_get:
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:
tst zh
brne OBJ_GetFirstChild_get
tst zl
brne OBJ_GetFirstChild_get
clc
rjmp OBJ_GetFirstChild_ret
OBJ_GetFirstChild_get:
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:
tst zh
brne OBJ_GetNext_get
tst zl
brne OBJ_GetNext_get
clc
rjmp OBJ_GetNext_ret
OBJ_GetNext_get:
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:
tst zh
brne OBJ_GetBelow_get
tst zl
breq 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:
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, !Z
OBJ_EmitSignal:
push zl
push zh
rcall OBJ_EmitSignal_savedZ
pop zh
pop zl
rjmp OBJ_EmitSignal_ret
OBJ_EmitSignal_savedZ:
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
rjmp OBJ_HandleSignal ; (any, !Z)
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:
push zl
push zh
mov r18, zl
or r18, zh
clc
breq OBJ_TreeHandleSignal_done
rcall objectHandleSignalSaveInRegs
brcs OBJ_TreeHandleSignal_done
rcall OBJ_GetFirstChild
OBJ_TreeHandleSignal_loop:
mov zl, r18
mov zh, r19
or r18, r19
clc
breq OBJ_TreeHandleSignal_done
rcall OBJ_TreeHandleSignal ; recursion
;rcall objectHandleSignalSaveInRegs
brcs OBJ_TreeHandleSignal_done
rcall OBJ_GetNext
rjmp OBJ_TreeHandleSignal_loop
OBJ_TreeHandleSignal_done:
pop zh
pop zl
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:
push zl
push zh
OBJ_TreeAllHandleSignal_loop:
mov r18, zl
or r18, zh
breq OBJ_TreeAllHandleSignal_done
rcall objectHandleSignalSaveInRegs
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
ret
; @end
; ---------------------------------------------------------------------------
; @routine objectHandleSignalSaveInRegs
;
; @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
objectHandleSignalSaveInRegs:
push r16
push r17
push xl
push xh
rcall OBJ_HandleSignal
pop xh
pop xl
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, !Z
OBJ_HandleSignal:
push zl
push zh
rcall objGetHandlerFromSignalMap
brcc OBJ_HandleSignal_done
rcall OBJ_HandleSignal_jmpR19R18
OBJ_HandleSignal_done:
pop zh
pop zl
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 any, !Z
objGetHandlerFromSignalMap:
push zl
push zh
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
clc
breq objGetHandlerFromSignalMap_done
cp r16, r23
brne objGetHandlerFromSignalMap_next
cp r17, r22
brne objGetHandlerFromSignalMap_next
mov r23, r18
or r23, r19
clc
breq objGetHandlerFromSignalMap_done
sec ; found handler
rjmp objGetHandlerFromSignalMap_done
objGetHandlerFromSignalMap_next:
rjmp objGetHandlerFromSignalMap_loop
objGetHandlerFromSignalMap_done:
pop zh
pop zl
ret
; @end
#endif