Skip to content

Add support for using XIP cache as SRAM#2932

Open
will-v-pi wants to merge 52 commits into
raspberrypi:developfrom
will-v-pi:xip-sram-new
Open

Add support for using XIP cache as SRAM#2932
will-v-pi wants to merge 52 commits into
raspberrypi:developfrom
will-v-pi:xip-sram-new

Conversation

@will-v-pi
Copy link
Copy Markdown
Contributor

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

This adds a new xip_ram binary type (RP2350 only) which puts all code & data in XIP SRAM, and a pico_use_xip_sram_for_time_critical CMake function to put functions marked as time_critical in XIP SRAM instead of regular SRAM. The pico_use_xip_sram_for_time_critical 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_use_xip_sram_for_time_critical is not implemented in Bazel, so pico_critical_xip_sram_test uses a custom linker script instead, for the same effect.

Supercedes #2660, and fixes #2653

Includes #2645, which links with raspberrypi/pico-extras#99

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
@will-v-pi
Copy link
Copy Markdown
Contributor Author

Can you clarify the intent and use case for this new xip_ram binary type?

The new xip_ram binary type is not for speed, it's to make a binary that doesn't use Main SRAM at all, so that Main SRAM can be used for something else - a use case for this could be a bootloader. It is entirely separate from all the changes we've discussed before.

The stuff we discussed before is now replaced with the pico_use_xip_sram_for_time_critical function, to avoid the need for new binary types. This places only the time critical functions in XIP SRAM.

Is the new xip_ram binary type an attempt to do something similar? I'm still focused in RP2040 development, and think a new "copy_to_xip_and_ram" binary type option, that is basically equivalent to the existing "copy_to_ram" binary type option, except that it places all the TARGET eXecutable .text and .time_critical.text content into XIP SRAM could be useful.

Placing all of .text in XIP SRAM could be an extension to this in a separate PR (it would be more complex), but I think a better extension is your #2677 to allow placing whole files in .time_critical.text (if it can be made to work for older CMake).

Comment thread src/rp2_common/pico_platform_sections/include/pico/platform/sections.h Outdated
Comment thread src/rp2040/pico_platform/memmap_default.ld
Comment thread src/rp2_common/pico_platform_sections/include/pico/platform/sections.h Outdated
Comment thread src/rp2_common/pico_platform_sections/include/pico/platform/sections.h Outdated
// 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
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.

i guess this #ifdef is still useful to avoid wasting space, but for my own edification, does the "src == dest" take care of everything (i.e. in NO_FLASH binaries, was it the case that src == dest in all case)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Currently yes, in NO_FLASH binaries src == dest for everything, as there is no copying performed - although new PSRAM variables will end up with src != dest, but that's handled in runtime_init not here.

These changes aren't actually needed anymore to make this PR work, but I think they're still useful to allow creating no_flash binaries that do copy their data around (eg if you need to load a sparse binary over the UART bootloader, squashing it together makes the transfer faster).

The code is still loaded before boot on rp2040, so doesn't need copying
Copy link
Copy Markdown
Contributor

@kilograham kilograham left a comment

Choose a reason for hiding this comment

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

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?

@will-v-pi
Copy link
Copy Markdown
Contributor Author

Just to clarify regarding 1, this is two separate ideas combined into one PR, because they both use XIP SRAM

  • For RP2040 & RP2350, this adds the ability for copy_to_ram/no_flash binaries to put all their time critical functions into XIP SRAM, as the XIP AHB ports would otherwise be unused
  • For RP2350 only, this adds the new xip_ram binary type to create XIP SRAM only binaries, where all the code & data is in XIP SRAM - these could be useful for bootloaders

This does not add the ability to place arbitrary data in XIP SRAM - I can add that if it would be useful

@kilograham
Copy link
Copy Markdown
Contributor

yeah, i mean historically i guess we needed different binary types for different linker scripts, but that is no longer strictly the case.

it probably makes sense to continue to have binary types for "where stuff gets put by the linker script", but up til now that is mostly "where all the stuff goes".

If we have main ram and xip ram, it is unlikely the main code/data will be split between, so you're likely to just want to access the xip-cache; which can(/may already be) something you can specify via cmake. By this i guess I'm talking about the enabling of XIP RAM (pinning) vs the storing of code/data there (though the latter requires the former not vice versa)

Maybe it is just me, but i find xip-ram confusing since PSRAM is also via XIP. I don't know if xip-cache is better, since it isn't the cache when being used as ram!

@steffenyount
Copy link
Copy Markdown

steffenyount commented May 22, 2026

Hi @will-v-pi

