Execute in RAM after copying from Flash or ROM

Technical Note 11578

Targets:
ARM

Component:
General

Updated:
2/28/2013 2:36 PM

Introduction

This Technical Note applies to IAR Embedded Workbench for ARM version 5.20 and later. The wanted behavior is to run all code in RAM to gain execution speed.

Overview

The toolchain has features to make it possible to copy all (or most) of the code to RAM at program startup. In order to take advantage of these features there are 4 actions to take.

The 4 actions to take are

  • Make a second vector table, placed in RAM
  • Edit .icf file so that CODE (except startup code) is copied to RAM at startup time.
  • At runtime (after startup) remap memory so that the vector table in RAM is used.
  • Study the .map file to see the effect of the above modifications

The 4 actions shown in detail for 2 different devices

These are the steps, in detail, that needs to be taken in order change your application to be able to run from RAM.
The 2 parallel examples are meant to show the differences between these ARM cores, and between these chip manufacturers.

Example projects:


Make a second vector table, placed in RAM

Cortex-M3 (AT91SAM3U)
Modifications are made in the board_cstartup_iar.c file located in \arm\examples\Atmel\at91lib\boards\at91sam3u-ek

Added C function:

void DummyHandlerROM(void)

Edited all entries except __iar_program_start and .__ptr = __sfe( "CSTACK" ) }, in ...

