Add FreeRTOS heap4 intro card

This commit is contained in:
mpabi
2026-05-02 00:53:25 +02:00
commit e69aaa6d61
29 changed files with 2250 additions and 0 deletions
+63
View File
@@ -0,0 +1,63 @@
name: Render PDF
on:
push:
branches:
- deploy
workflow_dispatch:
jobs:
render-pdf:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install TeX
run: |
if ! command -v latexmk >/dev/null 2>&1; then
if ! command -v apt-get >/dev/null 2>&1; then
echo "latexmk is missing and apt-get is unavailable" >&2
exit 1
fi
if command -v sudo >/dev/null 2>&1; then
SUDO=sudo
else
SUDO=
fi
$SUDO apt-get update
$SUDO apt-get install -y --no-install-recommends \
latexmk \
texlive-fonts-recommended \
texlive-lang-polish \
texlive-latex-base \
texlive-latex-extra \
texlive-latex-recommended
fi
- name: Render PDF with commit metadata
run: ./scripts/render_pdf.sh
- name: Commit rendered PDF
run: |
set -eu
repo_name="${GITHUB_REPOSITORY#*/}"
pdf_file="$(find doc/pdf -maxdepth 1 -type f -name '*.pdf' -print -quit)"
if [ -z "$pdf_file" ]; then
echo "rendered PDF is missing" >&2
exit 1
fi
remote_sha="$(git ls-remote origin refs/heads/deploy | cut -f1)"
if [ "$remote_sha" != "$GITHUB_SHA" ]; then
echo "deploy advanced from $GITHUB_SHA to $remote_sha; skip publishing stale PDF"
exit 0
fi
git config user.name "gitea-actions"
git config user.email "gitea-actions@noreply.local"
printf '%s\n' "$GITHUB_SHA" > doc/pdf/source-commit.txt
git add -u doc/pdf
git add -f "$pdf_file"
git add doc/pdf/source-commit.txt
git diff --cached --quiet && exit 0
git commit -m "Render ${repo_name} PDF for ${GITHUB_SHA::12} [skip actions]"
git push origin HEAD:deploy
+18
View File
@@ -0,0 +1,18 @@
*.aux
*.log
*.out
*.fls
*.fdb_latexmk
*.synctex.gz
*.pdf
build-meta.tex
.rv/
.nvim/
.vim/
.build/
.gdb_history
host-build/
build/*/prog.bin
build/*/prog.elf
build/*/prog.lst
build/*/prog.map
+112
View File
@@ -0,0 +1,112 @@
RISCV_PREFIX ?= riscv64-unknown-elf-
CC := $(RISCV_PREFIX)gcc
OBJCOPY := $(RISCV_PREFIX)objcopy
OBJDUMP := $(RISCV_PREFIX)objdump
SIZE := $(RISCV_PREFIX)size
HOST_CC ?= cc
DEBUG ?= 1
ifeq ($(DEBUG),1)
DBGFLAGS := -g3 -ggdb
else
DBGFLAGS :=
endif
RV_ENV_ROOT ?= /opt/rv-env
SUPPORT_ROOT ?= $(RV_ENV_ROOT)/vendor/Hazard3
H3_COMMON ?= $(SUPPORT_ROOT)/test/sim/common
H3_INIT ?= $(H3_COMMON)/init.S
LDSCRIPT ?= $(H3_COMMON)/link_hazard3.ld
LAB_RUNTIME_DIR ?= $(RV_ENV_ROOT)/vendor/lab-runtime
MEMOPS ?= $(LAB_RUNTIME_DIR)/memops.c
BUILD_ROOT ?= build
HOST_BUILD_ROOT ?= host-build
TASKS := \
task01_heap_map \
task02_free_list \
task03_heap_init \
task04_alignment \
task05_malloc_first_fit \
task06_split_block \
task07_free_insert \
task08_coalescing \
task09_config_macros \
task10_heap4_demo
ARCH ?= rv32i_zicsr_zifencei
ABI ?= ilp32
COMMON_FLAGS := -std=c99 -march=$(ARCH) -mabi=$(ABI) -nostdlib -nostartfiles -ffreestanding -fno-builtin -fno-stack-protector $(DBGFLAGS) -Wall -Wextra -Isrc/tasks
LINK_FLAGS := -Wl,--no-relax -Wl,-T,$(LDSCRIPT)
LIBS := -lgcc
EMIT_FLAGS := -std=c99 -march=$(ARCH) -mabi=$(ABI) -O -ffreestanding -fno-builtin -fno-stack-protector -nostdlib -nostartfiles -Wall -Wextra -Isrc/tasks
CFLAGS_STEP := $(COMMON_FLAGS) -O
HOST_CFLAGS := -std=c99 -O0 -g -Wall -Wextra -DHOST_PRINTF=1 -Isrc/tasks
.PHONY: all tasks host \
task1 task2 task3 task4 task5 task6 task7 task8 task9 task10 \
t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 \
host-task1 host-task2 host-task3 host-task4 host-task5 host-task6 host-task7 host-task8 host-task9 host-task10 \
ht1 ht2 ht3 ht4 ht5 ht6 ht7 ht8 ht9 ht10 \
clean check-support $(TASKS)
all: tasks
tasks: $(TASKS)
host: $(addprefix $(HOST_BUILD_ROOT)/,$(addsuffix /prog,$(TASKS)))
task1 t1: $(word 1,$(TASKS))
task2 t2: $(word 2,$(TASKS))
task3 t3: $(word 3,$(TASKS))
task4 t4: $(word 4,$(TASKS))
task5 t5: $(word 5,$(TASKS))
task6 t6: $(word 6,$(TASKS))
task7 t7: $(word 7,$(TASKS))
task8 t8: $(word 8,$(TASKS))
task9 t9: $(word 9,$(TASKS))
task10 t10: $(word 10,$(TASKS))
host-task1 ht1: $(HOST_BUILD_ROOT)/$(word 1,$(TASKS))/prog
host-task2 ht2: $(HOST_BUILD_ROOT)/$(word 2,$(TASKS))/prog
host-task3 ht3: $(HOST_BUILD_ROOT)/$(word 3,$(TASKS))/prog
host-task4 ht4: $(HOST_BUILD_ROOT)/$(word 4,$(TASKS))/prog
host-task5 ht5: $(HOST_BUILD_ROOT)/$(word 5,$(TASKS))/prog
host-task6 ht6: $(HOST_BUILD_ROOT)/$(word 6,$(TASKS))/prog
host-task7 ht7: $(HOST_BUILD_ROOT)/$(word 7,$(TASKS))/prog
host-task8 ht8: $(HOST_BUILD_ROOT)/$(word 8,$(TASKS))/prog
host-task9 ht9: $(HOST_BUILD_ROOT)/$(word 9,$(TASKS))/prog
host-task10 ht10: $(HOST_BUILD_ROOT)/$(word 10,$(TASKS))/prog
check-support:
@test -f "$(H3_INIT)" || { echo "Missing $(H3_INIT). Run inside rv-env or set RV_ENV_ROOT=/path/to/rv32i-hazard3-env" >&2; exit 1; }
@test -f "$(LDSCRIPT)" || { echo "Missing $(LDSCRIPT)." >&2; exit 1; }
@test -f "$(MEMOPS)" || { echo "Missing $(MEMOPS)." >&2; exit 1; }
define task_rules
$(1): $(BUILD_ROOT)/$(1)/prog.bin $(BUILD_ROOT)/$(1)/prog.elf $(BUILD_ROOT)/$(1)/prog.lst $(BUILD_ROOT)/$(1)/$(1).s
$(BUILD_ROOT)/$(1)/prog.elf: crt0.S src/tasks/$(1).c src/tasks/heap4_common.h $(H3_INIT) $(LDSCRIPT) $(MEMOPS) | check-support
mkdir -p $$(@D)
$(CC) $(CFLAGS_STEP) $(LINK_FLAGS) -Wl,-Map,$(BUILD_ROOT)/$(1)/prog.map -o $$@ $(H3_INIT) crt0.S $(MEMOPS) src/tasks/$(1).c $(LIBS)
$(SIZE) -A -x $$@
$(BUILD_ROOT)/$(1)/prog.bin: $(BUILD_ROOT)/$(1)/prog.elf
$(OBJCOPY) -O binary $$< $$@
$(BUILD_ROOT)/$(1)/prog.lst: $(BUILD_ROOT)/$(1)/prog.elf
$(OBJDUMP) -d -M no-aliases,numeric $$< > $$@
$(BUILD_ROOT)/$(1)/$(1).s: src/tasks/$(1).c src/tasks/heap4_common.h | check-support
mkdir -p $$(@D)
$(CC) $(EMIT_FLAGS) -S -o $$@ $$<
$(HOST_BUILD_ROOT)/$(1)/prog: src/tasks/$(1).c src/tasks/heap4_common.h
mkdir -p $$(@D)
$(HOST_CC) $(HOST_CFLAGS) -o $$@ $$<
endef
$(foreach task,$(TASKS),$(eval $(call task_rules,$(task))))
clean:
rm -rf $(BUILD_ROOT) $(HOST_BUILD_ROOT)
+45
View File
@@ -0,0 +1,45 @@
# rv32i-freertos / heap4
Karta pracy 1/? z serii `rv32i-freertos`.
Temat: mechanika alokatora `heap_4.c` z FreeRTOS-a na małych przykładach
uruchamianych w środowisku RV32I.
Ta karta jest pomostem po kartach C: używa wskaźników, struktur, listy
jednokierunkowej, `static`, `typedef`, makr i arytmetyki adresów, ale nie
wymaga jeszcze schedulera, tasków ani przerwań.
Kod w `src/tasks` jest dydaktycznym modelem zachowania `heap_4`, a nie kopią
pliku upstream FreeRTOS.
## Taski
- `task01_heap_map.c` - mapa pojęć: sterta, blok, nagłówek bloku.
- `task02_free_list.c` - lista wolnych bloków.
- `task03_heap_init.c` - inicjalizacja sterty i wartownik końca listy.
- `task04_alignment.c` - wyrównanie rozmiarów i adresów.
- `task05_malloc_first_fit.c` - pierwszy pasujący wolny blok.
- `task06_split_block.c` - podział większego bloku.
- `task07_free_insert.c` - zwracanie bloku na listę wolnych.
- `task08_coalescing.c` - scalanie sąsiednich wolnych bloków.
- `task09_config_macros.c` - makra konfiguracyjne i warunkowy `printf`.
- `task10_heap4_demo.c` - mini-demonstracja `malloc/free` bez pełnego RTOS-a.
Hostowe `printf` jest dostępne tylko przez `-DHOST_PRINTF=1`; RV32I zapisuje
wyniki w globalnych zmiennych `volatile`.
## Budowanie
```bash
RV_ENV_ROOT=~/dev/workspace/rv/tools/rv32i-hazard3-student-env make tasks
make host
```
## Praca przez rvctl
```bash
./rvctl series cards fetch inf heap4
./rvctl card use inf heap4
./rvctl tasks list
./rvctl debug rv32i 1
```
+53
View File
@@ -0,0 +1,53 @@
.file "task01_heap_map.c"
.option nopic
.attribute arch, "rv32i2p1_zicsr2p0_zifencei2p0"
.attribute unaligned_access, 0
.attribute stack_align, 16
.text
.align 2
.globl main
.type main, @function
main:
li a5,8
sw a5,g_header_size,a4
sw a5,g_aligned_header_size,a4
li a5,1
sw a5,g_allocated_bit_set,a4
lla a5,g_total_block_bytes
li a4,24
sw a4,0(a5)
lw a5,0(a5)
addi a5,a5,-8
sw a5,g_user_bytes,a4
li a0,0
ret
.size main, .-main
.globl g_total_block_bytes
.globl g_user_bytes
.globl g_allocated_bit_set
.globl g_aligned_header_size
.globl g_header_size
.section .sbss,"aw",@nobits
.align 2
.type g_total_block_bytes, @object
.size g_total_block_bytes, 4
g_total_block_bytes:
.zero 4
.type g_user_bytes, @object
.size g_user_bytes, 4
g_user_bytes:
.zero 4
.type g_allocated_bit_set, @object
.size g_allocated_bit_set, 4
g_allocated_bit_set:
.zero 4
.type g_aligned_header_size, @object
.size g_aligned_header_size, 4
g_aligned_header_size:
.zero 4
.type g_header_size, @object
.size g_header_size, 4
g_header_size:
.zero 4
.ident "GCC: (15.2.0-23) 15.2.0"
.section .note.GNU-stack,"",@progbits
+73
View File
@@ -0,0 +1,73 @@
.file "task02_free_list.c"
.option nopic
.attribute arch, "rv32i2p1_zicsr2p0_zifencei2p0"
.attribute unaligned_access, 0
.attribute stack_align, 16
.text
.align 2
.globl main
.type main, @function
main:
addi sp,sp,-32
addi a5,sp,16
sw a5,24(sp)
li a5,32
sw a5,28(sp)
addi a5,sp,8
sw a5,16(sp)
li a5,80
sw a5,20(sp)
sw zero,8(sp)
li a5,24
sw a5,12(sp)
li a4,0
add a5,sp,a5
.L2:
lw a3,4(a5)
add a4,a4,a3
lw a5,0(a5)
bne a5,zero,.L2
sw a4,g_free_total,a5
li a3,0
addi a5,sp,24
j .L4
.L3:
lw a5,0(a5)
beq a5,zero,.L10
.L4:
lw a4,4(a5)
bgeu a3,a4,.L3
mv a3,a4
j .L3
.L10:
sw a3,g_largest_free,a5
addi a5,sp,24
li a4,0
.L5:
addi a4,a4,1
lw a5,0(a5)
bne a5,zero,.L5
sw a4,g_node_count,a5
li a0,0
addi sp,sp,32
jr ra
.size main, .-main
.globl g_node_count
.globl g_largest_free
.globl g_free_total
.section .sbss,"aw",@nobits
.align 2
.type g_node_count, @object
.size g_node_count, 4
g_node_count:
.zero 4
.type g_largest_free, @object
.size g_largest_free, 4
g_largest_free:
.zero 4
.type g_free_total, @object
.size g_free_total, 4
g_free_total:
.zero 4
.ident "GCC: (15.2.0-23) 15.2.0"
.section .note.GNU-stack,"",@progbits
+74
View File
@@ -0,0 +1,74 @@
.file "task03_heap_init.c"
.option nopic
.attribute arch, "rv32i2p1_zicsr2p0_zifencei2p0"
.attribute unaligned_access, 0
.attribute stack_align, 16
.text
.align 2
.globl main
.type main, @function
main:
lla a2,.LANCHOR0
andi a4,a2,7
mv a5,a2
beq a4,zero,.L2
andi a5,a2,-8
addi a5,a5,8
.L2:
lla a3,.LANCHOR0+160
sub a3,a3,a5
addi a4,a5,-8
andi a3,a3,-8
add a4,a4,a3
sw a4,end_marker,a3
sw zero,0(a4)
sw zero,4(a4)
sw a4,0(a5)
sub a3,a4,a5
sw a3,4(a5)
lla a1,start
sw a5,0(a1)
sw zero,4(a1)
sub a5,a5,a2
sw a5,g_aligned_offset,a2
sw a3,g_initial_free_size,a5
lw a5,0(a4)
seqz a5,a5
sw a5,g_end_is_last,a4
li a0,0
ret
.size main, .-main
.globl g_end_is_last
.globl g_aligned_offset
.globl g_initial_free_size
.bss
.align 2
.set .LANCHOR0,. + 0
.type heap_area, @object
.size heap_area, 168
heap_area:
.zero 168
.section .sbss,"aw",@nobits
.align 2
.type g_end_is_last, @object
.size g_end_is_last, 4
g_end_is_last:
.zero 4
.type g_aligned_offset, @object
.size g_aligned_offset, 4
g_aligned_offset:
.zero 4
.type g_initial_free_size, @object
.size g_initial_free_size, 4
g_initial_free_size:
.zero 4
.type end_marker, @object
.size end_marker, 4
end_marker:
.zero 4
.type start, @object
.size start, 8
start:
.zero 8
.ident "GCC: (15.2.0-23) 15.2.0"
.section .note.GNU-stack,"",@progbits
+47
View File
@@ -0,0 +1,47 @@
.file "task04_alignment.c"
.option nopic
.attribute arch, "rv32i2p1_zicsr2p0_zifencei2p0"
.attribute unaligned_access, 0
.attribute stack_align, 16
.text
.align 2
.globl main
.type main, @function
main:
addi sp,sp,-32
li a5,16
sw a5,g_request_1,a4
li a5,24
sw a5,g_request_9,a4
li a5,32
sw a5,g_request_17,a4
li a5,7
sw a5,g_address_delta,a4
li a0,0
addi sp,sp,32
jr ra
.size main, .-main
.globl g_address_delta
.globl g_request_17
.globl g_request_9
.globl g_request_1
.section .sbss,"aw",@nobits
.align 2
.type g_address_delta, @object
.size g_address_delta, 4
g_address_delta:
.zero 4
.type g_request_17, @object
.size g_request_17, 4
g_request_17:
.zero 4
.type g_request_9, @object
.size g_request_9, 4
g_request_9:
.zero 4
.type g_request_1, @object
.size g_request_1, 4
g_request_1:
.zero 4
.ident "GCC: (15.2.0-23) 15.2.0"
.section .note.GNU-stack,"",@progbits
@@ -0,0 +1,95 @@
.file "task05_malloc_first_fit.c"
.option nopic
.attribute arch, "rv32i2p1_zicsr2p0_zifencei2p0"
.attribute unaligned_access, 0
.attribute stack_align, 16
.text
.align 2
.globl main
.type main, @function
main:
lla a4,.LANCHOR0
andi a5,a4,7
beq a5,zero,.L2
andi a4,a4,-8
addi a4,a4,8
.L2:
mv a5,a4
addi a3,a4,120
sw a3,end_marker,a2
sw zero,120(a4)
sw zero,4(a3)
sw a3,0(a4)
li a2,120
sw a2,4(a4)
lla a2,start
sw a4,0(a2)
sw zero,4(a2)
li a1,31
j .L5
.L6:
mv a5,a4
.L5:
lw a4,4(a5)
bgtu a4,a1,.L7
lw a4,0(a5)
mv a2,a5
bne a4,a3,.L6
li a5,0
j .L4
.L7:
lw a4,0(a5)
sw a4,0(a2)
sw zero,0(a5)
lw a4,4(a5)
li a3,-2147483648
or a4,a4,a3
sw a4,4(a5)
addi a5,a5,8
.L4:
snez a4,a5
sw a4,g_allocation_ok,a3
lw a5,-4(a5)
slli a5,a5,1
srli a5,a5,1
sw a5,g_allocated_size,a4
lw a5,start
lw a5,4(a5)
sw a5,g_remaining_free,a4
li a0,0
ret
.size main, .-main
.globl g_allocation_ok
.globl g_remaining_free
.globl g_allocated_size
.bss
.align 2
.set .LANCHOR0,. + 0
.type heap_area, @object
.size heap_area, 136
heap_area:
.zero 136
.section .sbss,"aw",@nobits
.align 2
.type g_allocation_ok, @object
.size g_allocation_ok, 4
g_allocation_ok:
.zero 4
.type g_remaining_free, @object
.size g_remaining_free, 4
g_remaining_free:
.zero 4
.type g_allocated_size, @object
.size g_allocated_size, 4
g_allocated_size:
.zero 4
.type end_marker, @object
.size end_marker, 4
end_marker:
.zero 4
.type start, @object
.size start, 8
start:
.zero 8
.ident "GCC: (15.2.0-23) 15.2.0"
.section .note.GNU-stack,"",@progbits
@@ -0,0 +1,117 @@
.file "task06_split_block.c"
.option nopic
.attribute arch, "rv32i2p1_zicsr2p0_zifencei2p0"
.attribute unaligned_access, 0
.attribute stack_align, 16
.text
.align 2
.globl main
.type main, @function
main:
lla a4,.LANCHOR0
andi a5,a4,7
beq a5,zero,.L2
andi a4,a4,-8
addi a4,a4,8
.L2:
mv a5,a4
addi a3,a4,176
sw a3,end_marker,a2
sw zero,176(a4)
sw zero,4(a3)
sw a3,0(a4)
li a2,176
sw a2,4(a4)
lla a2,start
sw a4,0(a2)
sw zero,4(a2)
li a1,39
j .L7
.L10:
mv a5,a4
.L7:
lw a4,4(a5)
bgtu a4,a1,.L13
lw a4,0(a5)
mv a2,a5
bne a4,a3,.L10
li a5,0
j .L6
.L13:
addi a4,a4,-40
li a1,16
bleu a4,a1,.L4
sw a4,44(a5)
lw a4,0(a5)
sw a4,40(a5)
addi a4,a5,40
sw a4,0(a2)
li a4,40
sw a4,4(a5)
.L5:
sw zero,0(a5)
lw a4,4(a5)
li a2,-2147483648
or a4,a4,a2
sw a4,4(a5)
addi a5,a5,8
.L6:
lw a5,-4(a5)
slli a5,a5,1
srli a5,a5,1
sw a5,g_allocated_size,a4
lw a5,start
lw a4,4(a5)
sw a4,g_split_free_size,a2
beq a5,a3,.L11
li a4,0
.L9:
addi a4,a4,1
lw a5,0(a5)
bne a5,a3,.L9
.L8:
sw a4,g_free_nodes,a5
li a0,0
ret
.L4:
lw a4,0(a5)
sw a4,0(a2)
j .L5
.L11:
li a4,0
j .L8
.size main, .-main
.globl g_free_nodes
.globl g_split_free_size
.globl g_allocated_size
.bss
.align 2
.set .LANCHOR0,. + 0
.type heap_area, @object
.size heap_area, 200
heap_area:
.zero 200
.section .sbss,"aw",@nobits
.align 2
.type g_free_nodes, @object
.size g_free_nodes, 4
g_free_nodes:
.zero 4
.type g_split_free_size, @object
.size g_split_free_size, 4
g_split_free_size:
.zero 4
.type g_allocated_size, @object
.size g_allocated_size, 4
g_allocated_size:
.zero 4
.type end_marker, @object
.size end_marker, 4
end_marker:
.zero 4
.type start, @object
.size start, 8
start:
.zero 8
.ident "GCC: (15.2.0-23) 15.2.0"
.section .note.GNU-stack,"",@progbits
@@ -0,0 +1,116 @@
.file "task07_free_insert.c"
.option nopic
.attribute arch, "rv32i2p1_zicsr2p0_zifencei2p0"
.attribute unaligned_access, 0
.attribute stack_align, 16
.text
.align 2
.globl main
.type main, @function
main:
lla a5,.LANCHOR0
lla a4,.LANCHOR0+176
sw a4,end_marker,a3
sw a5,start,a3
lla a3,.LANCHOR0+128
sw a3,0(a5)
sw a4,128(a5)
sw zero,176(a5)
li a4,40
sw a4,4(a5)
li a4,48
sw a4,132(a5)
sw zero,180(a5)
li a4,32
sw a4,68(a5)
lla a5,start
lla a3,.LANCHOR0+64
.L2:
mv a4,a5
lw a5,0(a5)
bltu a5,a3,.L2
lla a3,.LANCHOR0
sw a5,64(a3)
lla a5,.LANCHOR0+64
sw a5,0(a4)
lw a5,start
beq a5,a3,.L16
sw zero,g_order_ok,a4
lla a4,.LANCHOR0+176
beq a5,a4,.L5
.L9:
mv a4,a5
li a3,0
lla a2,.LANCHOR0+176
.L6:
addi a3,a3,1
lw a4,0(a4)
bne a4,a2,.L6
sw a3,g_free_count,a4
li a4,0
lla a2,.LANCHOR0+176
.L7:
lw a3,4(a5)
add a4,a4,a3
lw a5,0(a5)
bne a5,a2,.L7
.L8:
sw a4,g_total_free,a5
li a0,0
ret
.L16:
lla a3,.LANCHOR0+64
lw a2,.LANCHOR0
li a4,0
beq a2,a3,.L17
.L4:
sw a4,g_order_ok,a3
j .L9
.L17:
lla a3,.LANCHOR0+128
lw a2,.LANCHOR0+64
bne a2,a3,.L4
lla a3,.LANCHOR0+176
lw a4,.LANCHOR0+128
sub a4,a4,a3
seqz a4,a4
j .L4
.L5:
sw zero,g_free_count,a5
li a4,0
j .L8
.size main, .-main
.globl g_total_free
.globl g_free_count
.globl g_order_ok
.bss
.align 2
.set .LANCHOR0,. + 0
.type heap_area, @object
.size heap_area, 192
heap_area:
.zero 192
.section .sbss,"aw",@nobits
.align 2
.type g_total_free, @object
.size g_total_free, 4
g_total_free:
.zero 4
.type g_free_count, @object
.size g_free_count, 4
g_free_count:
.zero 4
.type g_order_ok, @object
.size g_order_ok, 4
g_order_ok:
.zero 4
.type end_marker, @object
.size end_marker, 4
end_marker:
.zero 4
.type start, @object
.size start, 8
start:
.zero 8
.ident "GCC: (15.2.0-23) 15.2.0"
.section .note.GNU-stack,"",@progbits
+116
View File
@@ -0,0 +1,116 @@
.file "task08_coalescing.c"
.option nopic
.attribute arch, "rv32i2p1_zicsr2p0_zifencei2p0"
.attribute unaligned_access, 0
.attribute stack_align, 16
.text
.align 2
.globl main
.type main, @function
main:
lla a5,.LANCHOR0
lla a4,.LANCHOR0+160
sw a4,end_marker,a3
sw a5,start,a3
lla a3,.LANCHOR0+96
sw a3,0(a5)
sw a4,96(a5)
sw zero,160(a5)
li a4,48
sw a4,4(a5)
sw a4,52(a5)
li a4,64
sw a4,100(a5)
sw zero,164(a5)
lla a5,start
lla a3,.LANCHOR0+48
.L2:
mv a4,a5
lw a5,0(a5)
bltu a5,a3,.L2
lla a3,.LANCHOR0+96
beq a5,a3,.L12
.L3:
sw a5,.LANCHOR0+48,a3
lla a5,start
lla a3,.LANCHOR0+48
beq a4,a5,.L4
lw a2,4(a4)
slli a5,a2,1
srli a5,a5,1
add a5,a4,a5
beq a5,a3,.L13
.L4:
sw a3,0(a4)
lw a2,start
lla a5,.LANCHOR0+160
beq a2,a5,.L9
mv a5,a2
li a4,0
lla a3,.LANCHOR0+160
.L6:
addi a4,a4,1
lw a5,0(a5)
bne a5,a3,.L6
.L5:
sw a4,g_free_count,a5
lw a5,4(a2)
sw a5,g_merged_size,a4
lw a5,0(a2)
lla a4,.LANCHOR0+160
sub a5,a5,a4
seqz a5,a5
sw a5,g_merged_with_right,a4
li a0,0
ret
.L12:
li a5,112
sw a5,.LANCHOR0+52,a3
lw a5,0(a4)
lw a5,0(a5)
j .L3
.L13:
lla a3,.LANCHOR0
lw a5,52(a3)
add a5,a5,a2
sw a5,4(a4)
lw a3,48(a3)
j .L4
.L9:
li a4,0
j .L5
.size main, .-main
.globl g_merged_with_right
.globl g_merged_size
.globl g_free_count
.bss
.align 2
.set .LANCHOR0,. + 0
.type heap_area, @object
.size heap_area, 192
heap_area:
.zero 192
.section .sbss,"aw",@nobits
.align 2
.type g_merged_with_right, @object
.size g_merged_with_right, 4
g_merged_with_right:
.zero 4
.type g_merged_size, @object
.size g_merged_size, 4
g_merged_size:
.zero 4
.type g_free_count, @object
.size g_free_count, 4
g_free_count:
.zero 4
.type end_marker, @object
.size end_marker, 4
end_marker:
.zero 4
.type start, @object
.size start, 8
start:
.zero 8
.ident "GCC: (15.2.0-23) 15.2.0"
.section .note.GNU-stack,"",@progbits
@@ -0,0 +1,44 @@
.file "task09_config_macros.c"
.option nopic
.attribute arch, "rv32i2p1_zicsr2p0_zifencei2p0"
.attribute unaligned_access, 0
.attribute stack_align, 16
.text
.align 2
.globl main
.type main, @function
main:
li a5,256
sw a5,g_total_heap,a4
li a5,248
sw a5,g_adjusted_heap,a4
li a5,1
sw a5,g_dynamic_enabled,a4
sw zero,g_trace_is_host_only,a5
li a0,0
ret
.size main, .-main
.globl g_trace_is_host_only
.globl g_dynamic_enabled
.globl g_adjusted_heap
.globl g_total_heap
.section .sbss,"aw",@nobits
.align 2
.type g_trace_is_host_only, @object
.size g_trace_is_host_only, 4
g_trace_is_host_only:
.zero 4
.type g_dynamic_enabled, @object
.size g_dynamic_enabled, 4
g_dynamic_enabled:
.zero 4
.type g_adjusted_heap, @object
.size g_adjusted_heap, 4
g_adjusted_heap:
.zero 4
.type g_total_heap, @object
.size g_total_heap, 4
g_total_heap:
.zero 4
.ident "GCC: (15.2.0-23) 15.2.0"
.section .note.GNU-stack,"",@progbits
+253
View File
@@ -0,0 +1,253 @@
.file "task10_heap4_demo.c"
.option nopic
.attribute arch, "rv32i2p1_zicsr2p0_zifencei2p0"
.attribute unaligned_access, 0
.attribute stack_align, 16
.text
.align 2
.type heap_malloc_model, @function
heap_malloc_model:
beq a0,zero,.L1
addi a4,a0,8
andi a0,a0,7
beq a0,zero,.L3
andi a4,a4,-8
addi a4,a4,8
.L3:
lw a0,start
lw a3,end_marker
beq a0,a3,.L10
lla a2,start
j .L8
.L11:
mv a0,a5
.L8:
lw a5,4(a0)
bgeu a5,a4,.L12
lw a5,0(a0)
mv a2,a0
bne a5,a3,.L11
li a0,0
ret
.L12:
sub a3,a5,a4
li a1,16
bleu a3,a1,.L5
add a5,a0,a4
sw a3,4(a5)
lw a3,0(a0)
sw a3,0(a5)
sw a5,0(a2)
sw a4,4(a0)
.L6:
sw zero,0(a0)
lw a5,4(a0)
li a3,-2147483648
or a5,a5,a3
sw a5,4(a0)
lla a3,free_bytes_remaining
lw a5,0(a3)
sub a5,a5,a4
sw a5,0(a3)
lw a4,minimum_ever_free
bgeu a5,a4,.L7
sw a5,minimum_ever_free,a4
.L7:
addi a0,a0,8
ret
.L5:
lw a4,0(a0)
sw a4,0(a2)
mv a4,a5
j .L6
.L10:
li a0,0
.L1:
ret
.size heap_malloc_model, .-heap_malloc_model
.align 2
.type heap_free_model, @function
heap_free_model:
beq a0,zero,.L13
lw a5,-4(a0)
blt a5,zero,.L19
.L13:
ret
.L19:
addi a3,a0,-8
slli a5,a5,1
srli a2,a5,1
sw a2,-4(a0)
lla a4,free_bytes_remaining
lw a5,0(a4)
add a5,a5,a2
sw a5,0(a4)
lla a5,start
.L15:
mv a4,a5
lw a5,0(a5)
bgtu a3,a5,.L15
add a1,a3,a2
beq a5,a1,.L20
.L16:
sw a5,-8(a0)
lla a5,start
beq a4,a5,.L17
lw a2,4(a4)
slli a5,a2,1
srli a5,a5,1
add a5,a4,a5
beq a3,a5,.L21
.L17:
sw a3,0(a4)
ret
.L20:
lw a5,4(a5)
add a5,a5,a2
sw a5,-4(a0)
lw a5,0(a4)
lw a5,0(a5)
j .L16
.L21:
lw a5,-4(a0)
add a5,a5,a2
sw a5,4(a4)
lw a5,-8(a0)
sw a5,0(a4)
ret
.size heap_free_model, .-heap_free_model
.align 2
.globl main
.type main, @function
main:
addi sp,sp,-32
sw ra,28(sp)
sw s0,24(sp)
sw s1,20(sp)
sw s2,16(sp)
sw s3,12(sp)
sw s4,8(sp)
lla a4,.LANCHOR0
andi a3,a4,7
mv a5,a4
beq a3,zero,.L23
andi a4,a4,-8
addi a5,a4,8
.L23:
lla s0,.LANCHOR0+256
sub s0,s0,a5
andi s0,s0,-8
addi a4,a5,-8
add s0,s0,a4
sw s0,end_marker,a4
sw zero,0(s0)
sw zero,4(s0)
sw s0,0(a5)
sub a4,s0,a5
sw a4,4(a5)
lla s4,start
sw a5,0(s4)
sw zero,4(s4)
sw a4,free_bytes_remaining,a5
sw a4,minimum_ever_free,a5
li a0,24
call heap_malloc_model
mv s2,a0
li a0,40
call heap_malloc_model
mv s3,a0
mv a0,s2
call heap_free_model
li a0,16
call heap_malloc_model
mv s1,a0
mv a0,s3
call heap_free_model
mv a0,s1
call heap_free_model
snez s2,s2
snez s3,s3
and s2,s2,s3
snez s1,s1
and s1,s1,s2
sw s1,g_allocations_ok,a5
lw a5,0(s4)
beq s0,a5,.L24
mv a4,a5
li a3,0
.L25:
addi a3,a3,1
lw a4,0(a4)
bne s0,a4,.L25
sw a3,g_final_free_nodes,a2
li a3,0
.L26:
lw a2,4(a5)
add a3,a3,a2
lw a5,0(a5)
bne a5,a4,.L26
.L27:
sw a3,g_final_free_total,a5
lw a5,minimum_ever_free
sw a5,g_minimum_ever_free,a4
li a0,0
lw ra,28(sp)
lw s0,24(sp)
lw s1,20(sp)
lw s2,16(sp)
lw s3,12(sp)
lw s4,8(sp)
addi sp,sp,32
jr ra
.L24:
sw zero,g_final_free_nodes,a5
li a3,0
j .L27
.size main, .-main
.globl g_minimum_ever_free
.globl g_final_free_total
.globl g_final_free_nodes
.globl g_allocations_ok
.bss
.align 2
.set .LANCHOR0,. + 0
.type heap_area, @object
.size heap_area, 264
heap_area:
.zero 264
.section .sbss,"aw",@nobits
.align 2
.type minimum_ever_free, @object
.size minimum_ever_free, 4
minimum_ever_free:
.zero 4
.type free_bytes_remaining, @object
.size free_bytes_remaining, 4
free_bytes_remaining:
.zero 4
.type g_minimum_ever_free, @object
.size g_minimum_ever_free, 4
g_minimum_ever_free:
.zero 4
.type g_final_free_total, @object
.size g_final_free_total, 4
g_final_free_total:
.zero 4
.type g_final_free_nodes, @object
.size g_final_free_nodes, 4
g_final_free_nodes:
.zero 4
.type g_allocations_ok, @object
.size g_allocations_ok, 4
g_allocations_ok:
.zero 4
.type end_marker, @object
.size end_marker, 4
end_marker:
.zero 4
.type start, @object
.size start, 8
start:
.zero 8
.ident "GCC: (15.2.0-23) 15.2.0"
.section .note.GNU-stack,"",@progbits
+33
View File
@@ -0,0 +1,33 @@
.text
.global _start
.type _start, @function
_start:
# Initialize global pointer.
.option push
.option norelax
la gp, __global_pointer$
.option pop
# Stack pointer is intentionally not set here.
# In the Hazard3 testbench flow, common/init.S enters _start with sp
# already loaded from __stack_top and adjusted to leave the argc/argv
# area expected by newlib-style startup code.
# Clear the .bss segment so debug globals start in a known state.
la a0, __bss_start
la a1, __bss_end
clear_bss:
bgeu a0, a1, finish_bss
sb x0, 0(a0)
addi a0, a0, 1
j clear_bss
finish_bss:
call main
# Exit the testbench with main() return code (Hazard3 init.S provides _exit).
tail _exit
.size _start, .-_start
+153
View File
@@ -0,0 +1,153 @@
\documentclass[12pt]{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[polish]{babel}
\usepackage[a4paper,margin=2.0cm]{geometry}
\usepackage{array}
\usepackage{tabularx}
\usepackage{xcolor}
\usepackage{listings}
\usepackage{hyperref}
\usepackage{fancyhdr}
\usepackage{lastpage}
\usepackage{enumitem}
\definecolor{accent}{HTML}{16324A}
\definecolor{accentlight}{HTML}{EEF3F7}
\definecolor{rulegray}{HTML}{D7DEE5}
\hypersetup{colorlinks=true,linkcolor=blue,urlcolor=blue,citecolor=blue}
\IfFileExists{build-meta.tex}{\input{build-meta.tex}}{\newcommand{\BuildCommit}{local}}
\newcommand{\PublisherDomain}{mpabi}
\newcommand{\DocumentAuthor}{M. Pabiszczak}
\newcommand{\DocumentYear}{2026}
\newcommand{\CardArea}{inf}
\newcommand{\CardSeries}{rv32i-freertos}
\newcommand{\CardNumber}{01}
\newcommand{\CardCount}{??}
\newcommand{\CardSlug}{heap4}
\newcommand{\CardVersion}{v0.1}
\newcommand{\DocumentKey}{\PublisherDomain/\CardArea/\CardSeries/\CardNumber/\CardSlug/\CardVersion}
\newcommand{\DocumentUUID}{4654524c-73f2-46df-83a3-d448ba6d6c5a}
\renewcommand{\lstlistingname}{Listing}
\renewcommand{\lstlistlistingname}{Lista listingów}
\lstset{basicstyle=\ttfamily\small,columns=fullflexible,keepspaces=true,frame=single,breaklines=true,showstringspaces=false,numbers=left,numberstyle=\tiny\color{accent},stepnumber=1,numbersep=8pt,backgroundcolor=\color{accentlight},rulecolor=\color{rulegray},captionpos=b}
\newcommand{\TaskSection}[4]{\section{Task #1: #3}#4\lstinputlisting[language=C,caption={Task #1: #3},label={lst:task#1-c}]{../src/tasks/#2.c}\lstinputlisting[basicstyle=\ttfamily\scriptsize,caption={ASM dla task #1},label={lst:task#1-asm}]{../build/#2/#2.s}}
\pagestyle{fancy}
\fancyhf{}
\lhead{\textbf{FreeRTOS: heap\_4}}
\rhead{\small \DocumentAuthor, \DocumentYear}
\lfoot{\scriptsize commit \BuildCommit}
\cfoot{\scriptsize \thepage/\pageref{LastPage}}
\rfoot{\scriptsize uuid \DocumentUUID}
\renewcommand{\headrulewidth}{0.4pt}
\setlength{\headheight}{18pt}
\setlength{\footskip}{24pt}
\begin{document}
\sloppy
\noindent
\begin{tabular}{@{}lp{0.72\textwidth}@{}}
Project: & FreeRTOS: \texttt{heap\_4} \\
Subject: & Informatyka \\
Level: & 1, Zakres Podstawowy, PP \\
Topic: & dynamiczna alokacja pamięci, lista wolnych bloków, scalanie bloków \\
Revision date: & 02.05.2026 \\
Status: & Draft \\
Card in series: & \small\texttt{\CardNumber/\CardCount} \\
Card version: & \small\texttt{\CardVersion} \\
Card key: & \small\texttt{\DocumentKey} \\
UUID: & \small\texttt{\DocumentUUID} \\
Commit: & \small\texttt{\BuildCommit} \\
Scope: & pierwsza karta serii FreeRTOS; model dydaktyczny mechaniki \texttt{heap\_4.c} \\
Files used: & \small
\begin{tabular}[t]{@{}l@{}}
Task01: \texttt{task01\_heap\_map.c} \\
Task02: \texttt{task02\_free\_list.c} \\
Task03: \texttt{task03\_heap\_init.c} \\
Task04: \texttt{task04\_alignment.c} \\
Task05: \texttt{task05\_malloc\_first\_fit.c} \\
Task06: \texttt{task06\_split\_block.c} \\
Task07: \texttt{task07\_free\_insert.c} \\
Task08: \texttt{task08\_coalescing.c} \\
Task09: \texttt{task09\_config\_macros.c} \\
Task10: \texttt{task10\_heap4\_demo.c} \\
Common: \texttt{heap4\_common.h} \\
Runtime: \texttt{memops.c} \\
Startup: \texttt{crt0.S}
\end{tabular}
\end{tabular}
\vspace{0.8em}
\noindent\rule{\textwidth}{0.5pt}
\section{Cel}
Ta karta zaczyna serię FreeRTOS od \texttt{heap\_4}, ponieważ ten plik jest
naturalnym pomostem po kartach z języka C. Wymaga wskaźników, tablic,
struktur, listy jednokierunkowej, \texttt{static}, \texttt{typedef}, makr oraz
arytmetyki adresów, ale nie wymaga jeszcze schedulera, przerwań ani
uruchamiania tasków.
Przykłady są małym modelem edukacyjnym mechaniki \texttt{heap\_4.c}. Nie są
kopią pliku upstream FreeRTOS. Na RV32I wyniki są zapisywane w globalnych
zmiennych \texttt{volatile}; \texttt{printf} jest dostępny wyłącznie w wariancie
hostowym przez flagę \texttt{-DHOST\_PRINTF=1}.
\lstinputlisting[language=C,caption={Wspólny nagłówek dla karty \texttt{heap\_4}},label={lst:common-h}]{../src/tasks/heap4_common.h}
\subsection{\texttt{static inline} w nagłówku}
Helpery z Listingu~\ref{lst:common-h} są zapisane jako \texttt{static inline},
bo każdy task jest osobnym programem i dołącza ten sam nagłówek. \texttt{static}
daje prywatną kopię funkcji w każdym pliku \texttt{.c}, a \texttt{inline}
pozwala kompilatorowi wstawić krótkie obliczenia, takie jak wyrównanie rozmiaru
lub sprawdzenie bitu alokacji, bez kosztu zwykłego wywołania funkcji.
\section{Mapa karty}
\begin{tabularx}{\textwidth}{|p{2.1cm}|X|}
\hline
Task & Temat \\
\hline
1 & Mapa pojęć: obszar sterty, nagłówek bloku i bit alokacji. \\
\hline
2 & Lista wolnych bloków jako lista jednokierunkowa. \\
\hline
3 & Inicjalizacja sterty, pierwszy wolny blok i wartownik końca listy. \\
\hline
4 & Wyrównanie rozmiarów żądań i adresu początku sterty. \\
\hline
5 & Pierwszy pasujący blok, czyli zasada \texttt{first fit}. \\
\hline
6 & Podział dużego bloku na część przydzieloną i pozostały blok wolny. \\
\hline
7 & Zwracanie bloku i wstawianie go do listy według adresu. \\
\hline
8 & Scalanie sąsiednich wolnych bloków. \\
\hline
9 & Makra konfiguracyjne oraz hostowy \texttt{TRACE\_PRINTF}. \\
\hline
10 & Mini-demonstracja sekwencji \texttt{malloc/free}. \\
\hline
\end{tabularx}
\TaskSection{01}{task01_heap_map}{mapa \texttt{heap\_4}}{Listing~\ref{lst:task01-c} pokazuje nagłówek bloku, wyrównanie rozmiaru i bit oznaczający blok zajęty.}
\TaskSection{02}{task02_free_list}{lista wolnych bloków}{Listing~\ref{lst:task02-c} przechodzi po liście wolnych bloków i liczy sumę dostępnej pamięci.}
\TaskSection{03}{task03_heap_init}{inicjalizacja sterty}{Listing~\ref{lst:task03-c} tworzy pierwszy wolny blok oraz końcowy znacznik listy.}
\TaskSection{04}{task04_alignment}{wyrównanie}{Listing~\ref{lst:task04-c} pokazuje, dlaczego alokator zaokrągla rozmiary i adres początku sterty.}
\TaskSection{05}{task05_malloc_first_fit}{\texttt{first fit}}{Listing~\ref{lst:task05-c} wybiera pierwszy wolny blok wystarczająco duży dla żądania.}
\TaskSection{06}{task06_split_block}{podział bloku}{Listing~\ref{lst:task06-c} zostawia resztę dużego bloku na liście wolnych bloków.}
\TaskSection{07}{task07_free_insert}{\texttt{free} i wstawianie}{Listing~\ref{lst:task07-c} zwraca blok do listy tak, aby lista pozostała posortowana po adresach.}
\TaskSection{08}{task08_coalescing}{scalanie bloków}{Listing~\ref{lst:task08-c} scala blok z lewym i prawym sąsiadem, gdy adresy są ciągłe.}
\TaskSection{09}{task09_config_macros}{makra konfiguracyjne}{Listing~\ref{lst:task09-c} pokazuje małe odpowiedniki makr konfiguracyjnych FreeRTOS-a.}
\TaskSection{10}{task10_heap4_demo}{mini \texttt{heap\_4}}{Listing~\ref{lst:task10-c} łączy inicjalizację, alokację, zwalnianie i scalanie w jeden model.}
\section{Polecenia}
\begin{enumerate}[leftmargin=1.6em]
\item Zbuduj kartę dla RV32I poleceniem \texttt{make tasks}.
\item Zbuduj wariant hostowy poleceniem \texttt{make host}; wypisywanie działa tylko przez \texttt{HOST\_PRINTF}.
\item W tasku 6 zmień próg \texttt{MIN\_SPLIT\_SIZE} i sprawdź, kiedy blok nie jest dzielony.
\item W tasku 8 zmień rozmiary bloków tak, aby scalanie działało tylko z prawym sąsiadem.
\item W tasku 10 dodaj większą alokację, która ma się nie udać, i zapisz status w nowej zmiennej \texttt{volatile}.
\end{enumerate}
\end{document}
View File
+70
View File
@@ -0,0 +1,70 @@
#!/usr/bin/env sh
set -eu
DOC_DIR="doc"
TEX_FILE="main.tex"
script_dir=$(CDPATH= cd "$(dirname "$0")" && pwd)
repo_root=$(CDPATH= cd "$script_dir/.." && pwd)
repo_name="${REPO_NAME:-$(basename "$repo_root")}"
tex_path="$repo_root/$DOC_DIR/$TEX_FILE"
read_tex_command() {
sed -n "s/^\\\\newcommand{\\\\$1}{\\([^}]*\\)}$/\\1/p" "$tex_path" | head -n 1
}
publisher_domain=$(read_tex_command PublisherDomain)
card_area=$(read_tex_command CardArea)
card_series=$(read_tex_command CardSeries)
card_number=$(read_tex_command CardNumber)
card_slug=$(read_tex_command CardSlug)
card_version=$(read_tex_command CardVersion)
document_uuid=$(read_tex_command DocumentUUID)
if [ -z "$publisher_domain" ] || [ -z "$card_area" ] || [ -z "$card_series" ] || \
[ -z "$card_number" ] || [ -z "$card_slug" ] || [ -z "$card_version" ] || \
[ -z "$document_uuid" ]; then
echo "missing card metadata in $tex_path" >&2
exit 1
fi
commit="${GITEA_SHA:-${GITHUB_SHA:-}}"
if [ -z "$commit" ]; then
commit=$(git -C "$repo_root" rev-parse HEAD)
fi
short_commit=$(printf '%s' "$commit" | cut -c1-12)
meta_file="$repo_root/$DOC_DIR/build-meta.tex"
tmp_meta="$meta_file.tmp.$$"
cleanup() {
rm -f "$meta_file" "$tmp_meta"
}
trap cleanup EXIT HUP INT TERM
printf '\\newcommand{\\BuildCommit}{%s}\n' "$short_commit" > "$tmp_meta"
mv "$tmp_meta" "$meta_file"
pdf_out_dir="${PDF_OUT_DIR:-$repo_root/doc/pdf}"
mkdir -p "$pdf_out_dir"
out_dir=$(CDPATH= cd "$pdf_out_dir" && pwd)
pdf_basename="$publisher_domain-$card_area-$card_series-$card_number-$card_slug-$card_version-$document_uuid.pdf"
find "$out_dir" -maxdepth 1 -type f -name '*.pdf' -delete
(
cd "$repo_root/$DOC_DIR"
latexmk -pdf -interaction=nonstopmode -outdir="$out_dir" "$TEX_FILE"
)
source_pdf="$out_dir/${TEX_FILE%.tex}.pdf"
target_pdf="$out_dir/$pdf_basename"
if [ "$source_pdf" != "$target_pdf" ]; then
mv "$source_pdf" "$target_pdf"
fi
find "$out_dir" -maxdepth 1 -type f \( \
-name '*.aux' -o \
-name '*.log' -o \
-name '*.out' -o \
-name '*.fls' -o \
-name '*.fdb_latexmk' \
\) -delete
+61
View File
@@ -0,0 +1,61 @@
#ifndef HEAP4_COMMON_H
#define HEAP4_COMMON_H
#include <stddef.h>
#include <stdint.h>
#ifdef HOST_PRINTF
#include <stdio.h>
#define TRACE_PRINTF(...) printf(__VA_ARGS__)
#else
#define TRACE_PRINTF(...) ((void)0)
#endif
#define HEAP4_ARRAY_LEN(a) ((int)(sizeof(a) / sizeof((a)[0])))
#define HEAP4_ALIGNMENT ((size_t)8)
#define HEAP4_ALIGNMENT_MASK (HEAP4_ALIGNMENT - 1U)
#define HEAP4_ALLOCATED_BIT ((size_t)1U << (sizeof(size_t) * 8U - 1U))
typedef struct HeapBlock {
struct HeapBlock *next;
size_t size;
} HeapBlock;
static inline size_t heap4_align_up(size_t value)
{
if ((value & HEAP4_ALIGNMENT_MASK) != 0U)
value += HEAP4_ALIGNMENT - (value & HEAP4_ALIGNMENT_MASK);
return value;
}
static inline uintptr_t heap4_align_address(uintptr_t address)
{
uintptr_t mask;
mask = (uintptr_t)HEAP4_ALIGNMENT_MASK;
if ((address & mask) != 0U)
address += (uintptr_t)HEAP4_ALIGNMENT - (address & mask);
return address;
}
static inline size_t heap4_clear_allocated(size_t size)
{
return size & ~HEAP4_ALLOCATED_BIT;
}
static inline size_t heap4_mark_allocated(size_t size)
{
return size | HEAP4_ALLOCATED_BIT;
}
static inline int heap4_is_allocated(size_t size)
{
return (size & HEAP4_ALLOCATED_BIT) != 0U;
}
static inline int heap4_blocks_touch(HeapBlock *left, HeapBlock *right)
{
return (uint8_t *)left + heap4_clear_allocated(left->size) == (uint8_t *)right;
}
#endif
+29
View File
@@ -0,0 +1,29 @@
#include "heap4_common.h"
volatile size_t g_header_size;
volatile size_t g_aligned_header_size;
volatile size_t g_allocated_bit_set;
volatile size_t g_user_bytes;
volatile size_t g_total_block_bytes;
int main(void)
{
HeapBlock block;
size_t requested;
requested = 13U;
block.next = 0;
block.size = heap4_mark_allocated(heap4_align_up(requested + sizeof(HeapBlock)));
g_header_size = sizeof(HeapBlock);
g_aligned_header_size = heap4_align_up(sizeof(HeapBlock));
g_allocated_bit_set = heap4_is_allocated(block.size);
g_total_block_bytes = heap4_clear_allocated(block.size);
g_user_bytes = g_total_block_bytes - sizeof(HeapBlock);
TRACE_PRINTF("header=%u aligned=%u allocated=%u total=%u user=%u\n",
(unsigned)g_header_size, (unsigned)g_aligned_header_size,
(unsigned)g_allocated_bit_set, (unsigned)g_total_block_bytes,
(unsigned)g_user_bytes);
return 0;
}
+64
View File
@@ -0,0 +1,64 @@
#include "heap4_common.h"
volatile size_t g_free_total;
volatile size_t g_largest_free;
volatile int g_node_count;
static size_t list_total(HeapBlock *start)
{
HeapBlock *block;
size_t total;
total = 0U;
for (block = start->next; block != 0; block = block->next)
total += block->size;
return total;
}
static size_t list_largest(HeapBlock *start)
{
HeapBlock *block;
size_t largest;
largest = 0U;
for (block = start->next; block != 0; block = block->next)
if (block->size > largest)
largest = block->size;
return largest;
}
static int list_count(HeapBlock *start)
{
HeapBlock *block;
int count;
count = 0;
for (block = start->next; block != 0; block = block->next)
count++;
return count;
}
int main(void)
{
HeapBlock start;
HeapBlock a;
HeapBlock b;
HeapBlock c;
start.next = &a;
start.size = 0U;
a.next = &b;
a.size = 32U;
b.next = &c;
b.size = 80U;
c.next = 0;
c.size = 24U;
g_free_total = list_total(&start);
g_largest_free = list_largest(&start);
g_node_count = list_count(&start);
TRACE_PRINTF("free=%u largest=%u count=%d\n",
(unsigned)g_free_total, (unsigned)g_largest_free, g_node_count);
return 0;
}
+49
View File
@@ -0,0 +1,49 @@
#include "heap4_common.h"
#define HEAP_BYTES 160U
static uint8_t heap_area[HEAP_BYTES + HEAP4_ALIGNMENT];
static HeapBlock start;
static HeapBlock *end_marker;
volatile size_t g_initial_free_size;
volatile uintptr_t g_aligned_offset;
volatile int g_end_is_last;
static void heap_init(void)
{
uintptr_t raw;
uintptr_t aligned;
size_t available;
HeapBlock *first;
raw = (uintptr_t)&heap_area[0];
aligned = heap4_align_address(raw);
available = HEAP_BYTES - (size_t)(aligned - raw);
available &= ~HEAP4_ALIGNMENT_MASK;
first = (HeapBlock *)aligned;
end_marker = (HeapBlock *)(aligned + available - sizeof(HeapBlock));
end_marker->next = 0;
end_marker->size = 0U;
first->next = end_marker;
first->size = (uint8_t *)end_marker - (uint8_t *)first;
start.next = first;
start.size = 0U;
}
int main(void)
{
heap_init();
g_aligned_offset = (uintptr_t)start.next - (uintptr_t)&heap_area[0];
g_initial_free_size = start.next->size;
g_end_is_last = (start.next->next == end_marker) && (end_marker->next == 0);
TRACE_PRINTF("offset=%u free=%u end_last=%d\n",
(unsigned)g_aligned_offset, (unsigned)g_initial_free_size,
g_end_is_last);
return 0;
}
+26
View File
@@ -0,0 +1,26 @@
#include "heap4_common.h"
volatile size_t g_request_1;
volatile size_t g_request_9;
volatile size_t g_request_17;
volatile uintptr_t g_address_delta;
int main(void)
{
uint8_t bytes[32];
uintptr_t raw;
uintptr_t aligned;
g_request_1 = heap4_align_up(1U + sizeof(HeapBlock));
g_request_9 = heap4_align_up(9U + sizeof(HeapBlock));
g_request_17 = heap4_align_up(17U + sizeof(HeapBlock));
raw = (uintptr_t)&bytes[1];
aligned = heap4_align_address(raw);
g_address_delta = aligned - raw;
TRACE_PRINTF("r1=%u r9=%u r17=%u delta=%u\n",
(unsigned)g_request_1, (unsigned)g_request_9,
(unsigned)g_request_17, (unsigned)g_address_delta);
return 0;
}
+73
View File
@@ -0,0 +1,73 @@
#include "heap4_common.h"
#define HEAP_BYTES 128U
static uint8_t heap_area[HEAP_BYTES + HEAP4_ALIGNMENT];
static HeapBlock start;
static HeapBlock *end_marker;
volatile size_t g_allocated_size;
volatile size_t g_remaining_free;
volatile int g_allocation_ok;
static void heap_init_one_block(void)
{
uintptr_t raw;
uintptr_t aligned;
HeapBlock *first;
raw = (uintptr_t)&heap_area[0];
aligned = heap4_align_address(raw);
first = (HeapBlock *)aligned;
end_marker = (HeapBlock *)(aligned + 120U);
end_marker->next = 0;
end_marker->size = 0U;
first->next = end_marker;
first->size = (uint8_t *)end_marker - (uint8_t *)first;
start.next = first;
start.size = 0U;
}
static void *heap_malloc_whole_block(size_t wanted)
{
HeapBlock *previous;
HeapBlock *block;
size_t total;
total = heap4_align_up(wanted + sizeof(HeapBlock));
previous = &start;
block = start.next;
while (block != end_marker) {
if (block->size >= total) {
previous->next = block->next;
block->next = 0;
block->size = heap4_mark_allocated(block->size);
return (uint8_t *)block + sizeof(HeapBlock);
}
previous = block;
block = block->next;
}
return 0;
}
int main(void)
{
void *p;
HeapBlock *allocated;
heap_init_one_block();
p = heap_malloc_whole_block(24U);
allocated = (HeapBlock *)((uint8_t *)p - sizeof(HeapBlock));
g_allocation_ok = p != 0;
g_allocated_size = heap4_clear_allocated(allocated->size);
g_remaining_free = start.next->size;
TRACE_PRINTF("ok=%d allocated=%u remaining=%u\n",
g_allocation_ok, (unsigned)g_allocated_size,
(unsigned)g_remaining_free);
return 0;
}
+93
View File
@@ -0,0 +1,93 @@
#include "heap4_common.h"
#define HEAP_BYTES 192U
#define MIN_SPLIT_SIZE ((size_t)(sizeof(HeapBlock) * 2U))
static uint8_t heap_area[HEAP_BYTES + HEAP4_ALIGNMENT];
static HeapBlock start;
static HeapBlock *end_marker;
volatile size_t g_allocated_size;
volatile size_t g_split_free_size;
volatile int g_free_nodes;
static void heap_init_one_block(void)
{
uintptr_t aligned;
HeapBlock *first;
aligned = heap4_align_address((uintptr_t)&heap_area[0]);
first = (HeapBlock *)aligned;
end_marker = (HeapBlock *)(aligned + 176U);
end_marker->next = 0;
end_marker->size = 0U;
first->next = end_marker;
first->size = (uint8_t *)end_marker - (uint8_t *)first;
start.next = first;
start.size = 0U;
}
static void *heap_malloc_split(size_t wanted)
{
HeapBlock *previous;
HeapBlock *block;
HeapBlock *remainder;
size_t total;
size_t original;
total = heap4_align_up(wanted + sizeof(HeapBlock));
previous = &start;
block = start.next;
while (block != end_marker) {
if (block->size >= total) {
original = block->size;
if (original - total > MIN_SPLIT_SIZE) {
remainder = (HeapBlock *)((uint8_t *)block + total);
remainder->size = original - total;
remainder->next = block->next;
previous->next = remainder;
block->size = total;
} else {
previous->next = block->next;
}
block->next = 0;
block->size = heap4_mark_allocated(block->size);
return (uint8_t *)block + sizeof(HeapBlock);
}
previous = block;
block = block->next;
}
return 0;
}
static int count_free_nodes(void)
{
HeapBlock *block;
int count;
count = 0;
for (block = start.next; block != end_marker; block = block->next)
count++;
return count;
}
int main(void)
{
void *p;
HeapBlock *allocated;
heap_init_one_block();
p = heap_malloc_split(32U);
allocated = (HeapBlock *)((uint8_t *)p - sizeof(HeapBlock));
g_allocated_size = heap4_clear_allocated(allocated->size);
g_split_free_size = start.next->size;
g_free_nodes = count_free_nodes();
TRACE_PRINTF("allocated=%u split=%u nodes=%d\n",
(unsigned)g_allocated_size, (unsigned)g_split_free_size,
g_free_nodes);
return 0;
}
+88
View File
@@ -0,0 +1,88 @@
#include "heap4_common.h"
static uint8_t heap_area[192];
static HeapBlock start;
static HeapBlock *end_marker;
volatile int g_order_ok;
volatile int g_free_count;
volatile size_t g_total_free;
static void insert_block(HeapBlock *block)
{
HeapBlock *iterator;
for (iterator = &start; iterator->next < block; iterator = iterator->next)
;
block->next = iterator->next;
iterator->next = block;
}
static void heap_free_model(void *p)
{
HeapBlock *block;
if (p == 0)
return;
block = (HeapBlock *)((uint8_t *)p - sizeof(HeapBlock));
block->size = heap4_clear_allocated(block->size);
insert_block(block);
}
static int count_free(void)
{
HeapBlock *block;
int count;
count = 0;
for (block = start.next; block != end_marker; block = block->next)
count++;
return count;
}
static size_t total_free(void)
{
HeapBlock *block;
size_t total;
total = 0U;
for (block = start.next; block != end_marker; block = block->next)
total += block->size;
return total;
}
int main(void)
{
HeapBlock *a;
HeapBlock *b;
HeapBlock *c;
void *payload;
a = (HeapBlock *)&heap_area[0];
b = (HeapBlock *)&heap_area[64];
c = (HeapBlock *)&heap_area[128];
end_marker = (HeapBlock *)&heap_area[176];
start.next = a;
a->next = c;
c->next = end_marker;
end_marker->next = 0;
a->size = 40U;
b->size = heap4_mark_allocated(32U);
c->size = 48U;
end_marker->size = 0U;
payload = (uint8_t *)b + sizeof(HeapBlock);
heap_free_model(payload);
g_order_ok = start.next == a && a->next == b && b->next == c && c->next == end_marker;
g_free_count = count_free();
g_total_free = total_free();
TRACE_PRINTF("order=%d count=%d total=%u\n",
g_order_ok, g_free_count, (unsigned)g_total_free);
return 0;
}
+76
View File
@@ -0,0 +1,76 @@
#include "heap4_common.h"
static uint8_t heap_area[192];
static HeapBlock start;
static HeapBlock *end_marker;
volatile int g_free_count;
volatile size_t g_merged_size;
volatile int g_merged_with_right;
static void insert_block_merge(HeapBlock *block)
{
HeapBlock *iterator;
uint8_t *block_end;
for (iterator = &start; iterator->next < block; iterator = iterator->next)
;
block_end = (uint8_t *)block + block->size;
if (block_end == (uint8_t *)iterator->next) {
block->size += iterator->next->size;
block->next = iterator->next->next;
} else {
block->next = iterator->next;
}
if (iterator != &start && heap4_blocks_touch(iterator, block)) {
iterator->size += block->size;
iterator->next = block->next;
} else {
iterator->next = block;
}
}
static int count_free(void)
{
HeapBlock *block;
int count;
count = 0;
for (block = start.next; block != end_marker; block = block->next)
count++;
return count;
}
int main(void)
{
HeapBlock *left;
HeapBlock *middle;
HeapBlock *right;
left = (HeapBlock *)&heap_area[0];
middle = (HeapBlock *)&heap_area[48];
right = (HeapBlock *)&heap_area[96];
end_marker = (HeapBlock *)&heap_area[160];
start.next = left;
left->next = right;
right->next = end_marker;
end_marker->next = 0;
left->size = 48U;
middle->size = 48U;
right->size = 64U;
end_marker->size = 0U;
insert_block_merge(middle);
g_free_count = count_free();
g_merged_size = start.next->size;
g_merged_with_right = start.next->next == end_marker;
TRACE_PRINTF("count=%d size=%u merged_right=%d\n",
g_free_count, (unsigned)g_merged_size, g_merged_with_right);
return 0;
}
+34
View File
@@ -0,0 +1,34 @@
#include "heap4_common.h"
#ifndef CONFIG_TOTAL_HEAP_SIZE
#define CONFIG_TOTAL_HEAP_SIZE 256U
#endif
#ifndef CONFIG_SUPPORT_DYNAMIC_ALLOCATION
#define CONFIG_SUPPORT_DYNAMIC_ALLOCATION 1
#endif
#define CONFIG_ADJUSTED_HEAP_SIZE (CONFIG_TOTAL_HEAP_SIZE - HEAP4_ALIGNMENT)
volatile size_t g_total_heap;
volatile size_t g_adjusted_heap;
volatile int g_dynamic_enabled;
volatile int g_trace_is_host_only;
int main(void)
{
g_total_heap = CONFIG_TOTAL_HEAP_SIZE;
g_adjusted_heap = CONFIG_ADJUSTED_HEAP_SIZE;
g_dynamic_enabled = CONFIG_SUPPORT_DYNAMIC_ALLOCATION;
#ifdef HOST_PRINTF
g_trace_is_host_only = 1;
#else
g_trace_is_host_only = 0;
#endif
TRACE_PRINTF("heap=%u adjusted=%u dynamic=%d host_trace=%d\n",
(unsigned)g_total_heap, (unsigned)g_adjusted_heap,
g_dynamic_enabled, g_trace_is_host_only);
return 0;
}
+175
View File
@@ -0,0 +1,175 @@
#include "heap4_common.h"
#define HEAP_BYTES 256U
#define MIN_SPLIT_SIZE ((size_t)(sizeof(HeapBlock) * 2U))
static uint8_t heap_area[HEAP_BYTES + HEAP4_ALIGNMENT];
static HeapBlock start;
static HeapBlock *end_marker;
volatile int g_allocations_ok;
volatile int g_final_free_nodes;
volatile size_t g_final_free_total;
volatile size_t g_minimum_ever_free;
static size_t free_bytes_remaining;
static size_t minimum_ever_free;
static size_t list_total(void)
{
HeapBlock *block;
size_t total;
total = 0U;
for (block = start.next; block != end_marker; block = block->next)
total += block->size;
return total;
}
static int list_count(void)
{
HeapBlock *block;
int count;
count = 0;
for (block = start.next; block != end_marker; block = block->next)
count++;
return count;
}
static void insert_block_merge(HeapBlock *block)
{
HeapBlock *iterator;
uint8_t *block_end;
for (iterator = &start; iterator->next < block; iterator = iterator->next)
;
block_end = (uint8_t *)block + block->size;
if (block_end == (uint8_t *)iterator->next) {
block->size += iterator->next->size;
block->next = iterator->next->next;
} else {
block->next = iterator->next;
}
if (iterator != &start && heap4_blocks_touch(iterator, block)) {
iterator->size += block->size;
iterator->next = block->next;
} else {
iterator->next = block;
}
}
static void heap_init(void)
{
uintptr_t raw;
uintptr_t aligned;
size_t available;
HeapBlock *first;
raw = (uintptr_t)&heap_area[0];
aligned = heap4_align_address(raw);
available = HEAP_BYTES - (size_t)(aligned - raw);
available &= ~HEAP4_ALIGNMENT_MASK;
first = (HeapBlock *)aligned;
end_marker = (HeapBlock *)(aligned + available - sizeof(HeapBlock));
end_marker->next = 0;
end_marker->size = 0U;
first->next = end_marker;
first->size = (uint8_t *)end_marker - (uint8_t *)first;
start.next = first;
start.size = 0U;
free_bytes_remaining = first->size;
minimum_ever_free = free_bytes_remaining;
}
static void *heap_malloc_model(size_t wanted)
{
HeapBlock *previous;
HeapBlock *block;
HeapBlock *remainder;
size_t total;
size_t original;
if (wanted == 0U)
return 0;
total = heap4_align_up(wanted + sizeof(HeapBlock));
previous = &start;
block = start.next;
while (block != end_marker) {
if (block->size >= total) {
original = block->size;
if (original - total > MIN_SPLIT_SIZE) {
remainder = (HeapBlock *)((uint8_t *)block + total);
remainder->size = original - total;
remainder->next = block->next;
previous->next = remainder;
block->size = total;
} else {
previous->next = block->next;
total = original;
}
block->next = 0;
block->size = heap4_mark_allocated(block->size);
free_bytes_remaining -= total;
if (free_bytes_remaining < minimum_ever_free)
minimum_ever_free = free_bytes_remaining;
return (uint8_t *)block + sizeof(HeapBlock);
}
previous = block;
block = block->next;
}
return 0;
}
static void heap_free_model(void *p)
{
HeapBlock *block;
size_t size;
if (p == 0)
return;
block = (HeapBlock *)((uint8_t *)p - sizeof(HeapBlock));
if (!heap4_is_allocated(block->size))
return;
size = heap4_clear_allocated(block->size);
block->size = size;
free_bytes_remaining += size;
insert_block_merge(block);
}
int main(void)
{
void *a;
void *b;
void *c;
heap_init();
a = heap_malloc_model(24U);
b = heap_malloc_model(40U);
heap_free_model(a);
c = heap_malloc_model(16U);
heap_free_model(b);
heap_free_model(c);
g_allocations_ok = a != 0 && b != 0 && c != 0;
g_final_free_nodes = list_count();
g_final_free_total = list_total();
g_minimum_ever_free = minimum_ever_free;
TRACE_PRINTF("ok=%d nodes=%d free=%u min=%u\n",
g_allocations_ok, g_final_free_nodes,
(unsigned)g_final_free_total, (unsigned)g_minimum_ever_free);
return 0;
}