8
votes

I am programming an ARM Cortex-R4 and I have a few binary files that I'd like to execute them from TCRAM, just to see if the increase in performance is good enough.

I know I'd have to write a function to copy the binaries to the RAM (which can be accomplished with the linker script, and knowing the size of the binaries). But how would they run?

Imagine this: The first binary has func1(), func2(), func3() and func4(). I'd copy the entire module to TCRAM and how would I call a function there? I'd have to use a function pointer to that specific function? And what if func4(), calls func2() and func3()? If I'm not mistaken they'd point to the piece of code located in the flash. Does that mean I'd have to re write those funcs? Use entirely function pointers? I've been told that just the linker script is enough to do all of this and I needn't worry about anything, but I still don't understand how it works.

3

3 Answers

10
votes

On GCC: Just put the function in the .data section:

__attribute__( ( section(".data") ) )

It will be copied over with the rest of your initialzed variables by the startup code (no need to mess with the linker scipt). You may also need a "long_call" option as well if the function ends up "far away" from the rest of the code after being placed into RAM.

__attribute__( ( long_call, section(".data") ) )

Example:

__attribute__( ( long_call, section(".data") ) ) void ram_foobar (void) { ... }

You may get an compiler warning that can be safely ignored:

Warning: ignoring changed section attributes for .data
6
votes

You have two options.

  1. Copy them as you suggest, compile with pc relative.
  2. Use a linker file with a different load/run address.

A simple copy will only work if the routines do not use any absolute addresses. It maybe fine if they do use the absolute address as I guess you are going to leave a copy in standard RAM. However, this may not get the full benefit of the TCM.

With a linker script, you can specify a different LOAD and RUN locations.

sections {
 .text { *(.text); } >FLASH
 .tcm {
       *(.tcm);
  } >TCM_MEM AT>FLASH
  .data { *(.data); } > RAM
  .bss : NOLOAD { *(.bss); } > RAM
}

Note especially AT>FLASH.

See also: gnu linker map file... and many more on stackoverflow. The Gnu Ld manual has information on LMA sections (LOAD address). Your LMA would be flash, but the VMA (RUN address) would be TCM. The manual link above also shows how to copy. The RAM, FLASH, and TCM_MEM are defined with ld MEMORY information, depending on the addresses are for your board. All of this will be documented in a MAP file. Be sure to generate a MAP file and examine the addresses to double check your ld script.

The 2nd case also requires a copy (at start-up or at least before the first TCM function use). However, the compiler can use absolute addresses and they will be in the TCM memory. Also any function within the main DRAM can call the TCM function directly. With the first case, you must use function pointers to call the TCM code. If you wish global variables to be placed in this memory, you can use attributes to put them in different sections and use gnu ld to place them appropriately. I think there is ITCM and DTCM? So maybe this doesn't apply for you, or you need two sections.

The linker script is more generic and will work best if you put complicated functionality in the TCM. Just using -fpic, etc and copying may get things working quickly, especially if you only have a single pure function.

2
votes

Nowadays (then-a-days as well?) you can just use the macro __RAM_FUNC, __RAMFUNC_EXT(bank, name) or __RAMFUNC(bank)