From 88f70ff674d3dce22abbf677af8b50b416639dc4 Mon Sep 17 00:00:00 2001 From: Alberto Dequino Date: Tue, 17 Feb 2026 16:38:44 +0100 Subject: [PATCH 1/4] First L2 allocator implementation --- targets/magia_v2/include/utils/alloc.h | 126 +++++++++++++++++++++++++ targets/magia_v2/link.ld | 11 +++ targets/magia_v2/src/alloc.c | 80 ++++++++++++++++ 3 files changed, 217 insertions(+) create mode 100644 targets/magia_v2/include/utils/alloc.h create mode 100644 targets/magia_v2/src/alloc.c diff --git a/targets/magia_v2/include/utils/alloc.h b/targets/magia_v2/include/utils/alloc.h new file mode 100644 index 0000000..d6a7794 --- /dev/null +++ b/targets/magia_v2/include/utils/alloc.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2023-2026 ETH Zurich and University of Bologna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + * + * Authors: + * Alberto Dequino + * + * MAGIA allocator + */ + +#ifndef ALLOC_H +#define ALLOC_H + + +#include +#include +#include + +/* + * All allocated memory blocks are aligned to this boundary for optimal access performance. + */ +#define ALLOC_ALIGNMENT 4 + +/** + * Macro to align a size to the memory alignment boundary. + */ +#define ALLOC_ALIGN(size) (((size) + (ALLOC_ALIGNMENT - 1)) & ~(ALLOC_ALIGNMENT - 1)) + +/** + * Memory block structure for the freelist allocator. + * + * This structure is used internally to track free memory blocks in a linked list. + * Each allocated block has this header prepended to store metadata. + */ +typedef struct MemoryBlock { + struct MemoryBlock *next; /**< Pointer to the next free block in the list. */ + size_t size; /**< Size of the memory block in bytes. */ +} MemoryBlock; + +/** + * This function allocates a block of memory of the specified size from the dataram heap. + * The allocated memory is aligned to ALLOC_ALIGNMENT bytes. The memory is not initialized. + * + * The allocated memory should be freed using magia_l2_free() when no longer needed. + */ +void *magia_l2_malloc(size_t size); + +/** + * This function returns a memory block to the free list, making it available for future + * allocations. The memory block is added to the head of the freelist for efficient reuse. + * + * The pointer must have been returned by a previous call to magia_l2_malloc(). + * After calling this function, the memory pointed to by ptr should not be accessed. + */ +void magia_l2_free(void *ptr); + +/** + * This function allocates memory for an array of num elements, each of size bytes, + * and initializes all bytes to zero. + * + * The allocated memory should be freed using magia_l2_free() when no longer needed. + */ +void *magia_l2_calloc(size_t num, size_t size); + +/** + * This function changes the size of the memory block pointed to by ptr to size bytes. + * The contents are unchanged up to the minimum of the old and new sizes. + * If the new size is larger, the additional memory is uninitialized. + * + * If reallocation fails, the original memory block is unchanged. + */ +void *magia_l2_realloc(void *ptr, size_t size); + +/** + * Gets the total size of the dataram l2 heap. + */ +size_t magia_l2_heap_size(void); + +/** + * This function calculates the total amount of free memory by traversing the freelist + * and summing the sizes of all free blocks, plus any remaining unallocated heap space. + */ +size_t magia_l2_heap_free(void); + +/** + * Gets the amount of allocated memory in the l2 heap. + */ +size_t magia_l2_heap_used(void); + +/** + * This function verifies if the given pointer points to a memory block that was + * allocated by magia_l2_malloc() and is within the heap bounds. + */ +bool magia_l2_ptr_valid(void *ptr); + +/** + * This function validates the integrity of the heap data structures, including: + * - Freelist consistency + * - Memory block header validity + * - Heap boundary checks + * + * This function is intended for debugging and should not be used in production code + * due to its performance impact. + */ +bool magia_l2_heap_check(void); + + +#endif //ALLOC_H + + + + + + diff --git a/targets/magia_v2/link.ld b/targets/magia_v2/link.ld index 80d235b..45b6db3 100644 --- a/targets/magia_v2/link.ld +++ b/targets/magia_v2/link.ld @@ -122,6 +122,17 @@ SECTIONS _bss_end = .; } > dataram + .l2_heap : + { + . = ALIGN(4); + sl2_heap = .; + _sl2_heap = .; + *(.l2_heap); + *(.l2_heap.*) + el2_heap = .; + _el2_heap = .; + } > dataram + /* ensure there is enough room for stack */ .stack (NOLOAD): { . = ALIGN(4); diff --git a/targets/magia_v2/src/alloc.c b/targets/magia_v2/src/alloc.c new file mode 100644 index 0000000..5ecf7f7 --- /dev/null +++ b/targets/magia_v2/src/alloc.c @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2023-2026 ETH Zurich and University of Bologna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + * + * Authors: + * Alberto Dequino + * + * MAGIA allocator + */ + +#include +#include + +#include "utils/alloc.h" +#include "addr_map/tile_addr_map.h" + +extern void *_sl2_heap; +extern void *_el2_heap; + +static uint8_t *l2_heap_end = (uint8_t *)&_el2_heap; +static uint8_t *l2_heap_start = (uint8_t *)&_sl2_heap; + +static MemoryBlock *l2_heap_freelist = NULL; + +/** + * THIS MALLOC IS NOT THREAD SAFE! + * + * Make sure only one tile is only accessing this malloc at a time, either by using amo locks/barriers, + * or by synchronizing. + */ +static void *region_malloc(uint8_t **ptr, uint8_t *end, MemoryBlock **freelist, size_t size) { + size_t total_size = ALLOC_ALIGN(size + sizeof(MemoryBlock)); + + MemoryBlock **prev = freelist; + MemoryBlock *curr = *freelist; + + while (curr) { + if (curr->size >= size) { + *prev = curr->next; + return (void *)(curr + 1); + } + prev = &curr->next; + curr = curr->next; + } + + if (*ptr + total_size > end) return NULL; + + MemoryBlock *b = (MemoryBlock *)(*ptr); + b->size = size; + *ptr += total_size; + + return (void *)(b + 1); +} + +static void region_free(MemoryBlock **freelist, void *ptr) { + if (!ptr) return; + MemoryBlock *b = (MemoryBlock *)((uint8_t *)ptr - sizeof(MemoryBlock)); + b->next = *freelist; + *freelist = b; +} + +void *magia_l2_malloc(size_t size) { + return region_malloc(&l2_heap_start, l2_heap_end, &l2_heap_freelist, size); +} + +void magia_l2_free(void *ptr){ + region_free(&l2_heap_freelist, ptr); +} \ No newline at end of file From c6c326efd53fb6322dae240432ce5d9f4b2aa9ed Mon Sep 17 00:00:00 2001 From: Alberto Dequino Date: Thu, 26 Feb 2026 16:03:09 +0100 Subject: [PATCH 2/4] Modified linker script --- targets/magia_v2/link.ld | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/targets/magia_v2/link.ld b/targets/magia_v2/link.ld index 45b6db3..207e3b2 100644 --- a/targets/magia_v2/link.ld +++ b/targets/magia_v2/link.ld @@ -127,8 +127,7 @@ SECTIONS . = ALIGN(4); sl2_heap = .; _sl2_heap = .; - *(.l2_heap); - *(.l2_heap.*) + . = . + L2_HEAP_SIZE; el2_heap = .; _el2_heap = .; } > dataram From b7c6deab61653671ee324eb583154abc24556157 Mon Sep 17 00:00:00 2001 From: Alberto Dequino Date: Wed, 4 Mar 2026 17:34:57 +0100 Subject: [PATCH 3/4] Updating picolibc script --- CMakeLists.txt | 12 +++++++---- cmake/picolibc.cmake | 20 +++++++++---------- cmake/toolchain_gcc_pulp.cmake | 15 ++++++++------ .../magia_v2/include/addr_map/tile_addr_map.h | 1 + 4 files changed, 28 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8615da1..99eac8a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,6 +57,12 @@ else() message(STATUS "[MAGIA-SDK] DISASSEMBLE_LIBRARIES : OFF") endif() +# Set host-specific flags +set(MESH_ARCH "riscv32") +set(MESH_FAMILY "riscv32") +set(MESH_ENDIAN "little") +set(MESH_SYSTEM "unknown") + include(${CMAKE_CURRENT_LIST_DIR}/cmake/utils.cmake) ################################################################################ @@ -67,10 +73,8 @@ include(${CMAKE_CURRENT_LIST_DIR}/cmake/utils.cmake) # Depending on the target, following static libraries have to added by the targets add_subdirectory(targets) -if (COMPILER STREQUAL "LLVM") - # VIVIANEP: Include the picolibc library - include(${CMAKE_CURRENT_LIST_DIR}/cmake/picolibc.cmake) -endif() +# VIVIANEP: Include the picolibc library +include(${CMAKE_CURRENT_LIST_DIR}/cmake/picolibc.cmake) # Include other subdirectories add_subdirectory(hal) diff --git a/cmake/picolibc.cmake b/cmake/picolibc.cmake index 20311ad..11584d4 100644 --- a/cmake/picolibc.cmake +++ b/cmake/picolibc.cmake @@ -7,19 +7,19 @@ include(ExternalProject) -message(STATUS "[MAGIA-SDK] Setting up picolibc for Host (ISA: ${ISA}, ABI: ${ABI})") +message(STATUS "[MAGIA-SDK] Setting up picolibc for Mesh (ISA: ${ISA}, ABI: ${ABI})") -set(CROSS_C_COMPILER "${CMAKE_C_COMPILER}") -set(CROSS_C_COMPILER_ARGS "-target ${CROSS_COMPILE} -march=${ISA} -nostdlib" CACHE STRING "Compiler arguments") -# VIVIANEP: These flags are only for building Picolibc; adding them globally breaks -# app builds (e.g., missing ) or causes issues in freestanding mode. -set(CROSS_C_ARGS "-Werror=double-promotion -Wno-unsupported-floating-point-opt -fshort-enums ${CMAKE_ALT_C_OPTIONS} -march=${ISA} -mabi=${ABI}") -set(CROSS_C_LINK_ARGS "-Wl,-z,noexecstack -march=${ISA} -mabi=${ABI}") +set(CROSS_C_COMPILER "${CMAKE_C_COMPILER}") +set(CROSS_C_ARGS "--target=${CROSS_COMPILE} -nostdlib -ggdb -gdwarf-4 -gstrict-dwarf -mno-relax") +set(CROSS_C_LINK_ARGS "--target=${CROSS_COMPILE} -nostdlib -fno-common -Wl,-z,noexecstack -fuse-ld=lld") -set(CROSS_AR "${CMAKE_AR}") -set(CROSS_STRIP "${CMAKE_STRIP}") +set(CROSS_AR "${CMAKE_AR}") +set(CROSS_STRIP "${CMAKE_STRIP}") -set(CROSS_SKIP_SANITY_CHECK "true") +set(CROSS_CPU "${MESH_ARCH}") +set(CROSS_CPU_FAMILY "${MESH_FAMILY}") +set(CROSS_ENDIAN "${MESH_ENDIAN}") +set(CROSS_SYSTEM "${MESH_SYSTEM}") # Prepare Meson arrays function(prepare_meson_array output_var input_string) diff --git a/cmake/toolchain_gcc_pulp.cmake b/cmake/toolchain_gcc_pulp.cmake index 51010c1..d07e839 100644 --- a/cmake/toolchain_gcc_pulp.cmake +++ b/cmake/toolchain_gcc_pulp.cmake @@ -9,9 +9,12 @@ set(CMAKE_EXECUTABLE_SUFFIX ".elf") set(CMAKE_SYSTEM_NAME Generic) -set(CMAKE_C_COMPILER riscv32-unknown-elf-gcc) -set(CMAKE_CXX_COMPILER riscv32-unknown-elf-g++) -set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) -set(CMAKE_OBJCOPY riscv32-unknown-elf-objcopy) -set(CMAKE_OBJDUMP riscv32-unknown-elf-objdump) -set(CMAKE_AR riscv32-unknown-elf-ar) \ No newline at end of file +set(CROSS_COMPILE riscv32-unknown-elf) +set(CMAKE_C_COMPILER ${CROSS_COMPILE}-gcc) +set(CMAKE_CXX_COMPILER ${CROSS_COMPILE}-g++) +set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) +set(CMAKE_OBJCOPY ${CROSS_COMPILE}-objcopy) +set(CMAKE_OBJDUMP ${CROSS_COMPILE}-objdump) +set(CMAKE_AR ${CROSS_COMPILE}-ar) +set(CMAKE_STRIP ${CROSS_COMPILE}-strip) + diff --git a/targets/magia_v2/include/addr_map/tile_addr_map.h b/targets/magia_v2/include/addr_map/tile_addr_map.h index aad50ee..b64aa12 100644 --- a/targets/magia_v2/include/addr_map/tile_addr_map.h +++ b/targets/magia_v2/include/addr_map/tile_addr_map.h @@ -50,6 +50,7 @@ #define TEST_END_ADDR (0xCCFF0000) #define PRINT_ADDR (0xFFFF0004) #define MHARTID_OFFSET (0x00100000) +#define L2_HEAP_SIZE (0x00100000) #define IDMA_BASE_AXI2OBI (IDMA_BASE) // direction=0, L2 to L1 #define IDMA_BASE_OBI2AXI (IDMA_BASE + 0x200) // direction=1, L1 to L2 From 309799ba1221160ccad03c95f26ac2a9d8690f4e Mon Sep 17 00:00:00 2001 From: Alberto Dequino Date: Thu, 5 Mar 2026 15:39:53 +0100 Subject: [PATCH 4/4] WIP picolib integration --- CMakeLists.txt | 7 ++-- cmake/picolibc.cmake | 61 ++++++++++++++++++++++----------- targets/magia_v2/CMakeLists.txt | 2 ++ targets/magia_v2/config.cmake | 13 +++++++ 4 files changed, 59 insertions(+), 24 deletions(-) create mode 100644 targets/magia_v2/config.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index c7c7167..385bf53 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,6 +38,8 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +#include("targets/${TARGET_PLATFORM}/config.cmake") + project(magia-sdk LANGUAGES C ASM) set(ABI ilp32) @@ -71,12 +73,9 @@ include(${CMAKE_CURRENT_LIST_DIR}/cmake/utils.cmake) # Depending on the target, following static libraries have to added by the targets add_subdirectory(targets) -<<<<<<< HEAD # VIVIANEP: Include the picolibc library -include(${CMAKE_CURRENT_LIST_DIR}/cmake/picolibc.cmake) +#include(${CMAKE_CURRENT_LIST_DIR}/cmake/picolibc.cmake) -======= ->>>>>>> main # Include other subdirectories add_subdirectory(hal) # add_subdirectory(devices) diff --git a/cmake/picolibc.cmake b/cmake/picolibc.cmake index 11584d4..718fc9d 100644 --- a/cmake/picolibc.cmake +++ b/cmake/picolibc.cmake @@ -10,8 +10,8 @@ include(ExternalProject) message(STATUS "[MAGIA-SDK] Setting up picolibc for Mesh (ISA: ${ISA}, ABI: ${ABI})") set(CROSS_C_COMPILER "${CMAKE_C_COMPILER}") -set(CROSS_C_ARGS "--target=${CROSS_COMPILE} -nostdlib -ggdb -gdwarf-4 -gstrict-dwarf -mno-relax") -set(CROSS_C_LINK_ARGS "--target=${CROSS_COMPILE} -nostdlib -fno-common -Wl,-z,noexecstack -fuse-ld=lld") +set(CROSS_C_ARGS "-march=${ISA} -mabi=${ABI} -nostdlib -ggdb -gdwarf-4 -gstrict-dwarf -mno-relax") +set(CROSS_C_LINK_ARGS "-march=${ISA} -mabi=${ABI} -nostdlib -fno-common -Wl,-z,noexecstack ") set(CROSS_AR "${CMAKE_AR}") set(CROSS_STRIP "${CMAKE_STRIP}") @@ -32,44 +32,65 @@ function(prepare_meson_array output_var input_string) set(${output_var} "${result}" PARENT_SCOPE) endfunction() -prepare_meson_array(CROSS_C_COMPILER_ARGS_LIST "${CROSS_C_COMPILER_ARGS}") prepare_meson_array(CROSS_C_ARGS_LIST "${CROSS_C_ARGS}") prepare_meson_array(CROSS_C_LINK_ARGS_LIST "${CROSS_C_LINK_ARGS}") set(PICOLIBC_SRC_DIR ${CMAKE_BINARY_DIR}/picolibc-src) -set(PICOLIBC_BUILD_DIR ${CMAKE_BINARY_DIR}/picolibc-build-${ISA}-${ABI}) -set(PICOLIBC_INSTALL_DIR ${CMAKE_BINARY_DIR}/picolibc-install-${ISA}-${ABI}) -set(PICOLIBC_CROSS_FILE ${CMAKE_BINARY_DIR}/picolibc-cross-file-${ISA}-${ABI}.txt) - +set(PICOLIBC_BUILD_DIR ${CMAKE_BINARY_DIR}/picolibc-build) +set(PICOLIBC_INSTALL_DIR ${CMAKE_BINARY_DIR}/picolibc-install) +set(PICOLIBC_CROSS_FILE ${CMAKE_BINARY_DIR}/picolibc-cross-file.txt) # Generate the Meson cross-file configure_file(${CMAKE_CURRENT_LIST_DIR}/../scripts/picolibc-cross-file.txt.in ${PICOLIBC_CROSS_FILE} @ONLY) -message(STATUS "[MAGIA-SDK] Saving cross compilation file to ${PICOLIBC_CROSS_FILE}") + +set(PICOLIB_MULTILIB ${PICOLIB_MESH}) +if(NOT ${PICOLIB_CLUSTER_SNITCH} STREQUAL "None") + list(APPEND PICOLIB_MULTILIB ${PICOLIB_CLUSTER_SNITCH}) +endif() +string(JOIN "," PICOLIB_MULTILIB ${PICOLIB_MULTILIB}) + + # Add picolibc as an external project ExternalProject_Add( - picolibc-${ISA}-${ABI} + picolibc GIT_REPOSITORY https://github.com/picolibc/picolibc.git GIT_TAG main SOURCE_DIR ${PICOLIBC_SRC_DIR} BINARY_DIR ${PICOLIBC_BUILD_DIR} INSTALL_DIR ${PICOLIBC_INSTALL_DIR} - CONFIGURE_COMMAND meson setup ${PICOLIBC_BUILD_DIR} ${PICOLIBC_SRC_DIR} --cross-file ${PICOLIBC_CROSS_FILE} --prefix ${PICOLIBC_INSTALL_DIR} --default-library=static + CONFIGURE_COMMAND meson setup ${PICOLIBC_BUILD_DIR} ${PICOLIBC_SRC_DIR} --cross-file ${PICOLIBC_CROSS_FILE} -D multilib-list=${PICOLIB_MULTILIB} --prefix ${PICOLIBC_INSTALL_DIR} --default-library=static BUILD_COMMAND ninja -C ${PICOLIBC_BUILD_DIR} INSTALL_COMMAND ninja -C ${PICOLIBC_BUILD_DIR} install - BUILD_BYPRODUCTS ${PICOLIBC_INSTALL_DIR}/lib/libc.a - LOG_CONFIGURE ON - LOG_BUILD ON + BUILD_BYPRODUCTS + ${PICOLIBC_INSTALL_DIR}/lib/${PICOLIB_MESH}/libc.a + ${PICOLIBC_INSTALL_DIR}/lib/${PICOLIB_CLUSTER_SNITCH}/libc.a + #LOG_CONFIGURE ON + #LOG_BUILD ON LOG_INSTALL ON ) -set(PICOLIBC_TARGET picolibc-${ISA}-${ABI}) - -add_library(picolibc STATIC IMPORTED GLOBAL) +set(PICOLIBC_TARGET picolibc) -set_target_properties(picolibc PROPERTIES - IMPORTED_LOCATION "${PICOLIBC_INSTALL_DIR}/lib/libc.a" +################################################################################ +# Mesh Picolibc Library +################################################################################ +add_library(picolibc_mesh STATIC IMPORTED GLOBAL) +set_target_properties(picolibc_mesh PROPERTIES + IMPORTED_LOCATION "${PICOLIBC_INSTALL_DIR}/lib/${PICOLIB_MESH}/libc.a" ) - -add_dependencies(picolibc picolibc-${ISA_HOST}-${ABI}) \ No newline at end of file +add_dependencies(picolibc_mesh picolibc) + +################################################################################ +# Snitch Picolibc Library +################################################################################ +if(${ISA_CLUSTER_SNITCH} STREQUAL "None") + return() +else() + add_library(picolibc_cluster_snitch STATIC IMPORTED GLOBAL) + set_target_properties(picolibc_cluster_snitch PROPERTIES + IMPORTED_LOCATION "${PICOLIBC_INSTALL_DIR}/lib/${PICOLIB_CLUSTER_SNITCH}/libc.a" + ) + add_dependencies(picolibc_cluster_snitch picolibc) +endif() \ No newline at end of file diff --git a/targets/magia_v2/CMakeLists.txt b/targets/magia_v2/CMakeLists.txt index 94a7702..9b2a895 100644 --- a/targets/magia_v2/CMakeLists.txt +++ b/targets/magia_v2/CMakeLists.txt @@ -9,6 +9,8 @@ add_library(runtime STATIC) +#add_dependencies(runtime picolibc) + file(GLOB_RECURSE ASM_SOURCES "src/crt0.S" ) diff --git a/targets/magia_v2/config.cmake b/targets/magia_v2/config.cmake new file mode 100644 index 0000000..5019e04 --- /dev/null +++ b/targets/magia_v2/config.cmake @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: 2025 ETH Zurich and University of Bologna +# SPDX-License-Identifier: Apache-2.0 + +# WIESEP: It is important to set the ISA and ABI for the host and the cluster snitch +set(ABI_MESH ilp32) +set(ISA_MESH rv32imcxgap9) +set(PICOLIB_MESH rv32im/ilp32) +set(COMPILERRT_MESH rv32imcxgap9) + +set(ABI_CLUSTER_SNITCH None) +set(ISA_CLUSTER_SNITCH None) +set(PICOLIB_CLUSTER_SNITCH None) +set(COMPILERRT_CLUSTER_SNITCH None) \ No newline at end of file