diff --git a/bazel/config/BUILD.bazel b/bazel/config/BUILD.bazel index ea8187924..dfb3e992a 100644 --- a/bazel/config/BUILD.bazel +++ b/bazel/config/BUILD.bazel @@ -237,6 +237,7 @@ string_flag( "no_flash", "copy_to_ram", "blocked_ram", + "xip_ram", ], ) diff --git a/bazel/constraint/BUILD.bazel b/bazel/constraint/BUILD.bazel index 8fcd1a611..211aac6eb 100644 --- a/bazel/constraint/BUILD.bazel +++ b/bazel/constraint/BUILD.bazel @@ -303,3 +303,8 @@ config_setting( name = "pico_binary_type_blocked_ram", flag_values = {"//bazel/config:PICO_DEFAULT_BINARY_TYPE": "blocked_ram"}, ) + +config_setting( + name = "pico_binary_type_xip_ram", + flag_values = {"//bazel/config:PICO_DEFAULT_BINARY_TYPE": "xip_ram"}, +) diff --git a/src/common/pico_base_headers/BUILD.bazel b/src/common/pico_base_headers/BUILD.bazel index c86234768..8f15e44f6 100644 --- a/src/common/pico_base_headers/BUILD.bazel +++ b/src/common/pico_base_headers/BUILD.bazel @@ -78,6 +78,7 @@ cc_library( "//bazel/constraint:pico_binary_type_no_flash": ["PICO_NO_FLASH=1"], "//bazel/constraint:pico_binary_type_copy_to_ram": ["PICO_COPY_TO_RAM=1"], "//bazel/constraint:pico_binary_type_blocked_ram": ["PICO_USE_BLOCKED_RAM=1"], + "//bazel/constraint:pico_binary_type_xip_ram": ["PICO_XIP_RAM=1"], "//conditions:default": [], }), ) diff --git a/src/rp2040/pico_platform/memmap_blocked_ram.ld b/src/rp2040/pico_platform/memmap_blocked_ram.ld index 7d7ab9e9b..049e0b099 100644 --- a/src/rp2040/pico_platform/memmap_blocked_ram.ld +++ b/src/rp2040/pico_platform/memmap_blocked_ram.ld @@ -12,6 +12,7 @@ INCLUDE "memmap_default.incl" * └── memmap_default.incl rp2_common/pico_standard_link * ├── set_memory_locations.incl rp2_common/pico_standard_link * ├── memory_flash.incl rp2_common/pico_standard_link + * ├── memory_xip_ram.incl rp2_common/pico_standard_link * ├── memory_ram.incl rp2_common/pico_standard_link * ├── memory_scratch.incl rp2_common/pico_standard_link * ├── memory_generated.incl rp2_common/pico_standard_link diff --git a/src/rp2040/pico_platform/memmap_copy_to_ram.ld b/src/rp2040/pico_platform/memmap_copy_to_ram.ld index 1ea516d55..330f17023 100644 --- a/src/rp2040/pico_platform/memmap_copy_to_ram.ld +++ b/src/rp2040/pico_platform/memmap_copy_to_ram.ld @@ -9,6 +9,7 @@ INCLUDE "memmap_copy_to_ram.incl" * └── memmap_copy_to_ram.incl rp2_common/pico_standard_link * ├── set_memory_locations.incl rp2_common/pico_standard_link * ├── memory_flash.incl rp2_common/pico_standard_link + * ├── memory_xip_ram.incl rp2_common/pico_standard_link * ├── memory_ram.incl rp2_common/pico_standard_link * ├── memory_scratch.incl rp2_common/pico_standard_link * ├── memory_generated.incl rp2_common/pico_standard_link diff --git a/src/rp2040/pico_platform/memmap_default.ld b/src/rp2040/pico_platform/memmap_default.ld index 2f4d3bf9b..b02671ea7 100644 --- a/src/rp2040/pico_platform/memmap_default.ld +++ b/src/rp2040/pico_platform/memmap_default.ld @@ -9,6 +9,7 @@ INCLUDE "memmap_default.incl" * └── memmap_default.incl rp2_common/pico_standard_link * ├── set_memory_locations.incl rp2_common/pico_standard_link * ├── memory_flash.incl rp2_common/pico_standard_link + * ├── memory_xip_ram.incl rp2_common/pico_standard_link * ├── memory_ram.incl rp2_common/pico_standard_link * ├── memory_scratch.incl rp2_common/pico_standard_link * ├── memory_generated.incl rp2_common/pico_standard_link diff --git a/src/rp2040/pico_platform/memmap_no_flash.ld b/src/rp2040/pico_platform/memmap_no_flash.ld index dddfbd4e6..1ae20f2de 100644 --- a/src/rp2040/pico_platform/memmap_no_flash.ld +++ b/src/rp2040/pico_platform/memmap_no_flash.ld @@ -8,6 +8,7 @@ INCLUDE "memmap_no_flash.incl" * memmap_no_flash.ld rp2040/pico_platform * └── memmap_no_flash.incl rp2_common/pico_standard_link * ├── set_memory_locations.incl rp2_common/pico_standard_link + * ├── memory_xip_ram.incl rp2_common/pico_standard_link * ├── memory_ram.incl rp2_common/pico_standard_link * ├── memory_scratch.incl rp2_common/pico_standard_link * ├── memory_generated.incl rp2_common/pico_standard_link diff --git a/src/rp2350/pico_platform/BUILD.bazel b/src/rp2350/pico_platform/BUILD.bazel index 4efa080e5..65d4adc6a 100644 --- a/src/rp2350/pico_platform/BUILD.bazel +++ b/src/rp2350/pico_platform/BUILD.bazel @@ -61,6 +61,7 @@ exports_files( "memmap_copy_to_ram.ld", "memmap_default.ld", "memmap_no_flash.ld", + "memmap_xip_ram.ld", ], ) @@ -79,6 +80,11 @@ linker_scripts( link_scripts = ["memmap_no_flash.ld"], ) +linker_scripts( + name = "memmap_xip_ram", + link_scripts = ["memmap_xip_ram.ld"], +) + cc_library( name = "default_linker_script", target_compatible_with = ["//bazel/constraint:rp2350"], @@ -133,3 +139,21 @@ cc_library( "memmap_no_flash", ], ) + +# PICO_BUILD_DEFINE: PICO_XIP_RAM, whether this is a 'xip_ram' build, type=bool, default=0, but dependent on CMake options, group=pico_standard_link +cc_library( + name = "xip_ram_linker_script", + target_compatible_with = ["//bazel/constraint:rp2350"], + visibility = [ + "//src/rp2_common/pico_standard_link:__pkg__", + ], + # The order of the linker scripts below is important. + # Prevent buildifier from reordering them. + # buildifier: leave-alone + deps = [ + "//src/rp2_common/pico_crt0:no_warn_rwx_flag", + "//src/rp2350/pico_platform/script_include:rp2350_linker_scripts", + "//src/rp2_common/pico_standard_link/script_include:rp2_linker_scripts", + "memmap_xip_ram", + ], +) diff --git a/src/rp2350/pico_platform/memmap_copy_to_ram.ld b/src/rp2350/pico_platform/memmap_copy_to_ram.ld index 0f2df7a27..b9437c80e 100644 --- a/src/rp2350/pico_platform/memmap_copy_to_ram.ld +++ b/src/rp2350/pico_platform/memmap_copy_to_ram.ld @@ -9,6 +9,7 @@ INCLUDE "memmap_copy_to_ram.incl" * └── memmap_copy_to_ram.incl rp2_common/pico_standard_link * ├── set_memory_locations.incl rp2_common/pico_standard_link * ├── memory_flash.incl rp2_common/pico_standard_link + * ├── memory_xip_ram.incl rp2_common/pico_standard_link * ├── memory_ram.incl rp2_common/pico_standard_link * ├── memory_scratch.incl rp2_common/pico_standard_link * ├── memory_generated.incl rp2_common/pico_standard_link diff --git a/src/rp2350/pico_platform/memmap_default.ld b/src/rp2350/pico_platform/memmap_default.ld index 21a002792..badeb4630 100644 --- a/src/rp2350/pico_platform/memmap_default.ld +++ b/src/rp2350/pico_platform/memmap_default.ld @@ -9,6 +9,7 @@ INCLUDE "memmap_default.incl" * └── memmap_default.incl rp2_common/pico_standard_link * ├── set_memory_locations.incl rp2_common/pico_standard_link * ├── memory_flash.incl rp2_common/pico_standard_link + * ├── memory_xip_ram.incl rp2_common/pico_standard_link * ├── memory_ram.incl rp2_common/pico_standard_link * ├── memory_scratch.incl rp2_common/pico_standard_link * ├── memory_generated.incl rp2_common/pico_standard_link diff --git a/src/rp2350/pico_platform/memmap_no_flash.ld b/src/rp2350/pico_platform/memmap_no_flash.ld index d9f643f04..55e4d085a 100644 --- a/src/rp2350/pico_platform/memmap_no_flash.ld +++ b/src/rp2350/pico_platform/memmap_no_flash.ld @@ -8,6 +8,7 @@ INCLUDE "memmap_no_flash.incl" * memmap_no_flash.ld rp2350/pico_platform * └── memmap_no_flash.incl rp2_common/pico_standard_link * ├── set_memory_locations.incl rp2_common/pico_standard_link + * ├── memory_xip_ram.incl rp2_common/pico_standard_link * ├── memory_ram.incl rp2_common/pico_standard_link * ├── memory_scratch.incl rp2_common/pico_standard_link * ├── memory_generated.incl rp2_common/pico_standard_link diff --git a/src/rp2350/pico_platform/memmap_xip_ram.ld b/src/rp2350/pico_platform/memmap_xip_ram.ld new file mode 100644 index 000000000..56c936fa2 --- /dev/null +++ b/src/rp2350/pico_platform/memmap_xip_ram.ld @@ -0,0 +1,42 @@ +INCLUDE "memmap_xip_ram.incl" + +/* BEGIN_MEMMAP_INCLUDE_TREE + * This is the default include tree for this file (generated by tools/memmap_annotate.py + * and tools/memmap_include_tree.py). To override any files in this tree, see the + * pico_add_linker_script_override_path CMake function under pico_standard_link. + * + * memmap_xip_ram.ld rp2350/pico_platform + * └── memmap_xip_ram.incl rp2_common/pico_standard_link + * ├── set_memory_locations.incl rp2_common/pico_standard_link + * ├── memory_ram.incl rp2_common/pico_standard_link + * ├── memory_scratch.incl rp2_common/pico_standard_link + * ├── memory_generated.incl rp2_common/pico_standard_link + * ├── memory_extra.incl rp2_common/pico_standard_link + * ├── memory_aliases_xip_ram_only.incl rp2_common/pico_standard_link + * └── sections_no_flash.incl rp2_common/pico_standard_link + * ├── sections_no_flash_text.incl rp2_common/pico_standard_link + * │ ├── section_no_flash_text.incl rp2_common/pico_standard_link + * │ ├── section_no_flash_rodata.incl rp2_common/pico_standard_link + * │ ├── sections_arm_ex.incl rp2_common/pico_standard_link + * │ └── section_binary_info.incl rp2_common/pico_standard_link + * ├── section_generated_post_text.incl rp2_common/pico_standard_link + * ├── section_extra_post_text.incl rp2_common/pico_standard_link + * ├── sections_no_flash_data.incl rp2_common/pico_standard_link + * │ ├── section_no_flash_data.incl rp2_common/pico_standard_link + * │ ├── section_uninitialized_data.incl rp2_common/pico_standard_link + * │ ├── section_tls.incl rp2_common/pico_standard_link + * │ └── section_persistent_data.incl rp2_common/pico_standard_link + * ├── section_generated_post_data.incl rp2_common/pico_standard_link + * ├── section_extra_post_data.incl rp2_common/pico_standard_link + * ├── section_heap.incl rp2_common/pico_standard_link + * ├── sections_scratch.incl rp2_common/pico_standard_link + * ├── section_generated_post_scratch.incl rp2_common/pico_standard_link + * ├── section_extra_post_scratch.incl rp2_common/pico_standard_link + * ├── sections_stack.incl rp2_common/pico_standard_link + * ├── section_end.incl rp2_common/pico_standard_link + * ├── section_generated_post_end.incl rp2_common/pico_standard_link + * ├── section_extra_post_end.incl rp2_common/pico_standard_link + * ├── section_platform_end.incl rp2350/pico_platform + * ├── section_generated_post_platform_end.incl rp2_common/pico_standard_link + * └── section_extra_post_platform_end.incl rp2_common/pico_standard_link + * END_MEMMAP_INCLUDE_TREE */ diff --git a/src/rp2_common/hardware_flash/flash.c b/src/rp2_common/hardware_flash/flash.c index fbca8de2c..5526db827 100644 --- a/src/rp2_common/hardware_flash/flash.c +++ b/src/rp2_common/hardware_flash/flash.c @@ -10,6 +10,7 @@ #if PICO_RP2040 #include "hardware/structs/io_qspi.h" #include "hardware/structs/ssi.h" +#include "hardware/structs/xip.h" #else #include "hardware/structs/qmi.h" #include "hardware/regs/otp_data.h" @@ -127,7 +128,9 @@ static void __no_inline_not_in_flash_func(flash_rp2350_restore_qmi_cs1)(const fl typedef struct flash_hardware_save_state { -#if !PICO_RP2040 +#if PICO_RP2040 + uint32_t xip_ctrl; +#else flash_rp2350_qmi_save_state_t qmi_save; #endif uint32_t qspi_pads[count_of(pads_qspi_hw->io)]; @@ -139,7 +142,9 @@ static void __no_inline_not_in_flash_func(flash_save_hardware_state)(flash_hardw for (size_t i = 0; i < count_of(pads_qspi_hw->io); ++i) { state->qspi_pads[i] = pads_qspi_hw->io[i]; } -#if !PICO_RP2040 +#if PICO_RP2040 + state->xip_ctrl = xip_ctrl_hw->ctrl; +#else flash_rp2350_save_qmi_cs1(&state->qmi_save); #endif } @@ -148,7 +153,9 @@ static void __no_inline_not_in_flash_func(flash_restore_hardware_state)(flash_ha for (size_t i = 0; i < count_of(pads_qspi_hw->io); ++i) { pads_qspi_hw->io[i] = state->qspi_pads[i]; } -#if !PICO_RP2040 +#if PICO_RP2040 + xip_ctrl_hw->ctrl = state->xip_ctrl; +#else // Tail call! flash_rp2350_restore_qmi_cs1(&state->qmi_save); #endif diff --git a/src/rp2_common/hardware_riscv_platform_timer/BUILD.bazel b/src/rp2_common/hardware_riscv_platform_timer/BUILD.bazel index 790be1e40..943e0504d 100644 --- a/src/rp2_common/hardware_riscv_platform_timer/BUILD.bazel +++ b/src/rp2_common/hardware_riscv_platform_timer/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:cc_library.bzl", "cc_library") -load("//bazel:defs.bzl", "compatible_with_rp2") +load("//bazel:defs.bzl", "compatible_with_rp2", "incompatible_with_config") package(default_visibility = ["//visibility:public"]) @@ -7,7 +7,7 @@ cc_library( name = "hardware_riscv_platform_timer", hdrs = ["include/hardware/riscv_platform_timer.h"], includes = ["include"], - target_compatible_with = compatible_with_rp2() + ["@platforms//cpu:riscv32"], + target_compatible_with = compatible_with_rp2() + incompatible_with_config("//bazel/constraint:rp2040"), deps = [ "//src/rp2_common:hardware_structs", "//src/rp2_common:pico_platform", diff --git a/src/rp2_common/hardware_sync_spin_lock/include/hardware/sync/spin_lock.h b/src/rp2_common/hardware_sync_spin_lock/include/hardware/sync/spin_lock.h index 2be493d6f..5b88e870b 100644 --- a/src/rp2_common/hardware_sync_spin_lock/include/hardware/sync/spin_lock.h +++ b/src/rp2_common/hardware_sync_spin_lock/include/hardware/sync/spin_lock.h @@ -10,62 +10,102 @@ #include "pico.h" #include "hardware/sync.h" -// PICO_CONFIG: PICO_USE_SW_SPIN_LOCKS, Use software implementation for spin locks, type=bool, default=1 on RP2350 due to errata, group=hardware_sync +// PICO_CONFIG: PICO_USE_SW_SPIN_LOCKS, Use software implementation for spin locks, type=bool, default=1 on RP2350 due to errata E2, group=hardware_sync #ifndef PICO_USE_SW_SPIN_LOCKS #if PICO_RP2350 -#define PICO_USE_SW_SPIN_LOCKS 1 +#define PICO_USE_SW_SPIN_LOCKS !PICO_XIP_RAM #endif #endif // PICO_CONFIG: PICO_SPINLOCK_ID_IRQ, Spinlock ID for IRQ protection, min=0, max=31, default=9, group=hardware_sync #ifndef PICO_SPINLOCK_ID_IRQ +#if PICO_RP2350 && !PICO_USE_SW_SPIN_LOCKS +#define PICO_SPINLOCK_ID_IRQ 5 +#else #define PICO_SPINLOCK_ID_IRQ 9 #endif +#endif // PICO_CONFIG: PICO_SPINLOCK_ID_TIMER, Spinlock ID for Timer protection, min=0, max=31, default=10, group=hardware_sync #ifndef PICO_SPINLOCK_ID_TIMER +#if PICO_RP2350 && !PICO_USE_SW_SPIN_LOCKS +#define PICO_SPINLOCK_ID_TIMER 6 +#else #define PICO_SPINLOCK_ID_TIMER 10 #endif +#endif // PICO_CONFIG: PICO_SPINLOCK_ID_HARDWARE_CLAIM, Spinlock ID for Hardware claim protection, min=0, max=31, default=11, group=hardware_sync #ifndef PICO_SPINLOCK_ID_HARDWARE_CLAIM +#if PICO_RP2350 && !PICO_USE_SW_SPIN_LOCKS +#define PICO_SPINLOCK_ID_HARDWARE_CLAIM 7 +#else #define PICO_SPINLOCK_ID_HARDWARE_CLAIM 11 #endif +#endif // PICO_CONFIG: PICO_SPINLOCK_ID_RAND, Spinlock ID for Random Number Generator, min=0, max=31, default=12, group=hardware_sync #ifndef PICO_SPINLOCK_ID_RAND +#if PICO_RP2350 && !PICO_USE_SW_SPIN_LOCKS +#define PICO_SPINLOCK_ID_RAND 10 +#else #define PICO_SPINLOCK_ID_RAND 12 #endif +#endif // PICO_CONFIG: PICO_SPINLOCK_ID_ATOMIC, Spinlock ID for atomics, min=0, max=31, default=13, group=hardware_sync #ifndef PICO_SPINLOCK_ID_ATOMIC +#if PICO_RP2350 && !PICO_USE_SW_SPIN_LOCKS +#define PICO_SPINLOCK_ID_ATOMIC 11 +#else #define PICO_SPINLOCK_ID_ATOMIC 13 #endif +#endif // PICO_CONFIG: PICO_SPINLOCK_ID_OS1, First Spinlock ID reserved for use by low level OS style software, min=0, max=31, default=14, group=hardware_sync #ifndef PICO_SPINLOCK_ID_OS1 +#if PICO_RP2350 && !PICO_USE_SW_SPIN_LOCKS +#define PICO_SPINLOCK_ID_OS1 18 +#else #define PICO_SPINLOCK_ID_OS1 14 #endif +#endif // PICO_CONFIG: PICO_SPINLOCK_ID_OS2, Second Spinlock ID reserved for use by low level OS style software, min=0, max=31, default=15, group=hardware_sync #ifndef PICO_SPINLOCK_ID_OS2 +#if PICO_RP2350 && !PICO_USE_SW_SPIN_LOCKS +#define PICO_SPINLOCK_ID_OS2 19 +#else #define PICO_SPINLOCK_ID_OS2 15 #endif +#endif // PICO_CONFIG: PICO_SPINLOCK_ID_STRIPED_FIRST, Lowest Spinlock ID in the 'striped' range, min=0, max=31, default=16, group=hardware_sync #ifndef PICO_SPINLOCK_ID_STRIPED_FIRST +#if PICO_RP2350 && !PICO_USE_SW_SPIN_LOCKS +#define PICO_SPINLOCK_ID_STRIPED_FIRST 20 +#else #define PICO_SPINLOCK_ID_STRIPED_FIRST 16 #endif +#endif // PICO_CONFIG: PICO_SPINLOCK_ID_STRIPED_LAST, Highest Spinlock ID in the 'striped' range, min=0, max=31, default=23, group=hardware_sync #ifndef PICO_SPINLOCK_ID_STRIPED_LAST +#if PICO_RP2350 && !PICO_USE_SW_SPIN_LOCKS +#define PICO_SPINLOCK_ID_STRIPED_LAST 25 +#else #define PICO_SPINLOCK_ID_STRIPED_LAST 23 #endif +#endif // PICO_CONFIG: PICO_SPINLOCK_ID_CLAIM_FREE_FIRST, Lowest Spinlock ID in the 'claim free' range, min=0, max=31, default=24, group=hardware_sync #ifndef PICO_SPINLOCK_ID_CLAIM_FREE_FIRST +#if PICO_RP2350 && !PICO_USE_SW_SPIN_LOCKS +#define PICO_SPINLOCK_ID_CLAIM_FREE_FIRST 26 +#else #define PICO_SPINLOCK_ID_CLAIM_FREE_FIRST 24 #endif +#endif #ifdef PICO_SPINLOCK_ID_CLAIM_FREE_END #warning PICO_SPINLOCK_ID_CLAIM_FREE_END has been renamed to PICO_SPINLOCK_ID_CLAIM_FREE_LAST diff --git a/src/rp2_common/pico_crt0/crt0.S b/src/rp2_common/pico_crt0/crt0.S index fa113fbab..39b6e8303 100644 --- a/src/rp2_common/pico_crt0/crt0.S +++ b/src/rp2_common/pico_crt0/crt0.S @@ -11,6 +11,7 @@ #include "hardware/regs/addressmap.h" #include "hardware/regs/sio.h" +#include "hardware/regs/xip.h" #include "pico/binary_info/defs.h" #include "boot/picobin.h" #include "pico/bootrom.h" @@ -24,6 +25,20 @@ #define PICO_CRT0_NEAR_CALLS 0 #endif +// PICO_CONFIG: PICO_USE_XIP_CACHE_AS_RAM, Whether to use xip cache as ram, default=PICO_XIP_RAM, type=bool, group=pico_crt0 +#ifndef PICO_USE_XIP_CACHE_AS_RAM +#define PICO_USE_XIP_CACHE_AS_RAM PICO_XIP_RAM +#endif + +// PICO_CONFIG: PICO_CRT0_NO_DATA_COPY, Whether crt0 should perform the data copies - usually copying from flash into sram, default=1 for no_flash builds, 0 otherwise, type=bool, group=pico_crt0 +#ifndef PICO_CRT0_NO_DATA_COPY +#if PICO_RP2040 +#define PICO_CRT0_NO_DATA_COPY (PICO_NO_FLASH && !PICO_USE_XIP_CACHE_AS_RAM) +#else +#define PICO_CRT0_NO_DATA_COPY PICO_NO_FLASH +#endif +#endif + #ifdef NDEBUG #ifndef COLLAPSE_IRQS #define COLLAPSE_IRQS @@ -461,6 +476,14 @@ hold_non_core0_in_bootrom: b _enter_vtable_in_r0 1: +#if PICO_RP2040 && PICO_USE_XIP_CACHE_AS_RAM +_disable_xip_cache: + // Disable the XIP cache on RP2040 making its SRAM available for use + ldr r0, =(REG_ALIAS_CLR_BITS + XIP_CTRL_BASE + XIP_CTRL_OFFSET) + movs r1, #XIP_CTRL_EN_BITS + str r1, [r0] +#endif + #if !PICO_RP2040 && PICO_EMBED_XIP_SETUP && !PICO_NO_FLASH // Execute boot2 on the core 0 stack (it also gets copied into BOOTRAM due // to inclusion in the data copy table below). Note the reference @@ -481,7 +504,7 @@ _call_xip_setup: // In a NO_FLASH binary, don't perform .data etc copy, since it's loaded // in-place by the SRAM load. Still need to clear .bss -#if !PICO_NO_FLASH +#if !PICO_CRT0_NO_DATA_COPY adr r4, data_cpy_table // assume there is at least one entry @@ -548,11 +571,21 @@ platform_entry: // symbol for stack traces b 1b -#if !PICO_NO_FLASH +#if !PICO_CRT0_NO_DATA_COPY +#if PICO_NO_FLASH +data_cpy: + // skip copies with same source and destination + cmp r1, r2 + bne data_cpy_start + bx lr +#else + // go straight into the copy + #define data_cpy_start data_cpy +#endif data_cpy_loop: ldm r1!, {r0} stm r2!, {r0} -data_cpy: +data_cpy_start: cmp r2, r3 blo data_cpy_loop bx lr @@ -629,6 +662,12 @@ data_cpy_table: .word __scratch_y_start__ .word __scratch_y_end__ +#if PICO_TIME_CRITICAL_TEXT_IN_XIP_RAM +.word __xip_ram_time_critical_text_source__ +.word __xip_ram_time_critical_text_start__ +.word __xip_ram_time_critical_text_end__ +#endif + .word 0 // null terminator // ---------------------------------------------------------------------------- diff --git a/src/rp2_common/pico_crt0/crt0_riscv.S b/src/rp2_common/pico_crt0/crt0_riscv.S index 31d39749f..e13f32d96 100644 --- a/src/rp2_common/pico_crt0/crt0_riscv.S +++ b/src/rp2_common/pico_crt0/crt0_riscv.S @@ -34,6 +34,14 @@ #define PICO_CRT0_INCLUDE_PICOBIN_END_BLOCK (PICO_CRT0_INCLUDE_PICOBIN_BLOCK && !PICO_NO_FLASH) #endif +#ifndef PICO_CRT0_NO_DATA_COPY +#define PICO_CRT0_NO_DATA_COPY PICO_NO_FLASH +#endif + +#ifndef PICO_USE_XIP_CACHE_AS_RAM +#define PICO_USE_XIP_CACHE_AS_RAM PICO_XIP_RAM +#endif + // If vectors are in RAM, we put them in the .data section, so that they are // preloaded by _reset_handler (assuming this is not a loaded-in-place // binary). @@ -348,7 +356,7 @@ _call_xip_setup: // In a NO_FLASH binary, don't perform .data etc copy, since it's loaded // in-place by the SRAM load. Still need to clear .bss -#if !PICO_NO_FLASH +#if !PICO_CRT0_NO_DATA_COPY la a4, data_cpy_table // assume there is at least one entry @@ -405,14 +413,22 @@ platform_entry: // symbol for stack traces ebreak j 1b - -#if !PICO_NO_FLASH +#if !PICO_CRT0_NO_DATA_COPY +#if PICO_NO_FLASH +data_cpy: + // skip copies with same source and destination + bne a0, a1, data_cpy_start + ret +#else + // go straight into the copy + #define data_cpy_start data_cpy +#endif data_cpy_loop: lw a0, (a1) sw a0, (a2) addi a1, a1, 4 addi a2, a2, 4 -data_cpy: +data_cpy_start: bltu a2, a3, data_cpy_loop ret #endif @@ -480,6 +496,12 @@ data_cpy_table: .word __scratch_y_start__ .word __scratch_y_end__ +#if PICO_TIME_CRITICAL_TEXT_IN_XIP_RAM +.word __xip_ram_time_critical_text_source__ +.word __xip_ram_time_critical_text_start__ +.word __xip_ram_time_critical_text_end__ +#endif + .word 0 // null terminator // ---------------------------------------------------------------------------- diff --git a/src/rp2_common/pico_crt0/embedded_start_block.inc.S b/src/rp2_common/pico_crt0/embedded_start_block.inc.S index 000da904b..52899b861 100644 --- a/src/rp2_common/pico_crt0/embedded_start_block.inc.S +++ b/src/rp2_common/pico_crt0/embedded_start_block.inc.S @@ -39,7 +39,7 @@ #endif #ifndef PICO_CRT0_PIN_XIP_SRAM -#define PICO_CRT0_PIN_XIP_SRAM 0 +#define PICO_CRT0_PIN_XIP_SRAM (PICO_USE_XIP_CACHE_AS_RAM || PICO_XIP_SRAM) #endif #if PICO_CRT0_IMAGE_TYPE_TBYB diff --git a/src/rp2_common/pico_platform_sections/include/pico/platform/sections.h b/src/rp2_common/pico_platform_sections/include/pico/platform/sections.h index 591e9e3b2..7b3d251ed 100644 --- a/src/rp2_common/pico_platform_sections/include/pico/platform/sections.h +++ b/src/rp2_common/pico_platform_sections/include/pico/platform/sections.h @@ -162,21 +162,24 @@ * \ingroup pico_platform * * Decorates a function name, such that the function will execute from RAM (assuming it is not inlined - * into a flash function by the compiler) to avoid possible flash latency. Currently this macro is identical + * into a flash function by the compiler) to avoid possible flash latency. By default, this macro is identical * in implementation to `__not_in_flash_func`, however the semantics are distinct and a `__time_critical_func` - * may in the future be treated more specially to reduce the overhead when calling such function from a flash - * function. + * can be treated more specially to reduce the overhead when calling such a function. + * + * For binaries that are not executing from flash (eg copy_to_ram and no_flash), one special treatment can be + * using the \ref`pico_use_xip_sram_for_time_critical` CMake function to place them in XIP RAM instead, as the + * XIP ports would be otherwise unused. * * For example a function called my_func taking an int parameter: * * void __time_critical_func(my_func)(int some_arg) { * - * The function is placed in the `.time_critical.` linker section + * The function is placed in the `.time_critical.text.` linker section * * \see __not_in_flash_func */ #ifndef __time_critical_func -#define __time_critical_func(func_name) __not_in_flash_func(func_name) +#define __time_critical_func(func_name) __noinline __attribute__((section(".time_critical.text." __STRING(func_name)))) func_name #endif /*! \brief Indicate a function should not be stored in flash and should not be inlined @@ -198,7 +201,7 @@ #else #ifndef RAM_SECTION_NAME -#define RAM_SECTION_NAME(x) .time_critical.##x +#define RAM_SECTION_NAME(x) .time_critical.text.##x #endif #ifndef SECTION_NAME diff --git a/src/rp2_common/pico_standard_link/BUILD.bazel b/src/rp2_common/pico_standard_link/BUILD.bazel index 4ebfdd428..5047fe72c 100644 --- a/src/rp2_common/pico_standard_link/BUILD.bazel +++ b/src/rp2_common/pico_standard_link/BUILD.bazel @@ -35,6 +35,7 @@ alias( "//bazel/constraint:pico_binary_type_no_flash": "//src/rp2_common/pico_standard_link:no_flash_linker_script", "//bazel/constraint:pico_binary_type_copy_to_ram": "//src/rp2_common/pico_standard_link:copy_to_ram_linker_script", "//bazel/constraint:pico_binary_type_blocked_ram": "//src/rp2_common/pico_standard_link:blocked_ram_linker_script", + "//bazel/constraint:pico_binary_type_xip_ram": "//src/rp2_common/pico_standard_link:xip_ram_linker_script", # Then for the default type "//bazel/constraint:rp2040": "//src/rp2040/pico_platform:default_linker_script", "//bazel/constraint:rp2350": "//src/rp2350/pico_platform:default_linker_script", @@ -68,6 +69,14 @@ alias( }), ) +alias( + name = "xip_ram_linker_script", + actual = select({ + "//bazel/constraint:rp2350": "//src/rp2350/pico_platform:xip_ram_linker_script", + "//conditions:default": "//bazel:incompatible_cc_lib", + }), +) + cc_library( name = "pico_standard_link", target_compatible_with = compatible_with_rp2(), diff --git a/src/rp2_common/pico_standard_link/CMakeLists.txt b/src/rp2_common/pico_standard_link/CMakeLists.txt index f4cf41ba3..e8586aa48 100644 --- a/src/rp2_common/pico_standard_link/CMakeLists.txt +++ b/src/rp2_common/pico_standard_link/CMakeLists.txt @@ -109,6 +109,70 @@ if (NOT TARGET pico_standard_link) set_target_properties(${TARGET} PROPERTIES PICO_TARGET_BINARY_TYPE ${TYPE}) endfunction() + # pico_include_in_generated_section(TARGET SECTION FILE) + # \brief\ Append a linker script include file to a generated section of the linker script + # + # Arranges for FILE to be INCLUDEd inside the generated SECTION of the target's linker script. + # + # This is primarily intended for internal SDK use - users should instead override the + # section_extra_SECTION.incl files, using pico_add_linker_script_override_path. + # + # \param\ TARGET The target whose linker script should be modified + # \param\ SECTION The linker script section name to append to (e.g. post_text) + # \param\ FILE Path to the linker script fragment to INCLUDE + function(pico_include_in_generated_section TARGET SECTION FILE) + get_target_property(already_generated ${TARGET} PICO_TARGET_LINKER_SCRIPT_INCLUDE_${SECTION}) + set_property(TARGET ${TARGET} APPEND PROPERTY PICO_TARGET_LINKER_SCRIPT_INCLUDE_${SECTION} "${FILE}") + # Make sure directory is empty before generating files, to avoid stale overrides + file(REMOVE_RECURSE ${CMAKE_BINARY_DIR}/generated/pico_standard_link/${TARGET}) + if (NOT already_generated) + file(GENERATE OUTPUT ${CMAKE_BINARY_DIR}/generated/pico_standard_link/${TARGET}/section_generated_${SECTION}.incl + CONTENT "INCLUDE \"$,\"\nINCLUDE \">\"" + ) + pico_add_linker_script_override_path(${TARGET} ${CMAKE_BINARY_DIR}/generated/pico_standard_link/${TARGET}) + endif() + endfunction() + + # pico_set_compile_definition(TARGET DEFINE VALUE) + # \brief\ Set a compile definition on a target, guarding against conflicting redefinitions + # + # Equivalent to target_compile_definitions(TARGET PRIVATE DEFINE=VALUE) but tracks the value + # as a target property so that a second call with the same DEFINE and the same VALUE is silently + # ignored, while a second call with a different VALUE is a fatal error. + # + # \param\ TARGET The target to add the compile definition to + # \param\ DEFINE The preprocessor symbol name + # \param\ VALUE The value to assign to the symbol + function(pico_set_compile_definition TARGET DEFINE VALUE) + get_target_property(already_set ${TARGET} PICO_TARGET_DEFINITION_${DEFINE}) + if (already_set MATCHES "NOTFOUND") + set_target_properties(${TARGET} PROPERTIES PICO_TARGET_DEFINITION_${DEFINE} ${VALUE}) + target_compile_definitions(${TARGET} PRIVATE ${DEFINE}=${VALUE}) + else() + if (NOT ${VALUE} STREQUAL ${already_set}) + message(FATAL_ERROR "Multiple calls to pico_set_compile_definition for ${DEFINE} with different values (${already_set} vs ${VALUE})") + endif() + endif() + endfunction() + + # pico_use_xip_sram_for_time_critical(TARGET) + # \brief\ Place time-critical code for the target into XIP SRAM + # + # Configures the target to run functions marked __time_critical_func() from XIP SRAM rather than + # normal SRAM, as it has dedicated ports which are otherwise unused in no_flash and copy_to_ram + # binaries. This sets PICO_TIME_CRITICAL_TEXT_IN_XIP_RAM=1, PICO_USE_XIP_CACHE_AS_RAM=1, and + # injects the required linker script fragment via pico_include_in_generated_section. + # + # This should not be used for flash binaries, as the XIP ports are in use there, and therefore + # this will just make time-critical functions slower. + # + # \param\ TARGET The target whose time-critical functions should run from XIP SRAM + function(pico_use_xip_sram_for_time_critical TARGET) + target_compile_definitions(${TARGET} PRIVATE PICO_TIME_CRITICAL_TEXT_IN_XIP_RAM=1) + pico_set_compile_definition(${TARGET} PICO_USE_XIP_CACHE_AS_RAM 1) # may be set elsewhere too + pico_include_in_generated_section(${TARGET} post_text "section_time_critical_xip_ram_text.incl") + endfunction() + # PICO_CMAKE_CONFIG: PICO_DEFAULT_BINARY_TYPE, The default binary type to use, type=string, default=default, group=build # slightly messy as we support both the preferred PICO_DEFAULT_BINARY_TYPE and the individual variables if (NOT PICO_DEFAULT_BINARY_TYPE) @@ -184,15 +248,22 @@ if (NOT TARGET pico_standard_link) pico_add_link_depend(pico_standard_link ${_LINKER_SCRIPT_EXPRESSION}) unset(_LINKER_SCRIPT_EXPRESSION) - # PICO_NO_FLASH will be set based on PICO_TARGET_BUILD_TYPE target property being equal to no_flash if set, otherwise to the value of the PICO_NO_FLASH cmake variable unless PICO_TARGET_TYPE is set to something else + set(NO_FLASH_BINARY_TYPES no_flash xip_ram) + set(COPY_TO_RAM_BINARY_TYPES copy_to_ram) + set(XIP_RAM_BINARY_TYPES xip_ram) + + # PICO_NO_FLASH will be set based on PICO_TARGET_BUILD_TYPE target property being in NO_FLASH_BINARY_TYPES if set, otherwise to the value of the PICO_NO_FLASH cmake variable unless PICO_TARGET_TYPE is set to something else # PICO_BUILD_DEFINE: PICO_NO_FLASH, whether this is a 'no_flash' build, type=bool, default=0, but dependent on CMake options, group=pico_standard_link - target_compile_definitions(pico_standard_link INTERFACE PICO_NO_FLASH=$,no_flash>,1,$,$>>>) + target_compile_definitions(pico_standard_link INTERFACE PICO_NO_FLASH=$,${NO_FLASH_BINARY_TYPES}>,1,$,$>>>) # PICO_USE_BLOCKED_RAM will be set based on PICO_TARGET_BUILD_TYPE target property being equal to use_blocked_ram if set, otherwise to the value of the PICO_USE_BLOCKED_RAM cmake variable unless PICO_TARGET_TYPE is set to something else # PICO_BUILD_DEFINE: PICO_USE_BLOCKED_RAM, whether this is a 'blocked_ram' build, type=bool, default=0, but dependent on CMake options, group=pico_standard_link target_compile_definitions(pico_standard_link INTERFACE PICO_USE_BLOCKED_RAM=$,use_blocked_ram>,1,$,$>>>) - # PICO_COPY_TO_RAM will be set based on PICO_TARGET_BUILD_TYPE target property being equal to copy_to_ram if set, otherwise to the value of the PICO_COPY_TO_RAM cmake variable unless PICO_TARGET_TYPE is set to something else + # PICO_COPY_TO_RAM will be set based on PICO_TARGET_BUILD_TYPE target property being in COPY_TO_RAM_BINARY_TYPES if set, otherwise to the value of the PICO_COPY_TO_RAM cmake variable unless PICO_TARGET_TYPE is set to something else # PICO_BUILD_DEFINE: PICO_COPY_TO_RAM, whether this is a 'copy_to_ram' build, type=bool, default=0, but dependent on CMake options, group=pico_standard_link - target_compile_definitions(pico_standard_link INTERFACE PICO_COPY_TO_RAM=$,copy_to_ram>,1,$,$>>>) + target_compile_definitions(pico_standard_link INTERFACE PICO_COPY_TO_RAM=$,${COPY_TO_RAM_BINARY_TYPES}>,1,$,$>>>) + # PICO_XIP_RAM will be set based on PICO_TARGET_BUILD_TYPE target property being in XIP_RAM_BINARY_TYPES if set, otherwise to the value of the PICO_XIP_RAM cmake variable unless PICO_TARGET_TYPE is set to something else + # PICO_BUILD_DEFINE: PICO_XIP_RAM, whether this is a 'xip_ram' build, type=bool, default=0, but dependent on CMake options, group=pico_standard_link + target_compile_definitions(pico_standard_link INTERFACE PICO_XIP_RAM=$,${XIP_RAM_BINARY_TYPES}>,1,$,$>>>) target_compile_definitions(pico_standard_link INTERFACE PICO_CMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}") if (PICO_DEOPTIMIZED_DEBUG AND "${CMAKE_BUILD_TYPE}" STREQUAL "Debug") diff --git a/src/rp2_common/pico_standard_link/script_include/memmap_copy_to_ram.incl b/src/rp2_common/pico_standard_link/script_include/memmap_copy_to_ram.incl index f54a3e833..5d05531f5 100644 --- a/src/rp2_common/pico_standard_link/script_include/memmap_copy_to_ram.incl +++ b/src/rp2_common/pico_standard_link/script_include/memmap_copy_to_ram.incl @@ -3,6 +3,7 @@ INCLUDE "set_memory_locations.incl" /* Include memory regions used */ INCLUDE "memory_flash.incl" +INCLUDE "memory_xip_ram.incl" INCLUDE "memory_ram.incl" INCLUDE "memory_scratch.incl" INCLUDE "memory_generated.incl" diff --git a/src/rp2_common/pico_standard_link/script_include/memmap_default.incl b/src/rp2_common/pico_standard_link/script_include/memmap_default.incl index 4f3233509..27d50deee 100644 --- a/src/rp2_common/pico_standard_link/script_include/memmap_default.incl +++ b/src/rp2_common/pico_standard_link/script_include/memmap_default.incl @@ -3,6 +3,7 @@ INCLUDE "set_memory_locations.incl" /* Include memory regions used */ INCLUDE "memory_flash.incl" +INCLUDE "memory_xip_ram.incl" INCLUDE "memory_ram.incl" INCLUDE "memory_scratch.incl" INCLUDE "memory_generated.incl" diff --git a/src/rp2_common/pico_standard_link/script_include/memmap_no_flash.incl b/src/rp2_common/pico_standard_link/script_include/memmap_no_flash.incl index c043470e9..8c9cf4ba2 100644 --- a/src/rp2_common/pico_standard_link/script_include/memmap_no_flash.incl +++ b/src/rp2_common/pico_standard_link/script_include/memmap_no_flash.incl @@ -2,6 +2,7 @@ INCLUDE "set_memory_locations.incl" /* Include memory regions used */ +INCLUDE "memory_xip_ram.incl" INCLUDE "memory_ram.incl" INCLUDE "memory_scratch.incl" INCLUDE "memory_generated.incl" diff --git a/src/rp2_common/pico_standard_link/script_include/memmap_xip_ram.incl b/src/rp2_common/pico_standard_link/script_include/memmap_xip_ram.incl new file mode 100644 index 000000000..64c4c912a --- /dev/null +++ b/src/rp2_common/pico_standard_link/script_include/memmap_xip_ram.incl @@ -0,0 +1,28 @@ +/* Include platform memory locations */ +INCLUDE "set_memory_locations.incl" + +/* Allow customisation of XIP_RAM_SCRATCH_SIZE */ +XIP_RAM_SCRATCH_SIZE = DEFINED(XIP_RAM_SCRATCH_SIZE) ? XIP_RAM_SCRATCH_SIZE : 2k; + +/* Split XIP_RAM into RAM and SCRATCH */ +RAM_ORIGIN = XIP_RAM_ORIGIN; +RAM_LENGTH = XIP_RAM_LENGTH - (XIP_RAM_SCRATCH_SIZE*2); +SCRATCH_X_ORIGIN = XIP_RAM_ORIGIN + XIP_RAM_LENGTH - (XIP_RAM_SCRATCH_SIZE*2); +SCRATCH_X_LENGTH = XIP_RAM_SCRATCH_SIZE; +SCRATCH_Y_ORIGIN = XIP_RAM_ORIGIN + XIP_RAM_LENGTH - XIP_RAM_SCRATCH_SIZE; +SCRATCH_Y_LENGTH = XIP_RAM_SCRATCH_SIZE; + +/* Include memory regions used */ +INCLUDE "memory_ram.incl" +INCLUDE "memory_scratch.incl" +INCLUDE "memory_generated.incl" +INCLUDE "memory_extra.incl" + +/* Include aliases for no_flash storage memory regions (alias to themselves) */ +INCLUDE "memory_aliases_xip_ram_only.incl" + +/* Define entry point symbol */ +ENTRY(_entry_point) + +/* Include no_flash sections */ +INCLUDE "sections_no_flash.incl" diff --git a/src/rp2_common/pico_standard_link/script_include/memory_aliases_flash.incl b/src/rp2_common/pico_standard_link/script_include/memory_aliases_flash.incl index 370b63ed1..200d878bb 100644 --- a/src/rp2_common/pico_standard_link/script_include/memory_aliases_flash.incl +++ b/src/rp2_common/pico_standard_link/script_include/memory_aliases_flash.incl @@ -2,5 +2,6 @@ REGION_ALIAS("TEXT_STORE", FLASH); REGION_ALIAS("RAM_STORE", FLASH); +REGION_ALIAS("XIP_RAM_STORE", FLASH); REGION_ALIAS("SCRATCH_X_STORE", FLASH); REGION_ALIAS("SCRATCH_Y_STORE", FLASH); diff --git a/src/rp2_common/pico_standard_link/script_include/memory_aliases_no_flash.incl b/src/rp2_common/pico_standard_link/script_include/memory_aliases_no_flash.incl index 258072736..2d48e870f 100644 --- a/src/rp2_common/pico_standard_link/script_include/memory_aliases_no_flash.incl +++ b/src/rp2_common/pico_standard_link/script_include/memory_aliases_no_flash.incl @@ -2,5 +2,6 @@ REGION_ALIAS("TEXT_STORE", RAM); REGION_ALIAS("RAM_STORE", RAM); +REGION_ALIAS("XIP_RAM_STORE", XIP_RAM); REGION_ALIAS("SCRATCH_X_STORE", SCRATCH_X); REGION_ALIAS("SCRATCH_Y_STORE", SCRATCH_Y); diff --git a/src/rp2_common/pico_standard_link/script_include/memory_aliases_xip_ram_only.incl b/src/rp2_common/pico_standard_link/script_include/memory_aliases_xip_ram_only.incl new file mode 100644 index 000000000..258072736 --- /dev/null +++ b/src/rp2_common/pico_standard_link/script_include/memory_aliases_xip_ram_only.incl @@ -0,0 +1,6 @@ +/* Store everything where it came from (ram/scratch) */ + +REGION_ALIAS("TEXT_STORE", RAM); +REGION_ALIAS("RAM_STORE", RAM); +REGION_ALIAS("SCRATCH_X_STORE", SCRATCH_X); +REGION_ALIAS("SCRATCH_Y_STORE", SCRATCH_Y); diff --git a/src/rp2_common/pico_standard_link/script_include/section_time_critical_xip_ram_text.incl b/src/rp2_common/pico_standard_link/script_include/section_time_critical_xip_ram_text.incl new file mode 100644 index 000000000..5d933adcc --- /dev/null +++ b/src/rp2_common/pico_standard_link/script_include/section_time_critical_xip_ram_text.incl @@ -0,0 +1,15 @@ +/* Defines the following symbols for use by code: + __xip_ram_time_critical_text_start__, __xip_ram_time_critical_text_end__, __xip_ram_time_critical_text_source__ +*/ + +SECTIONS +{ + .xip_ram_time_critical_text : { + __xip_ram_time_critical_text_start__ = .; + . = ALIGN(4); + *(.time_critical.text*) + . = ALIGN(4); + __xip_ram_time_critical_text_end__ = .; + } > XIP_RAM AT> XIP_RAM_STORE + __xip_ram_time_critical_text_source__ = LOADADDR(.xip_ram_time_critical_text); +} diff --git a/src/rp2_common/pico_standard_link/script_include/set_memory_locations.incl b/src/rp2_common/pico_standard_link/script_include/set_memory_locations.incl index 54d68c88a..9e92524c4 100644 --- a/src/rp2_common/pico_standard_link/script_include/set_memory_locations.incl +++ b/src/rp2_common/pico_standard_link/script_include/set_memory_locations.incl @@ -24,4 +24,3 @@ SCRATCH_Y_ORIGIN = DEFINED(SCRATCH_Y_ORIGIN) ? SCRATCH_Y_ORIGIN : SCRATCH_Y_ORIG SCRATCH_Y_LENGTH = DEFINED(SCRATCH_Y_LENGTH) ? SCRATCH_Y_LENGTH : SCRATCH_Y_LENGTH_DEFAULT; XIP_RAM_ORIGIN = DEFINED(XIP_RAM_ORIGIN) ? XIP_RAM_ORIGIN : XIP_RAM_ORIGIN_DEFAULT; XIP_RAM_LENGTH = DEFINED(XIP_RAM_LENGTH) ? XIP_RAM_LENGTH : XIP_RAM_LENGTH_DEFAULT; - diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3b22ce491..e7bb50632 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -17,6 +17,7 @@ if (PICO_ON_DEVICE) add_subdirectory(cmsis_test) add_subdirectory(pico_sem_test) add_subdirectory(pico_sha256_test) + add_subdirectory(pico_xip_sram_test) add_subdirectory(pico_low_power_test) add_subdirectory(pico_async_context_test) add_subdirectory(pico_thread_local_test) diff --git a/test/pico_xip_sram_test/BUILD.bazel b/test/pico_xip_sram_test/BUILD.bazel new file mode 100644 index 000000000..ef9b49c8e --- /dev/null +++ b/test/pico_xip_sram_test/BUILD.bazel @@ -0,0 +1,91 @@ +load("@rules_cc//cc:cc_binary.bzl", "cc_binary") +load("@rules_cc//cc:cc_library.bzl", "cc_library") +load("//bazel:defs.bzl", "compatible_with_rp2") +load("//bazel/util:transition.bzl", "extra_copts_for_all_deps", "pico_set_binary_type", "pico_set_linker_script") + +package(default_visibility = ["//visibility:public"]) + +alias( + name = "pico_critical_xip_sram_test_extra_link", + actual = select({ + "//bazel/constraint:rp2040": "//bazel:empty_cc_lib", + "//conditions:default": "//src/rp2_common/hardware_riscv_platform_timer", + }), + visibility = ["//visibility:private"], +) + +cc_binary( + name = "pico_critical_xip_sram_test_actual", + testonly = True, + srcs = ["pico_critical_xip_sram_test.c"], + tags = ["manual"], # Built via pico_critical_xip_sram_test + deps = [ + ":pico_critical_xip_sram_test_extra_link", + "//src/rp2_common/hardware_dma", + "//src/rp2_common/pico_multicore", + "//src/rp2_common/pico_stdlib", + "//test/pico_test", + ], +) + +# pico_use_xip_sram_for_time_critical isn't implemented in Bazel, so manually +# do that function with this linker script +cc_library( + name = "pico_critical_xip_sram_test_linker_script", + # The order of the linker scripts below is important. + # Prevent buildifier from reordering them. + # buildifier: leave-alone + deps = [ + "//test/pico_xip_sram_test/pico_critical_xip_sram_test_scripts", + "//src/rp2_common/pico_standard_link:default_linker_script", + ], +) + +pico_set_binary_type( + name = "pico_critical_xip_sram_test_typed", + testonly = True, + src = ":pico_critical_xip_sram_test_actual", + binary_type = "copy_to_ram", + target_compatible_with = compatible_with_rp2(), +) + +pico_set_linker_script( + name = "pico_critical_xip_sram_test_linked", + testonly = True, + src = ":pico_critical_xip_sram_test_typed", + linker_script = "//test/pico_xip_sram_test:pico_critical_xip_sram_test_linker_script", + target_compatible_with = compatible_with_rp2(), +) + +extra_copts_for_all_deps( + name = "pico_critical_xip_sram_test", + testonly = True, + src = ":pico_critical_xip_sram_test_linked", + extra_copts = [ + "-DPICO_TIME_CRITICAL_TEXT_IN_XIP_RAM=1", + "-DPICO_USE_XIP_CACHE_AS_RAM=1", + ], + target_compatible_with = compatible_with_rp2(), +) + +# Currently doesn't fit, because bazel doesn't have a pico_minimize_runtime equivalent +exports_files(["pico_xip_sram_test.c"]) +# cc_binary( +# name = "pico_xip_sram_test_actual", +# testonly = True, +# srcs = ["pico_xip_sram_test.c"], +# tags = ["manual"], # Built via pico_xip_sram_test +# deps = [ +# "//src/rp2_common/pico_stdlib", +# "//src/rp2_common/pico_multicore", +# "//src/rp2_common/hardware_dma", +# ], +# ) +# +# pico_set_binary_type( +# name = "pico_xip_sram_test", +# testonly = True, +# src = ":pico_xip_sram_test_actual", +# binary_type = "xip_ram", +# target_compatible_with = compatible_with_rp2() + incompatible_with_config("//bazel/constraint:rp2040"), +# ) diff --git a/test/pico_xip_sram_test/CMakeLists.txt b/test/pico_xip_sram_test/CMakeLists.txt new file mode 100644 index 000000000..165a9698c --- /dev/null +++ b/test/pico_xip_sram_test/CMakeLists.txt @@ -0,0 +1,31 @@ +# Use XIP SRAM for time critical functions +add_executable(pico_critical_xip_sram_test pico_critical_xip_sram_test.c) +target_link_libraries(pico_critical_xip_sram_test PRIVATE pico_stdlib pico_multicore hardware_dma pico_test) +if (NOT PICO_RP2040) + target_link_libraries(pico_critical_xip_sram_test PRIVATE hardware_riscv_platform_timer) +endif() +pico_set_binary_type(pico_critical_xip_sram_test copy_to_ram) +pico_use_xip_sram_for_time_critical(pico_critical_xip_sram_test) +pico_enable_stdio_usb(pico_critical_xip_sram_test 1) # test with USB as that invokes flash functions +pico_add_extra_outputs(pico_critical_xip_sram_test) + +# Use XIP SRAM for time critical functions (no_flash build) +add_executable(pico_critical_xip_sram_test_no_flash pico_critical_xip_sram_test.c) +target_link_libraries(pico_critical_xip_sram_test_no_flash PRIVATE pico_stdlib pico_multicore hardware_dma pico_test) +if (NOT PICO_RP2040) + target_link_libraries(pico_critical_xip_sram_test_no_flash PRIVATE hardware_riscv_platform_timer) +endif() +pico_set_binary_type(pico_critical_xip_sram_test_no_flash no_flash) +pico_use_xip_sram_for_time_critical(pico_critical_xip_sram_test_no_flash) +pico_enable_stdio_usb(pico_critical_xip_sram_test 1) +pico_add_extra_outputs(pico_critical_xip_sram_test_no_flash) + +if (NOT PICO_RP2040 AND NOT PICO_C_COMPILER_IS_CLANG) + # XIP SRAM only binary, clang version is too big + add_executable(pico_xip_sram_test pico_xip_sram_test.c) + target_link_libraries(pico_xip_sram_test PRIVATE pico_stdlib) + pico_set_binary_type(pico_xip_sram_test xip_ram) + pico_minimize_runtime(pico_xip_sram_test INCLUDE PRINTF PRINTF_MINIMAL DEFAULT_ALARM_POOL PANIC FLOAT) + target_compile_definitions(pico_xip_sram_test PRIVATE PICO_HEAP_SIZE=0x200) + pico_add_extra_outputs(pico_xip_sram_test) +endif() \ No newline at end of file diff --git a/test/pico_xip_sram_test/pico_critical_xip_sram_test.c b/test/pico_xip_sram_test/pico_critical_xip_sram_test.c new file mode 100644 index 000000000..00c1c41ca --- /dev/null +++ b/test/pico_xip_sram_test/pico_critical_xip_sram_test.c @@ -0,0 +1,182 @@ +#include +#include "pico/stdlib.h" +#include "pico/test.h" +#include "pico/multicore.h" +#include "hardware/dma.h" +#if PICO_RP2040 +#include "hardware/structs/systick.h" +#else +#include "hardware/riscv_platform_timer.h" +#endif +#include "hardware/structs/busctrl.h" + + +PICOTEST_MODULE_NAME("XIP_SRAM", "critical xip sram test"); + + +int __time_critical_func(test_func_xip)(void) { +#if PICO_RP2040 + systick_hw->rvr = 0x00ffffff; + systick_hw->cvr = 0; +#else + riscv_timer_set_mtimecmp(0xffffffffffffffff); + riscv_timer_set_mtime(0); +#endif + + volatile uint32_t i = 0; + i += 4; + i += i; + i += 7; + i += i; + i += i; + +#if PICO_RP2040 + return systick_hw->rvr - systick_hw->cvr; +#else + return riscv_timer_get_mtime(); +#endif +} + +int __no_inline_not_in_flash_func(test_func_sram)(void) { +#if PICO_RP2040 + systick_hw->rvr = 0x00ffffff; + systick_hw->cvr = 0; +#else + riscv_timer_set_mtimecmp(0xffffffffffffffff); + riscv_timer_set_mtime(0); +#endif + + volatile uint32_t i = 0; + i += 4; + i += i; + i += 7; + i += i; + i += i; + +#if PICO_RP2040 + return systick_hw->rvr - systick_hw->cvr; +#else + return riscv_timer_get_mtime(); +#endif +} + + +void core1_entry() { + // Just read memory from SRAM bank 0 repeatedly + // word-striped across 4 banks, so read every 16 bytes +#ifndef __riscv + pico_default_asm_volatile( + "1:\n" + "ldr r0, =%c0\n" + "ldr r1, [r0, #0]\n" + "ldr r2, [r0, #16]\n" + "ldr r3, [r0, #32]\n" + "ldr r4, [r0, #48]\n" + "adds r0, #64\n" + "ldr r1, [r0, #0]\n" + "ldr r2, [r0, #16]\n" + "ldr r3, [r0, #32]\n" + "ldr r4, [r0, #48]\n" + "adds r0, #64\n" + "ldr r1, [r0, #0]\n" + "ldr r2, [r0, #16]\n" + "ldr r3, [r0, #32]\n" + "ldr r4, [r0, #48]\n" + "b 1b\n" + : : "i" (SRAM_BASE) : "r0", "r1", "r2", "r3", "r4" + ); +#else + pico_default_asm_volatile( + "1:\n" + "li a0, %0\n" + "lw a1, 0(a0)\n" + "lw a2, 16(a0)\n" + "lw a3, 32(a0)\n" + "lw a4, 48(a0)\n" + "addi a0, a0, 64\n" + "lw a1, 0(a0)\n" + "lw a2, 16(a0)\n" + "lw a3, 32(a0)\n" + "lw a4, 48(a0)\n" + "addi a0, a0, 64\n" + "lw a1, 0(a0)\n" + "lw a2, 16(a0)\n" + "lw a3, 32(a0)\n" + "lw a4, 48(a0)\n" + "j 1b\n" + : : "i" (SRAM_BASE) : "a0", "a1", "a2", "a3", "a4" + ); +#endif +} + + +void trigger_dma(void) { + int dat[8]; + for (int i = 0; i < count_of(dat); i++) { + int chan = dma_claim_unused_channel(true); + dma_channel_config c = dma_channel_get_default_config(chan); + channel_config_set_transfer_data_size(&c, DMA_SIZE_32); + channel_config_set_read_increment(&c, true); + channel_config_set_write_increment(&c, true); + uint32_t from = SRAM_BASE; + uint32_t to = SRAM_BASE + ((SRAM4_BASE - SRAM_BASE) / 2); + uint32_t size = ((SRAM4_BASE - SRAM_BASE) / 2) / 4; + dma_channel_configure(chan, &c, (uint32_t*)to, (uint32_t*)from, dma_encode_transfer_count(size), true); + dat[i] = chan; + } + for (int i = 0; i < count_of(dat); i++) { + dma_channel_unclaim(dat[i]); + } +} + + +int main(void) { + stdio_init_all(); + printf("pico_xip_sram_test begins\n"); + + PICOTEST_START(); + + PICOTEST_START_SECTION("test_func_addresses") + printf("test_func_xip at %p\n", test_func_xip); + printf("test_func_sram at %p\n", test_func_sram); + + PICOTEST_CHECK((uint32_t)test_func_xip >= XIP_SRAM_BASE && (uint32_t)test_func_xip < XIP_SRAM_END, "test_func_xip is not in XIP SRAM"); + PICOTEST_CHECK((uint32_t)test_func_sram >= SRAM_STRIPED_BASE && (uint32_t)test_func_sram < SRAM4_BASE, "test_func_sram is not in SRAM 0-3"); + PICOTEST_END_SECTION() + + multicore_launch_core1(core1_entry); + +#if PICO_RP2040 + systick_hw->csr = 0x4 | 0x1; // clock source and enable +#else + riscv_timer_set_fullspeed(true); + riscv_timer_set_enabled(true); + riscv_timer_set_mtimecmp(0xffffffffffffffff); +#endif + + // Give core1 and DMA high priority + hw_set_bits(&busctrl_hw->priority, BUSCTRL_BUS_PRIORITY_PROC1_BITS | BUSCTRL_BUS_PRIORITY_DMA_R_BITS | BUSCTRL_BUS_PRIORITY_DMA_W_BITS); + hw_clear_bits(&busctrl_hw->priority, BUSCTRL_BUS_PRIORITY_PROC0_BITS); + + PICOTEST_START_SECTION("test_func"); + int test_func_xip_cycles = 0; + int test_func_sram_cycles = 0; + for (int i = 0; i < 5; i++) { + printf("running... %d\n", i); + trigger_dma(); + int tmp = test_func_xip(); + test_func_xip_cycles += tmp; + printf("test_func_xip: %d\n", tmp); + trigger_dma(); + tmp = test_func_sram(); + test_func_sram_cycles += tmp; + printf("test_func_sram: %d\n", tmp); + sleep_ms(500); + } + + PICOTEST_CHECK(test_func_xip_cycles < test_func_sram_cycles, "test_func_xip took longer than test_func_sram"); + + PICOTEST_END_SECTION(); + + PICOTEST_END_TEST(); +} diff --git a/test/pico_xip_sram_test/pico_critical_xip_sram_test_scripts/BUILD.bazel b/test/pico_xip_sram_test/pico_critical_xip_sram_test_scripts/BUILD.bazel new file mode 100644 index 000000000..2132016fd --- /dev/null +++ b/test/pico_xip_sram_test/pico_critical_xip_sram_test_scripts/BUILD.bazel @@ -0,0 +1,8 @@ +load("//bazel/util:pico_linker_scripts.bzl", "linker_scripts") + +package(default_visibility = ["//test/pico_xip_sram_test:__pkg__"]) + +linker_scripts( + name = "pico_critical_xip_sram_test_scripts", + include_scripts = glob(["*.incl"]), +) diff --git a/test/pico_xip_sram_test/pico_critical_xip_sram_test_scripts/section_extra_post_text.incl b/test/pico_xip_sram_test/pico_critical_xip_sram_test_scripts/section_extra_post_text.incl new file mode 100644 index 000000000..41fa5962b --- /dev/null +++ b/test/pico_xip_sram_test/pico_critical_xip_sram_test_scripts/section_extra_post_text.incl @@ -0,0 +1 @@ +INCLUDE "section_time_critical_xip_ram_text.incl" \ No newline at end of file diff --git a/test/pico_xip_sram_test/pico_xip_sram_test.c b/test/pico_xip_sram_test/pico_xip_sram_test.c new file mode 100644 index 000000000..aa3610843 --- /dev/null +++ b/test/pico_xip_sram_test/pico_xip_sram_test.c @@ -0,0 +1,16 @@ +#include +#include "pico/stdlib.h" + + +int main(void) { + stdio_init_all(); + printf("pico_xip_sram_test begins\n"); + + for (int i = 0; i < 5; i++) { + printf("running... %d\n", i); + sleep_ms(500); + } + + printf("pico_xip_sram_test ends\n"); + return 0; +} diff --git a/tools/bazel_build.py b/tools/bazel_build.py index 45ffa41ef..b773a5442 100755 --- a/tools/bazel_build.py +++ b/tools/bazel_build.py @@ -59,6 +59,7 @@ "//test/pico_low_power_test:low_power_test_simple", "//test/pico_low_power_test:external_sleep_timer", "//test/pico_async_context_test:pico_async_context_test", + "//test/pico_xip_sram_test:pico_critical_xip_sram_test", # Pretty much only Picotool and pioasm build on Windows. "//..." if os.name == "nt" else "",