Skip to content

Add support for using XIP cache as SRAM#2932

Merged
kilograham merged 66 commits into
raspberrypi:developfrom
will-v-pi:xip-sram-new
Jun 3, 2026
Merged

Add support for using XIP cache as SRAM#2932
kilograham merged 66 commits into
raspberrypi:developfrom
will-v-pi:xip-sram-new

Conversation

@will-v-pi

@will-v-pi will-v-pi commented May 13, 2026

Copy link
Copy Markdown
Contributor

This adds a new xip_ram binary type (RP2350 only) which puts everything (code, data, and stack) in XIP SRAM, and a pico_place_time_critical_functions CMake function to put functions marked as time_critical in specified memory (eg XIP SRAM or scratch) instead of regular SRAM. The pico_place_time_critical_functions(TARGET xip_ram) is only useful for copy_to_ram and no_flash binary types - it will still work for default binary types, but makes everything slower instead of faster.

Adds tests of both - currently the pico_xip_sram_test doesn't fit on Clang or Bazel so is skipped on both, and pico_place_time_critical_functions is not implemented in Bazel, so pico_critical_xip_sram_test sets the compile definitions directly, for the same effect.

Supercedes #2660, and fixes #2653

will-v-pi added 30 commits March 6, 2026 15:29
Allows for much simpler custom linker scripts
…ript_var variables

Means that CMake doesn't need to know the default memory addresses for different platforms
…l files easier

Restructured so that it includes the platform-specific files before common ones, so common ones can be overridden
Use new include_linker_script_dir and use_linker_script_file functions to add the linker arguments
Breaking change for Bazel builds using different binary types, instead of setting PICO_DEFAULT_LINKER_SCRIPT to eg `//src/rp2_common/pico_crt0:no_flash_linker_script` it is now `//src/rp2_common/pico_standard_link:no_flash_linker_script`
Treat rp2040 layout (boot2 instead of embedded blocks) as the outlier
Allows overriding what to exclude from .text/.rodata and put in .data
These were being placed in Flash due to a missing space, and also are under libc on some compilers
Add PICO_LINKER_SCRIPT_INCLUDE_DIRS and PICO_LINKER_DEFAULT_LOCATIONS_PATH, instead of hardcoded paths under PICO_LINKER_SCRIPT_PATH

Also improve pico_set_linker_script_var and pico_add_linker_script_override_path to better utilise generator expressions
Required changes to the way bazel views these files
…d sections_... which contain multiple

Only exceptions are section_..._data and section_bss, as these contain data/bss and tdata/tbss - these are kept together as they are treated as a single section
…ink_libraries, as it uses generator expressions

Also add more checks to kitchen_sink
Intended for platform specific overrides, whereas post_end is for cross-platform overrides, similar to section_end vs section_platform_end
Use spinlock IDs that are unaffected by E2
@steffenyount

Copy link
Copy Markdown

With memory_psram.incl and memory_xip_ram.incl providing integrated region support out-of-the-box, the comment/example text provided in memory_extra.incl file seems less relevant, and should probably be updated.

kilograham and others added 2 commits May 26, 2026 16:52
PSRAM and xip_ram are now supported by default

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PICO_XIP_RAM should probably be integrated for PICO_DEFAULT_BINARY_TYPE and PICO_XIP_RAM resolution and exclusion, like all the other built-in binary types being supported above.

Use PICO_DEFAULT_BINARY_TYPE in the generator expressions, to remove need for PICO_NO_FLASH etc, and fixup the legacy variable handling to that effect

Now throws an error if both PICO_DEFAULT_BINARY_TYPE and one of PICO_NO_FLASH etc are specified - just use PICO_DEFAULT_BINARY_TYPE
Comment thread src/rp2_common/pico_standard_link/CMakeLists.txt
Comment thread src/rp2_common/pico_standard_link/CMakeLists.txt
Comment thread src/rp2_common/pico_standard_link/CMakeLists.txt
Comment thread src/rp2_common/pico_standard_link/CMakeLists.txt
@kilograham

Copy link
Copy Markdown
Contributor

ok, i'm reasonably cool with all this, but

Any other placements (eg code in PSRAM, data in XIP_SRAM) currently require custom linker script sections and custom section attributes.

A bit confusing as there is data in XIP_SRAM describe just above that

I think i'm still a bit weirded out about the cmake function to put time_critical elsewhere

I wonder if we should

  1. make sure we have the full gamut of in_ram, in_blah functions (including adding in_scratch_x as an alias for scratch_x)
  2. make .time_critical, .not_in_flash definitions based on that (can still default to .time_critical I guess), but we could just make it target in_ram, or whatever if you want to specify a different location (same for not_in_flash i guess)

