diff options
m--------- | 3rd-party/pico-sdk | 0 | ||||
-rw-r--r-- | CMakeLists.txt | 6 | ||||
-rw-r--r-- | GNUmakefile | 8 | ||||
-rw-r--r-- | README.md | 34 | ||||
-rwxr-xr-x | build-aux/lint-bin | 36 | ||||
-rw-r--r-- | libhw/rp2040_include/libhw/rp2040_hwspi.h | 5 | ||||
-rw-r--r-- | libmisc/include/libmisc/macro.h | 8 | ||||
-rw-r--r-- | libmisc/include/libmisc/private.h | 7 | ||||
-rw-r--r-- | libmisc/tests/test_macro.c | 25 |
9 files changed, 96 insertions, 33 deletions
diff --git a/3rd-party/pico-sdk b/3rd-party/pico-sdk -Subproject 0e28a1b3cf28296a40f9c8c42d6340bdd7ebb30 +Subproject 1c00d64a4e0fdf948494c9aaf4d257b5739796a diff --git a/CMakeLists.txt b/CMakeLists.txt index b90d000..c6c7068 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,13 +43,13 @@ function(target_embed_sources arg_compile_target arg_link_target arg_hdrname) set(embed_objs) foreach(embed_src IN LISTS ARGN) add_custom_command( - OUTPUT "${embed_src}.obj" + OUTPUT "${embed_src}.o" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMMAND mkdir -p -- "$<PATH:GET_PARENT_PATH,${CMAKE_CURRENT_BINARY_DIR}/${embed_src}>" && - ${CMAKE_LINKER} -r -b binary -o "${CMAKE_CURRENT_BINARY_DIR}/${embed_src}.obj" "${embed_src}" + ${CMAKE_LINKER} -r -b binary -o "${CMAKE_CURRENT_BINARY_DIR}/${embed_src}.o" "${embed_src}" DEPENDS "${embed_src}" ) - list(APPEND embed_objs "${embed_src}.obj") + list(APPEND embed_objs "${embed_src}.o") endforeach() set_source_files_properties("${embed_objs}" PROPERTIES EXTERNAL_OBJECT true diff --git a/GNUmakefile b/GNUmakefile index 5f49647..0913aec 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -81,7 +81,7 @@ $(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/Makefile)): buil mkdir -p $(@D) && cd $(@D) && cmake -DPICO_PLATFORM=$(firstword $(subst -, ,$*)) -DCMAKE_BUILD_TYPE=$(lastword $(subst -, ,$*)) ../.. $(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/build)): build/%/build: build/%/Makefile generate - $(MAKE) -C $(<D) INNER=t + $(MAKE) -C $(<D) .PHONY: $(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/build)) check: build @@ -89,7 +89,7 @@ check: build .PHONY: check $(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/check)): build/%/check: build/%/Makefile - CTEST_OUTPUT_ON_FAILURE=1 $(MAKE) -C $(<D) INNER=t test + CTEST_OUTPUT_ON_FAILURE=1 $(MAKE) -C $(<D) test .PHONY: $(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/check)) # `lint` and `format` ########################################################## @@ -104,7 +104,9 @@ build-aux/venv: build-aux/requirements.txt # `lint` ########### lint: - $(MAKE) -k INNER=t $(patsubst sources_%,lint/%,$(filter sources_%,$(.VARIABLES))) + $(MAKE) -k INNER=t $(patsubst sources_%,lint/%,$(filter sources_%,$(.VARIABLES))) lint/bin +lint/bin: build build-aux/lint-bin + ./build-aux/lint-bin $(foreach t,$(build_types),build/rp2040-$t/cmd/sbc_harness/sbc_harness.elf) lint/sh lint/bash: lint/%: shellcheck $(sources_$*) lint/python3: lint/%: build-aux/venv @@ -18,15 +18,29 @@ At the time of this writing, on Parabola GNU/Linux-libre that means: - arm-none-eabi-binutils 2.42-1 - arm-none-eabi-gcc 14.1.0-1 - arm-none-eabi-newlib 4.4.0.20231231-1 - - picotool 2.0.0-2 + - picotool 2.1.1-1 Then, simply run `make`. This will create -`build/rp2040-*/cmd/sbc_harness/sbc_harness.{bin,uf2,elf}` files. The -`.bin` file is the raw firmware image; the `.uf2` file is that wrapped -into a [USB Flashing Format (UF2)](https://github.com/microsoft/uf2) -container that can be used with the bootrom flasher (yes, the -`.uf2` is expected to be about twice the size of the `.bin`); the -`.elf` is the firmware image plus debugger symbols. +`build/rp2040-*/cmd/sbc_harness/sbc_harness.{elf,bin,hex,uf2}` files: + + - The `.elf` is the firmware image plus debugger symbols and + relocation data. + - The `.bin` file is the raw firmware image (`objcopy -Obinary + INFILE.elf OUTFILE.bin`). + - The `.hex` file is the raw firmware image, encoded in the [Intel + HEX](https://archive.org/details/IntelHEXStandard) format (`objcopy + -Oihex INFILE.elf OUTFILE.hex`). Note that unlike the `.bin`, the + `.hex` may contain gaps/holes; holes are filled with 0x00-bytes in + the `.bin`, but tools for working with the `.hex` may fill them + with other data, causing minor differences when comparing the + `.bin` and `.hex`. (Yes, the `.hex` is expected to be about 2.8 + times the size of the `.bin`; twice for being ASCII-encoded hex, + plus another 13 bytes overhead for every 16 bytes of input.) + - The `.uf2` file is the `.bin` wrapped into a [USB Flashing Format + (UF2)](https://github.com/microsoft/uf2) container that can be used + with the bootrom flasher. (Yes, the `.uf2` is expected to be about + twice the size of the `.bin`; each 128-byte block of input is + wrapped in a 256-byte UF2 block.) There are several ways of putting this firmware file onto the harness: @@ -55,9 +69,7 @@ There are several ways of putting this firmware file onto the harness: The harness uses DHCP to acquire an IPv4 address, then serves the 9P protocol over TCP: - - TCP port: 564 (9P does not have a standard TCP port number, but - this is the default port number used by most 9P-over-TCP clients, - including the Linux kernel's v9fs driver). + - TCP port: 564 - Supported protocol versions: - `9P2000` (base protocol): Yes - `9P2000.u` (Unix extension): Yes, with Linux kernel @@ -82,7 +94,7 @@ library for your programming language of choice. Some notes on choosing a client: - On x86-32, the Linux kernel v9fs driver is known to drop entries - from directory listings; I advise using 9pfuse instead of you want + from directory listings; I advise using 9pfuse instead if you want to mount it on 32-bit systems. - I generally like mounting it as a real filesystem, but this means that you only get errno errors, and the more-helpful error strings diff --git a/build-aux/lint-bin b/build-aux/lint-bin index 2fe8e4b..ffc2a12 100755 --- a/build-aux/lint-bin +++ b/build-aux/lint-bin @@ -5,7 +5,22 @@ # SPDX-License-Identifier: AGPL-3.0-or-later set -euE -o pipefail +shopt -s extglob +# There are several exisi files we can use: +# +# Binaries: +# - ${elf} : firmware image with debug symbols and relocationd data +# - ${elf%.elf}.bin : raw firmware image +# - ${elf%.elf}.hex : .bin as Intel HEX +# - ${elf%.elf}.uf2 : .bin as USB Flashing Format (UF2) +# +# Textual info: +# - ${elf%.elf}.dis : `objdump --section-headers ${elf}; objdump --disassemble ${elf}; picotool coprodis --quiet ${elf}` +# - ${elf}.map : `ld --print-map` info + +# Input is `ld --print-map` format. +# # Output is a series of lines in the format "symbol location size # source". Whitespace may seem silly. objdump_globals() { @@ -30,7 +45,9 @@ lint_globals() { cd "$rel_base" total=0 while read -r symbol addr size source; do - : "$addr" + if (( addr == 0 )); then + continue + fi case "$source" in /*) # libg.a(whatever.o) -> libg.a @@ -38,26 +55,31 @@ lint_globals() { # resolve `..` components source="$(realpath --canonicalize-missing --no-symlinks -- "$source")" ;; - CMakeFiles/*.dir/*.obj) + CMakeFiles/*.dir/*.@(obj|o)) # CMakeFiles/sbc_harnes_objs.dir/... source="${source#CMakeFiles/*.dir/}" - source="${source%.obj}" + source="${source%.@(obj|o)}" source="${source//__/..}" source="$(realpath --canonicalize-missing --no-symlinks --relative-to="$topdir" -- "$source")" ;; esac - printf '%s %s 0x%04x\n' "$source" "$symbol" "$size" + printf "%s %s 0x%04x (%'d)\n" "$source" "$symbol" "$size" "$size" total=$((total + size)) done - printf '~ Total 0x%04x\n' "$total" + printf "~ Total 0x%04x (%'d)\n" "$total" "$total" } | LC_COLLATE=C sort } | column -t } main() { - echo 'Global variables:' - lint_globals 'build/rp2040-Release/cmd/sbc_harness/sbc_harness.elf.map' | sed 's/^/ /' + local elf + for elf in "$@"; do + { + echo 'Global variables:' + lint_globals "${elf}.map" | sed 's/^/ /' + } > "${elf%.elf}.lint.globals" + done } main "$@" diff --git a/libhw/rp2040_include/libhw/rp2040_hwspi.h b/libhw/rp2040_include/libhw/rp2040_hwspi.h index b1abe0c..53a7b03 100644 --- a/libhw/rp2040_include/libhw/rp2040_hwspi.h +++ b/libhw/rp2040_include/libhw/rp2040_hwspi.h @@ -20,8 +20,9 @@ enum rp2040_hwspi_instance { struct rp2040_hwspi { BEGIN_PRIVATE(LIBHW_RP2040_HWSPI_H) - void /*spi_inst_t*/ *inst; - uint pin_cs; + LM_IF(IS_IMPLEMENTATION_FOR(LIBHW_RP2040_HWSPI_H))(spi_inst_t)(void) *inst; + + uint pin_cs; END_PRIVATE(LIBHW_RP2040_HWSPI_H) }; LO_IMPLEMENTATION_H(spi, struct rp2040_hwspi, rp2040_hwspi) diff --git a/libmisc/include/libmisc/macro.h b/libmisc/include/libmisc/macro.h index fe61410..b3e235c 100644 --- a/libmisc/include/libmisc/macro.h +++ b/libmisc/include/libmisc/macro.h @@ -17,9 +17,11 @@ /* numeric */ #define LM_ARRAY_LEN(ary) (sizeof(ary)/sizeof((ary)[0])) -#define LM_CEILDIV(n, d) ( ((n)+(d)-1) / (d) ) -#define LM_ROUND_UP(n, d) ( LM_CEILDIV(n, d) * (d) ) /** Return `n` rounded up to the nearest multiple of `d` */ -#define LM_NEXT_POWER_OF_2(x) ( (x) ? 1ULL<<((sizeof(unsigned long long)*8)-__builtin_clzll(x)) : 1) +#define LM_CEILDIV(n, d) ( ((n)+(d)-1) / (d) ) /** Return ceil(n/d) */ +#define LM_ROUND_UP(n, d) ( LM_CEILDIV(n, d) * (d) ) /** Return `n` rounded up to the nearest multiple of `d` */ +#define LM_ROUND_DOWN(n, d) ( ((n)/(d)) * (d) ) /** Return `n` rounded down to the nearest multiple of `d` */ +#define LM_NEXT_POWER_OF_2(x) ( (x) ? 1ULL<<((sizeof(unsigned long long)*8)-__builtin_clzll(x)) : 1) /** Return the lowest power of 2 that is > x */ +#define LM_FLOORLOG2(x) ((sizeof(unsigned long long)*8)-__builtin_clzll(x)-1) /** Return floor(log_2(x) */ /* strings */ diff --git a/libmisc/include/libmisc/private.h b/libmisc/include/libmisc/private.h index 1db7915..c5382a7 100644 --- a/libmisc/include/libmisc/private.h +++ b/libmisc/include/libmisc/private.h @@ -1,6 +1,6 @@ /* libmisc/private.h - Utilities to hide struct fields * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later */ @@ -10,7 +10,8 @@ #include <libmisc/macro.h> #define YES LM_SENTINEL() -#define BEGIN_PRIVATE(name) LM_IF(LM_IS_SENTINEL(IMPLEMENTATION_FOR_##name))()(struct {) -#define END_PRIVATE(name) LM_IF(LM_IS_SENTINEL(IMPLEMENTATION_FOR_##name))()(} LM_CAT2_(_HIDDEN_, __COUNTER__);) +#define IS_IMPLEMENTATION_FOR(name) LM_IS_SENTINEL(IMPLEMENTATION_FOR_##name) +#define BEGIN_PRIVATE(name) LM_IF(IS_IMPLEMENTATION_FOR(name))()(struct {) +#define END_PRIVATE(name) LM_IF(IS_IMPLEMENTATION_FOR(name))()(} LM_CAT2_(_HIDDEN_, __COUNTER__);) #endif /* _LIBMISC_PRIVATE_H_ */ diff --git a/libmisc/tests/test_macro.c b/libmisc/tests/test_macro.c index 7cbf9d3..69655d1 100644 --- a/libmisc/tests/test_macro.c +++ b/libmisc/tests/test_macro.c @@ -1,6 +1,6 @@ /* libmisc/tests/test_macro.c - Tests for <libmisc/macro.h> * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later */ @@ -9,6 +9,7 @@ #include "test.h" int main() { + printf("== LM_NEXT_POWER_OF_2 =====================================\n"); /* valid down to 0. */ test_assert(LM_NEXT_POWER_OF_2(0) == 1); test_assert(LM_NEXT_POWER_OF_2(1) == 2); @@ -28,5 +29,27 @@ int main() { /* Valid up to 0x8000000000000000-1 = (1<<63)-1 */ test_assert(LM_NEXT_POWER_OF_2(0x8000000000000000) == 0); /* :( */ + printf("== LM_FLOORLOG2 ===========================================\n"); + /* valid down to 1. */ + test_assert(LM_FLOORLOG2(1) == 0); + test_assert(LM_FLOORLOG2(2) == 1); + test_assert(LM_FLOORLOG2(3) == 1); + test_assert(LM_FLOORLOG2(4) == 2); + test_assert(LM_FLOORLOG2(5) == 2); + test_assert(LM_FLOORLOG2(6) == 2); + test_assert(LM_FLOORLOG2(7) == 2); + test_assert(LM_FLOORLOG2(8) == 3); + /* ... */ + test_assert(LM_FLOORLOG2(16) == 4); + /* ... */ + test_assert(LM_FLOORLOG2(0x80000000) == 31); + /* ... */ + test_assert(LM_FLOORLOG2(0xFFFFFFFF) == 31); + test_assert(LM_FLOORLOG2(0x100000000) == 32); + /* ... */ + test_assert(LM_FLOORLOG2(0x8000000000000000) == 63); + /* ... */ + test_assert(LM_FLOORLOG2(0xFFFFFFFFFFFFFFFF) == 63); + return 0; } |