ARM Technical Support Knowledge Articles

SPLITTING CODE BETWEEN EPROM AND FLASH MEMORY

Applies to: C251 C Compiler

Answer

QUESTION

I'm using the Keil 251 tools C and Assembly code for a project I'm designing. I need to create 2 separate code areas: one for on-chip code and one for off-chip (FLASH or ROM) code. I want to locate some functions on-chip (for speed) and some functions off-chip. What's the best way to go about this?

ANSWER

There are a number of ways to solve this problem. However, the following example should be easy to implement for most developers.


If you only need the two code areas and they will both be updated at the same time (new OTPs and new ROM devices) you may place the ROM(LARGE) pragma before on-chip functions and the ROM(HUGE) pragma before off-chip functions. For example:

#pragma ROM(HUGE)
void external_function (void);

#pragma ROM(LARGE)
void internal_function (void)
{
external_function ();
}

You must determine if this is acceptable for your application. Remember to use the #pragma ROM settings before each function prototype so that the compiler generates the proper code (LCALL or ECALL) for each function.

When you link your application, the L251 linker places the ROM(LARGE) functions in the CODE class and the ROM(HUGE) functions in the ECODE class. You must tell the linker where these classes reside so that they are located for your ROM/EPROM/FLASH memory arrangement.

Finally, you create separate HEX files for each device using the OH251 object-HEX converter. For example:

OH251 abs_obj_file HEXFILE(INTERNAL.HEX) HEX RANGE(0xFF0000-0xFF1FFF)
OH251 abs_obj_file HEXFILE(EXTERNAL.HEX) HEX RANGE(0xFF2000-0xFF7FFF)

This creates INTERNAL.HEX with code from 0xFF0000 to 0xFF1FFF and EXTERNAL.HEX with code from 0xFF2000 to 0xFF7FFF.

Another method of supporting 2 code areas involves 2 program areas and a jump table. The following rules apply to this method.

  1. The on-chip code is compiled with ROM(LARGE).
  2. The off-chip code is compiled with ROM(HUGE).
  3. On-chip code calls stub routines that are really address entries in a jump table in off-chip memory.
  4. Jump table entries transfer control to the REAL functions (in off-chip memory).

In the following example, we assume that we have on-chip CODE memory from 0xFF0000 to 0xFF1FFF and off-chip memory from 0xFF2000 to 0xFF7FFF.

STEP ONE:

Configure the linker to locate CODE from 0xFF0000-0xFF1FFF and ECODE from 0xFF2200-0xFF7FFF using the following command line:

L251 ... CLASSES (CODE (0xFF0000-0xFF1FFF), ECODE (0xFF2200-0xFF7FFF))

Note that we start ECODE at 0xFF2200 rather than 0xFF2000. The 200 bytes are saved for the jump table. You may need to adjust this number up or down.

STEP TWO:

Create all external functions with the prefix _ext_ and using ROM(HUGE). For example:

/*** X_FUNC1.C ***/
#pragma FC(REENTRANT)
#pragma ROM(HUGE)

int _ext_func_1 (
  unsigned int a,
  unsigned int b,
  unsigned int c)
{
return (a+b+c);
}

You may even want to save the external function in filenames that start with X_ so you can easily recognize them.

STEP THREE:

Create the jump table functions for each external function. The jump table is created using in-line assembly and should be created in a separate file (to avoid disabling the optimized on an important function or code block). Note that the function names in the jump table do not include the _ext_ prefix. These are the functions you will call from your main, internal program. The jump table entries are located at unique addresses using the _at_ keyword. You must be responsible for defining unique addresses for the table. For example:

/*** FUNC1.C ***/
#pragma FC(REENTRANT)
#pragma ROM(HUGE)

#pragma SRC

int func_1 (
  unsigned int a,
  unsigned int b,
  unsigned int c) _at_ 0xFF2000   // This must be unique among the table entries
{
#pragma ASM
EXTERN  CODE:FAR  ( _ext_func_1?? )        // Use "??" at the end of function name
        EJMP      _ext_func_1??
#pragma ENDASM

a=a, b=b, c=c;  // Avoid compiler warnings for unused arguments
return (0);     // Avoid no-return value warnings
}

Since the SRC directive is used, the C251 compiler generates FUNC1.SRC when it compiles this file.

STEP FOUR:

Create functions in the internal code that call functions defined as the jump table routines. For example:

/*** MAIN.C ***/
#pragma FC(REENTRANT)

#pragma ROM(HUGE)

extern int func_1 (
  unsigned int a,
  unsigned int b,
  unsigned int c);

#pragma ROM(LARGE)

void main (void)
{
volatile int k;

k = func_1 (1, 2, 3);
}

Note that the func_1 function is prototyped as ROM(HUGE). This is so that the external function (_ext_func1) which is also declared as ROM(HUGE) actually returns to the main C function.

STEP FIVE:

Compile and Assemble and Link the files as follows:

C251 MAIN.C ...
C251 X_FUNC1.C ...
C251 FUNC1.C ...
A251 FUNC1.SRC ...

L251 MAIN.OBJ, X_FUNX1.OBJ, FUNC1.OBJ CLASSES (CODE (0xFF0000-0xFF1FFF), ECODE (0xFF2200-0xFF7FFF))

STEP SIX:

Create separate HEX files for each device. For example:

OH251 MAIN HEXFILE(INTERNAL.HEX) HEX RANGE(0xFF0000-0xFF1FFF)
OH251 MAIN HEXFILE(EXTERNAL.HEX) HEX RANGE(0xFF2000-0xFF7FFF)

This creates INTERNAL.HEX with code from 0xFF0000 to 0xFF1FFF and EXTERNAL.HEX with code from 0xFF2000 to 0xFF7FFF. You use these files when you program your ROM/EPROM/FLASH devices.

STEP SEVEN:

Verify that segments and classes are located in the correct areas by viewing the MAP file created by the linker. In this case, we see that ?PR?FUNC_1... (the call table entry) and ?PR?X_FUNC1 (the external function) are located at 0xFF2000 and 0xFF2200 respectively.

START     STOP      LENGTH    ALIGN  RELOC    MEMORY CLASS   SEGMENT NAME
=========================================================================
000000H   000007H   000008H   ---    AT..     DATA           "REG BANK 0"
000008H   000107H   000100H   BYTE   UNIT     EDATA          ?STACK
FF0000H   FF0002H   000003H   ---    OFFS..   CODE           ?CO?START251?4
FF0003H   FF001BH   000019H   BYTE   INSEG    CODE           ?PR?MAIN?MAIN
FF001CH   FF002EH   000013H   BYTE   UNIT     CODE           ?C_C51STARTUP
FF002FH   FF0031H   000003H   BYTE   UNIT     CODE           ?C_C51STARTUP?3
FF2000H   FF2006H   000007H   BYTE   AT..     ECODE          ?PR?FUNC_1???FUNC1
FF2200H   FF2204H   000005H   BYTE   INSEG    ECODE          ?PR?X_FUNC1

DOWNLOAD

251JTAB.ZIP contains the code for this example.

Article last edited on: 2005-09-22 12:57:31

Rate this article

[Bad]
|
|
[Good]
Disagree? Move your mouse over the bar and click

Did you find this article helpful? Yes No

How can we improve this article?

Link to this article
Copyright © 2011 ARM Limited. All rights reserved. External (Open), Non-Confidential