will-v-pi added 3 commits May 29, 2026 11:59
…er script injections

This adds section_xip_ram.incl into every linker script, and provides the __in_xip_ram macro to put stuff there

__time_critical_func then uses the PICO_TIME_CRITICAL_PLACEMENT define to select where to place code, so that can be overriden to be __in_xip_ram to place time critical functions in xip_ram

Also works for placing time critical functions in scratch x/y
Also re-add note to pico_place_time_critical_functions not to use xip_ram for flash binaries
@will-v-pi

Copy link
Copy Markdown
Contributor Author

Following those suggestions, I've refactored this to no longer use linker script generation, and just use compile definitions instead. I've also added the new macros in sections.h (__in_ram, __in_scratch_x/y, __in_xip_ram) to place data in those sections, with __in_xip_ram throwing an error if PICO_USE_XIP_CACHE_AS_RAM isn't set.

This means the new function is pico_place_time_critical_functions(TARGET MEMORY), which can be used to place the time critical functions in xip_ram, or scratch_x/y. All this does is set the PICO_TIME_CRITICAL_PLACEMENT compile definition, along with setting PICO_USE_XIP_CACHE_AS_RAM=1 if xip_ram is used.

I've also added a pico_use_xip_cache_as_ram function, which just sets PICO_USE_XIP_CACHE_AS_RAM=1.

I've left in the pico_include_in_generated_section function, as it could be useful in the future.

now identical to memory_aliases_no_flash

