diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..4444fb591 --- /dev/null +++ b/.clang-format @@ -0,0 +1,2 @@ +AllowShortFunctionsOnASingleLine: None +BasedOnStyle: Google diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 000000000..85df8ff87 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,26 @@ +Checks: > + -*, + clang-analyzer-*, + bugprone-*, + performance-*, + portability-*, + misc-*, + readability-*, + modernize-*, + -clang-analyzer-alpha*, + -bugprone-easily-swappable-parameters, + -bugprone-exception-escape, + -bugprone-narrowing-conversions, + -bugprone-reserved-identifier, + -misc-include-cleaner, + -modernize-avoid-c-arrays, + -modernize-use-auto, + -modernize-use-nodiscard, + -modernize-use-trailing-return-type, + -readability-function-cognitive-complexity, + -readability-identifier-length, + -readability-implicit-bool-conversion, + -readability-magic-numbers +WarningsAsErrors: '' +HeaderFilterRegex: '.*' +FormatStyle: file diff --git a/.clangd-bin b/.clangd-bin new file mode 100644 index 000000000..bef1314fd --- /dev/null +++ b/.clangd-bin @@ -0,0 +1 @@ +/stuff/tools/llvm/ATfE-21.1.1/bin/clangd diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..517cd760a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,19 @@ +version: "3.9" + +services: + pico2: + image: pico2:25.10 + user: "${UID:-1000}:${GID:-1000}" + working_dir: /stuff/work/pico-sdk + environment: + USER: uzleo + HOME: /home/uzleo + entrypoint: ["/usr/bin/env", "fish"] + volumes: + - /stuff/work:/stuff/work + - /stuff/tools:/stuff/tools + - /home/uzleo:/home/uzleo + - /etc/passwd:/etc/passwd:ro + - /etc/group:/etc/group:ro + stdin_open: true + tty: true diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 000000000..5088d19bc --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,60 @@ +cmake_minimum_required(VERSION 3.30) + +include(../pico_sdk_init.cmake) + +set(CMAKE_CXX_SCAN_FOR_MODULES ON) + +project(examples C CXX ASM) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +pico_sdk_init() + +if (DEFINED PICO_COMPILER_SYSROOT) + set(LIBCXX_STD_MODULE_DIR "${PICO_COMPILER_SYSROOT}/share/libc++/v1") + set(LIBCXX_STD_MODULE "${LIBCXX_STD_MODULE_DIR}/std.cppm") +else() + message(FATAL_ERROR "PICO_COMPILER_SYSROOT is not set; cannot locate libc++ std module") +endif() + +if (NOT CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS) + find_program(CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS + NAMES clang-scan-deps clang-scan-deps-21 clang-scan-deps-20 + PATHS ${PICO_TOOLCHAIN_PATH}/bin /usr/bin) +endif() + +add_executable(led_blink + led_blink_raw.cpp +) +target_compile_features(led_blink PRIVATE cxx_std_26) +target_compile_options(led_blink PRIVATE + $<$:-Weverything -Wno-c++98-compat> + $<$:-Weverything -Wno-c++98-compat> +) +target_link_libraries(led_blink pico_stdlib) +pico_set_printf_implementation(led_blink none) +pico_enable_stdio_usb(led_blink 1) +pico_enable_stdio_uart(led_blink 0) + +if (PICO_CLIB STREQUAL "llvm_libc") + # libdummyhost provides stdio symbols for llvm-libc runtimes. + target_link_options(led_blink PRIVATE -ldummyhost) +endif() + +target_sources(led_blink PRIVATE + FILE_SET cxx_modules TYPE CXX_MODULES + BASE_DIRS ${CMAKE_CURRENT_LIST_DIR}/sdk + FILES sdk/hw/hw.cppm +) + +if (EXISTS "${LIBCXX_STD_MODULE}") + target_sources(led_blink PRIVATE + FILE_SET libcxx_modules TYPE CXX_MODULES + BASE_DIRS "${LIBCXX_STD_MODULE_DIR}" + FILES "${LIBCXX_STD_MODULE}" + ) +else() + message(FATAL_ERROR "libc++ std module not found at ${LIBCXX_STD_MODULE}; import std will fail") +endif() + +pico_add_extra_outputs(led_blink) diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 000000000..464d7d248 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,18 @@ +# Building without USB/stdio using LLVM Embedded Toolchain + +For bare-metal targets that don’t need USB stdio, configure with the LLVM Embedded Toolchain sysroot and skip picotool/UF2. Example (building `led_blink` on pico2): +``` +rm -rf build +cmake -G Ninja -S examples -B build -DPICO_BOARD=pico2 \ + -DPICO_COMPILER=pico_arm_cortex_m33_clang \ + -DPICO_TOOLCHAIN_PATH=/stuff/tools/llvm/ATfE-21.1.1 \ + -DPICO_COMPILER_SYSROOT=/stuff/tools/llvm/ATfE-21.1.1/lib/clang-runtimes/arm-none-eabi/armv8m.main_hard_fp_exn_rtti_unaligned_size \ + -DPICO_NO_PICOTOOL=1 \ + -DCMAKE_TRY_COMPILE_PLATFORM_VARIABLES="PICO_COMPILER_SYSROOT;PICO_CLANG_RUNTIMES;PICO_CLIB" \ + -DCMAKE_C_STANDARD_INCLUDE_DIRECTORIES="/stuff/tools/llvm/ATfE-21.1.1/lib/clang-runtimes/arm-none-eabi/include/" \ + -DCMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES="/stuff/tools/llvm/ATfE-21.1.1/lib/clang-runtimes/arm-none-eabi/include/c++/v1/;/stuff/tools/llvm/ATfE-21.1.1/lib/clang-runtimes/arm-none-eabi/include/" + +cmake --build build +``` + +Adjust paths for your toolchain install; some ATfE versions add a `_size` suffix to the runtime directory. Re-enable picotool/USB stdio if needed. diff --git a/examples/led_blink_raw.cpp b/examples/led_blink_raw.cpp new file mode 100644 index 000000000..1a27a87b5 --- /dev/null +++ b/examples/led_blink_raw.cpp @@ -0,0 +1,12 @@ + +import pico.hw; + +auto main() -> int { + pico::hw::InitializeBoard(); + + pico::hw::InitializeLedPin(); + while (true) { + pico::hw::ToggleLed(); + pico::hw::BusyDelay(12000000); + } +} diff --git a/examples/sdk/hw/hw.cppm b/examples/sdk/hw/hw.cppm new file mode 100644 index 000000000..e4ecf22ba --- /dev/null +++ b/examples/sdk/hw/hw.cppm @@ -0,0 +1,70 @@ + +module; + +#include "hardware/structs/io_bank0.h" +#include "hardware/structs/padsbank0.h" +#include "hardware/structs/sio.h" +#include "pico/platform.h" +#include "pico/stdio.h" + +export module pico.hw; + +import std; + +namespace pico::hw { + +export auto InitializeBoard() -> void; +export auto InitializeLedPin() -> void; +export auto BusyDelay(std::uint32_t cycles) -> void; +export auto ToggleLed() -> void; + +} // namespace pico::hw + +namespace { + +std::uint8_t constexpr kLedPin{25}; + +template > + requires(std::unsigned_integral or std::same_as>) +consteval auto GetLedMask() -> T { + std::bitset<32> led_mask{}; + led_mask.set(kLedPin); + + if constexpr (std::is_same_v>) { + return led_mask; + } + + return static_cast(led_mask.to_ulong()); +} + +} // namespace + +namespace pico::hw { + +auto InitializeBoard() -> void { + stdio_init_all(); +} + +auto InitializeLedPin() -> void { + // Configure the pad for push-pull output: 4 mA drive, Schmitt enabled, no + // pulls. + padsbank0_hw->io[kLedPin] = + (PADS_BANK0_GPIO25_DRIVE_VALUE_4MA << PADS_BANK0_GPIO25_DRIVE_LSB) | + PADS_BANK0_GPIO25_SCHMITT_BITS; + + // Route the pin to the SIO peripheral so we can drive it directly. + io_bank0_hw->io[kLedPin].ctrl = GPIO_FUNC_SIO; + + // Enable output on the pin via SIO. + sio_hw->gpio_oe_set = GetLedMask(); +} + +auto BusyDelay(std::uint32_t cycles) -> void { + busy_wait_at_least_cycles(cycles); +} + +auto ToggleLed() -> void { + sio_hw->gpio_togl = GetLedMask(); +} + +} // namespace pico::hw diff --git a/src/rp2_common/pico_clib_interface/CMakeLists.txt b/src/rp2_common/pico_clib_interface/CMakeLists.txt index 84d3faf62..741485ae1 100644 --- a/src/rp2_common/pico_clib_interface/CMakeLists.txt +++ b/src/rp2_common/pico_clib_interface/CMakeLists.txt @@ -1,6 +1,10 @@ if (NOT TARGET pico_clib_interface) pico_add_library(pico_clib_interface) + target_sources(pico_clib_interface INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/fini_stub.c + ) + # ---- newlib ---- pico_add_library(pico_newlib_interface) diff --git a/src/rp2_common/pico_clib_interface/fini_stub.c b/src/rp2_common/pico_clib_interface/fini_stub.c new file mode 100644 index 000000000..ad5299ae7 --- /dev/null +++ b/src/rp2_common/pico_clib_interface/fini_stub.c @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2025 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "pico.h" + +// Bare-metal stub so __libc_fini_array can resolve _fini without pulling in +// hosted runtime shutdown logic. +void __weak _fini(void) {} diff --git a/src/rp2_common/pico_crt0/rp2350/memmap_default.ld b/src/rp2_common/pico_crt0/rp2350/memmap_default.ld index bce316d14..48a5478a5 100644 --- a/src/rp2_common/pico_crt0/rp2350/memmap_default.ld +++ b/src/rp2_common/pico_crt0/rp2350/memmap_default.ld @@ -77,24 +77,26 @@ SECTIONS . = ALIGN(4); /* preinit data */ - PROVIDE_HIDDEN (__preinit_array_start = .); + PROVIDE (__bothinit_array_start = .); + PROVIDE (__preinit_array_start = .); KEEP(*(SORT(.preinit_array.*))) KEEP(*(.preinit_array)) - PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE (__preinit_array_end = .); . = ALIGN(4); /* init data */ - PROVIDE_HIDDEN (__init_array_start = .); + PROVIDE (__init_array_start = .); KEEP(*(SORT(.init_array.*))) KEEP(*(.init_array)) - PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE (__init_array_end = .); + PROVIDE (__bothinit_array_end = .); . = ALIGN(4); /* finit data */ - PROVIDE_HIDDEN (__fini_array_start = .); + PROVIDE (__fini_array_start = .); *(SORT(.fini_array.*)) *(.fini_array) - PROVIDE_HIDDEN (__fini_array_end = .); + PROVIDE (__fini_array_end = .); *(.eh_frame*) . = ALIGN(4); @@ -299,4 +301,3 @@ SECTIONS /* todo assert on extra code */ } - diff --git a/src/rp2_common/pico_platform_compiler/include/pico/platform/compiler.h b/src/rp2_common/pico_platform_compiler/include/pico/platform/compiler.h index 7f24008a2..44af9f326 100644 --- a/src/rp2_common/pico_platform_compiler/include/pico/platform/compiler.h +++ b/src/rp2_common/pico_platform_compiler/include/pico/platform/compiler.h @@ -27,6 +27,11 @@ #else #define PICO_C_COMPILER_IS_GNU 1 #endif +/* Some libc variants (e.g. picolibc/LLVM embedded toolchain) don't provide + * __printflike; fall back to the usual GCC-style format attribute. */ +#ifndef __printflike +#define __printflike(a, b) __attribute__((__format__(printf, a, b))) +#endif #elif defined __ICCARM__ #ifndef __aligned #define __aligned(x) __attribute__((__aligned__(x))) diff --git a/tools/pioasm/CMakeLists.txt b/tools/pioasm/CMakeLists.txt index dcca23860..36bd5d04b 100644 --- a/tools/pioasm/CMakeLists.txt +++ b/tools/pioasm/CMakeLists.txt @@ -23,6 +23,7 @@ add_executable(pioasm gen/lexer.cpp gen/parser.cpp ) +target_compile_definitions(pioasm PRIVATE _GTHREAD_USE_COND_INIT_FUNC) target_sources(pioasm PRIVATE c_sdk_output.cpp) target_sources(pioasm PRIVATE python_output.cpp)