feat: rebuild heap4 card around upstream FreeRTOS allocator
This commit is contained in:
+4
-13
@@ -1,18 +1,9 @@
|
|||||||
*.aux
|
.stem/
|
||||||
*.log
|
|
||||||
*.out
|
|
||||||
*.fls
|
|
||||||
*.fdb_latexmk
|
|
||||||
*.synctex.gz
|
|
||||||
*.pdf
|
|
||||||
build-meta.tex
|
|
||||||
.rv/
|
|
||||||
.nvim/
|
|
||||||
.vim/
|
|
||||||
.build/
|
|
||||||
.gdb_history
|
|
||||||
host-build/
|
host-build/
|
||||||
build/*/prog.bin
|
build/*/prog.bin
|
||||||
build/*/prog.elf
|
build/*/prog.elf
|
||||||
build/*/prog.lst
|
build/*/prog.lst
|
||||||
build/*/prog.map
|
build/*/prog.map
|
||||||
|
build/*/*.o
|
||||||
|
cmake-build-*/
|
||||||
|
compile_commands.json
|
||||||
|
|||||||
+114
@@ -0,0 +1,114 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
|
if(NOT PICO_SDK_PATH)
|
||||||
|
if(DEFINED ENV{PICO_SDK_PATH})
|
||||||
|
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "Set PICO_SDK_PATH to a Raspberry Pi Pico SDK checkout")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include(${PICO_SDK_PATH}/external/pico_sdk_import.cmake)
|
||||||
|
|
||||||
|
project(freertos_heap4_rp2350 C CXX ASM)
|
||||||
|
set(CMAKE_C_STANDARD 11)
|
||||||
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
|
# The card and allocator are C-only. Debian's compact RISC-V toolchain does
|
||||||
|
# not ship libstdc++ headers, so keep the SDK's optional new/delete source out
|
||||||
|
# while preserving the interface targets expected by pico_stdlib.
|
||||||
|
add_library(pico_cxx_options_headers INTERFACE)
|
||||||
|
target_include_directories(pico_cxx_options_headers SYSTEM INTERFACE
|
||||||
|
${PICO_SDK_PATH}/src/rp2_common/pico_cxx_options/include)
|
||||||
|
add_library(pico_cxx_options INTERFACE)
|
||||||
|
target_link_libraries(pico_cxx_options INTERFACE pico_cxx_options_headers)
|
||||||
|
|
||||||
|
pico_sdk_init()
|
||||||
|
|
||||||
|
if(NOT PICO_PLATFORM STREQUAL "rp2350-riscv")
|
||||||
|
message(FATAL_ERROR "This card targets the RP2350 RISC-V cores")
|
||||||
|
endif()
|
||||||
|
if(NOT HEAP4_UPSTREAM_ROOT)
|
||||||
|
if(DEFINED ENV{HEAP4_UPSTREAM_ROOT})
|
||||||
|
set(HEAP4_UPSTREAM_ROOT $ENV{HEAP4_UPSTREAM_ROOT})
|
||||||
|
else()
|
||||||
|
set(HEAP4_UPSTREAM_ROOT /opt/FreeRTOS-Kernel)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
if(NOT EXISTS ${HEAP4_UPSTREAM_ROOT}/portable/MemMang/heap_4.c)
|
||||||
|
message(FATAL_ERROR "Pinned FreeRTOS heap_4.c not found at ${HEAP4_UPSTREAM_ROOT}")
|
||||||
|
endif()
|
||||||
|
if(NOT FREERTOS_RP2350_PATH)
|
||||||
|
if(DEFINED ENV{FREERTOS_RP2350_PATH})
|
||||||
|
set(FREERTOS_RP2350_PATH $ENV{FREERTOS_RP2350_PATH})
|
||||||
|
else()
|
||||||
|
set(FREERTOS_RP2350_PATH /opt/FreeRTOS-RP2350)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
if(NOT EXISTS ${FREERTOS_RP2350_PATH}/portable/ThirdParty/GCC/RP2350_RISC-V/portASM.S)
|
||||||
|
message(FATAL_ERROR "Compatible RP2350 FreeRTOS core/port not found at ${FREERTOS_RP2350_PATH}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(FREERTOS_CONFIG_FILE_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/include)
|
||||||
|
# Raspberry Pi's port CMake uses FREERTOS_KERNEL_PATH for its matching core.
|
||||||
|
# Keep the stable allocator root separate and add its heap_4.c explicitly.
|
||||||
|
set(FREERTOS_KERNEL_PATH ${FREERTOS_RP2350_PATH})
|
||||||
|
add_subdirectory(
|
||||||
|
${FREERTOS_RP2350_PATH}/portable/ThirdParty/GCC/RP2350_RISC-V
|
||||||
|
${CMAKE_BINARY_DIR}/freertos-kernel)
|
||||||
|
|
||||||
|
set(HEAP4_PROFILE "observe" CACHE STRING "observe, debug or release")
|
||||||
|
set_property(CACHE HEAP4_PROFILE PROPERTY STRINGS observe debug release)
|
||||||
|
set(HEAP4_BINARY_TYPE "no_flash" CACHE STRING "Pico SDK binary type")
|
||||||
|
set_property(CACHE HEAP4_BINARY_TYPE PROPERTY STRINGS no_flash default)
|
||||||
|
|
||||||
|
if(HEAP4_PROFILE STREQUAL "observe")
|
||||||
|
set(HEAP4_COMPILE_OPTIONS
|
||||||
|
-O0 -g3 -fno-omit-frame-pointer -fno-inline
|
||||||
|
-fno-optimize-sibling-calls)
|
||||||
|
elseif(HEAP4_PROFILE STREQUAL "debug")
|
||||||
|
set(HEAP4_COMPILE_OPTIONS
|
||||||
|
-Og -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls)
|
||||||
|
elseif(HEAP4_PROFILE STREQUAL "release")
|
||||||
|
set(HEAP4_COMPILE_OPTIONS -O2)
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "HEAP4_PROFILE must be observe, debug or release")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(MODEL_TASKS
|
||||||
|
task01_first_fit_split
|
||||||
|
task02_address_order_coalesce)
|
||||||
|
|
||||||
|
foreach(task IN LISTS MODEL_TASKS)
|
||||||
|
set(task_source src/tasks/${task}.c)
|
||||||
|
add_executable(${task} ${task_source})
|
||||||
|
target_include_directories(${task} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/src/tasks)
|
||||||
|
set_property(SOURCE ${task_source} APPEND PROPERTY COMPILE_OPTIONS
|
||||||
|
${HEAP4_COMPILE_OPTIONS} -Wall -Wextra -Wpedantic)
|
||||||
|
target_link_libraries(${task} pico_stdlib)
|
||||||
|
pico_enable_stdio_usb(${task} 0)
|
||||||
|
pico_enable_stdio_uart(${task} 0)
|
||||||
|
if(NOT HEAP4_BINARY_TYPE STREQUAL "default")
|
||||||
|
pico_set_binary_type(${task} ${HEAP4_BINARY_TYPE})
|
||||||
|
endif()
|
||||||
|
pico_add_extra_outputs(${task})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set(heap4_task task03_freertos_heap4)
|
||||||
|
set(heap4_source src/tasks/${heap4_task}.c)
|
||||||
|
add_executable(${heap4_task} ${heap4_source})
|
||||||
|
target_sources(${heap4_task} PRIVATE
|
||||||
|
${HEAP4_UPSTREAM_ROOT}/portable/MemMang/heap_4.c)
|
||||||
|
target_include_directories(${heap4_task} PRIVATE
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/include
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/tasks)
|
||||||
|
set_property(SOURCE ${heap4_source} APPEND PROPERTY COMPILE_OPTIONS
|
||||||
|
${HEAP4_COMPILE_OPTIONS} -Wall -Wextra -Wpedantic)
|
||||||
|
target_link_libraries(${heap4_task} pico_stdlib FreeRTOS-Kernel)
|
||||||
|
pico_enable_stdio_usb(${heap4_task} 0)
|
||||||
|
pico_enable_stdio_uart(${heap4_task} 0)
|
||||||
|
if(NOT HEAP4_BINARY_TYPE STREQUAL "default")
|
||||||
|
pico_set_binary_type(${heap4_task} ${HEAP4_BINARY_TYPE})
|
||||||
|
endif()
|
||||||
|
pico_add_extra_outputs(${heap4_task})
|
||||||
@@ -6,11 +6,18 @@ OBJDUMP := $(RISCV_PREFIX)objdump
|
|||||||
SIZE := $(RISCV_PREFIX)size
|
SIZE := $(RISCV_PREFIX)size
|
||||||
HOST_CC ?= cc
|
HOST_CC ?= cc
|
||||||
|
|
||||||
DEBUG ?= 1
|
PROFILE ?= observe
|
||||||
ifeq ($(DEBUG),1)
|
ifeq ($(PROFILE),observe)
|
||||||
|
OPTFLAGS := -O0 -fno-omit-frame-pointer -fno-inline -fno-optimize-sibling-calls
|
||||||
DBGFLAGS := -g3 -ggdb
|
DBGFLAGS := -g3 -ggdb
|
||||||
else
|
else ifeq ($(PROFILE),debug)
|
||||||
|
OPTFLAGS := -Og -fno-omit-frame-pointer -fno-optimize-sibling-calls
|
||||||
|
DBGFLAGS := -g3 -ggdb
|
||||||
|
else ifeq ($(PROFILE),release)
|
||||||
|
OPTFLAGS := -O2
|
||||||
DBGFLAGS :=
|
DBGFLAGS :=
|
||||||
|
else
|
||||||
|
$(error PROFILE must be observe, debug or release)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
RV_ENV_ROOT ?= /opt/rv-env
|
RV_ENV_ROOT ?= /opt/rv-env
|
||||||
@@ -21,36 +28,35 @@ LDSCRIPT ?= $(H3_COMMON)/link_hazard3.ld
|
|||||||
LAB_RUNTIME_DIR ?= $(RV_ENV_ROOT)/vendor/lab-runtime
|
LAB_RUNTIME_DIR ?= $(RV_ENV_ROOT)/vendor/lab-runtime
|
||||||
MEMOPS ?= $(LAB_RUNTIME_DIR)/memops.c
|
MEMOPS ?= $(LAB_RUNTIME_DIR)/memops.c
|
||||||
|
|
||||||
|
LOCAL_FREERTOS := $(abspath ../lab-rv32i-freertos-task-stack-vector/vendor/FreeRTOS-Kernel)
|
||||||
|
FREERTOS_KERNEL_PATH ?= $(if $(wildcard /opt/FreeRTOS-Kernel/include/FreeRTOS.h),/opt/FreeRTOS-Kernel,$(LOCAL_FREERTOS))
|
||||||
|
FREERTOS_PORT := $(FREERTOS_KERNEL_PATH)/portable/GCC/RISC-V
|
||||||
|
HEAP4_SOURCE := $(FREERTOS_KERNEL_PATH)/portable/MemMang/heap_4.c
|
||||||
|
|
||||||
BUILD_ROOT ?= build
|
BUILD_ROOT ?= build
|
||||||
HOST_BUILD_ROOT ?= host-build
|
HOST_BUILD_ROOT ?= host-build
|
||||||
TASKS := \
|
TASKS := \
|
||||||
task01_heap_map \
|
task01_first_fit_split \
|
||||||
task02_free_list \
|
task02_address_order_coalesce \
|
||||||
task03_heap_init \
|
task03_freertos_heap4
|
||||||
task04_alignment \
|
|
||||||
task05_malloc_first_fit \
|
|
||||||
task06_split_block \
|
|
||||||
task07_free_insert \
|
|
||||||
task08_coalescing \
|
|
||||||
task09_config_macros \
|
|
||||||
task10_heap4_demo
|
|
||||||
|
|
||||||
ARCH ?= rv32i_zicsr_zifencei
|
ARCH ?= rv32i_zicsr_zifencei
|
||||||
ABI ?= ilp32
|
ABI ?= ilp32
|
||||||
|
COMMON_FLAGS := -std=c11 -march=$(ARCH) -mabi=$(ABI) -nostdlib -nostartfiles \
|
||||||
COMMON_FLAGS := -std=c99 -march=$(ARCH) -mabi=$(ABI) -nostdlib -nostartfiles -ffreestanding -fno-builtin -fno-stack-protector $(DBGFLAGS) -Wall -Wextra -Isrc/tasks
|
-ffreestanding -fno-builtin -fno-stack-protector -ffunction-sections \
|
||||||
LINK_FLAGS := -Wl,--no-relax -Wl,-T,$(LDSCRIPT)
|
-fdata-sections $(OPTFLAGS) $(DBGFLAGS) -Wall -Wextra -Wpedantic
|
||||||
|
MODEL_CPPFLAGS := -Isrc/tasks
|
||||||
|
KERNEL_CPPFLAGS := -Iinclude/freestanding -Iinclude -Isrc/tasks \
|
||||||
|
-I$(FREERTOS_KERNEL_PATH)/include -I$(FREERTOS_PORT)
|
||||||
|
LINK_FLAGS := -Wl,--no-relax -Wl,--gc-sections -T $(LDSCRIPT)
|
||||||
LIBS := -lgcc
|
LIBS := -lgcc
|
||||||
EMIT_FLAGS := -std=c99 -march=$(ARCH) -mabi=$(ABI) -O -ffreestanding -fno-builtin -fno-stack-protector -nostdlib -nostartfiles -Wall -Wextra -Isrc/tasks
|
HOST_FLAGS := -std=c11 $(OPTFLAGS) $(DBGFLAGS) -Wall -Wextra -Wpedantic \
|
||||||
CFLAGS_STEP := $(COMMON_FLAGS) -O
|
-DHOST_PRINTF=1 -Isrc/tasks
|
||||||
HOST_CFLAGS := -std=c99 -O0 -g -Wall -Wextra -DHOST_PRINTF=1 -Isrc/tasks
|
HOST_HEAP4_FLAGS := $(HOST_FLAGS) -DHEAP4_HOST_ADAPTER=1 -Iinclude/host-shim
|
||||||
|
|
||||||
.PHONY: all tasks host \
|
.PHONY: all tasks host task1 task2 task3 t1 t2 t3 \
|
||||||
task1 task2 task3 task4 task5 task6 task7 task8 task9 task10 \
|
host-task1 host-task2 host-task3 ht1 ht2 ht3 clean check-support check-kernel \
|
||||||
t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 \
|
$(TASKS)
|
||||||
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
|
all: tasks
|
||||||
tasks: $(TASKS)
|
tasks: $(TASKS)
|
||||||
@@ -59,54 +65,66 @@ host: $(addprefix $(HOST_BUILD_ROOT)/,$(addsuffix /prog,$(TASKS)))
|
|||||||
task1 t1: $(word 1,$(TASKS))
|
task1 t1: $(word 1,$(TASKS))
|
||||||
task2 t2: $(word 2,$(TASKS))
|
task2 t2: $(word 2,$(TASKS))
|
||||||
task3 t3: $(word 3,$(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-task1 ht1: $(HOST_BUILD_ROOT)/$(word 1,$(TASKS))/prog
|
||||||
host-task2 ht2: $(HOST_BUILD_ROOT)/$(word 2,$(TASKS))/prog
|
host-task2 ht2: $(HOST_BUILD_ROOT)/$(word 2,$(TASKS))/prog
|
||||||
host-task3 ht3: $(HOST_BUILD_ROOT)/$(word 3,$(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:
|
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 "$(H3_INIT)" || { echo "Missing $(H3_INIT). Run inside hazard3-sim." >&2; exit 1; }
|
||||||
@test -f "$(LDSCRIPT)" || { echo "Missing $(LDSCRIPT)." >&2; exit 1; }
|
@test -f "$(LDSCRIPT)" || { echo "Missing $(LDSCRIPT)." >&2; exit 1; }
|
||||||
@test -f "$(MEMOPS)" || { echo "Missing $(MEMOPS)." >&2; exit 1; }
|
@test -f "$(MEMOPS)" || { echo "Missing $(MEMOPS)." >&2; exit 1; }
|
||||||
|
|
||||||
define task_rules
|
check-kernel:
|
||||||
$(1): $(BUILD_ROOT)/$(1)/prog.bin $(BUILD_ROOT)/$(1)/prog.elf $(BUILD_ROOT)/$(1)/prog.lst $(BUILD_ROOT)/$(1)/$(1).s
|
@test -f "$(HEAP4_SOURCE)" || { echo "Missing pinned FreeRTOS heap_4.c at $(HEAP4_SOURCE)." >&2; exit 1; }
|
||||||
|
@grep -F 'FreeRTOS Kernel V11.3.0' "$(FREERTOS_KERNEL_PATH)/include/FreeRTOS.h" >/dev/null || { echo "Expected FreeRTOS Kernel V11.3.0." >&2; exit 1; }
|
||||||
|
|
||||||
$(BUILD_ROOT)/$(1)/prog.elf: crt0.S src/tasks/$(1).c src/tasks/heap4_common.h $(H3_INIT) $(LDSCRIPT) $(MEMOPS) | check-support
|
define model_task_rules
|
||||||
|
$(1): $(BUILD_ROOT)/$(1)/prog.bin $(BUILD_ROOT)/$(1)/prog.elf $(BUILD_ROOT)/$(1)/prog.lst
|
||||||
|
|
||||||
|
$(BUILD_ROOT)/$(1)/prog.elf: crt0.S src/tasks/$(1).c src/tasks/heap4_model.h $(H3_INIT) $(LDSCRIPT) $(MEMOPS) | check-support
|
||||||
mkdir -p $$(@D)
|
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)
|
$(CC) $(COMMON_FLAGS) $(MODEL_CPPFLAGS) $(LINK_FLAGS) -Wl,-Map,$(BUILD_ROOT)/$(1)/prog.map -o $$@ $(H3_INIT) crt0.S $(MEMOPS) src/tasks/$(1).c $(LIBS)
|
||||||
$(SIZE) -A -x $$@
|
$(SIZE) -A -x $$@
|
||||||
|
|
||||||
$(BUILD_ROOT)/$(1)/prog.bin: $(BUILD_ROOT)/$(1)/prog.elf
|
$(BUILD_ROOT)/$(1)/prog.bin: $(BUILD_ROOT)/$(1)/prog.elf
|
||||||
$(OBJCOPY) -O binary $$< $$@
|
$(OBJCOPY) -O binary $$< $$@
|
||||||
|
|
||||||
$(BUILD_ROOT)/$(1)/prog.lst: $(BUILD_ROOT)/$(1)/prog.elf
|
$(BUILD_ROOT)/$(1)/prog.lst: $(BUILD_ROOT)/$(1)/prog.elf
|
||||||
$(OBJDUMP) -d -M no-aliases,numeric $$< > $$@
|
$(OBJDUMP) -d -S -M no-aliases,numeric $$< > $$@
|
||||||
|
|
||||||
$(BUILD_ROOT)/$(1)/$(1).s: src/tasks/$(1).c src/tasks/heap4_common.h | check-support
|
$(HOST_BUILD_ROOT)/$(1)/prog: src/tasks/$(1).c src/tasks/heap4_model.h
|
||||||
mkdir -p $$(@D)
|
mkdir -p $$(@D)
|
||||||
$(CC) $(EMIT_FLAGS) -S -o $$@ $$<
|
$(HOST_CC) $(HOST_FLAGS) -o $$@ $$<
|
||||||
|
|
||||||
$(HOST_BUILD_ROOT)/$(1)/prog: src/tasks/$(1).c src/tasks/heap4_common.h
|
|
||||||
mkdir -p $$(@D)
|
|
||||||
$(HOST_CC) $(HOST_CFLAGS) -o $$@ $$<
|
|
||||||
endef
|
endef
|
||||||
|
|
||||||
$(foreach task,$(TASKS),$(eval $(call task_rules,$(task))))
|
$(eval $(call model_task_rules,$(word 1,$(TASKS))))
|
||||||
|
$(eval $(call model_task_rules,$(word 2,$(TASKS))))
|
||||||
|
|
||||||
|
TASK03 := $(word 3,$(TASKS))
|
||||||
|
TASK03_KERNEL_SOURCES := \
|
||||||
|
$(FREERTOS_KERNEL_PATH)/tasks.c \
|
||||||
|
$(FREERTOS_KERNEL_PATH)/list.c \
|
||||||
|
$(HEAP4_SOURCE) \
|
||||||
|
$(FREERTOS_PORT)/port.c \
|
||||||
|
$(FREERTOS_PORT)/portASM.S
|
||||||
|
|
||||||
|
$(TASK03): $(BUILD_ROOT)/$(TASK03)/prog.bin $(BUILD_ROOT)/$(TASK03)/prog.elf $(BUILD_ROOT)/$(TASK03)/prog.lst
|
||||||
|
|
||||||
|
$(BUILD_ROOT)/$(TASK03)/prog.elf: crt0.S src/tasks/$(TASK03).c include/FreeRTOSConfig.h $(TASK03_KERNEL_SOURCES) $(H3_INIT) $(LDSCRIPT) $(MEMOPS) | check-support check-kernel
|
||||||
|
mkdir -p $(@D)
|
||||||
|
$(CC) $(COMMON_FLAGS) $(KERNEL_CPPFLAGS) $(LINK_FLAGS) -Wl,-Map,$(BUILD_ROOT)/$(TASK03)/prog.map -o $@ $(H3_INIT) crt0.S $(MEMOPS) $(TASK03_KERNEL_SOURCES) src/tasks/$(TASK03).c $(LIBS)
|
||||||
|
$(SIZE) -A -x $@
|
||||||
|
|
||||||
|
$(BUILD_ROOT)/$(TASK03)/prog.bin: $(BUILD_ROOT)/$(TASK03)/prog.elf
|
||||||
|
$(OBJCOPY) -O binary $< $@
|
||||||
|
|
||||||
|
$(BUILD_ROOT)/$(TASK03)/prog.lst: $(BUILD_ROOT)/$(TASK03)/prog.elf
|
||||||
|
$(OBJDUMP) -d -S -M no-aliases,numeric $< > $@
|
||||||
|
|
||||||
|
$(HOST_BUILD_ROOT)/$(TASK03)/prog: src/tasks/$(TASK03).c include/host-shim/FreeRTOS.h include/host-shim/task.h $(HEAP4_SOURCE) | check-kernel
|
||||||
|
mkdir -p $(@D)
|
||||||
|
$(HOST_CC) $(HOST_HEAP4_FLAGS) -o $@ src/tasks/$(TASK03).c $(HEAP4_SOURCE)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(BUILD_ROOT) $(HOST_BUILD_ROOT)
|
rm -rf $(BUILD_ROOT) $(HOST_BUILD_ROOT)
|
||||||
|
|||||||
@@ -1,73 +1,69 @@
|
|||||||
# rv32i-freertos / heap4
|
# Karta pracy: FreeRTOS `heap_4`
|
||||||
|
|
||||||
Karta pracy `01/14` z serii `rv32i-freertos`; jest opcjonalnym fundamentem L1.
|
Trzy krótkie zadania po kartach `pointers` i `structures`:
|
||||||
|
|
||||||
Temat: mechanika alokatora `heap_4.c` z FreeRTOS-a na małych przykładach
|
1. first-fit + split na arenie 256 B;
|
||||||
uruchamianych w środowisku RV32I.
|
2. lista adresowa + scalanie `A | B | C`;
|
||||||
|
3. niezmodyfikowany FreeRTOS-Kernel V11.3.0 `heap_4.c`.
|
||||||
|
|
||||||
Ta karta jest pomostem po kartach C: używa wskaźników, struktur, listy
|
Task 3 linkuje upstream `portable/MemMang/heap_4.c` z commita
|
||||||
jednokierunkowej, `static`, `typedef`, makr i arytmetyki adresów, ale nie
|
`9b777ae5c5b8e9e456065a00294d1e5f5f9facf5`.
|
||||||
wymaga jeszcze schedulera, tasków ani przerwań.
|
|
||||||
|
|
||||||
Kod w `src/tasks` jest dydaktycznym modelem zachowania `heap_4`, a nie kopią
|
- AMD64: rzeczywisty algorytm + jednowątkowy adapter sekcji krytycznej.
|
||||||
pliku upstream FreeRTOS.
|
- Hazard3: `tasks.c`, `list.c`, `heap_4.c` i oficjalny port RISC-V.
|
||||||
|
- RP2350: zgodny core+port z forka Raspberry Pi (`4f7299d6ea74`) oraz
|
||||||
|
podstawiony stabilny allocator V11.3.0.
|
||||||
|
|
||||||
## Taski
|
## Jedno wejście: `stemctl`
|
||||||
|
|
||||||
- `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`.
|
|
||||||
|
|
||||||
## Gałęzie zadań
|
|
||||||
|
|
||||||
Gałąź `deploy` jest pełną publiczną wersją karty. Każde zadanie ma osobną
|
|
||||||
gałąź startową `tasks/*`, na przykład `tasks/05-malloc-first-fit`. Taka gałąź
|
|
||||||
nie jest wycinkiem repozytorium: zawiera dokumentację, treść karty, `Makefile`,
|
|
||||||
kod pomocniczy i pliki danego zadania.
|
|
||||||
|
|
||||||
Uczeń nie commituje bezpośrednio do `tasks/*`. W repozytorium klasy tworzy
|
|
||||||
gałąź pochodną, na przykład `students/u01/tasks/05-malloc-first-fit`.
|
|
||||||
|
|
||||||
## Powiązanie z FreeRTOS Book v1.1.0
|
|
||||||
|
|
||||||
To jest opcjonalna karta `K01` z
|
|
||||||
[mapy serii](../README.md). Jej źródłem pojęciowym jest rozdział 3 książki
|
|
||||||
*Mastering the FreeRTOS Real Time Kernel*, przede wszystkim sekcja 3.2.4 o
|
|
||||||
`heap_4` oraz rysunki 3.1–3.4. Rozdział o heapie nie ma numerowanego programu
|
|
||||||
z zestawu `Example001`–`Example025`, dlatego karta rozkłada mechanikę
|
|
||||||
alokatora na własne, krótsze eksperymenty:
|
|
||||||
|
|
||||||
- Taski 01–03 odtwarzają mapę bloku, wolną listę i inicjalizację heapu;
|
|
||||||
- Taski 04–08 izolują wyrównanie, first-fit, podział, wstawianie i scalanie;
|
|
||||||
- Task 09 łączy konfigurację z sekcjami 3.1.3–3.1.5;
|
|
||||||
- Task 10 składa te elementy w jeden model zachowania `heap_4`.
|
|
||||||
|
|
||||||
Karta nie jest kopią upstreamowego `heap_4.c` ani listingów książki. Jest
|
|
||||||
modelem dydaktycznym, po którym karta `K02` przechodzi na prawdziwy plik
|
|
||||||
`portable/MemMang/heap_4.c` z FreeRTOS V11.3.0.
|
|
||||||
|
|
||||||
## Budowanie
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
RV_ENV_ROOT=~/dev/workspace/rv/tools/rv32i-hazard3-student-env make tasks
|
stemctl series cards fetch freertos heap4
|
||||||
make host
|
stemctl test native-amd64 freertos heap4 1
|
||||||
|
stemctl test hazard3-sim freertos heap4 2
|
||||||
|
stemctl debug hazard3-sim freertos heap4 3
|
||||||
|
stemctl test rp2350 freertos heap4 3
|
||||||
|
stemctl deploy rp2350 freertos heap4 3 --device /dev/bus/usb/BBB/DDD
|
||||||
|
stemctl debug rp2350 freertos heap4 3 --device /dev/bus/usb/BBB/DDD
|
||||||
```
|
```
|
||||||
|
|
||||||
## Praca przez rvctl
|
- `debug rp2350`: roboczy ELF `no_flash` ładowany do SRAM.
|
||||||
|
- `deploy rp2350`: trwały obraz w SPI flash, odczytany przez breakpointy.
|
||||||
|
|
||||||
|
## Kontrakt zadań
|
||||||
|
|
||||||
|
| Task | Sprawdza | Wynik kluczowy |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | alignment, header, split | `wanted + remainder == 256` |
|
||||||
|
| 2 | lista po adresie, coalescing | `2 bloki -> 1 blok`, `96 -> 144 B` |
|
||||||
|
| 3 | prawdziwe API FreeRTOS | free wraca do F0, minimum nie rośnie, OOM = NULL |
|
||||||
|
|
||||||
|
## Debugowanie Task 3
|
||||||
|
|
||||||
|
Automatyczny start: `heap4_fragmented_checkpoint`.
|
||||||
|
|
||||||
|
```gdb
|
||||||
|
p g_fragmented_stats
|
||||||
|
p g_final_stats
|
||||||
|
p xFreeBytesRemaining
|
||||||
|
p xMinimumEverFreeBytesRemaining
|
||||||
|
p xStart
|
||||||
|
p pxEnd
|
||||||
|
x/160bx ucHeap
|
||||||
|
b prvInsertBlockIntoFreeList
|
||||||
|
b pvPortMalloc
|
||||||
|
b vPortFree
|
||||||
|
```
|
||||||
|
|
||||||
|
W UI: Termdebug po lewej; źródło i listing po prawej; bash pod Neovimem.
|
||||||
|
`F5` continue, `F9` breakpoint, `F10` next, `F11` step, `Shift-F11`
|
||||||
|
finish, `F8` stepi, `:StudentStack`, `:StudentMemory`, `:StudentLst`.
|
||||||
|
|
||||||
|
## Test repozytorium
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./rvctl series cards fetch inf heap4
|
./tests/test_host.sh
|
||||||
./rvctl card use inf heap4
|
bash -n tools/card-action.sh
|
||||||
./rvctl tasks list
|
./scripts/render_pdf.sh
|
||||||
./rvctl debug rv32i 1
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Źródło i licencja: [UPSTREAM.md](UPSTREAM.md).
|
||||||
|
|||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
# Upstream contract
|
||||||
|
|
||||||
|
- Project: FreeRTOS-Kernel
|
||||||
|
- Version: V11.3.0
|
||||||
|
- Commit: `9b777ae5c5b8e9e456065a00294d1e5f5f9facf5`
|
||||||
|
- Source used by Task 3: `portable/MemMang/heap_4.c`
|
||||||
|
- License: MIT (as shipped in the pinned upstream checkout)
|
||||||
|
|
||||||
|
RP2350 needs a port that is newer than the V11.3.0 tag:
|
||||||
|
|
||||||
|
- Project: Raspberry Pi fork of FreeRTOS-Kernel
|
||||||
|
- Commit: `4f7299d6ea746b27a9dd19e87af568e34bd65b15`
|
||||||
|
- Files used on RP2350: matching kernel core plus
|
||||||
|
`portable/ThirdParty/GCC/RP2350_RISC-V`
|
||||||
|
- Allocator used on RP2350: still the stable V11.3.0 `heap_4.c` above,
|
||||||
|
compiled instead of the fork's development-branch allocator.
|
||||||
|
|
||||||
|
The canonical containers provide `/opt/FreeRTOS-Kernel`; the RP2350 profile
|
||||||
|
also provides `/opt/FreeRTOS-RP2350`. The card carries no allocator copy.
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
.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
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
.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
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
.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
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
.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
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
.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
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
.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
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
.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
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
.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
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
.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
|
|
||||||
@@ -1,253 +0,0 @@
|
|||||||
.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
|
|
||||||
+276
-256
@@ -1,21 +1,18 @@
|
|||||||
\documentclass[12pt]{article}
|
\documentclass[11pt]{article}
|
||||||
\usepackage[T1]{fontenc}
|
\usepackage[T1]{fontenc}
|
||||||
\usepackage[utf8]{inputenc}
|
\usepackage[utf8]{inputenc}
|
||||||
\usepackage[polish]{babel}
|
\usepackage[polish]{babel}
|
||||||
\usepackage[a4paper,margin=2.0cm]{geometry}
|
\usepackage[a4paper,margin=1.75cm]{geometry}
|
||||||
\usepackage{array}
|
\usepackage{array,tabularx,booktabs}
|
||||||
\usepackage{tabularx}
|
\usepackage{amsmath,amssymb}
|
||||||
\usepackage{xcolor}
|
\usepackage{xcolor,listings}
|
||||||
\usepackage{listings}
|
\usepackage{hyperref,fancyhdr,lastpage}
|
||||||
\usepackage{hyperref}
|
|
||||||
\usepackage{fancyhdr}
|
|
||||||
\usepackage{lastpage}
|
|
||||||
\usepackage{enumitem}
|
\usepackage{enumitem}
|
||||||
|
|
||||||
\definecolor{accent}{HTML}{16324A}
|
\definecolor{accent}{HTML}{16324A}
|
||||||
\definecolor{accentlight}{HTML}{EEF3F7}
|
\definecolor{accentlight}{HTML}{EEF3F7}
|
||||||
\definecolor{rulegray}{HTML}{D7DEE5}
|
\definecolor{rulegray}{HTML}{D7DEE5}
|
||||||
\hypersetup{colorlinks=true,linkcolor=blue,urlcolor=blue,citecolor=blue}
|
\hypersetup{colorlinks=true,linkcolor=accent,urlcolor=blue}
|
||||||
\IfFileExists{build-meta.tex}{\input{build-meta.tex}}{\newcommand{\BuildCommit}{local}}
|
\IfFileExists{build-meta.tex}{\input{build-meta.tex}}{\newcommand{\BuildCommit}{local}}
|
||||||
\newcommand{\PublisherDomain}{mpabi}
|
\newcommand{\PublisherDomain}{mpabi}
|
||||||
\newcommand{\DocumentAuthor}{M. Pabiszczak}
|
\newcommand{\DocumentAuthor}{M. Pabiszczak}
|
||||||
@@ -25,267 +22,290 @@
|
|||||||
\newcommand{\CardNumber}{01}
|
\newcommand{\CardNumber}{01}
|
||||||
\newcommand{\CardCount}{14}
|
\newcommand{\CardCount}{14}
|
||||||
\newcommand{\CardSlug}{heap4}
|
\newcommand{\CardSlug}{heap4}
|
||||||
\newcommand{\CardVersion}{v0.1}
|
\newcommand{\CardVersion}{v0.2}
|
||||||
\newcommand{\DocumentKey}{\PublisherDomain/\CardArea/\CardSeries/\CardNumber/\CardSlug/\CardVersion}
|
\newcommand{\DocumentKey}{\PublisherDomain/\CardArea/\CardSeries/\CardNumber/\CardSlug/\CardVersion}
|
||||||
\newcommand{\DocumentUUID}{4654524c-73f2-46df-83a3-d448ba6d6c5a}
|
\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}[5]{\section{Task #1: #3}\subsection*{Algorytm i zakresy linii}#4\lstinputlisting[language=C,caption={Task #1: #3},label={lst:task#1-c}]{../src/tasks/#2.c}\subsection*{Co sprawdzić w ASM}#5\lstinputlisting[basicstyle=\ttfamily\scriptsize,caption={ASM dla task #1},label={lst:task#1-asm}]{../build/#2/#2.s}}
|
|
||||||
|
|
||||||
|
\lstset{
|
||||||
|
language=C,basicstyle=\ttfamily\scriptsize,columns=fullflexible,
|
||||||
|
keepspaces=true,frame=single,breaklines=true,showstringspaces=false,
|
||||||
|
numbers=left,numberstyle=\tiny\color{accent},numbersep=6pt,
|
||||||
|
backgroundcolor=\color{accentlight},rulecolor=\color{rulegray}
|
||||||
|
}
|
||||||
\pagestyle{fancy}
|
\pagestyle{fancy}
|
||||||
\fancyhf{}
|
\fancyhf{}
|
||||||
\lhead{\textbf{FreeRTOS: heap\_4}}
|
\lhead{\textbf{FreeRTOS: heap\_4}}
|
||||||
\rhead{\small \DocumentAuthor, \DocumentYear}
|
\rhead{\small karta 01/14}
|
||||||
\lfoot{\scriptsize commit \BuildCommit}
|
\lfoot{\scriptsize commit \BuildCommit}
|
||||||
\cfoot{\scriptsize \thepage/\pageref{LastPage}}
|
\cfoot{\scriptsize \thepage/\pageref{LastPage}}
|
||||||
\rfoot{\scriptsize uuid \DocumentUUID}
|
\rfoot{\scriptsize V11.3.0 / \CardVersion}
|
||||||
\renewcommand{\headrulewidth}{0.4pt}
|
\setlength{\headheight}{15pt}
|
||||||
\setlength{\headheight}{18pt}
|
\setlength{\footskip}{22pt}
|
||||||
\setlength{\footskip}{24pt}
|
\setlist[itemize]{nosep,leftmargin=1.5em}
|
||||||
|
\setlist[enumerate]{itemsep=.25em,leftmargin=1.7em}
|
||||||
|
\newcommand{\checkline}{\(\square\)\;}
|
||||||
|
|
||||||
\begin{document}
|
\begin{document}
|
||||||
\sloppy
|
\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: & 14.07.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}
|
\begin{center}
|
||||||
\noindent\rule{\textwidth}{0.5pt}
|
{\LARGE\bfseries Karta pracy: FreeRTOS \texttt{heap\_4}}\par
|
||||||
|
\vspace{.4em}
|
||||||
|
{\large model $\rightarrow$ prawdziwy upstream $\rightarrow$ RP2350}\par
|
||||||
|
\end{center}
|
||||||
|
|
||||||
\section{Cel}
|
\begin{tabularx}{\textwidth}{@{}lX@{}}
|
||||||
Ta karta zaczyna serię FreeRTOS od \texttt{heap\_4}, ponieważ ten plik jest
|
\toprule
|
||||||
naturalnym pomostem po kartach z języka C. Wymaga wskaźników, tablic,
|
Klucz & \texttt{\DocumentKey} \\
|
||||||
struktur, listy jednokierunkowej, \texttt{static}, \texttt{typedef}, makr oraz
|
Wersja / commit & \texttt{\CardVersion} / \texttt{\BuildCommit} \\
|
||||||
arytmetyki adresów, ale nie wymaga jeszcze schedulera, przerwań ani
|
Data & 14.07.2026 \\
|
||||||
uruchamiania tasków.
|
Allocator & FreeRTOS-Kernel V11.3.0, \texttt{9b777ae5c5b8} \\
|
||||||
|
Port RP2350 & fork Raspberry Pi, \texttt{4f7299d6ea74} \\
|
||||||
Przykłady są małym modelem edukacyjnym mechaniki \texttt{heap\_4.c}. Nie są
|
Źródło & \texttt{portable/MemMang/heap\_4.c} — bez modyfikacji \\
|
||||||
kopią pliku upstream FreeRTOS. Na RV32I wyniki są zapisywane w globalnych
|
Punkt wejścia & \texttt{stemctl} \\
|
||||||
zmiennych \texttt{volatile}; \texttt{printf} jest dostępny wyłącznie w wariancie
|
\bottomrule
|
||||||
hostowym przez flagę \texttt{-DHOST\_PRINTF=1}.
|
|
||||||
|
|
||||||
W tej karcie słowo „sterta” oznacza obszar pamięci, którym zarządza alokator.
|
|
||||||
W \texttt{heap\_4} taki obszar jest zwykle statyczną tablicą bajtów, więc linker
|
|
||||||
może umieścić go w sekcji \texttt{.bss}. Sama sekcja \texttt{.bss} nie jest jednak
|
|
||||||
alokacją dynamiczną: dopiero kod \texttt{pvPortMalloc}/\texttt{vPortFree} albo
|
|
||||||
model z tej karty dzieli bajty tego bufora na bloki, prowadzi listę wolnych
|
|
||||||
bloków i wykonuje scalanie. W Task 03 widać ten moment przejścia od zwykłego
|
|
||||||
statycznego bufora do sterty zarządzanej przez algorytm.
|
|
||||||
|
|
||||||
Listingi C i ASM mają numerowane linie. Opisy w sekcjach tasków odnoszą się
|
|
||||||
do numerów widocznych po lewej stronie listingów C.
|
|
||||||
|
|
||||||
\subsection{Powiązanie z FreeRTOS Book v1.1.0}
|
|
||||||
|
|
||||||
Karta K01 odpowiada rozdziałowi 3 książki \emph{Mastering the FreeRTOS Real
|
|
||||||
Time Kernel}, przede wszystkim sekcji 3.2.4 o \texttt{heap\_4} oraz rysunkom
|
|
||||||
3.1--3.4. Ten rozdział nie ma programu z numerowanego zestawu
|
|
||||||
\texttt{Example001}--\texttt{Example025}. Dlatego Taski 01--08 są krótkimi,
|
|
||||||
własnymi eksperymentami izolującymi kolejne elementy algorytmu, a Task 10
|
|
||||||
składa je w jeden model.
|
|
||||||
|
|
||||||
Nie kopiujemy listingu upstream ani projektu Win32/MSVC. Ta karta służy do
|
|
||||||
zrozumienia mechaniki; karta K02 przechodzi na niezmodyfikowany
|
|
||||||
\texttt{portable/MemMang/heap\_4.c} z FreeRTOS V11.3.0. Pełna mapa książki,
|
|
||||||
lekcji i kart znajduje się w pliku \texttt{series/inf/README.md}.
|
|
||||||
|
|
||||||
\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{Organizacja gałęzi}
|
|
||||||
Gałąź \texttt{deploy} jest pełną publiczną wersją karty. Każde zadanie ma
|
|
||||||
osobną gałąź startową \texttt{tasks/*}, na przykład
|
|
||||||
\texttt{tasks/05-malloc-first-fit}. Taka gałąź nie jest wycinkiem repozytorium:
|
|
||||||
zawiera dokumentację, treść karty, \texttt{Makefile}, kod pomocniczy i pliki
|
|
||||||
danego zadania.
|
|
||||||
|
|
||||||
Uczeń nie commituje bezpośrednio do \texttt{tasks/*}. W repozytorium klasy
|
|
||||||
tworzy gałąź pochodną, na przykład
|
|
||||||
\texttt{students/u01/tasks/05-malloc-first-fit}.
|
|
||||||
|
|
||||||
\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}
|
\end{tabularx}
|
||||||
|
|
||||||
\TaskSection{01}{task01_heap_map}{mapa \texttt{heap\_4}}{
|
\section*{Tylko trzy kroki}
|
||||||
\begin{itemize}[leftmargin=1.6em]
|
\begin{enumerate}
|
||||||
\item Linie 3--7 definiują zmienne \texttt{volatile}, czyli obserwowalne wyniki taska.
|
\item First-fit + split: skąd bierze się drugi nagłówek.
|
||||||
\item Linie 11--16 tworzą pojedynczy blok i zapisują w jego polu \texttt{size} rozmiar z bitem alokacji.
|
\item Free-list + coalescing: dlaczego lista jest uporządkowana po adresie.
|
||||||
\item Linie 18--22 rozbijają nagłówek bloku na wartości pomocnicze: rozmiar nagłówka, rozmiar wyrównany, bit zajętości, rozmiar całego bloku i część użytkownika.
|
\item API FreeRTOS: \texttt{pvPortMalloc}, \texttt{vPortFree}, stats, OOM.
|
||||||
\item Linie 24--27 wypisują te same wartości tylko w wariancie hostowym; na RV32I makro \texttt{TRACE\_PRINTF} znika.
|
|
||||||
\item Wynik sprawdzaj w \texttt{g\_header\_size}, \texttt{g\_allocated\_bit\_set}, \texttt{g\_total\_block\_bytes} i \texttt{g\_user\_bytes}.
|
|
||||||
\end{itemize}
|
|
||||||
}{
|
|
||||||
W ASM szukaj operacji ustawiania najwyższego bitu rozmiaru oraz zapisów do symboli globalnych \texttt{g\_*}. Dostęp do pól \texttt{block.next} i \texttt{block.size} powinien być zwykłym zapisem pod adres bazowy stosu z przesunięciem.
|
|
||||||
}
|
|
||||||
\TaskSection{02}{task02_free_list}{lista wolnych bloków}{
|
|
||||||
\begin{itemize}[leftmargin=1.6em]
|
|
||||||
\item Linie 7--16 implementują sumowanie rozmiarów bloków na liście.
|
|
||||||
\item Linie 18--28 przechodzą po tej samej liście i zapamiętują największy blok.
|
|
||||||
\item Linie 30--39 liczą liczbę węzłów listy.
|
|
||||||
\item Linie 43--55 budują ręcznie listę \texttt{start -> a -> b -> c -> NULL}.
|
|
||||||
\item Linie 57--59 uruchamiają trzy funkcje pomiarowe i zapisują wyniki w \texttt{volatile}.
|
|
||||||
\end{itemize}
|
|
||||||
}{
|
|
||||||
W ASM zwróć uwagę na pętle po wskaźniku \texttt{block = block->next}. To jest podstawowy idiom przechodzenia po liście jednokierunkowej, widoczny jako ładowanie pola \texttt{next} i skok warunkowy.
|
|
||||||
}
|
|
||||||
\TaskSection{03}{task03_heap_init}{inicjalizacja sterty}{
|
|
||||||
\begin{itemize}[leftmargin=1.6em]
|
|
||||||
\item Linie 3--7 definiują bufor sterty, węzeł startowy listy i wskaźnik końcowego wartownika.
|
|
||||||
\item Linie 20--23 wyrównują początek sterty i obcinają dostępną długość do wielokrotności wyrównania.
|
|
||||||
\item Linie 25--28 ustawiają adres i pola końcowego wartownika.
|
|
||||||
\item Linie 30--34 tworzą pierwszy wolny blok i podpinają go za \texttt{start}.
|
|
||||||
\item Linie 39--43 wykonują inicjalizację i zapisują trzy wartości kontrolne.
|
|
||||||
\end{itemize}
|
|
||||||
}{
|
|
||||||
W ASM szukaj maskowania dolnych bitów adresu i rozmiaru. Warto też porównać zapisy do \texttt{first->next}, \texttt{first->size}, \texttt{start.next} i \texttt{start.size}; każdy z nich jest dostępem do pola struktury.
|
|
||||||
}
|
|
||||||
\TaskSection{04}{task04_alignment}{wyrównanie}{
|
|
||||||
\begin{itemize}[leftmargin=1.6em]
|
|
||||||
\item Linie 3--6 definiują wyniki pokazujące wpływ wyrównania.
|
|
||||||
\item Linie 14--16 liczą rzeczywiste rozmiary bloków dla żądań 1, 9 i 17 bajtów, po dodaniu nagłówka.
|
|
||||||
\item Linie 18--20 biorą celowo nie-wyrównany adres \texttt{\&bytes[1]} i wyliczają przesunięcie do kolejnej granicy wyrównania.
|
|
||||||
\item Linie 22--24 są hostowym wypisem kontrolnym.
|
|
||||||
\end{itemize}
|
|
||||||
}{
|
|
||||||
W ASM znajdź operacje \texttt{and} używane do testowania dolnych bitów oraz dodawanie brakującej liczby bajtów do wyrównania. To jest ten sam mechanizm, którego używa alokator dla rozmiaru bloku i początku sterty.
|
|
||||||
}
|
|
||||||
\TaskSection{05}{task05_malloc_first_fit}{\texttt{first fit}}{
|
|
||||||
\begin{itemize}[leftmargin=1.6em]
|
|
||||||
\item Linie 13--30 inicjalizują stertę z jednym wolnym blokiem oraz wartownikiem końca.
|
|
||||||
\item Linie 38--40 zamieniają żądanie użytkownika na całkowity rozmiar bloku i ustawiają początek przeszukiwania listy.
|
|
||||||
\item Linie 42--51 realizują algorytm \texttt{first fit}: idą po liście do pierwszego bloku o wystarczającym rozmiarze.
|
|
||||||
\item Linie 44--47 zdejmują znaleziony blok z listy wolnych, oznaczają go jako zajęty i zwracają adres danych użytkownika.
|
|
||||||
\item Linie 61--67 wykonują alokację i zapisują, czy się udała, jaki rozmiar dostał blok i ile wolnego miejsca zostało na liście.
|
|
||||||
\end{itemize}
|
|
||||||
}{
|
|
||||||
W ASM obserwuj porównanie \texttt{block->size >= total}, zmianę \texttt{previous->next} oraz dodanie \texttt{sizeof(HeapBlock)} do adresu bloku przed zwróceniem wskaźnika użytkownika.
|
|
||||||
}
|
|
||||||
\TaskSection{06}{task06_split_block}{podział bloku}{
|
|
||||||
\begin{itemize}[leftmargin=1.6em]
|
|
||||||
\item Linie 3--12 definiują rozmiar sterty, minimalny sensowny rozmiar reszty i zmienne wynikowe.
|
|
||||||
\item Linie 14--28 tworzą jeden duży wolny blok.
|
|
||||||
\item Linie 38--44 szukają bloku pasującego do żądania i zapamiętują jego pierwotny rozmiar.
|
|
||||||
\item Linie 45--50 wykonują podział: nowy blok \texttt{remainder} zaczyna się pod adresem \texttt{block + total}.
|
|
||||||
\item Linie 51--56 obsługują przypadek bez podziału, oznaczają blok jako zajęty i zwracają adres użytkownika.
|
|
||||||
\item Linie 65--73 liczą pozostałe wolne bloki, a linie 81--87 zapisują wynik demonstracji.
|
|
||||||
\end{itemize}
|
|
||||||
}{
|
|
||||||
W ASM szukaj arytmetyki adresów dla \texttt{remainder}: adres bloku plus \texttt{total}. To najważniejszy fragment pokazujący, że dzielenie bloku jest tylko przesunięciem wskaźnika i zapisaniem nowego nagłówka.
|
|
||||||
}
|
|
||||||
\TaskSection{07}{task07_free_insert}{\texttt{free} i wstawianie}{
|
|
||||||
\begin{itemize}[leftmargin=1.6em]
|
|
||||||
\item Linie 11--20 wstawiają blok do listy w miejscu wynikającym z porządku adresów.
|
|
||||||
\item Linie 22--32 modelują \texttt{free}: z adresu użytkownika wracają do nagłówka bloku, czyszczą bit alokacji i wywołują wstawianie.
|
|
||||||
\item Linie 34--54 zawierają funkcje kontrolne liczące węzły oraz łączny rozmiar wolnej pamięci.
|
|
||||||
\item Linie 63--76 budują układ \texttt{a}, \texttt{b}, \texttt{c}, gdzie \texttt{b} jest zajętym blokiem między dwoma wolnymi.
|
|
||||||
\item Linie 78--83 zwalniają \texttt{b} i sprawdzają, czy lista ma kolejność \texttt{a -> b -> c -> end}.
|
|
||||||
\end{itemize}
|
|
||||||
}{
|
|
||||||
W ASM zwróć uwagę na porównywanie adresów w pętli z linii 15. To porządkowanie po adresie jest przygotowaniem do scalania bloków w następnym tasku.
|
|
||||||
}
|
|
||||||
\TaskSection{08}{task08_coalescing}{scalanie bloków}{
|
|
||||||
\begin{itemize}[leftmargin=1.6em]
|
|
||||||
\item Linie 11--17 znajdują miejsce w liście, w którym powinien znaleźć się zwracany blok.
|
|
||||||
\item Linie 19--25 sprawdzają sąsiedztwo z prawym blokiem; jeśli adres końca zwracanego bloku jest adresem następnego, rozmiary są łączone.
|
|
||||||
\item Linie 27--32 sprawdzają sąsiedztwo z lewym blokiem i ewentualnie dołączają scalony wynik do lewej strony.
|
|
||||||
\item Linie 35--44 liczą końcową liczbę wolnych bloków.
|
|
||||||
\item Linie 52--65 budują trzy sąsiednie bloki w pamięci, a linia 67 uruchamia scalanie środkowego bloku.
|
|
||||||
\item Linie 69--71 zapisują, czy po scaleniu został jeden blok i jaki ma rozmiar.
|
|
||||||
\end{itemize}
|
|
||||||
}{
|
|
||||||
W ASM szukaj testu \texttt{(uint8\_t *)block + block->size == iterator->next}. To jest sedno scalania: alokator nie porównuje indeksów, tylko rzeczywiste adresy końca i początku bloków.
|
|
||||||
}
|
|
||||||
\TaskSection{09}{task09_config_macros}{makra konfiguracyjne}{
|
|
||||||
\begin{itemize}[leftmargin=1.6em]
|
|
||||||
\item Linie 3--9 definiują wartości domyślne tylko wtedy, gdy nie zostały podane z zewnątrz przez kompilator.
|
|
||||||
\item Linia 11 tworzy wartość pochodną od konfiguracji i wyrównania.
|
|
||||||
\item Linie 20--22 zapisują wartości makr do zmiennych \texttt{volatile}, żeby były widoczne w debugerze.
|
|
||||||
\item Linie 24--28 pokazują kompilację warunkową: host ustawia \texttt{g\_trace\_is\_host\_only} na 1, RV32I na 0.
|
|
||||||
\item Linie 30--32 wypisują wynik tylko w wariancie hostowym.
|
|
||||||
\end{itemize}
|
|
||||||
}{
|
|
||||||
W ASM dla RV32I nie powinno być wywołania \texttt{printf}. Sprawdź też, że makra konfiguracyjne nie są zmiennymi w pamięci, tylko stałymi wstawionymi do kodu przez preprocesor.
|
|
||||||
}
|
|
||||||
\TaskSection{10}{task10_heap4_demo}{mini \texttt{heap\_4}}{
|
|
||||||
\begin{itemize}[leftmargin=1.6em]
|
|
||||||
\item Linie 18--38 to funkcje diagnostyczne przechodzące po liście wolnych bloków.
|
|
||||||
\item Linie 40--62 wstawiają blok i scalają go z prawym oraz lewym sąsiadem.
|
|
||||||
\item Linie 64--88 inicjalizują stertę: wyrównują początek, ustawiają wartownika, pierwszy wolny blok i liczniki wolnej pamięci.
|
|
||||||
\item Linie 90--131 implementują alokację: sprawdzają rozmiar żądania, szukają bloku, dzielą go lub zdejmują w całości z listy, oznaczają jako zajęty i aktualizują minimum wolnej pamięci.
|
|
||||||
\item Linie 133--149 implementują zwalnianie: wracają z adresu użytkownika do nagłówka, sprawdzają bit alokacji, przywracają rozmiar i scalają blok.
|
|
||||||
\item Linie 157--169 wykonują sekwencję \texttt{malloc/free} i zapisują stan końcowy alokatora.
|
|
||||||
\end{itemize}
|
|
||||||
}{
|
|
||||||
W ASM porównaj trzy fragmenty: inicjalizację listy, pętlę szukania wolnego bloku oraz wywołanie \texttt{insert\_block\_merge}. To pokazuje, że pełny model składa się z prostych operacji wskaźnikowych poznanych w poprzednich taskach.
|
|
||||||
}
|
|
||||||
|
|
||||||
\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{enumerate}
|
||||||
|
|
||||||
|
\section*{Warunek zaliczenia}
|
||||||
|
\begin{itemize}
|
||||||
|
\item \checkline przewiduję rozmiary nagłówków i bloków na AMD64/RV32;
|
||||||
|
\item \checkline rozpoznaję fragmentację: suma wolnych bajtów $\neq$ największy blok;
|
||||||
|
\item \checkline pokazuję split i dwa kierunki scalania w Memory;
|
||||||
|
\item \checkline odczytuję \texttt{xStart}, \texttt{pxEnd}, minimum-ever i stack frame;
|
||||||
|
\item \checkline Task 3 daje \texttt{pass=1} na host, Hazard3 i RP2350.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Start — polecenia i platformy}
|
||||||
|
|
||||||
|
\begin{lstlisting}[language=bash,numbers=none]
|
||||||
|
stemctl test native-amd64 freertos heap4 1
|
||||||
|
stemctl test hazard3-sim freertos heap4 2
|
||||||
|
stemctl debug hazard3-sim freertos heap4 3
|
||||||
|
stemctl test rp2350 freertos heap4 3
|
||||||
|
stemctl deploy rp2350 freertos heap4 3 \
|
||||||
|
--device /dev/bus/usb/BBB/DDD
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
\begin{tabularx}{\textwidth}{@{}p{3.1cm}XXX@{}}
|
||||||
|
\toprule
|
||||||
|
& AMD64 & Hazard3 & RP2350 \\
|
||||||
|
\midrule
|
||||||
|
Task 1--2 & model + sanitizery & model na RTL & build \\
|
||||||
|
Task 3 & V11.3 + adapter 1-thread & pełny V11.3 + port RISC-V & zgodny core+port RP; allocator V11.3 \\
|
||||||
|
Debug & GDB & GDB stub RTL & OpenOCD; SRAM \\
|
||||||
|
Deploy & --- & --- & SPI flash + verify \\
|
||||||
|
\bottomrule
|
||||||
|
\end{tabularx}
|
||||||
|
|
||||||
|
\subsection*{Termdebug}
|
||||||
|
\begin{tabularx}{\textwidth}{@{}lXlX@{}}
|
||||||
|
\toprule
|
||||||
|
\texttt{F5} & continue & \texttt{F9} & breakpoint \\
|
||||||
|
\texttt{F10} & next & \texttt{F11} & step \\
|
||||||
|
\texttt{Shift-F11} & finish & \texttt{F8} & stepi \\
|
||||||
|
\texttt{:StudentStack} & frame + stos & \texttt{:StudentLst} & listing ELF-a \\
|
||||||
|
\bottomrule
|
||||||
|
\end{tabularx}
|
||||||
|
|
||||||
|
\textbf{Strategia obserwacji}: breakpoint przed zmianą $\rightarrow$ Memory
|
||||||
|
$\rightarrow$ continue/finish $\rightarrow$ Memory. Nie opieramy karty na data
|
||||||
|
watchpointach.
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Task 1 — first-fit i split}
|
||||||
|
|
||||||
|
\subsection*{Policz przed uruchomieniem}
|
||||||
|
\begin{tabular}{@{}lcc@{}}
|
||||||
|
\toprule
|
||||||
|
& AMD64 & RV32 \\
|
||||||
|
\midrule
|
||||||
|
\texttt{sizeof(ModelBlock)} & \rule{1.6cm}{.2pt} & \rule{1.6cm}{.2pt} \\
|
||||||
|
request & 13 B & 13 B \\
|
||||||
|
\texttt{align8(header + request)} & \rule{1.6cm}{.2pt} & \rule{1.6cm}{.2pt} \\
|
||||||
|
remainder z 256 B & \rule{1.6cm}{.2pt} & \rule{1.6cm}{.2pt} \\
|
||||||
|
offset payloadu & \rule{1.6cm}{.2pt} & \rule{1.6cm}{.2pt} \\
|
||||||
|
\bottomrule
|
||||||
|
\end{tabular}
|
||||||
|
|
||||||
|
\subsection*{Do wykonania}
|
||||||
|
\begin{enumerate}
|
||||||
|
\item Wskaż nagłówek bloku przydzielonego i nagłówek remainder.
|
||||||
|
\item Sprawdź: \texttt{wanted + remainder == 256}.
|
||||||
|
\item Zmień request 13 na 17; przewidź wynik bez uruchamiania.
|
||||||
|
\item W listingu znajdź dodawanie bajtowego offsetu do adresu areny.
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
\lstinputlisting{../src/tasks/task01_first_fit_split.c}
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Task 2 — lista adresowa i coalescing}
|
||||||
|
|
||||||
|
\subsection*{Eksperyment}
|
||||||
|
\begin{center}
|
||||||
|
\texttt{A:48 | B:48 | C:48}\quad
|
||||||
|
$\xrightarrow{\text{free A, free C}}$\quad
|
||||||
|
\texttt{A:48 -> C:48}\quad
|
||||||
|
$\xrightarrow{\text{free B}}$\quad
|
||||||
|
\texttt{A:144}
|
||||||
|
\end{center}
|
||||||
|
|
||||||
|
\subsection*{Do wykonania}
|
||||||
|
\begin{enumerate}
|
||||||
|
\item Zatrzymaj program w \texttt{task02\_fragmented\_checkpoint}.
|
||||||
|
\item Zapisz adresy i rozmiary dwóch elementów free-list.
|
||||||
|
\item Wykonaj \texttt{F5}; zatrzymaj w \texttt{task02\_debug\_checkpoint}.
|
||||||
|
\item Wskaż pierwszy warunek scalania: z blokiem po prawej.
|
||||||
|
\item Wskaż drugi warunek scalania: z blokiem po lewej.
|
||||||
|
\item Wyjaśnij, czemu kolejność po adresie redukuje koszt szukania sąsiadów.
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
\subsection*{Tabela obserwacji}
|
||||||
|
\begin{tabular}{@{}lccc@{}}
|
||||||
|
\toprule
|
||||||
|
Stan & liczba bloków & suma & największy \\
|
||||||
|
\midrule
|
||||||
|
przed B & \rule{1.4cm}{.2pt} & \rule{1.4cm}{.2pt} & \rule{1.4cm}{.2pt} \\
|
||||||
|
po B & \rule{1.4cm}{.2pt} & \rule{1.4cm}{.2pt} & \rule{1.4cm}{.2pt} \\
|
||||||
|
\bottomrule
|
||||||
|
\end{tabular}
|
||||||
|
|
||||||
|
\lstinputlisting{../src/tasks/task02_address_order_coalesce.c}
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Task 3 — prawdziwy FreeRTOS \texttt{heap\_4.c}}
|
||||||
|
|
||||||
|
\subsection*{Sekwencja testowa}
|
||||||
|
\begin{enumerate}
|
||||||
|
\item init przez pierwsze \texttt{pvPortMalloc(1)} i \texttt{vPortFree}; zapisz $F_0$;
|
||||||
|
\item malloc: 24 B, 40 B, 16 B; zapisz $F_1$;
|
||||||
|
\item free pierwszego i trzeciego; oczekuj 2 wolnych bloków;
|
||||||
|
\item free środkowego; oczekuj jednego bloku i $F_{final}=F_0$;
|
||||||
|
\item malloc większy niż heap; oczekuj \texttt{NULL} i jednego hooka.
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
\subsection*{Inwarianty — zaznacz po teście}
|
||||||
|
\begin{itemize}
|
||||||
|
\item \checkline $F_0 > F_1$;
|
||||||
|
\item \checkline $F_{final}=F_0$;
|
||||||
|
\item \checkline minimum-ever $\leq F_1$ i nie rośnie po free;
|
||||||
|
\item \checkline każdy payload ma adres podzielny przez 8;
|
||||||
|
\item \checkline OOM zwraca \texttt{NULL};
|
||||||
|
\item \checkline końcowa free-list ma dokładnie jeden blok.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\lstinputlisting{../src/tasks/task03_freertos_heap4.c}
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Czytanie upstream \texttt{heap\_4.c}}
|
||||||
|
|
||||||
|
\subsection*{Znajdź w pliku — nie czytaj całego od góry}
|
||||||
|
\begin{lstlisting}[language=bash,numbers=none]
|
||||||
|
K=/opt/FreeRTOS-Kernel/portable/MemMang/heap_4.c
|
||||||
|
rg -n 'xHeapStructSize|pvPortMalloc|prvHeapInit' "$K"
|
||||||
|
rg -n 'prvInsertBlockIntoFreeList|vPortFree' "$K"
|
||||||
|
rg -n 'xFreeBytesRemaining|xMinimumEver' "$K"
|
||||||
|
rg -n 'heapADD_WILL_OVERFLOW|heapBLOCK_ALLOCATED' "$K"
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
\begin{itemize}[leftmargin=*,itemsep=2pt]
|
||||||
|
\item \texttt{xHeapStructSize}: dlaczego jest wyrównany oddzielnie od
|
||||||
|
\texttt{sizeof}?
|
||||||
|
\item \texttt{heapBLOCK\_ALLOCATED\_BITMASK}: który bit rozmiaru oznacza
|
||||||
|
właściciela?
|
||||||
|
\item \texttt{pvPortMalloc}: gdzie są overflow, alignment, first-fit i split?
|
||||||
|
\item \texttt{vPortFree}: jak odzyskuje nagłówek z payloadu?
|
||||||
|
\item \texttt{prvInsertBlockIntoFreeList}: gdzie są dwa kierunki scalania?
|
||||||
|
\item \texttt{xMinimumEverFreeBytesRemaining}: dlaczego free go nie zwiększa?
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\subsection*{Breakpointy}
|
||||||
|
\begin{lstlisting}[numbers=none]
|
||||||
|
b pvPortMalloc
|
||||||
|
b vPortFree
|
||||||
|
b prvInsertBlockIntoFreeList
|
||||||
|
p xStart
|
||||||
|
p pxEnd
|
||||||
|
p xFreeBytesRemaining
|
||||||
|
p xMinimumEverFreeBytesRemaining
|
||||||
|
x/160bx ucHeap
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{RP2350 — deploy i dowód sprzętowy}
|
||||||
|
|
||||||
|
\subsection*{Polecenie}
|
||||||
|
\begin{lstlisting}[language=bash,numbers=none]
|
||||||
|
stemctl probe list
|
||||||
|
stemctl deploy rp2350 freertos heap4 3 \
|
||||||
|
--device /dev/bus/usb/BBB/DDD
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
\subsection*{Automatyczny test zatrzymuje się dwa razy}
|
||||||
|
\begin{enumerate}
|
||||||
|
\item \texttt{heap4\_fragmented\_checkpoint}: 2 wolne bloki;
|
||||||
|
\item \texttt{task03\_debug\_checkpoint}: heap odtworzony, OOM obsłużony.
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
\subsection*{Zapis ucznia}
|
||||||
|
\begin{tabular}{@{}ll@{}}
|
||||||
|
\toprule
|
||||||
|
Wielkość & Wartość \\
|
||||||
|
\midrule
|
||||||
|
\texttt{initial free} & \rule{4cm}{.2pt} \\
|
||||||
|
\texttt{after allocations} & \rule{4cm}{.2pt} \\
|
||||||
|
\texttt{minimum ever} & \rule{4cm}{.2pt} \\
|
||||||
|
\texttt{final free} & \rule{4cm}{.2pt} \\
|
||||||
|
\texttt{sp / fp / pc} & \rule{7cm}{.2pt} \\
|
||||||
|
\bottomrule
|
||||||
|
\end{tabular}
|
||||||
|
|
||||||
|
\subsection*{Kontrakt}
|
||||||
|
\begin{itemize}
|
||||||
|
\item flash: write + verify; ELF: RISC-V;
|
||||||
|
\item breakpointy sprzętowe, nie data watchpoint;
|
||||||
|
\item \texttt{aligned=1 oom=1 hooks=1 asserts=0 pass=1};
|
||||||
|
\item \texttt{sp \& 15 == 0};
|
||||||
|
\item \texttt{rp2350-hardware-ok task=task03 heap\_4=upstream}.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\textbf{Operacje są rozdzielone}: \texttt{debug} ładuje do SRAM;
|
||||||
|
\texttt{deploy} zapisuje trwały obraz do SPI flash.
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Podsumowanie i oddanie}
|
||||||
|
|
||||||
|
\subsection*{Odpowiedz jednym zdaniem}
|
||||||
|
\begin{enumerate}
|
||||||
|
\item Dlaczego \texttt{heap\_4} scala, a nie tylko odkłada blok na listę?\\[.6em]
|
||||||
|
\rule{\textwidth}{.2pt}
|
||||||
|
\item Dlaczego „wolne razem” nie oznacza „można przydzielić jeden duży blok”?\\[.6em]
|
||||||
|
\rule{\textwidth}{.2pt}
|
||||||
|
\item Gdzie leży metadata bloku przydzielonego aplikacji?\\[.6em]
|
||||||
|
\rule{\textwidth}{.2pt}
|
||||||
|
\item Co mierzy minimum-ever-free, a czego nie mierzy?\\[.6em]
|
||||||
|
\rule{\textwidth}{.2pt}
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
\subsection*{Oddaj}
|
||||||
|
\begin{itemize}
|
||||||
|
\item \checkline wyniki 3 tasków na AMD64;
|
||||||
|
\item \checkline Hazard3: trzy kody wyjścia 0;
|
||||||
|
\item \checkline zrzut Task 2: przed i po scaleniu;
|
||||||
|
\item \checkline zrzut Task 3: source + listing + Memory + Stack;
|
||||||
|
\item \checkline wynik RP2350 \texttt{rp2350-hardware-ok};
|
||||||
|
\item \checkline wypełnione inwarianty i cztery odpowiedzi.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\vfill
|
||||||
|
\noindent\textbf{Dalej}: taski FreeRTOS, scheduler, osobne stosy, 1 kHz tick;
|
||||||
|
następnie cienki C++ header wrapper i użycie w projekcie hoveboard.
|
||||||
|
|
||||||
\end{document}
|
\end{document}
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
#ifndef FREERTOS_CONFIG_H
|
||||||
|
#define FREERTOS_CONFIG_H
|
||||||
|
|
||||||
|
#define configCPU_CLOCK_HZ ( 150000000UL )
|
||||||
|
#define configTICK_RATE_HZ ( 1000U )
|
||||||
|
#define configMTIME_BASE_ADDRESS ( 0xC0000100UL )
|
||||||
|
#define configMTIMECMP_BASE_ADDRESS ( 0xC0000108UL )
|
||||||
|
|
||||||
|
#define configUSE_PREEMPTION 1
|
||||||
|
#define configUSE_TIME_SLICING 1
|
||||||
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
#define configUSE_IDLE_HOOK 0
|
||||||
|
#define configUSE_PASSIVE_IDLE_HOOK 0
|
||||||
|
#define configUSE_TICK_HOOK 0
|
||||||
|
#define configMAX_PRIORITIES 4
|
||||||
|
#define configMINIMAL_STACK_SIZE 128
|
||||||
|
#define configMAX_TASK_NAME_LEN 12
|
||||||
|
#define configTICK_TYPE_WIDTH_IN_BITS TICK_TYPE_WIDTH_32_BITS
|
||||||
|
#define configIDLE_SHOULD_YIELD 1
|
||||||
|
|
||||||
|
#define configNUMBER_OF_CORES 1
|
||||||
|
#define configTICK_CORE 0
|
||||||
|
#define configUSE_CORE_AFFINITY 0
|
||||||
|
#define configRUN_MULTIPLE_PRIORITIES 0
|
||||||
|
#define configSUPPORT_PICO_SYNC_INTEROP 0
|
||||||
|
|
||||||
|
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||||
|
#define configSUPPORT_STATIC_ALLOCATION 0
|
||||||
|
#define configTOTAL_HEAP_SIZE ( 4096U )
|
||||||
|
#define configAPPLICATION_ALLOCATED_HEAP 1
|
||||||
|
#define configUSE_MALLOC_FAILED_HOOK 1
|
||||||
|
#define configHEAP_CLEAR_MEMORY_ON_FREE 0
|
||||||
|
#define configENABLE_HEAP_PROTECTOR 0
|
||||||
|
|
||||||
|
#define configUSE_TIMERS 0
|
||||||
|
#define configUSE_MUTEXES 0
|
||||||
|
#define configUSE_RECURSIVE_MUTEXES 0
|
||||||
|
#define configUSE_COUNTING_SEMAPHORES 0
|
||||||
|
#define configUSE_TASK_NOTIFICATIONS 1
|
||||||
|
#define configUSE_TRACE_FACILITY 1
|
||||||
|
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
|
||||||
|
#define configGENERATE_RUN_TIME_STATS 0
|
||||||
|
#define configUSE_CO_ROUTINES 0
|
||||||
|
#define configUSE_NEWLIB_REENTRANT 0
|
||||||
|
#define configUSE_POSIX_ERRNO 0
|
||||||
|
#define configCHECK_FOR_STACK_OVERFLOW 0
|
||||||
|
|
||||||
|
#define INCLUDE_vTaskDelay 0
|
||||||
|
#define INCLUDE_vTaskDelayUntil 0
|
||||||
|
#define INCLUDE_vTaskDelete 0
|
||||||
|
#define INCLUDE_vTaskSuspend 0
|
||||||
|
#define INCLUDE_xTaskGetSchedulerState 0
|
||||||
|
|
||||||
|
#define configENABLE_FPU 0
|
||||||
|
#define configENABLE_VPU 0
|
||||||
|
#if !defined(PICO_RP2350)
|
||||||
|
#define configISR_STACK_SIZE_WORDS 128
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __ASSEMBLER__
|
||||||
|
void heap4_lab_assert(const char *file, int line);
|
||||||
|
#define configASSERT(condition) \
|
||||||
|
do { if (!(condition)) heap4_lab_assert(__FILE__, __LINE__); } while (0)
|
||||||
|
#else
|
||||||
|
#define configASSERT(condition)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#ifndef FREERTOS_RISC_V_CHIP_SPECIFIC_EXTENSIONS_H
|
||||||
|
#define FREERTOS_RISC_V_CHIP_SPECIFIC_EXTENSIONS_H
|
||||||
|
|
||||||
|
/* Hazard3 adds no architectural registers to the base RV32I context. */
|
||||||
|
#define portasmHAS_MTIME 1
|
||||||
|
#define portasmHAS_SIFIVE_CLINT 0
|
||||||
|
#define portasmADDITIONAL_CONTEXT_SIZE 0
|
||||||
|
|
||||||
|
.macro portasmSAVE_ADDITIONAL_REGISTERS
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro portasmRESTORE_ADDITIONAL_REGISTERS
|
||||||
|
.endm
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#ifndef HEAP4_FREESTANDING_STDLIB_H
|
||||||
|
#define HEAP4_FREESTANDING_STDLIB_H
|
||||||
|
#include <stddef.h>
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#ifndef HEAP4_FREESTANDING_STRING_H
|
||||||
|
#define HEAP4_FREESTANDING_STRING_H
|
||||||
|
#include <stddef.h>
|
||||||
|
void *memcpy(void *destination, const void *source, size_t count);
|
||||||
|
void *memset(void *destination, int value, size_t count);
|
||||||
|
size_t strlen(const char *text);
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
#ifndef HEAP4_HOST_FREERTOS_H
|
||||||
|
#define HEAP4_HOST_FREERTOS_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef int BaseType_t;
|
||||||
|
typedef uintptr_t portPOINTER_SIZE_TYPE;
|
||||||
|
|
||||||
|
typedef struct xHeapStats {
|
||||||
|
size_t xAvailableHeapSpaceInBytes;
|
||||||
|
size_t xSizeOfLargestFreeBlockInBytes;
|
||||||
|
size_t xSizeOfSmallestFreeBlockInBytes;
|
||||||
|
size_t xNumberOfFreeBlocks;
|
||||||
|
size_t xMinimumEverFreeBytesRemaining;
|
||||||
|
size_t xNumberOfSuccessfulAllocations;
|
||||||
|
size_t xNumberOfSuccessfulFrees;
|
||||||
|
} HeapStats_t;
|
||||||
|
|
||||||
|
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||||
|
#define configTOTAL_HEAP_SIZE ((size_t)4096U)
|
||||||
|
#define configAPPLICATION_ALLOCATED_HEAP 1
|
||||||
|
#define configUSE_MALLOC_FAILED_HOOK 1
|
||||||
|
#define configHEAP_CLEAR_MEMORY_ON_FREE 0
|
||||||
|
#define configENABLE_HEAP_PROTECTOR 0
|
||||||
|
|
||||||
|
#define portBYTE_ALIGNMENT 8U
|
||||||
|
#define portBYTE_ALIGNMENT_MASK (portBYTE_ALIGNMENT - 1U)
|
||||||
|
#define portMAX_DELAY (~(size_t)0U)
|
||||||
|
|
||||||
|
#define PRIVILEGED_DATA
|
||||||
|
#define PRIVILEGED_FUNCTION
|
||||||
|
#define mtCOVERAGE_TEST_MARKER() do { } while (0)
|
||||||
|
#define traceMALLOC(pointer, size) do { (void)(pointer); (void)(size); } while (0)
|
||||||
|
#define traceFREE(pointer, size) do { (void)(pointer); (void)(size); } while (0)
|
||||||
|
#define taskENTER_CRITICAL() do { } while (0)
|
||||||
|
#define taskEXIT_CRITICAL() do { } while (0)
|
||||||
|
|
||||||
|
void heap4_lab_assert(const char *file, int line);
|
||||||
|
void vApplicationMallocFailedHook(void);
|
||||||
|
void *pvPortMalloc(size_t wanted_size);
|
||||||
|
void vPortFree(void *pointer);
|
||||||
|
size_t xPortGetFreeHeapSize(void);
|
||||||
|
size_t xPortGetMinimumEverFreeHeapSize(void);
|
||||||
|
void vPortGetHeapStats(HeapStats_t *stats);
|
||||||
|
void vPortHeapResetState(void);
|
||||||
|
#define configASSERT(condition) \
|
||||||
|
do { if (!(condition)) heap4_lab_assert(__FILE__, __LINE__); } while (0)
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef HEAP4_HOST_TASK_H
|
||||||
|
#define HEAP4_HOST_TASK_H
|
||||||
|
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
|
||||||
|
void vTaskSuspendAll(void);
|
||||||
|
BaseType_t xTaskResumeAll(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
#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,25 @@
|
|||||||
|
#ifndef HEAP4_MODEL_H
|
||||||
|
#define HEAP4_MODEL_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define MODEL_ALIGNMENT ((size_t)8U)
|
||||||
|
|
||||||
|
typedef struct ModelBlock ModelBlock;
|
||||||
|
|
||||||
|
struct ModelBlock {
|
||||||
|
ModelBlock *next;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline size_t model_align_up(size_t value)
|
||||||
|
{
|
||||||
|
return (value + MODEL_ALIGNMENT - 1U) & ~(MODEL_ALIGNMENT - 1U);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(HOST_PRINTF)
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
#include "heap4_model.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ARENA_BYTES = 256,
|
||||||
|
REQUEST_BYTES = 13,
|
||||||
|
WANTED_BYTES = (sizeof(ModelBlock) + REQUEST_BYTES + 7U) & ~7U
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ModelBlock allocated;
|
||||||
|
uint8_t payload[WANTED_BYTES - sizeof(ModelBlock)];
|
||||||
|
ModelBlock remainder;
|
||||||
|
uint8_t free_payload[ARENA_BYTES - WANTED_BYTES - sizeof(ModelBlock)];
|
||||||
|
} SplitArena;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
uint64_t force_alignment;
|
||||||
|
SplitArena blocks;
|
||||||
|
} AlignedSplitArena;
|
||||||
|
|
||||||
|
AlignedSplitArena g_split_arena;
|
||||||
|
ModelBlock *g_free_head;
|
||||||
|
volatile size_t g_header_bytes;
|
||||||
|
volatile size_t g_wanted_bytes;
|
||||||
|
volatile size_t g_remainder_bytes;
|
||||||
|
volatile size_t g_payload_offset;
|
||||||
|
volatile int g_split_addresses_aligned;
|
||||||
|
volatile int g_task01_pass;
|
||||||
|
|
||||||
|
__attribute__((noinline)) void task01_debug_checkpoint(void)
|
||||||
|
{
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
__asm__ volatile("" ::: "memory");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
SplitArena *arena = &g_split_arena.blocks;
|
||||||
|
uintptr_t base = (uintptr_t)&arena->allocated;
|
||||||
|
uintptr_t remainder = (uintptr_t)&arena->remainder;
|
||||||
|
|
||||||
|
arena->allocated.next = NULL;
|
||||||
|
arena->allocated.size = WANTED_BYTES;
|
||||||
|
arena->remainder.next = NULL;
|
||||||
|
arena->remainder.size = ARENA_BYTES - WANTED_BYTES;
|
||||||
|
arena->payload[0] = (uint8_t)'A';
|
||||||
|
g_free_head = &arena->remainder;
|
||||||
|
|
||||||
|
g_header_bytes = sizeof(ModelBlock);
|
||||||
|
g_wanted_bytes = WANTED_BYTES;
|
||||||
|
g_remainder_bytes = arena->remainder.size;
|
||||||
|
g_payload_offset = (size_t)((uintptr_t)&arena->payload[0] - base);
|
||||||
|
g_split_addresses_aligned =
|
||||||
|
(base % MODEL_ALIGNMENT) == 0U &&
|
||||||
|
(remainder % MODEL_ALIGNMENT) == 0U;
|
||||||
|
g_task01_pass =
|
||||||
|
g_wanted_bytes == model_align_up(sizeof(ModelBlock) + REQUEST_BYTES) &&
|
||||||
|
(size_t)(remainder - base) == g_wanted_bytes &&
|
||||||
|
g_remainder_bytes + g_wanted_bytes == ARENA_BYTES &&
|
||||||
|
g_payload_offset == sizeof(ModelBlock) &&
|
||||||
|
g_split_addresses_aligned;
|
||||||
|
|
||||||
|
task01_debug_checkpoint();
|
||||||
|
|
||||||
|
#if defined(HOST_PRINTF)
|
||||||
|
printf("header=%zu wanted=%zu remainder=%zu payload=%zu aligned=%d pass=%d\n",
|
||||||
|
g_header_bytes, g_wanted_bytes, g_remainder_bytes,
|
||||||
|
g_payload_offset, g_split_addresses_aligned, g_task01_pass);
|
||||||
|
#endif
|
||||||
|
return g_task01_pass ? 0 : 1;
|
||||||
|
}
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
#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,136 @@
|
|||||||
|
#include "heap4_model.h"
|
||||||
|
|
||||||
|
enum { BLOCK_BYTES = 48 };
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ModelBlock first;
|
||||||
|
uint8_t first_payload[BLOCK_BYTES - sizeof(ModelBlock)];
|
||||||
|
ModelBlock middle;
|
||||||
|
uint8_t middle_payload[BLOCK_BYTES - sizeof(ModelBlock)];
|
||||||
|
ModelBlock last;
|
||||||
|
uint8_t last_payload[BLOCK_BYTES - sizeof(ModelBlock)];
|
||||||
|
} CoalesceArena;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
uint64_t force_alignment;
|
||||||
|
CoalesceArena blocks;
|
||||||
|
} AlignedCoalesceArena;
|
||||||
|
|
||||||
|
AlignedCoalesceArena g_coalesce_arena;
|
||||||
|
ModelBlock *g_free_head;
|
||||||
|
volatile size_t g_before_nodes;
|
||||||
|
volatile size_t g_before_total;
|
||||||
|
volatile size_t g_before_largest;
|
||||||
|
volatile size_t g_after_nodes;
|
||||||
|
volatile size_t g_after_total;
|
||||||
|
volatile size_t g_after_largest;
|
||||||
|
volatile int g_task02_pass;
|
||||||
|
|
||||||
|
static void insert_and_coalesce(ModelBlock *block)
|
||||||
|
{
|
||||||
|
ModelBlock *previous = NULL;
|
||||||
|
ModelBlock *current = g_free_head;
|
||||||
|
|
||||||
|
while (current != NULL && (uintptr_t)current < (uintptr_t)block)
|
||||||
|
{
|
||||||
|
previous = current;
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
block->next = current;
|
||||||
|
if (current != NULL &&
|
||||||
|
(uint8_t *)block + block->size == (uint8_t *)current)
|
||||||
|
{
|
||||||
|
block->size += current->size;
|
||||||
|
block->next = current->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (previous != NULL &&
|
||||||
|
(uint8_t *)previous + previous->size == (uint8_t *)block)
|
||||||
|
{
|
||||||
|
previous->size += block->size;
|
||||||
|
previous->next = block->next;
|
||||||
|
}
|
||||||
|
else if (previous != NULL)
|
||||||
|
{
|
||||||
|
previous->next = block;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_free_head = block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void measure(size_t *nodes, size_t *total, size_t *largest)
|
||||||
|
{
|
||||||
|
ModelBlock *block;
|
||||||
|
|
||||||
|
*nodes = 0U;
|
||||||
|
*total = 0U;
|
||||||
|
*largest = 0U;
|
||||||
|
for (block = g_free_head; block != NULL; block = block->next)
|
||||||
|
{
|
||||||
|
(*nodes)++;
|
||||||
|
*total += block->size;
|
||||||
|
if (block->size > *largest)
|
||||||
|
{
|
||||||
|
*largest = block->size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((noinline)) void task02_fragmented_checkpoint(void)
|
||||||
|
{
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
__asm__ volatile("" ::: "memory");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((noinline)) void task02_debug_checkpoint(void)
|
||||||
|
{
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
__asm__ volatile("" ::: "memory");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
CoalesceArena *arena = &g_coalesce_arena.blocks;
|
||||||
|
size_t nodes;
|
||||||
|
size_t total;
|
||||||
|
size_t largest;
|
||||||
|
|
||||||
|
arena->first.size = BLOCK_BYTES;
|
||||||
|
arena->middle.size = BLOCK_BYTES;
|
||||||
|
arena->last.size = BLOCK_BYTES;
|
||||||
|
g_free_head = NULL;
|
||||||
|
|
||||||
|
insert_and_coalesce(&arena->first);
|
||||||
|
insert_and_coalesce(&arena->last);
|
||||||
|
measure(&nodes, &total, &largest);
|
||||||
|
g_before_nodes = nodes;
|
||||||
|
g_before_total = total;
|
||||||
|
g_before_largest = largest;
|
||||||
|
task02_fragmented_checkpoint();
|
||||||
|
|
||||||
|
insert_and_coalesce(&arena->middle);
|
||||||
|
measure(&nodes, &total, &largest);
|
||||||
|
g_after_nodes = nodes;
|
||||||
|
g_after_total = total;
|
||||||
|
g_after_largest = largest;
|
||||||
|
g_task02_pass =
|
||||||
|
g_before_nodes == 2U && g_before_total == 96U &&
|
||||||
|
g_before_largest == 48U && g_after_nodes == 1U &&
|
||||||
|
g_after_total == 144U && g_after_largest == 144U &&
|
||||||
|
g_free_head == &arena->first && g_free_head->next == NULL;
|
||||||
|
|
||||||
|
task02_debug_checkpoint();
|
||||||
|
|
||||||
|
#if defined(HOST_PRINTF)
|
||||||
|
printf("before_nodes=%zu before_total=%zu before_largest=%zu "
|
||||||
|
"after_nodes=%zu after_total=%zu after_largest=%zu pass=%d\n",
|
||||||
|
g_before_nodes, g_before_total, g_before_largest,
|
||||||
|
g_after_nodes, g_after_total, g_after_largest, g_task02_pass);
|
||||||
|
#endif
|
||||||
|
return g_task02_pass ? 0 : 1;
|
||||||
|
}
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
#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,122 @@
|
|||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "task.h"
|
||||||
|
|
||||||
|
#if defined(HOST_PRINTF)
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint8_t ucHeap[configTOTAL_HEAP_SIZE] __attribute__((aligned(portBYTE_ALIGNMENT)));
|
||||||
|
|
||||||
|
HeapStats_t g_fragmented_stats;
|
||||||
|
HeapStats_t g_final_stats;
|
||||||
|
volatile size_t g_initial_free;
|
||||||
|
volatile size_t g_after_allocations;
|
||||||
|
volatile size_t g_final_free;
|
||||||
|
volatile size_t g_minimum_ever_free;
|
||||||
|
volatile int g_allocations_aligned;
|
||||||
|
volatile int g_oom_is_null;
|
||||||
|
volatile int g_malloc_failed_hooks;
|
||||||
|
volatile int g_assert_failures;
|
||||||
|
volatile int g_task03_pass;
|
||||||
|
|
||||||
|
void vApplicationMallocFailedHook(void)
|
||||||
|
{
|
||||||
|
g_malloc_failed_hooks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void heap4_lab_assert(const char *file, int line)
|
||||||
|
{
|
||||||
|
(void)file;
|
||||||
|
(void)line;
|
||||||
|
g_assert_failures++;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(HEAP4_HOST_ADAPTER)
|
||||||
|
void vTaskSuspendAll(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseType_t xTaskResumeAll(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
__attribute__((noinline)) void heap4_fragmented_checkpoint(void)
|
||||||
|
{
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
__asm__ volatile("" ::: "memory");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((noinline)) void task03_debug_checkpoint(void)
|
||||||
|
{
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
__asm__ volatile("" ::: "memory");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
void *probe;
|
||||||
|
void *a;
|
||||||
|
void *b;
|
||||||
|
void *c;
|
||||||
|
void *too_large;
|
||||||
|
|
||||||
|
vPortHeapResetState();
|
||||||
|
probe = pvPortMalloc(1U);
|
||||||
|
if (probe != NULL)
|
||||||
|
{
|
||||||
|
vPortFree(probe);
|
||||||
|
}
|
||||||
|
g_initial_free = xPortGetFreeHeapSize();
|
||||||
|
|
||||||
|
a = pvPortMalloc(24U);
|
||||||
|
b = pvPortMalloc(40U);
|
||||||
|
c = pvPortMalloc(16U);
|
||||||
|
g_after_allocations = xPortGetFreeHeapSize();
|
||||||
|
g_allocations_aligned =
|
||||||
|
a != NULL && b != NULL && c != NULL &&
|
||||||
|
((uintptr_t)a % portBYTE_ALIGNMENT) == 0U &&
|
||||||
|
((uintptr_t)b % portBYTE_ALIGNMENT) == 0U &&
|
||||||
|
((uintptr_t)c % portBYTE_ALIGNMENT) == 0U;
|
||||||
|
|
||||||
|
vPortFree(a);
|
||||||
|
vPortFree(c);
|
||||||
|
vPortGetHeapStats(&g_fragmented_stats);
|
||||||
|
heap4_fragmented_checkpoint();
|
||||||
|
|
||||||
|
vPortFree(b);
|
||||||
|
g_final_free = xPortGetFreeHeapSize();
|
||||||
|
g_minimum_ever_free = xPortGetMinimumEverFreeHeapSize();
|
||||||
|
vPortGetHeapStats(&g_final_stats);
|
||||||
|
|
||||||
|
too_large = pvPortMalloc(configTOTAL_HEAP_SIZE * 2U);
|
||||||
|
g_oom_is_null = too_large == NULL;
|
||||||
|
g_task03_pass =
|
||||||
|
probe != NULL && g_allocations_aligned &&
|
||||||
|
g_initial_free > g_after_allocations &&
|
||||||
|
g_final_free == g_initial_free &&
|
||||||
|
g_minimum_ever_free <= g_after_allocations &&
|
||||||
|
g_fragmented_stats.xNumberOfFreeBlocks == 2U &&
|
||||||
|
g_final_stats.xNumberOfFreeBlocks == 1U &&
|
||||||
|
g_final_stats.xSizeOfLargestFreeBlockInBytes == g_initial_free &&
|
||||||
|
g_oom_is_null && g_malloc_failed_hooks == 1 &&
|
||||||
|
g_assert_failures == 0;
|
||||||
|
|
||||||
|
task03_debug_checkpoint();
|
||||||
|
|
||||||
|
#if defined(HOST_PRINTF)
|
||||||
|
printf("initial=%zu after=%zu fragmented=%zu final=%zu min=%zu "
|
||||||
|
"aligned=%d oom=%d hooks=%d asserts=%d pass=%d\n",
|
||||||
|
g_initial_free, g_after_allocations,
|
||||||
|
g_fragmented_stats.xNumberOfFreeBlocks, g_final_free,
|
||||||
|
g_minimum_ever_free, g_allocations_aligned, g_oom_is_null,
|
||||||
|
g_malloc_failed_hooks, g_assert_failures, g_task03_pass);
|
||||||
|
#endif
|
||||||
|
return g_task03_pass ? 0 : 1;
|
||||||
|
}
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
#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;
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
#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;
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
#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;
|
|
||||||
}
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
#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;
|
|
||||||
}
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
#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;
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
#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;
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
#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;
|
|
||||||
}
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
#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;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
schema: 1
|
||||||
|
targets:
|
||||||
|
native:
|
||||||
|
profile: native-amd64
|
||||||
|
actions: [build, test, run, debug]
|
||||||
|
hazard3-baremetal:
|
||||||
|
profile: hazard3-sim
|
||||||
|
actions: [build, test, run, debug]
|
||||||
|
rp2350-rv:
|
||||||
|
profile: rp2350
|
||||||
|
actions: [build, test, deploy, debug]
|
||||||
|
actions:
|
||||||
|
build: [bash, tools/card-action.sh, build]
|
||||||
|
test: [bash, tools/card-action.sh, test]
|
||||||
|
run: [bash, tools/card-action.sh, run]
|
||||||
|
deploy: [bash, tools/card-action.sh, deploy]
|
||||||
|
debug: [bash, tools/card-action.sh, debug]
|
||||||
|
artifacts:
|
||||||
|
directory: .stem/artifacts
|
||||||
Executable
+15
@@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
elf="${1:?usage: check_task03_elf.sh ELF [tool-prefix]}"
|
||||||
|
prefix="${2:-riscv64-unknown-elf-}"
|
||||||
|
nm="${prefix}nm"
|
||||||
|
objdump="${prefix}objdump"
|
||||||
|
|
||||||
|
test -s "$elf"
|
||||||
|
for symbol in pvPortMalloc vPortFree prvInsertBlockIntoFreeList ucHeap \
|
||||||
|
heap4_fragmented_checkpoint task03_debug_checkpoint g_task03_pass; do
|
||||||
|
"$nm" -a "$elf" | grep -E "[[:space:]]${symbol}$" >/dev/null
|
||||||
|
done
|
||||||
|
"$objdump" -d "$elf" | grep -E 'addi[[:space:]]+sp,sp,-' >/dev/null
|
||||||
|
printf 'PASS Task 3 links upstream heap_4 and observable checkpoints: %s\n' "$elf"
|
||||||
Executable
+22
@@ -0,0 +1,22 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
make -C "$root" PROFILE=observe host >/dev/null
|
||||||
|
|
||||||
|
check_output() {
|
||||||
|
local program="$1" expected="$2" actual
|
||||||
|
actual="$($program)"
|
||||||
|
if [[ "$actual" != "$expected" ]]; then
|
||||||
|
printf 'FAIL %s\nexpected: %s\nactual: %s\n' "$program" "$expected" "$actual" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
printf 'PASS %s: %s\n' "$(basename -- "$(dirname -- "$program")")" "$actual"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_output "$root/host-build/task01_first_fit_split/prog" \
|
||||||
|
'header=16 wanted=32 remainder=224 payload=16 aligned=1 pass=1'
|
||||||
|
check_output "$root/host-build/task02_address_order_coalesce/prog" \
|
||||||
|
'before_nodes=2 before_total=96 before_largest=48 after_nodes=1 after_total=144 after_largest=144 pass=1'
|
||||||
|
check_output "$root/host-build/task03_freertos_heap4/prog" \
|
||||||
|
'initial=4080 after=3952 fragmented=2 final=4080 min=3952 aligned=1 oom=1 hooks=1 asserts=0 pass=1'
|
||||||
Executable
+358
@@ -0,0 +1,358 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
action="${1:?action is required}"
|
||||||
|
root="${STEM_REPO:-$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)}"
|
||||||
|
profile="${STEM_PROFILE:-native-amd64}"
|
||||||
|
target="${STEM_TARGET:-native}"
|
||||||
|
selector="${STEM_TASK:-task3}"
|
||||||
|
state="${STEM_STATE_DIR:-$root/.stem/instances/local}"
|
||||||
|
|
||||||
|
tasks=(
|
||||||
|
task01_first_fit_split
|
||||||
|
task02_address_order_coalesce
|
||||||
|
task03_freertos_heap4
|
||||||
|
)
|
||||||
|
|
||||||
|
resolve_task() {
|
||||||
|
local value="${1,,}" digits number stem
|
||||||
|
for stem in "${tasks[@]}"; do
|
||||||
|
if [[ "$value" == "$stem" ]]; then
|
||||||
|
printf '%s\n' "$stem"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [[ "$value" =~ ^(task|t)?[-_]?0*([1-3])($|[-_].*) ]]; then
|
||||||
|
digits="${BASH_REMATCH[2]}"
|
||||||
|
number=$((10#$digits))
|
||||||
|
printf '%s\n' "${tasks[number - 1]}"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
printf 'Unknown task selector: %s\n' "$1" >&2
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
|
||||||
|
task_stem="$(resolve_task "$selector")"
|
||||||
|
task_digits="${task_stem#task}"
|
||||||
|
task_digits="${task_digits%%_*}"
|
||||||
|
task_number=$((10#$task_digits))
|
||||||
|
task_key="$(printf 'task%02d' "$task_number")"
|
||||||
|
source_file="$root/src/tasks/$task_stem.c"
|
||||||
|
artifact_dir="$root/.stem/artifacts/$profile/$target/$task_key"
|
||||||
|
mkdir -p "$state" "$artifact_dir"
|
||||||
|
|
||||||
|
freertos_kernel_path() {
|
||||||
|
if [[ -n "${FREERTOS_KERNEL_PATH:-}" ]]; then
|
||||||
|
printf '%s\n' "$FREERTOS_KERNEL_PATH"
|
||||||
|
elif [[ -f /opt/FreeRTOS-Kernel/portable/MemMang/heap_4.c ]]; then
|
||||||
|
printf '%s\n' /opt/FreeRTOS-Kernel
|
||||||
|
else
|
||||||
|
printf '%s\n' "$root/../lab-rv32i-freertos-task-stack-vector/vendor/FreeRTOS-Kernel"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_kernel() {
|
||||||
|
local kernel="$1"
|
||||||
|
test -f "$kernel/portable/MemMang/heap_4.c"
|
||||||
|
grep -F 'FreeRTOS Kernel V11.3.0' "$kernel/include/FreeRTOS.h" >/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
freertos_rp2350_path() {
|
||||||
|
if [[ -n "${FREERTOS_RP2350_PATH:-}" ]]; then
|
||||||
|
printf '%s\n' "$FREERTOS_RP2350_PATH"
|
||||||
|
else
|
||||||
|
printf '%s\n' /opt/FreeRTOS-RP2350
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_rp2350_kernel() {
|
||||||
|
local kernel="$1"
|
||||||
|
test -f "$kernel/portable/ThirdParty/GCC/RP2350_RISC-V/portASM.S"
|
||||||
|
grep -F '<DEVELOPMENT BRANCH>' "$kernel/include/FreeRTOS.h" >/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
copy_artifact() {
|
||||||
|
local path="$1"
|
||||||
|
[[ -f "$path" ]] && cp -f "$path" "$artifact_dir/"
|
||||||
|
}
|
||||||
|
|
||||||
|
build_native() {
|
||||||
|
local mode="${1:-normal}" kernel build_dir output cc="${CC:-cc}"
|
||||||
|
local flags=(-std=c11 -O0 -g3 -fno-omit-frame-pointer -fno-inline
|
||||||
|
-fno-optimize-sibling-calls -Wall -Wextra -Wpedantic
|
||||||
|
-DHOST_PRINTF=1 -I"$root/src/tasks")
|
||||||
|
build_dir="$state/build/native/$task_stem"
|
||||||
|
output="$build_dir/prog"
|
||||||
|
if [[ "$mode" == sanitizer ]]; then
|
||||||
|
flags+=(-fsanitize=address,undefined)
|
||||||
|
fi
|
||||||
|
mkdir -p "$build_dir"
|
||||||
|
if [[ "$task_number" -eq 3 ]]; then
|
||||||
|
kernel="$(freertos_kernel_path)"
|
||||||
|
verify_kernel "$kernel"
|
||||||
|
flags+=(-DHEAP4_HOST_ADAPTER=1 -I"$root/include/host-shim")
|
||||||
|
"$cc" "${flags[@]}" "$source_file" \
|
||||||
|
"$kernel/portable/MemMang/heap_4.c" -o "$output"
|
||||||
|
else
|
||||||
|
"$cc" "${flags[@]}" "$source_file" -o "$output"
|
||||||
|
fi
|
||||||
|
objdump -dS "$output" > "$build_dir/prog.lst"
|
||||||
|
cp -f "$output" "$artifact_dir/prog"
|
||||||
|
copy_artifact "$build_dir/prog.lst"
|
||||||
|
printf '%s\n' "$output"
|
||||||
|
}
|
||||||
|
|
||||||
|
rv_env_root() {
|
||||||
|
if [[ -n "${RV_ENV_ROOT:-}" ]]; then
|
||||||
|
printf '%s\n' "$RV_ENV_ROOT"
|
||||||
|
elif [[ -d /opt/rv-env ]]; then
|
||||||
|
printf '%s\n' /opt/rv-env
|
||||||
|
else
|
||||||
|
printf '%s\n' /opt/stem
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
build_hazard3() {
|
||||||
|
local env_root kernel build_dir elf
|
||||||
|
env_root="$(rv_env_root)"
|
||||||
|
kernel="$(freertos_kernel_path)"
|
||||||
|
verify_kernel "$kernel"
|
||||||
|
build_dir="$state/build/hazard3"
|
||||||
|
make -B -C "$root" "task$task_number" \
|
||||||
|
"BUILD_ROOT=$build_dir" "RV_ENV_ROOT=$env_root" \
|
||||||
|
"FREERTOS_KERNEL_PATH=$kernel" PROFILE=observe >&2 || return
|
||||||
|
elf="$build_dir/$task_stem/prog.elf"
|
||||||
|
test -s "$elf"
|
||||||
|
copy_artifact "$elf"
|
||||||
|
copy_artifact "${elf%.elf}.bin"
|
||||||
|
copy_artifact "${elf%.elf}.lst"
|
||||||
|
copy_artifact "${elf%.elf}.map"
|
||||||
|
printf '%s\n' "$elf"
|
||||||
|
}
|
||||||
|
|
||||||
|
hazard3_tb() {
|
||||||
|
local env_root tb
|
||||||
|
env_root="$(rv_env_root)"
|
||||||
|
tb="$env_root/vendor/Hazard3/test/sim/tb_verilator/tb"
|
||||||
|
if [[ ! -x "$tb" ]]; then
|
||||||
|
make -C "$(dirname -- "$tb")" tb >&2
|
||||||
|
fi
|
||||||
|
printf '%s\n' "$tb"
|
||||||
|
}
|
||||||
|
|
||||||
|
build_rp2350() {
|
||||||
|
local binary_type="${1:-no_flash}" build_kind build_dir elf kernel rp_kernel
|
||||||
|
local cmake_args
|
||||||
|
case "$binary_type" in
|
||||||
|
no_flash) build_kind=ram ;;
|
||||||
|
default) build_kind=flash ;;
|
||||||
|
*) printf 'Unsupported RP2350 binary type: %s\n' "$binary_type" >&2; return 2 ;;
|
||||||
|
esac
|
||||||
|
kernel="$(freertos_kernel_path)"
|
||||||
|
verify_kernel "$kernel"
|
||||||
|
rp_kernel="$(freertos_rp2350_path)"
|
||||||
|
verify_rp2350_kernel "$rp_kernel"
|
||||||
|
build_dir="$state/build/rp2350-rv-$build_kind"
|
||||||
|
cmake_args=(
|
||||||
|
-S "$root" -B "$build_dir"
|
||||||
|
-DPICO_PLATFORM=rp2350-riscv
|
||||||
|
-DPICO_BOARD="${PICO_BOARD:-pico2_w}"
|
||||||
|
-DPICO_GCC_TRIPLE=riscv32-pico-elf
|
||||||
|
-DHEAP4_UPSTREAM_ROOT="$kernel"
|
||||||
|
-DFREERTOS_RP2350_PATH="$rp_kernel"
|
||||||
|
-DHEAP4_PROFILE=observe
|
||||||
|
-DHEAP4_BINARY_TYPE="$binary_type"
|
||||||
|
-DCMAKE_BUILD_TYPE=Debug
|
||||||
|
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
|
||||||
|
)
|
||||||
|
if command -v ninja >/dev/null 2>&1; then
|
||||||
|
cmake_args+=(-G Ninja)
|
||||||
|
else
|
||||||
|
cmake_args+=(-G "Unix Makefiles")
|
||||||
|
fi
|
||||||
|
if [[ -d /opt/picotool/picotool ]]; then
|
||||||
|
cmake_args+=(-Dpicotool_DIR=/opt/picotool/picotool)
|
||||||
|
fi
|
||||||
|
cmake "${cmake_args[@]}" >&2
|
||||||
|
cmake --build "$build_dir" --target "$task_stem" >&2
|
||||||
|
elf="$build_dir/$task_stem.elf"
|
||||||
|
test -s "$elf"
|
||||||
|
riscv64-unknown-elf-objdump -dS -M no-aliases,numeric "$elf" \
|
||||||
|
> "$build_dir/$task_stem.lst"
|
||||||
|
copy_artifact "$elf"
|
||||||
|
copy_artifact "$build_dir/$task_stem.bin"
|
||||||
|
copy_artifact "$build_dir/$task_stem.hex"
|
||||||
|
copy_artifact "$build_dir/$task_stem.uf2"
|
||||||
|
copy_artifact "$build_dir/$task_stem.dis"
|
||||||
|
copy_artifact "$build_dir/$task_stem.lst"
|
||||||
|
copy_artifact "$build_dir/$task_stem.elf.map"
|
||||||
|
printf '%s\n' "$elf"
|
||||||
|
}
|
||||||
|
|
||||||
|
openocd_target="${STEM_OPENOCD_TARGET:-target/rp2350.cfg}"
|
||||||
|
gdb_port="${GDB_PORT:-3333}"
|
||||||
|
gdb_target="${GDB_TARGET:-127.0.0.1:$gdb_port}"
|
||||||
|
openocd_pid=""
|
||||||
|
|
||||||
|
stop_owned_openocd() {
|
||||||
|
if [[ -n "$openocd_pid" ]]; then
|
||||||
|
kill "$openocd_pid" 2>/dev/null || true
|
||||||
|
wait "$openocd_pid" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
start_openocd() {
|
||||||
|
local log="$state/openocd-rp2350.log" attempt
|
||||||
|
if nc -z 127.0.0.1 "$gdb_port" 2>/dev/null; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
openocd -f interface/cmsis-dap.cfg \
|
||||||
|
-c "adapter speed ${STEM_ADAPTER_KHZ:-5000}" \
|
||||||
|
-c 'set USE_CORE { rv0 }' -c 'set USE_SMP 0' \
|
||||||
|
-c "set FLASHSIZE ${STEM_RP2350_FLASH_SIZE:-0x400000}" \
|
||||||
|
-f "$openocd_target" >"$log" 2>&1 &
|
||||||
|
openocd_pid=$!
|
||||||
|
for attempt in $(seq 1 80); do
|
||||||
|
if nc -z 127.0.0.1 "$gdb_port" 2>/dev/null; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
if ! kill -0 "$openocd_pid" 2>/dev/null; then
|
||||||
|
sed -n '1,240p' "$log" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
sleep 0.1
|
||||||
|
done
|
||||||
|
printf 'OpenOCD did not open GDB port %s\n' "$gdb_port" >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
flash_rp2350() {
|
||||||
|
local elf="$1" log="$state/openocd-rp2350-flash.log"
|
||||||
|
if nc -z 127.0.0.1 "$gdb_port" 2>/dev/null; then
|
||||||
|
printf 'GDB port %s is busy; stop the current debug session before deploy.\n' "$gdb_port" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if ! openocd -f interface/cmsis-dap.cfg \
|
||||||
|
-c "adapter speed ${STEM_ADAPTER_KHZ:-5000}" \
|
||||||
|
-c 'set USE_CORE { cm0 rv0 }' -c 'set USE_SMP 0' \
|
||||||
|
-c "set FLASHSIZE ${STEM_RP2350_FLASH_SIZE:-0x400000}" \
|
||||||
|
-f "$openocd_target" -c init \
|
||||||
|
-c 'if {[target_present rp2350.rv0]} { targets rp2350.rv0 } else { targets rp2350.cm0 }' \
|
||||||
|
-c 'reset halt' -c "flash write_image erase $elf" \
|
||||||
|
-c "verify_image $elf" -c 'reset run' -c shutdown >"$log" 2>&1; then
|
||||||
|
sed -n '1,260p' "$log" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
grep -E 'wrote [0-9]+ bytes|verified [0-9]+ bytes' "$log" || true
|
||||||
|
printf 'rp2350-flash-ok image=%s verify=passed architecture=RISC-V\n' "$elf"
|
||||||
|
}
|
||||||
|
|
||||||
|
hardware_test_task03() {
|
||||||
|
local elf="$1" output
|
||||||
|
start_openocd
|
||||||
|
trap stop_owned_openocd EXIT
|
||||||
|
output="$(gdb-multiarch -nx -q -batch "$elf" \
|
||||||
|
-ex 'set architecture riscv:rv32' \
|
||||||
|
-ex "target extended-remote $gdb_target" \
|
||||||
|
-ex 'monitor reset halt' \
|
||||||
|
-ex 'hbreak heap4_fragmented_checkpoint' \
|
||||||
|
-ex 'hbreak task03_debug_checkpoint' \
|
||||||
|
-ex continue \
|
||||||
|
-ex 'printf "fragmented blocks=%lu free=%lu largest=%lu\n", g_fragmented_stats.xNumberOfFreeBlocks, g_fragmented_stats.xAvailableHeapSpaceInBytes, g_fragmented_stats.xSizeOfLargestFreeBlockInBytes' \
|
||||||
|
-ex continue \
|
||||||
|
-ex 'printf "task03 initial=%lu after=%lu final=%lu min=%lu aligned=%d oom=%d hooks=%d asserts=%d pass=%d\n", g_initial_free, g_after_allocations, g_final_free, g_minimum_ever_free, g_allocations_aligned, g_oom_is_null, g_malloc_failed_hooks, g_assert_failures, g_task03_pass' \
|
||||||
|
-ex 'printf "frame sp=0x%08lx fp=0x%08lx pc=0x%08lx align=%lu\n", (unsigned long)$sp, (unsigned long)$s0, (unsigned long)$pc, ((unsigned long)$sp & 15)' \
|
||||||
|
-ex 'x/96bx ucHeap' \
|
||||||
|
-ex 'delete breakpoints' -ex 'monitor halt' -ex disconnect)"
|
||||||
|
printf '%s\n' "$output"
|
||||||
|
grep -E '^fragmented blocks=2 ' <<<"$output" >/dev/null
|
||||||
|
grep -E '^task03 .* aligned=1 oom=1 hooks=1 asserts=0 pass=1$' <<<"$output" >/dev/null
|
||||||
|
grep -E '^frame .* align=0$' <<<"$output" >/dev/null
|
||||||
|
printf 'rp2350-hardware-ok task=task03 heap_4=upstream load=flash\n'
|
||||||
|
}
|
||||||
|
|
||||||
|
configure_debug_view() {
|
||||||
|
export STEM_DEBUG_WINDOW_NAME=heap4
|
||||||
|
case "$task_number" in
|
||||||
|
1)
|
||||||
|
export STEM_DEBUG_INITIAL_BREAK=task01_debug_checkpoint
|
||||||
|
export STEM_DEBUG_MEMORY_EXPR='&g_split_arena' STEM_DEBUG_MEMORY_LENGTH=288
|
||||||
|
;;
|
||||||
|
2)
|
||||||
|
export STEM_DEBUG_INITIAL_BREAK=task02_fragmented_checkpoint
|
||||||
|
export STEM_DEBUG_MEMORY_EXPR='&g_coalesce_arena' STEM_DEBUG_MEMORY_LENGTH=160
|
||||||
|
;;
|
||||||
|
3)
|
||||||
|
export STEM_DEBUG_INITIAL_BREAK=heap4_fragmented_checkpoint
|
||||||
|
export STEM_DEBUG_MEMORY_EXPR='ucHeap' STEM_DEBUG_MEMORY_LENGTH=160
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$profile:$target:$action" in
|
||||||
|
native-amd64:native:build)
|
||||||
|
build_native normal >/dev/null
|
||||||
|
;;
|
||||||
|
native-amd64:native:test)
|
||||||
|
output="$(build_native sanitizer)"
|
||||||
|
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=halt_on_error=1 "$output"
|
||||||
|
;;
|
||||||
|
native-amd64:native:run)
|
||||||
|
output="$(build_native normal)"
|
||||||
|
exec "$output"
|
||||||
|
;;
|
||||||
|
native-amd64:native:debug)
|
||||||
|
output="$(build_native normal)"
|
||||||
|
export RV_REPO="$root" RV_EDITOR="${STEM_EDITOR:-nvim}"
|
||||||
|
export RV_HOST_ELF="$output" RV_HOST_SRC="$source_file"
|
||||||
|
export RV_HOST_LST="$(dirname -- "$output")/prog.lst"
|
||||||
|
exec /opt/stem/scripts/host-entry.sh debug "task$task_number"
|
||||||
|
;;
|
||||||
|
hazard3-sim:hazard3-baremetal:build)
|
||||||
|
build_hazard3 >/dev/null
|
||||||
|
;;
|
||||||
|
hazard3-sim:hazard3-baremetal:test|hazard3-sim:hazard3-baremetal:run)
|
||||||
|
elf="$(build_hazard3)"
|
||||||
|
tb="$(hazard3_tb)"
|
||||||
|
exec "$tb" --bin "${elf%.elf}.bin" --cpuret
|
||||||
|
;;
|
||||||
|
hazard3-sim:hazard3-baremetal:debug)
|
||||||
|
elf="$(build_hazard3)"
|
||||||
|
configure_debug_view
|
||||||
|
export STEM_DEBUG_BACKEND=hazard3 STEM_DEBUG_ELF="$elf"
|
||||||
|
export STEM_DEBUG_BIN="${elf%.elf}.bin" STEM_DEBUG_SRC="$source_file"
|
||||||
|
export STEM_DEBUG_LST="${elf%.elf}.lst"
|
||||||
|
exec /opt/stem/scripts/card-debug-ui.sh
|
||||||
|
;;
|
||||||
|
rp2350:rp2350-rv:build)
|
||||||
|
build_rp2350 >/dev/null
|
||||||
|
;;
|
||||||
|
rp2350:rp2350-rv:test)
|
||||||
|
elf="$(build_rp2350)"
|
||||||
|
riscv64-unknown-elf-readelf -h "$elf" | grep -F 'Machine:' | grep -F 'RISC-V'
|
||||||
|
if [[ "$task_number" -eq 3 ]]; then
|
||||||
|
"$root/tests/check_task03_elf.sh" "$elf"
|
||||||
|
fi
|
||||||
|
printf 'rp2350-build-ok task=%s binary_type=no_flash\n' "$task_key"
|
||||||
|
;;
|
||||||
|
rp2350:rp2350-rv:deploy)
|
||||||
|
elf="$(build_rp2350 default)"
|
||||||
|
flash_rp2350 "$elf"
|
||||||
|
if [[ "$task_number" -eq 3 ]]; then
|
||||||
|
hardware_test_task03 "$elf"
|
||||||
|
else
|
||||||
|
printf 'rp2350-deploy-ok task=%s load=flash persistent=1\n' "$task_key"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
rp2350:rp2350-rv:debug)
|
||||||
|
elf="$(build_rp2350)"
|
||||||
|
configure_debug_view
|
||||||
|
export STEM_DEBUG_BACKEND=rp2350 STEM_DEBUG_ELF="$elf"
|
||||||
|
export STEM_DEBUG_SRC="$source_file" STEM_DEBUG_LST="${elf%.elf}.lst"
|
||||||
|
exec /opt/stem/scripts/card-debug-ui.sh
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf 'Unsupported profile/target/action: %s/%s/%s\n' "$profile" "$target" "$action" >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
Reference in New Issue
Block a user