const IntVector __vector_table[] =
{
{ .__ptr = __sfe( "CSTACK" ) },
__iar_program_start,
DummyHandlerROM,
DummyHandlerROM,
DummyHandlerROM,
DummyHandlerROM,

...to point to DummyHandlerROM();
Added 2nd vector table placed in RAM...

__root const IntVector __vector_RAM_table[];

...which hold all vectors

{ .__ptr = __sfe( "CSTACK" ) },
__iar_program_start,

NMI_Handler,
HardFault_Handler,

 

ARM 7 (LPC2148)

Modifications are made in the cstartup.s file located in \arm\examples\NXP\IAR-LPC-214X\LCD\board

Added assembler function:

Dummy_Handler_ROM

Changed IRQ and FIQ ...

DC32 __iar_program_start ;; Reset
DC32 0 ;; Undefined instructions
DC32 0 ;; Software interrupt (SWI/SVC)
DC32 0 ;; Prefetch abort
DC32 0 ;; Data abort
DC32 0 ;; RESERVED
DC32 Dummy_Handler_ROM ;; IRQ
DC32 Dummy_Handler_ROM ;; FIQ

...to point to Dummy_Handler_ROM
Added 2nd vector table placed in RAM...

SECTION .intvec_RAM:CODE:ROOT(2)

...which hold vectors for IRQ and FIQ

ldr pc,[pc,#+24] ;; IRQ
ldr pc,[pc,#+24] ;; FIQ

DC32 irq_handler ;; IRQ
DC32 fiq_handler ;; FIQ

 

Edit .icf file so that CODE (except startup code) is copied to RAM at startup time.

Cortex-M3 (AT91SAM3U)
Modifications are made in the flash.icf file located in \arm\examples\Atmel\at91lib\boards\at91sam3u-ek\at91sam3u4

The start of the RAM region has to be adjusted so that the vectors in RAM fit below the RAM region.

define symbol __ICFEDIT_region_RAM0_start__ = 0x200000BC;

A symbol holding the address of the interrupt vectors in RAM is added.

define symbol RAM_vectors_start = 0x20000000;

The linker adds code for copying CODE to RAM when the below line is changed from...

initialize by copy { readwrite };

...to...

initialize by copy { readonly, readwrite };

...which is documented in the Development Guide, section "Running all code from RAM".

The interrupt vectors are copied to RAM, using the linker directive:

place at address mem:RAM_vectors_start { section .vectors_RAM };

 

ARM 7 (LPC2148)
Modifications are made in the Flash.icf file located in \arm\examples\NXP\IAR-LPC-214X\LCD\config

The size of the ordinary C stack has to be adjusted up, (with space taken from the IRQ and FIQ stacks).

define symbol __ICFEDIT_size_cstack__ = 0x2000;
define symbol __ICFEDIT_size_irqstack__ = 0x100;
define symbol __ICFEDIT_size_fiqstack__ = 0x100;

A symbol holding the address of the interrupt vectors in RAM is added.

define symbol RAM_intvec_start = 0x40000000;

The linker adds code for copying CODE to RAM when the below line is changed from...

initialize by copy { readwrite };

...to...

initialize by copy { readonly, readwrite };

...which is documented in the Development Guide, section "Running all code from RAM".

The interrupt vectors are copied to RAM, using the linker directive:

place at address mem:RAM_intvec_start { section .intvec_RAM };

 

At runtime (after startup) remap memory so that the vector table in RAM is used.

Cortex-M3 (AT91SAM3U)
One final modification is made to board_cstartup_iar.c located in \arm\examples\Atmel\at91lib\boards\at91sam3u-ek

The Cortex-M3 register VTOR holds the address of the vector table.

The source of...

unsigned int * src = __section_begin(".vectors");

... is changed to ...

unsigned int * src = __section_begin(".vectors_RAM");

 ...where the variable 'src' is used a few lines below to set VTOR, so that the vector table in RAM is used.

 

ARM 7 (LPC2148)

One modification is made to demo.c located in \arm\examples\NXP\LPC214x\IAR-LPC-214X\LCD\app

The MEMMAP register is set to RAM which forces the LPC2148 to remap the 0x40 lowest bytes of RAM down to address 0x00, thus starting to use the vector table in RAM.

The source of...

#ifdef FLASH
if (SYS_Init(FOSC, FCCLK, VPBDIV1, USER_FLASH,
0x0001FF0F,0x87FE01F1,0,0xFFFFFFFF))
return 1;
#else
if (SYS_Init(FOSC, FCCLK, VPBDIV1, USER_RAM,
0x0001FF0F,0x87FE01F1,0,0xFFFFFFFF))
return 1;
#endif

... is changed to ...

if (SYS_Init(FOSC, FCCLK, VPBDIV1, USER_RAM,
0x0001FF0F,0x87FE01F1,0,0xFFFFFFFF))
return 1;

... in order to set MEMMAP to RAM, and to disable the unwanted (in this context) flash-protection source.

Study the .map file to see the effect of the above modifications

Check these sections of the .map file
- PLACEMENT SUMMARY check in which memory objects are placed
- MODULE SUMMARY check placements of objects ("ro code" vs "rw code")
- ENTRY LIST check addresses of functions

The MODULE SUMMARY, as well as the summary at the end of the map file, shows the result.

Cortex-M3 (AT91SAM3U) Original Example
10 112 bytes of readonly code memory

368 bytes of readonly data memory
9 736 bytes of readwrite data memory


ARM 7 (LPC2148) Original Example
17 042 bytes of readonly code memory

2 245 bytes of readonly data memory
13 866 bytes of readwrite data memory

Cortex-M3 (AT91SAM3U) Modified Example
632 bytes of readonly code memory
9 644 bytes of readwrite code memory
10 075 bytes of readonly data memory
9 926 bytes of readwrite data memory

ARM 7 (LPC2148) Modified Example
736 bytes of readonly code memory
16 398 bytes of readwrite code memory
18 191 bytes of readonly data memory
15 856 bytes of readwrite data memory

Notes

Note A -- Linker protection of start up code

The linker protects sections that are referenced from the startup code from being affected by an 'initialize by copy' directive.

This includes

  • __low_level_init and all functions called and/or defined in the same compilation unit (.c file)
  • global (statically linked) C/C++ symbols

So the linker ensures that only code that runs after copy initialization has been finished will be copied to RAM. For this reason it is safe to add readonly in the
initialize by copy { readonly, readwrite }; command.
The linker log (option --log sections) is extended in IAR Embedded Workbench for ARM 6.10 with information of symbols marked as 'needed for init'.

Note B -- Why 2 different vector tables? OR Why DummyHandlerROM / Dummy_Handler_ROM

  • The section to be placed in RAM is section .intvec_RAM and not section .intvec (as you might expect). Why is it so?
  • Why can I not just copy the VectorTable in ROM/flash to RAM?

In Note A it is explained that the linker protects code used/referenced from startup. Furthermore the linker algorithm to figure out which code that's needed by the initialization process at startup marks all code in a module (i.e. a compiled file is a mdoule) and not only code referenced from cstartup, e.g. all code in a module where referenced interrupt handlers are defined.

So the suggested construction will minimize the amount of code that is placed in ROM/flash.

Note C -- effects of vector 0x14 (ARM7/AMR9) or 0x1C (Cortex-M) in LPC devices

Up to version 5.30 there was requirement of LPC specific labels in the vector table. These labels where the copying cannot be done by the initialization process at startup, because of the special (for ARM7/9 LPC-devices) __vector_0x14 (and __vector_0x1C for Cortex-M-devices), holding the checksum of the interrupt vectors. This checksum is calculated by ielftool after ilinkarm, but ielftool cannot calculate the checksum when changes are made to cstartup.s to enable automatic copying of the interrupt vectors, i.e. breaking references of what's needed by the initialization process at startup.

Note D -- comments on Note B and Note C

To cope with these two issues, the interrupt vectors are split into one part placed in ROM (used only by code in ROM) and another part placed in RAM (used by code in the application).

 

 

All product names are trademarks or registered trademarks of their respective owners.

Related Tech Notes

© IAR Systems 1995-2016 - All rights reserved.