Add FreeRTOS heap4 intro card
This commit is contained in:
@@ -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
@@ -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
|
||||||
@@ -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)
|
||||||
@@ -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
|
||||||
|
```
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
@@ -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}
|
||||||
Executable
+70
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user