I took a swing at adding that support for placing a whole file's functions into XIP SRAM. I think it turned out better than I anticipated, and it should be compatible with CMake 3.13.

Please consider adding my changes into your PR, and let me know what you think of it.

(the tests section probably needs some work)

you can find it here

Thanks,
-Steffen

will-v-pi added 2 commits May 22, 2026 10:59
Skip low power unpinning when PICO_USE_XIP_CACHE_AS_RAM is set

Take xip_ram as argument to pico_set_persistent_data_loc, to allow placing normally instead of specifying address

Add pico_critical_xip_sram_test_low_power test to check usin xip_ram for both works
@will-v-pi
Copy link
Copy Markdown
Contributor Author

yeah, i mean historically i guess we needed different binary types for different linker scripts, but that is no longer strictly the case.

it probably makes sense to continue to have binary types for "where stuff gets put by the linker script", but up til now that is mostly "where all the stuff goes".

I think it's still useful to have "standard" binary types which have their own memmap (and it in necessary for memmap_xip_ram.incl as I've currently written it), because picking a "standard" binary type is used to set the compile definitions. This is more necessary for Bazel, where the compile definitions have to be set using constraints, so it needs explicit binary types for that.

If we have main ram and xip ram, it is unlikely the main code/data will be split between, so you're likely to just want to access the xip-cache; which can(/may already be) something you can specify via cmake. By this i guess I'm talking about the enabling of XIP RAM (pinning) vs the storing of code/data there (though the latter requires the former not vice versa)

The first point of this PR (see "For RP2040 & RP2350 ..." in my comment above) is to split code between main ram and xip ram - it puts time critical function code in xip ram, and all other code/data in main ram.

Pinning can already be enabled using the PICO_CRT0_PIN_XIP_SRAM compile definition added by the low power PR for RP2350 - this PR adds a new PICO_USE_XIP_CACHE_AS_RAM which works on RP2040 too (on RP2350 it just enables pinning). I've also just added a check to the low power stuff to skip un-pinning if PICO_USE_XIP_CACHE_AS_RAM is set, so this can work with low power.

Maybe it is just me, but i find xip-ram confusing since PSRAM is also via XIP. I don't know if xip-cache is better, since it isn't the cache when being used as ram!

It's called "XIP_SRAM" in the addressmap.h files, and "Cache-as-SRAM" in the datasheet - I prefer calling it xip_ram, but happy to change if there's a consensus for something else.

@will-v-pi
Copy link
Copy Markdown
Contributor Author

Here's a full description of binary types, as I think they will be after this PR merged, if you want to propose new names for any of them:

  • no_flash - a binary that does not contain any code/data in Flash
    • storage address and runtime address of everything is the same (ie > XXX AT> XXX)
      • the exception is PSRAM, which is stored in main SRAM as A2 bootrom cannot load directly into PSRAM due to RP2350-E14
    • can use main SRAM, XIP_SRAM and PSRAM for code/data
    • by default, all code/data is in main SRAM
  • copy_to_ram - a binary that starts in Flash, but main code/data is copied to main SRAM for execution
    • storage address is flash for everything (ie > XXX AT> FLASH)
    • can use main SRAM, XIP_SRAM, PSRAM and Flash for code/data
    • by default, all code/data is in main SRAM, except for crt0.S which is in Flash
  • default - a binary that executes most code/data from Flash
    • storage address is flash for everything (ie > XXX AT> FLASH)
    • can use main SRAM, PSRAM and Flash for code/data, and XIP_SRAM with performance penalties to code/data in Flash
    • by default, all code is in Flash and all data is in main SRAM
  • xip_ram - a binary that does not contain any code/data in Flash or main SRAM (not available on RP2040)
    • storage address and runtime address of everything is the same (ie > XXX AT> XXX)
      • the exception is PSRAM, which is stored in XIP_SRAM as A2 bootrom cannot load directly into PSRAM due to RP2350-E14
    • can use XIP_SRAM and PSRAM for code/data - XIP_SRAM is used as if it were main SRAM, for the purposes of the macros below
    • by default, all code/data is in XIP_SRAM
  • blocked_ram - identical to default, but uses non-striped memory for main SRAM instead of striped (RP2040 only)

For binaries that can use main SRAM, they can place other code/data there using __not_in_flash and similar macros

For binaries that can use Flash, they can place other data there using the __in_flash macro

For binaries that can use PSRAM, they can place other data there using __in_psram and __uninitialized_psram macros

For binaries that can use XIP_SRAM (does not include xip_ram, as that uses XIP_SRAM as if it were main SRAM), they can place other code there using the __time_critical_func macro, provided they call pico_use_xip_sram_for_time_critical in their CMakeLists.txt

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

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