; *************************************************************************** ; 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. * ; *************************************************************************** ; Needed vars: ; - HEAP_START ; - HEAP_SIZE ; *************************************************************************** ; defines .equ HEAP_HEADER_BIT_USED = 0 ; *************************************************************************** ; data .dseg heapPtr: .byte 2 heapUsed: .byte 2 heapFree: .byte 2 heapDblFree: .byte 1 ; *************************************************************************** ; code .cseg ; --------------------------------------------------------------------------- ; @routine Heap_Init Heap_Init: ldi xl, LOW(HEAP_START) ldi xh, HIGH(HEAP_START) ldi r24, LOW((HEAP_SIZE-8) & 0xfffc) ; size minus chunk header, chunk footer, start, end ldi r25, HIGH((HEAP_SIZE-8) & 0xfffc) ; we allocate multiples of 4 bytes clr r16 sts heapUsed, r16 sts heapUsed+1, r16 ; write start header (two zero bytes) st X+, r16 st X+, r16 ; X now points to first chunk sts heapPtr, xl ; store global vars sts heapPtr+1, xh sts heapFree, r24 sts heapFree+1, r25 ; store header of first chunk (bit0=0, meaning: free chunk) st X+, r24 st X+, r25 add xl, r24 adc xh, r25 ; store footer of first chunk st X+, r24 st X+, r25 ; write end header (two zero bytes) st X+, r16 st X+, r16 ; okay sec ret ; @end ; --------------------------------------------------------------------------- ; @routine Heap_Alloc ; ; @param r25:r24 number of bytes to alloc ; @return CFLAG set of okay, cleared otherwise ; @return X start of allocated memory ; @clobbers r16, r17, r18, r19, r24, r25, X Heap_Alloc: rjmp heapAllocFirstFit ; @end ; --------------------------------------------------------------------------- ; @routine Heap_AllocAndZero ; ; Allocates data on the heap and presets all bytes with zero. ; ; @param r25:r24 number of bytes to alloc ; @return CFLAG set of okay, cleared otherwise ; @return X start of allocated memory ; @clobbers r16, r17, r18, r19, r24, r25, X Heap_AllocAndZero: push r24 push r25 rcall heapAllocFirstFit pop r25 pop r24 brcc Heap_AllocAndZero_ret push xl push xh clr r18 Heap_AllocAndZero_loop: st X+, r18 sbiw r25:r24, 1 brne Heap_AllocAndZero_loop pop xh pop xl sec Heap_AllocAndZero_ret: ret ; @end ; --------------------------------------------------------------------------- ; @routine heapAllocFirstFit ; ; @param r25:r24 number of bytes to alloc ; @return CFLAG set if okay, cleared otherwise ; @return X start of allocated memory ; @clobbers r16, r17, r18, r19, r24, r25, X heapAllocFirstFit: adiw r25:r24, 3 ; align size to next multiple of 4 andi r24, 0xfc ; mask lower two bits lds xl, heapPtr lds xh, heapPtr+1 heapAllocFirstFit_loop: ; read chunk header ld r18, X+ ld r19, X+ ; X now points to first data byte of chunk ; zero-header found? mov r16, r18 or r16, r19 breq heapAllocFirstFit_memFull ; yes, memory full ; chunk in use? sbrc r18, HEAP_HEADER_BIT_USED rjmp heapAllocFirstFit_next ; jump if used ; current chunk free, check size andi r18, 0xfc ; clear lower two bits mov r16, r18 mov r17, r19 sub r16, r24 sbc r17, r25 ; r17:r16=remainder brcs heapAllocFirstFit_next ; too small ; chunk size is okay, use it rcall heapUseChunk sec ret heapAllocFirstFit_next: andi r18, 0xfc add xl, r18 adc xh, r19 adiw xh:xl, 2 ; skip footer rjmp heapAllocFirstFit_loop heapAllocFirstFit_memFull: bigcall Led1_SetFastTiming clc ret ; @end ; --------------------------------------------------------------------------- ; @routine heapUseChunk ; ; @param r25:r24 wanted size ; @param r17:r16 size of current chunk minus wanted size (remainder) ; @param X points to data of current chunk ; @clobbers heapUseChunk: push xl push xh tst r17 brne heapUseChunk_split cpi r16, 8 ; at least 8 bytes left? brcs heapUseChunk_directAlloc ; nope, use full chunk heapUseChunk_split: sbiw xh:xl, 2 ; go back to chunk header ; X points to start of chunk header mov r18, r24 sbr r18, (1<