gui, heap: modified how the heap works.
not well enough tested, yet.
This commit is contained in:
@@ -48,24 +48,31 @@ heapDblFree: .byte 1
|
|||||||
Heap_Init:
|
Heap_Init:
|
||||||
ldi xl, LOW(HEAP_START)
|
ldi xl, LOW(HEAP_START)
|
||||||
ldi xh, HIGH(HEAP_START)
|
ldi xh, HIGH(HEAP_START)
|
||||||
ldi r24, LOW((HEAP_SIZE-6) & 0xfffc) ; size minus chunk header, chunk footer, start, end
|
ldi r24, LOW((HEAP_SIZE-8) & 0xfffc) ; size minus chunk header, chunk footer, start, end
|
||||||
ldi r25, HIGH((HEAP_SIZE-6) & 0xfffc) ; we allocate multiples of 4 bytes
|
ldi r25, HIGH((HEAP_SIZE-8) & 0xfffc) ; we allocate multiples of 4 bytes
|
||||||
clr r16
|
clr r16
|
||||||
sts heapUsed, r16
|
sts heapUsed, r16
|
||||||
sts heapUsed+1, r16
|
sts heapUsed+1, r16
|
||||||
st X+, r16 ; write start header
|
; write start header (two zero bytes)
|
||||||
st X+, r16
|
st X+, r16
|
||||||
|
st X+, r16
|
||||||
|
; X now points to first chunk
|
||||||
sts heapPtr, xl ; store global vars
|
sts heapPtr, xl ; store global vars
|
||||||
sts heapPtr+1, xh
|
sts heapPtr+1, xh
|
||||||
sts heapFree, r24
|
sts heapFree, r24
|
||||||
sts heapFree+1, r25
|
sts heapFree+1, r25
|
||||||
st X+, r24 ; store header of first chunk
|
; store header of first chunk (bit0=0, meaning: free chunk)
|
||||||
|
st X+, r24
|
||||||
st X+, r25
|
st X+, r25
|
||||||
add xl, r24
|
add xl, r24
|
||||||
adc xh, r25
|
adc xh, r25
|
||||||
st X+, r24 ; store footer of first chunk
|
; store footer of first chunk
|
||||||
|
st X+, r24
|
||||||
st X+, r25
|
st X+, r25
|
||||||
st X+, r16 ; write end footer
|
; write end header (two zero bytes)
|
||||||
|
st X+, r16
|
||||||
|
st X+, r16
|
||||||
|
; okay
|
||||||
sec
|
sec
|
||||||
ret
|
ret
|
||||||
; @end
|
; @end
|
||||||
@@ -124,7 +131,7 @@ Heap_AllocAndZero_ret:
|
|||||||
; @routine heapAllocFirstFit
|
; @routine heapAllocFirstFit
|
||||||
;
|
;
|
||||||
; @param r25:r24 number of bytes to alloc
|
; @param r25:r24 number of bytes to alloc
|
||||||
; @return CFLAG set of okay, cleared otherwise
|
; @return CFLAG set if okay, cleared otherwise
|
||||||
; @return X start of allocated memory
|
; @return X start of allocated memory
|
||||||
; @clobbers r16, r17, r18, r19, r24, r25, X
|
; @clobbers r16, r17, r18, r19, r24, r25, X
|
||||||
|
|
||||||
@@ -136,20 +143,24 @@ heapAllocFirstFit:
|
|||||||
lds xh, heapPtr+1
|
lds xh, heapPtr+1
|
||||||
|
|
||||||
heapAllocFirstFit_loop:
|
heapAllocFirstFit_loop:
|
||||||
ld r18, X+ ; read chunk header
|
; read chunk header
|
||||||
ld r19, X+
|
ld r18, X+
|
||||||
mov r16, r18 ; heap end reached?
|
ld r19, X+ ; X now points to first data byte of chunk
|
||||||
|
; zero-header found?
|
||||||
|
mov r16, r18
|
||||||
or r16, r19
|
or r16, r19
|
||||||
breq heapAllocFirstFit_memFull
|
breq heapAllocFirstFit_memFull ; yes, memory full
|
||||||
|
; chunk in use?
|
||||||
sbrc r18, HEAP_HEADER_BIT_USED
|
sbrc r18, HEAP_HEADER_BIT_USED
|
||||||
rjmp heapAllocFirstFit_next ; jump if used
|
rjmp heapAllocFirstFit_next ; jump if used
|
||||||
; current chunk free, check size
|
; current chunk free, check size
|
||||||
andi r18, 0xfc
|
andi r18, 0xfc ; clear lower two bits
|
||||||
mov r16, r18
|
mov r16, r18
|
||||||
mov r17, r19
|
mov r17, r19
|
||||||
sub r16, r24
|
sub r16, r24
|
||||||
sbc r17, r25 ; r17:r16=remainder
|
sbc r17, r25 ; r17:r16=remainder
|
||||||
brcs heapAllocFirstFit_next ; too small
|
brcs heapAllocFirstFit_next ; too small
|
||||||
|
; chunk size is okay, use it
|
||||||
rcall heapUseChunk
|
rcall heapUseChunk
|
||||||
sec
|
sec
|
||||||
ret
|
ret
|
||||||
@@ -161,12 +172,82 @@ heapAllocFirstFit_next:
|
|||||||
rjmp heapAllocFirstFit_loop
|
rjmp heapAllocFirstFit_loop
|
||||||
|
|
||||||
heapAllocFirstFit_memFull:
|
heapAllocFirstFit_memFull:
|
||||||
|
bigcall Led1_SetFastTiming
|
||||||
clc
|
clc
|
||||||
ret
|
ret
|
||||||
; @end
|
; @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<<HEAP_HEADER_BIT_USED)
|
||||||
|
; write new chunk start header
|
||||||
|
st X+, r18 ; with used bit set
|
||||||
|
st X+, r25 ; X now points to start of chunk data
|
||||||
|
add xl, r24
|
||||||
|
adc xh, r25
|
||||||
|
; X now points to the start of chunk footer
|
||||||
|
st X+, r18 ; write new chunk footer (with USED bit set)
|
||||||
|
st X+, r25 ; X now points behind chunk end header
|
||||||
|
; create chunk header for new free chunk
|
||||||
|
subi r16, 4 ; sub chunk header and footer from size
|
||||||
|
sbci r17, 0
|
||||||
|
andi r16, 0xfc ; clear USED bit
|
||||||
|
; store new heap pointer
|
||||||
|
sts heapPtr, xl
|
||||||
|
sts heapPtr+1, xh
|
||||||
|
; write new chunk header
|
||||||
|
st X+, r16 ; write new chunk header (with USED bit cleared)
|
||||||
|
st X+, r17 ; X now points to begin of next chunk data
|
||||||
|
add xl, r16
|
||||||
|
adc xh, r17 ; X now points behind chunk end header
|
||||||
|
st X+, r16 ; write new chunk footer (with USED bit cleared)
|
||||||
|
st X+, r17 ; X points to next chunk header
|
||||||
|
; update stats, pop X and return
|
||||||
|
rjmp heapUseChunk_statsPopRet
|
||||||
|
heapUseChunk_directAlloc:
|
||||||
|
ld r17, -X ; load allocated size from chunk header
|
||||||
|
ld r16, -X
|
||||||
|
mov r18, r16
|
||||||
|
sbr r18, (1<<HEAP_HEADER_BIT_USED)
|
||||||
|
st X, r18 ; set USED bit in chunk header
|
||||||
|
adiw xh:xl, 2 ; skip chunk header
|
||||||
|
add xl, r16 ; skip chunk data
|
||||||
|
adc xh, r17
|
||||||
|
st X, r18 ; set USED bit in chunk footer
|
||||||
|
adiw xh:xl, 2 ; X points to next chunk header
|
||||||
|
; store new heap pointer
|
||||||
|
sts heapPtr, xl
|
||||||
|
sts heapPtr+1, xh
|
||||||
|
; update stats, pop X and return
|
||||||
|
heapUseChunk_statsPopRet:
|
||||||
|
rcall heapAdjustStatsAlloc ; (r16, r17)
|
||||||
|
pop xh
|
||||||
|
pop xl
|
||||||
|
sec
|
||||||
|
ret
|
||||||
|
; @end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
; ---------------------------------------------------------------------------
|
; ---------------------------------------------------------------------------
|
||||||
; @routine heapAdjustStatsAlloc
|
; @routine heapAdjustStatsAlloc
|
||||||
;
|
;
|
||||||
@@ -225,7 +306,7 @@ heapAdjustStatsFree:
|
|||||||
; @routine Heap_Free
|
; @routine Heap_Free
|
||||||
;
|
;
|
||||||
; @param X pointer to previously allocated data
|
; @param X pointer to previously allocated data
|
||||||
; @clobbers r16, r17, r24, r25, X
|
; @clobbers r16, r17, r18, r19, r24, r25, X
|
||||||
|
|
||||||
Heap_Free:
|
Heap_Free:
|
||||||
sbiw xh:xl, 2 ; go back to chunk header
|
sbiw xh:xl, 2 ; go back to chunk header
|
||||||
@@ -244,10 +325,10 @@ Heap_Free:
|
|||||||
st X+, r24 ; write chunk footer
|
st X+, r24 ; write chunk footer
|
||||||
st X+, r25 ; X points to the next chunk header now
|
st X+, r25 ; X points to the next chunk header now
|
||||||
rcall heapAdjustStatsFree ; update stats (r16, r17)
|
rcall heapAdjustStatsFree ; update stats (r16, r17)
|
||||||
rcall heapCoalecseUp ; try to coalecse following chunk with this (r16, r17, r24, r25, X)
|
rcall heapCoalecseUp ; try to coalecse following chunk with this (r16, r17, r18, r19, r24, r25, X)
|
||||||
pop xh
|
pop xh
|
||||||
pop xl
|
pop xl
|
||||||
rcall heapCoalecseUp ; try to coalesce this chunk with predecessor (r16, r17, r24, r25, X)
|
rcall heapCoalecseUp ; try to coalesce this chunk with predecessor (r16, r17, r18, r19, r24, r25, X)
|
||||||
rjmp Heap_Free_ret
|
rjmp Heap_Free_ret
|
||||||
Heap_Free_dblFree:
|
Heap_Free_dblFree:
|
||||||
lds r24, heapDblFree
|
lds r24, heapDblFree
|
||||||
@@ -266,114 +347,78 @@ Heap_Free_ret:
|
|||||||
; ---------------------------------------------------------------------------
|
; ---------------------------------------------------------------------------
|
||||||
; @routine heapCoalecseUp
|
; @routine heapCoalecseUp
|
||||||
;
|
;
|
||||||
|
; Check whether the given chunk and the previous one are both free.
|
||||||
|
; If so combine them into a common free chunk.
|
||||||
|
;
|
||||||
; @param X pointer to chunk header
|
; @param X pointer to chunk header
|
||||||
; @clobbers r16, r17, r24, r25, X
|
; @clobbers r16, r17, r18, r19, r24, r25, X
|
||||||
|
|
||||||
heapCoalecseUp:
|
heapCoalecseUp:
|
||||||
ld r16, X+ ; end of heap reached(header==0x0000)?
|
; read current chunk header
|
||||||
ld r17, X
|
ld r24, X+
|
||||||
sbiw xh:xl, 1
|
ld r25, X
|
||||||
or r16, r17
|
sbiw xh:xl, 3
|
||||||
breq heapCoalecseUp_ret ; yes, jump
|
; read previous chunk footer
|
||||||
; read footer of preceeding chunk
|
ld r18, X+
|
||||||
ld r25, -X
|
ld r19, X+
|
||||||
ld r24, -X
|
; current chunk=end_of_heap?
|
||||||
; R25:R24=footer of preceeding chunk (i.e. size of previous chunk), X points to previous footer
|
mov r16, r24
|
||||||
mov r16, r24 ; check: beginning of heap reached (header==0x0000)?
|
|
||||||
or r16, r25
|
or r16, r25
|
||||||
breq heapCoalecseUp_ret ; yes, jump
|
breq heapCoalecseUp_done
|
||||||
sbrc r24, HEAP_HEADER_BIT_USED ; block used?
|
; current chunk in use?
|
||||||
rjmp heapCoalecseUp_ret ; jump if used
|
sbrc r24, HEAP_HEADER_BIT_USED
|
||||||
; previous chunk also free, coalesce, X points to current chunk header
|
rjmp heapCoalecseUp_done
|
||||||
adiw xh:xl, 2
|
; previous chunk=begin of heap?
|
||||||
; skip footer
|
mov r16, r18
|
||||||
ld r16, X+
|
or r16, r19
|
||||||
ld r17, X+
|
breq heapCoalecseUp_done
|
||||||
sbrc r16, HEAP_HEADER_BIT_USED ; current block used?
|
; previous chunk in use?
|
||||||
rjmp heapCoalecseUp_ret ; jump if used
|
sbrc r18, HEAP_HEADER_BIT_USED
|
||||||
|
rjmp heapCoalecseUp_done
|
||||||
|
|
||||||
; X now points to beginning of current chunk's data, R17:r16=size of current chunk, R25:R24=size of previous chunk
|
; clear lower two bits
|
||||||
; to go to start of previous chunk header: sub this chunk header, previous chunk footer, previous chunk header and previous data
|
andi r18, 0xfc
|
||||||
sbiw xh:xl, 6
|
andi r24, 0xfc
|
||||||
sub xl, r24
|
|
||||||
sbc xh, r25
|
; now:
|
||||||
; X points now to the beginning of the previous chunk header
|
; - both chunks are free and can be combined
|
||||||
; calculate size of new coalecsed chunk: add size of this chunk, size of previous chunk, 1 chunk header and 1 footer which are
|
; - X points to beginning of current header
|
||||||
; no longer needed now (since the one header and footer of the previous chunk now cover both chunks)
|
|
||||||
|
; calc combined size (sizes of both chunks plus 1 header and 1 footer)
|
||||||
|
add r24, r18
|
||||||
|
adc r25, r19
|
||||||
|
ldi r16, 4
|
||||||
|
clr r17
|
||||||
add r24, r16
|
add r24, r16
|
||||||
adc r25, r17
|
adc r25, r17 ; r25:r24=combined size
|
||||||
adiw r25:r24, 4
|
|
||||||
; write new chunk header
|
; check for heapPtr
|
||||||
|
lds r16, heapPtr
|
||||||
|
lds r17, heapPtr+1
|
||||||
|
sub r16, xl
|
||||||
|
sbc r17, xh
|
||||||
|
or r16, r17 ; r16=0 if heapPtr=current chunk
|
||||||
|
|
||||||
|
sbiw xh:xl, 4 ; subtract previous footer and header from pos
|
||||||
|
sub xl, r18 ; subtract size of previous chunk from pos
|
||||||
|
sbc xh, r19 ; X now points to beginning of previous chunk
|
||||||
|
|
||||||
|
; test heapPtr
|
||||||
|
tst r16
|
||||||
|
brne heapCoalecseUp_l1
|
||||||
|
; adjust heapPtr
|
||||||
|
sts heapPtr, xl
|
||||||
|
sts heapPtr+1, xh
|
||||||
|
heapCoalecseUp_l1:
|
||||||
|
; write new combined header
|
||||||
st X+, r24
|
st X+, r24
|
||||||
st X+, r25
|
st X+, r25
|
||||||
; skip full data size of the coalesced chunk
|
|
||||||
add xl, r24
|
add xl, r24
|
||||||
adc xh, r25
|
adc xh, r25
|
||||||
; write new chunk footer
|
; write new combined footer
|
||||||
st X+, r24
|
st X+, r24
|
||||||
st X+, r25
|
st X+, r25
|
||||||
; X now points to header of following chunk
|
heapCoalecseUp_done:
|
||||||
heapCoalecseUp_ret:
|
|
||||||
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<<HEAP_HEADER_BIT_USED)
|
|
||||||
st X+, r18 ; set used bit
|
|
||||||
st X+, r25
|
|
||||||
add xl, r24
|
|
||||||
adc xh, r25
|
|
||||||
; X now points to the start of chunk footer
|
|
||||||
st X+, r18
|
|
||||||
st X+, r25
|
|
||||||
; create chunk header for new free chunk
|
|
||||||
subi r16, 4 ; sub chunk header and footer from size
|
|
||||||
sbci r17, 0
|
|
||||||
andi r16, 0xfc ; clear USED bit
|
|
||||||
st X+, r16 ; write new chunk header
|
|
||||||
st X+, r17
|
|
||||||
add xl, r16
|
|
||||||
adc xh, r17
|
|
||||||
st X+, r16 ; write new chunk footer
|
|
||||||
st X+, r17
|
|
||||||
; update stats, pop X and return
|
|
||||||
rjmp heapUseChunk_statsPopRet
|
|
||||||
heapUseChunk_directAlloc:
|
|
||||||
ld r17, -X ; load allocated size from chunk header
|
|
||||||
ld r16, -X
|
|
||||||
mov r18, r16
|
|
||||||
sbr r18, (1<<HEAP_HEADER_BIT_USED)
|
|
||||||
st X, r18 ; set USED bit in chunk header
|
|
||||||
adiw xh:xl, 2 ; skip chunk header
|
|
||||||
add xl, r16 ; skip chunk data
|
|
||||||
adc xh, r17
|
|
||||||
st X, r18 ; set USED bit in chunk footer
|
|
||||||
; update stats, pop X and return
|
|
||||||
heapUseChunk_statsPopRet:
|
|
||||||
rcall heapAdjustStatsAlloc ; (r16, r17)
|
|
||||||
pop xh
|
|
||||||
pop xl
|
|
||||||
sec
|
|
||||||
ret
|
ret
|
||||||
; @end
|
; @end
|
||||||
|
|
||||||
@@ -382,4 +427,3 @@ heapUseChunk_statsPopRet:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -120,10 +120,10 @@ LayoutCtx_new_ret:
|
|||||||
; @routine LayoutCtx_free @global
|
; @routine LayoutCtx_free @global
|
||||||
;
|
;
|
||||||
; @param X pointer to layout context
|
; @param X pointer to layout context
|
||||||
; @clobbers r16, r17, r24, r25, X
|
; @clobbers r16, r17, r18, r19, r24, r25, X
|
||||||
|
|
||||||
LayoutCtx_free:
|
LayoutCtx_free:
|
||||||
bigjmp Heap_Free ; (r16, r17, r24, r25, X)
|
bigjmp Heap_Free ; (r16, r17, r18, r19, r24, r25, X)
|
||||||
; @end
|
; @end
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user