@kilograham kilograham left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I think it is worth being clear about thigns; if i understand correctly

  1. section .time_critical is now in RAM always (we should probably point out clearly that this is the case - maybe you already did - we don't want to change the name for histortical reasons in the linker script, but worth being verbose wherever we see it that it isn't striclty tied to the time_criitical macro any more

  2. __not_in_flash() should probably default to in_ram() but possibly be overridable like time_critical

  3. __time_critical (and __not_in_flash) can then i think default to in_ram (which would be defined as section ,time_critical)

it is probably worth adding doxygen to each of the new macros (and linking to the other ones where synojyms)

@steffenyount

steffenyount commented Jun 1, 2026

Copy link
Copy Markdown

Generally looks good

  1. I'm a bit confused as to what the RP2040/RP2350 options are - is this strictly xip_cache as ram (separate from using PSRAM as per the other PR)
  2. given the above, perhaps xip_ram is a poor name (not we also use xip_sram elsewhere), but:
  3. All the existing names are bad, so maybe this would be a good time to rationilze and maybe even add aliases for the old ones (or rather make the old ones aliases)

no_flash => not sure (ram, ram_stored?) - note i wonder if PICO_NO_FLASH isn't strictly the binary type define; it means there is nothing in flash, right, but that could be set for a binary which uses sram & xip_ram - maybe no_flash IS the base binary type, and you use the other controls to turn on XIP_RAM additionally? blocked_ram => not sure i care copy_to_ram => i guess this is ok xip_ram -> not sure

Just think it is worth enumerating all the possibilites (i.e. maybe there are subtypes of no_flash); how does PSRAM play with the above etc?

Perhaps renaming xip_ram to something like no_flash_using_xip_ram_as_ram would be more descriptive, since it is re-using the linker .incl section definitions from the no_flash binary type?

Or maybe implementing the xip_ram functionality as a link option rather than a whole binary type strategy (E.g: PICO_LINK_XIP_RAM_AS_RAM) that is compatible with the no_flash binary type would be cleaner?

Relatedly, there is precedent for the xip_ram kind of almost entire section definition re-use, as modeled by the blocked_ram binary type definition. In that case the only difference is seen in the memmap_blocked_ram.ld file where RAM_ORIGIN = 0x21000000; is being set before deferring with INCLUDE "memmap_default.incl".

For the blocked_ram binary type, has anyone considered eliminating the memmap_blocked_ram.ld file, setting the linker script symbol directly via parameter like -Wl,--defsym=RAM_ORIGIN=0x21000000, and then just using the vanilla memmap_default.ld when the blocked_ram binary type is set or when PICO_USE_BLOCKED_RAM is set?

Or alternatively pushing the flag evaluation down into the default_locations.ld file by replacing the line:
RAM_ORIGIN_DEFAULT = 0x20000000;
with something like:
RAM_ORIGIN_DEFAULT = (DEFINED(PICO_USE_BLOCKED_RAM) ? PICO_USE_BLOCKED_RAM : 0) ? 0x21000000 : 0x20000000;

It looks like the xip_ram binary type, could similarly have all of its custom symbol values (listed below) sent to the linker directly via parameter, thus eliminating the need for the memmap_xip_ram.ld file, by using the memmap_no_flash.ld file directly:

RAM_LENGTH
SCRATCH_X_ORIGIN
SCRATCH_X_LENGTH
SCRATCH_Y_ORIGIN
SCRATCH_Y_LENGTH

With this alternate approach, the sdk could cleanly focus on its three base binary layouts: default, copy_to_ram, and no_flash with blocked_ram and xip_ram binary types being implemented basically as short hand notation for configuration options on the default and no_flash base binary layouts respectively.
E.g: blocked_ram could be equivalent to setting:

PICO_DEFAULT_BINARY_TYPE=default
PICO_USE_BLOCKED_RAM=1

E.g: xip_ram could be equivalent to setting:

PICO_DEFAULT_BINARY_TYPE=no_flash
PICO_USE_XIP_CACHE_AS_XIP_RAM=1
PICO_LINK_XIP_RAM_AS_RAM=1

E.g: the FLASH and PSRAM configuration could be reimagined to operate similarly, with their __in_flash() and __in_psram() section macros throwing an error when the corresponding hardware isn't available, like when the PICO_USE_*_SIZE_BYTES parameter is 0 or undefined.

PICO_DEFAULT_BINARY_TYPE=default
PICO_USE_FLASH_SIZE_BYTES=8388608
PICO_DEFAULT_BINARY_TYPE=copy_to_ram
PICO_USE_PSRAM_SIZE_BYTES=8388608
PICO_LINK_PSRAM_AS_RAM

E.g: meanwhile for a larger performance oriented application running from ram, I might want to set the following options to selectively place whole sections (E.g: time_critical, not_in_flash, or .text*) of functions/instructions into XIP_RAM to take advantage of the dedicated AHB ports for their instruction bandwidth:

PICO_DEFAULT_BINARY_TYPE=copy_to_ram
PICO_USE_XIP_CACHE_AS_XIP_RAM=1
PICO_PLACE_TIME_CRITICAL_FUNCTIONS_IN_XIP_RAM=
PICO_PLACE_ALL_FUNCTIONS_IN_XIP_RAM='main.c.o;example.c.o'

Note: I'm trying out the following parameter prefix notation here to differentiate their effects, what do you think?
PICO_USE_* - parameters that reflect hardware constraints and affect memory region availability. E.g: the availability of a FLASH region, a PSRAM region, or the XIP_RAM region.
PICO_LINK_* - parameters that affect the linker script's general memory region assignments
PICO_PLACE_* - parameters that affect the linker script's section assignments into those memory regions,

will-v-pi added 3 commits June 2, 2026 17:12
All `__in_xxx` macros place directly into linker sections, which are located in the relevant memory

`__scratch_x` and `__scratch_y` are kept as aliases to `__in_scratch_x` and `__in_scratch_y`

`__not_in_flash` is placed using `PICO_NOT_IN_FLASH_PLACEMENT` which defaults to `__in_ram`, and the same for `__time_critical_func`, so they can be placed separately

pico_place_time_critical_functions -> pico_set_time_critical_placement, and add pico_set_not_in_flash_placement
Removes the ability to override XIP_RAM_ORIGIN and XIP_RAM_LENGTH (to prevent duplicate includes, which Clang doesn't like), but that is fine
@will-v-pi

Copy link
Copy Markdown
Contributor Author

@kilograham I have re-arranged sections.h to make it clearer what everything does:

  • All __in_xxx macros place directly into linker sections which are located in the relevant memory
  • __scratch_x and __scratch_y are kept as aliases to __in_scratch_x and __in_scratch_y
  • __not_in_flash is placed using PICO_NOT_IN_FLASH_PLACEMENT which defaults to __in_ram, and the same for __time_critical_func using PICO_TIME_CRITICAL_PLACEMENT which also defaults to __in_ram

@steffenyount Thanks, I have changed memmap_xip_ram.incl to include memmap_no_flash.incl, now that they are identical. I think I prefer to keep the blocked_ram and xip_ram customisations in separate binary types, otherwise the address setting would need to be duplicated between CMake and Bazel. The rest of what you're talking about sounds like a much larger refactor, which would be outside the scope of this PR, especially as this PR is now making minimal linker script modifications and doing the re-assignment through macros instead.

Regarding the ability to place all functions somewhere else, I think that definitely belongs in a different PR, and I think I'd want to see a use case which can't be solved by just annotating the functions with the __no_inline_not_in_flash_func or __time_critical_func macros?

will-v-pi added 2 commits June 2, 2026 18:12
Note that the xip_ram binary type still doesn't work in bazel, as the bazel build doesn't fit in xip_ram
@kilograham kilograham merged commit 5aa4bd6 into raspberrypi:develop Jun 3, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants