; *************************************************************************** ; 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-6) & 0xfffc) ; size minus chunk header, chunk footer, start, end ldi r25, HIGH((HEAP_SIZE-6) & 0xfffc) ; we allocate multiples of 4 bytes clr r16 sts heapUsed, r16 sts heapUsed+1, r16 st X+, r16 ; write start header st X+, r16 sts heapPtr, xl ; store global vars sts heapPtr+1, xh sts heapFree, r24 sts heapFree+1, r25 st X+, r24 ; store header of first chunk st X+, r25 add xl, r24 adc xh, r25 st X+, r24 ; store footer of first chunk st X+, r25 st X+, r16 ; write end footer 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 Heap_Alloc: rjmp heapAllocFirstFit ; @end ; --------------------------------------------------------------------------- ; @routine heapAllocFirstFit ; ; @param r25:r24 number of bytes to alloc ; @return CFLAG set of okay, cleared otherwise ; @return X start of allocated memory 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: ld r18, X+ ; read chunk header ld r19, X+ mov r16, r18 ; heap end reached? or r16, r19 breq heapAllocFirstFit_memFull sbrc r18, HEAP_HEADER_BIT_USED rjmp heapAllocFirstFit_next ; jump if used ; current chunk free, check size andi r18, 0xfc mov r16, r18 mov r17, r19 sub r16, r24 sbc r17, r25 ; r17:r16=remainder brcs heapAllocFirstFit_next ; too small 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: clc ret ; @end ; --------------------------------------------------------------------------- ; @routine heapAdjustStatsAlloc ; ; @param r25:r24 size of allocated chunk ; @clobbers r16, r17 heapAdjustStatsAlloc: ; adjust heapUsed lds r16, heapUsed lds r17, heapUsed+1 add r16, r24 adc r17, r25 sts heapUsed, r16 sts heapUsed+1, r17 ; adjust heapFree lds r16, heapFree lds r17, heapFree+1 sub r16, r24 sbc r17, r25 sts heapFree, r16 sts heapFree+1, r17 ret ; @end ; --------------------------------------------------------------------------- ; @routine heapAdjustStatsFree ; ; @param r25:r24 size of released chunk ; @clobbers r16, r17 heapAdjustStatsFree: ; adjust heapUsed lds r16, heapUsed lds r17, heapUsed+1 sub r16, r24 sbc r17, r25 sts heapUsed, r16 sts heapUsed+1, r17 ; adjust heapFree lds r16, heapFree lds r17, heapFree+1 add r16, r24 adc r17, r25 sts heapFree, r16 sts heapFree+1, r17 ret ; @end ; --------------------------------------------------------------------------- ; @routine Heap_Free ; ; @param X pointer to previously allocated data ; @clobbers r16, r17, r24, r25, X Heap_Free: sbiw xh:xl, 2 ; go back to chunk header ld r24, X+ ; read allocated size (and USED bit) ld r25, X+ sbrs r24, HEAP_HEADER_BIT_USED rjmp Heap_Free_dblFree ; not in use (double free!!) cbr r24, (1<