Dedicated placement of ROM copy sections for initialized data

15-Nov-2024

This article is for the TriCore toolchain. A similar approach applies to our other toolchains as they use the same linker script language.

When a variable is initialized as shown below, the initialization value for this variable needs to be placed in flash memory:

int var_1 = 10;

The linker-generated copy table includes information about:

  • Where this ROM copy section is located (source address)
  • To which address in RAM it needs to be copied (target address)
  • The number of bytes that need to be copied from the source to the target address

For more details about the C startup code, see Chapter 4.3. The C Startup Code in the TriCore User Guide.


Possible solutions

If you need to place those ROM copy sections in a dedicated memory range, the LSL language offers different approaches to solve this:


Using the run_addr keyword

The name of the ROM copy section is the same as the name of the RAM section, but the name of the ROM copy section is enclosed in square brackets [ ].

To select a ROM copy section in an LSL group, you need to use the full name, including the square brackets in the select line. Moreover, to have them parsed by the linker, you need to escape the square brackets using ‘\’.

For the C source line listed above, suppose the line is included in a file named
file_1.c. The default near allocation value is set to zero to prevent any near addressable sections without using the __near qualifier. In this case, the default section name would be.data.file_1.var_1 which consists of:

<section name prefix>.<module name>.<variable name>

The section name prefixes used for the different types of sections are described in chapter 1.12. Compiler Generated Sections of the TriCore User Guide.

To select the ROM copy section in an LSL group which is placed in ROM memory (for example, starting at offset 0x100 in pflash0 memory), and to have the RAM section placed (for example: starting at offset 0x200 in dspr0 RAM) you can use the following syntax:

section_layout :vtc:linear
{
    group MY_ROM_COPY_SECTIONS_RUN__ADDR ( ordered, run_addr = mem:mpe:pflash0[0x100] )
    {
        select "\[.data.file_1.var_1\]";
    }
    group MY_INITIALIZED_SECTIONS ( ordered, run_addr = mem:mpe:dspr0[0x200] )
    {
        select ".data.file_1.var_1";
    }
}

The linker-generated map file includes the following entries:

* Sections
===========

+ Space mpe:vtc:linear (MAU = 8bit)

+-------------------------------------------------------------------------------------------------------------------------------------------+
| Chip | Group | Section | Size (MAU) | Space addr | Chip addr | Alignment |
|===========================================================================================================================================|
| mpe:dspr0 | MY_INITIALIZED_SECTIONS | .data.file_1.var_1 (3) | 0x00000004 | 0x70000200 | 0x00000200 | 0x00000002 |
| mpe:pflash0 | | .text._Exit.libc (190) | 0x00000004 | 0x80000028 | 0x00000028 | 0x00000008 |
| mpe:pflash0 | | table (196) | 0x00000030 | 0x8000002c | 0x0000002c | 0x00000004 |
| mpe:pflash0 | | .text..cocofun_1.libcs_fpu (6) | 0x00000010 | 0x8000005c | 0x0000005c | 0x00000002 |
| mpe:pflash0 | | .text..cocofun_2.libcs_fpu (8) | 0x00000010 | 0x8000006c | 0x0000006c | 0x00000002 |
| mpe:pflash0 | | .text..cocofun_3.libcs_fpu (16) | 0x00000010 | 0x8000007c | 0x0000007c | 0x00000002 |
| mpe:pflash0 | | .text..cocofun_4.libcs_fpu (15) | 0x00000010 | 0x8000008c | 0x0000008c | 0x00000002 |
| mpe:pflash0 | | .text..cocofun_5.libcs_fpu (10) | 0x0000000a | 0x8000009c | 0x0000009c | 0x00000002 |
| mpe:pflash0 | | .text.__init_sp.libcs_fpu (13) | 0x00000016 | 0x800000a6 | 0x000000a6 | 0x00000002 |
| mpe:pflash0 | | .text._c_init.libcs_fpu (73) | 0x0000000c | 0x800000bc | 0x000000bc | 0x00000002 |
| mpe:pflash0 | | .text._ldmst_clear_byte.libcs_fpu (70) | 0x0000002e | 0x800000c8 | 0x000000c8 | 0x00000002 |
| mpe:pflash0 | | .text.file_1.main (2) | 0x00000008 | 0x800000f6 | 0x000000f6 | 0x00000002 |
| mpe:pflash0 | MY_ROM_COPY_SECTIONS_RUN__ADDR | [.data.file_1.var_1] (197) | 0x00000004 | 0x80000100 | 0x00000100 | 0x00000002 |
| mpe:pflash0 | | .text._c_init_entry.libcs_fpu (72) | 0x00000120 | 0x80000104 | 0x00000104 | 0x00000002 |
| mpe:pflash0 | | .text._ldmst_copy_byte.libcs_fpu (71) | 0x00000044 | 0x80000224 | 0x00000224 | 0x00000002 |

Using the load_addr keyword

This makes the linker select the ROM copy of initialized sections. When doing this, you need to remove the square brackets to select the section:

section_layout :vtc:linear
{
    group MY_ROM_COPY_SECTIONS_LOAD_ADDR ( ordered, load_addr = mem:mpe:pflash0[0x100] )
    {
        select ".data.file_1.var_1";
    }
    group MY_INITIALIZED_SECTIONS ( ordered, run_addr = mem:mpe:dspr0[0x200] )
    {
        select ".data.file_1.var_1";
    }
}

The zip file ROM_copy_placement includes a buildable example using a command line invocation. It can be extracted into an empty folder, and the gen.bat batch file can be invoked to build the example.


More resources

Was this answer helpful?