Skip to main content

IAR Embedded Workbench for RH850 3.20.x

ROPI

In this section:

The term ROPI (Read-Only Position-Independent) is a synonym for the Renesas term “PIC/PID”, and refers to RH850 ABI compliant position independence, where the PID base register is the static base pointer for accessing constant data as described by the RH850 ABI. In IAR Embedded Workbench for RH850, this base register is the constant data and code base TP. This means that, even though the linker places the code and data at fixed locations, the application can still be executed correctly when the linked image is placed at a different address than where it was linked.

In a system with ROPI applications, there might be a small amount of non-ROPI code that handles startup, dynamic loading of applications, shared firmware functions, etc. Such code must be compiled and linked separately from the ROPI applications.

Note

Only functions and read-only data are affected by ROPI, not variable data.

Drawbacks and limitations

There are some drawbacks and limitations to bear in mind when using ROPI:

  • The code generated for function pointer calls and accesses to read-only data will be somewhat larger

  • Data initialization at startup might be somewhat slower, and the initialization data might be somewhat larger

  • Interrupt handlers that use the #pragma vectordirective are not handled automatically

  • Data pointer constants cannot be initialized with the address of constant data, or a string literal. Writable pointers will be initialized automatically.

  • Some C library functions will work differently, mainly because they use RAM instead of ROM for storage (for example the functions for locale support). The C99 functions erf and gamma are not supported.

  • The processor registers GP and TP are used in the generated code to indicate where the application is placed in memory—GP is used for accessing read-write data, and TP is used for accessing constant data and to perform function-pointer calls. Normally, these registers are initialized by the startup code. When the code in two separately linked applications calls each other, the registers must be manually set or care taken to ensure that the called function does not use them.

Note

In some cases, there is an alternative to ROPI that avoids these limitations and drawbacks: If there is only a small number of possible placements for the application, you can compile the application without ROPI and link it multiple times, once for each possible placement. Then you can choose the correct image at load time. When applicable, this approach makes better use of the available hardware resources than using ROPI.

Creating a static startup module

To execute a ROPI application there must also be a static part, a startup program, because the reset vector must always be static. This program should contain:

  • a jump to the ROPI application start address

  • the __DebugBreak function, if you want to debug the application using C-SPY

  • any functions that should not be part of the ROPI application.

This basic sample program can be used as a starting point:

        module _ROPISTART
        section `.reset`:CODE:ROOT(4)
        public  _main
        extern  ___DebugBreak
        require ___DebugBreak
        code
_main:
        jr      F:my_address    ; This jumps to the reset vector
                                ; location 0x00 of the actual
                                ; program. This must match with
                                ; the offset used in the C-SPY
                                ; macro __loadImage
        end

This will include __DebugBreak and initialization code for any library parts that are located in the static part of the application. Add a require clause to the program for every additional C library function that should be static, for example _printf.

You can compile and link this startup program like a normal application. If you include runtime attributes, you can control which library that is used by the linker. If parts of the C runtime library are included, remember to include the data initialization routines.

If a static function should be visible to the ROPI application (such as the __DebugBreak function), you must export it from the linked application using the tool isymexport. Do not export symbols that exist in the ROPI module as well, such as __iar_program_start or _main. Which symbols that are made visible is determined by show clauses in the edit file (show.icf), for example show _printf. The syntax for the export is:

isymexport --edit show.icf static.out static.tab

If you need to call a static function from a ROPI module, you must declare it extern __absolute for the address to be initialized correctly.

Creating the ROPI module

To compile an application with position-independent code and read-only data, use the compiler command line option --ropi. The source code cannot contain any initializations that violate the ROPI model, that is, it cannot contain any constant data pointers to constant data, as in this example:

const char * const msg = "error string"; // cannot be initialized
                                         // in ROPI mode

Caution

To specify ROPI in the IDE, choose Project>Options>General Options>Target> Code and read-only data.

When you link the application, all code and constant data must be placed in a common block, tagged movable. For example:

define movable block TP_BLOCK with static base TP, alignment = 8,
               maximum size = 64k, minimum size = 4
  {
    ro section .sconst,
    ro section .pcconst16
  };

This example places constant data with the memory attribute __brel in the closest (to TP) 64 Kbytes of data memory, to allow efficient access to these objects.

Interrupt handling

The interrupt vector table—including setting it up—could be the responsibility of either module, but if the interrupt table is placed in the ROPI module, it must be placed in RAM and initialized at runtime.

Building and debugging the application

Include the symbol table generated by isymexport when you link the ROPI module, so that it can call functions in the static module. If the static module uses its own RAM objects, the two applications must be linked with disjoint RAM spaces.

To run the application in C-SPY, use the static program as the main project, and add a C-SPY macro file to this project, that loads the ROPI application image:

execUserSetup()
{
    __loadImage("ropi_module_path", offset, 0);
}

The offset parameter to __loadImage is the difference between the linked base address of the ROPI module—usually 0x00 for the reset vector—and its final address (my_address in the static assembler program, see Creating a static startup module). For more information about the __loadImage macro, see __loadImage.

Caution

You can also load the ROPI application image using the options on the Project>Options>Debugger>Images page in the IDE.