I Get Wrong Function Address

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

I Get Wrong Function Address

Jump to solution
1,423 Views
everkimage
Contributor IV

My mcu is MC9S12X.

In the map file,my two functions address are:

function_1 : 0x616E

function_2 : 0x527C

But when i use codes below to get the function address,the result always shift left 8bit:

volatile unsigned long addr_1, addr_2;

addr_1 = (unsigned long)function_1;

addr_2 = (unsigned long)function_2;

addr_1 == 0x616E00;

addr_2 == 0x527C00;

why?

Labels (1)
1 Solution
1,167 Views
lama
NXP TechSupport
NXP TechSupport

Yes, you are right but some additional should be taken into account which is modifier near or far. It is cause by default function placement. The memory model defines whether function is near (called by JSR and return code is RTS) or it is far function (called by CALL and return code is RTC). Of course you canuse explicit conversion where you will say to compiler hot to exactly process the function (be sure it is placed in the near space if you use near modifier)

(So a "far" function can be placed in a near space. The near function can be place in a far space only and only in the case when such a near space exists (4000~7FFF, C000~FFFF, 2000~3FFF,..se memory maps attached)) In this case the MCU automatically recognizes direct address in an offset of a far function (0xC000_00) and correctly uses it.

Finally,

Direct function address converted to a far space 0xC000 => 0xC000_00.

Something different is to convert far function pointer from far space to global address. Explained below or in attached example.

For example

 

#pragma CODE_SEG NEAR MY_SEG

 

void near fction1(void); // JSR used

void fction2(void);           // JSR used because of near segment ---not sure whether memory model takes precedence

void far fction1(void);     // CALL is used because of explicit conversion. Even the function is, for example placed

                                            // at 0xC000 the far pointer to it will be used with value 0xC000_00

 

#pragma CODE SEG DEFAULT

 

Now I’ll copy here an answer I was preparing on background.

 

Even I do not have full info about your initializations I would like to describe you briefly what you have to keep in mind.

There are different types of addresses near/far global/PPAG_OFFSET/RPAGE_OFFSET/…..

 

The map file shows real addresses (the form of the a classic hexadecimal number).

If you use pointers to a numbers then GLDx, GSTx assembler instructions are used to simplify access so the pointers looks correctly. (different situation is when you use local addressing page_offset form). Pleae lok into attached map files.

However, pointer to a function has different for in Code and environment processing. The address is switched. It makes some issues if you want ot copy some function from flash and you want to use its start and stop address in the copy cycle. In this case you have to transform the number you get as a unsigned long addr = (unsigned long) fction;

It is also good to test wat is difference if you combine variables and fucnctions definitions. I mean far and near.

 

So, if I have pointer to a function then I am able to transform it to a long number:

void far flash_ function(void);

unsigned long addr_of_flash_far_function;

unsigned long  global_addr_of_flash_far_function;

 

addr_of_flash_far_function = unsigned long (far_function);

global_addr_of_flash_far_function = ((addr_of_flash_far_function<<14) & 0x003FC000UL) | ((addr_of_flash_far_function >>8) & 0x00003FFFUL) | 0x00400000;

 

let function is at 0xE08000 (map file) then it is visualized in the debugger 0x8000E0 and to be able to get its correct global address to be able to access individual bytes by data accessing commands you have to transform it by above mentioned formula to get a global address 0x780000: (Gpage_offset)

 

0xE0_8000 => code warrior 0x8000_E0 => global address 0x780000

 

This global address can be used to access bytes of the function in the flash.

 

for ( i =  global_addr_of_flash_far_function, i < end; i++)

{

    unsigned char x;

   

     x = *((unsigned char *far)) i;    // read flash where the  “far_function” is placed

 

}

 

 

If I am working with a near space, for  example function at address 0xC000, then it is near function  (called by JSR and return code is RTS) and it can be called with this address. But when I consider it as a far function (implicit or explicit conversion is applied) then I need a far address of it which means it is converted to 0xC000_00 and it must contains return code RTC because calling assembler instruction is CALL)

 

Confusing? I know but when you try to perform code which copies PIC (position independent) functions from far flash to near or far RAM and then you are able to run them out of the RAM you will understand it perfectly. An example (from the bottom of my old table drawer) of such task is attached. (In the example I use nonpaged RAM for functions placement so backward conversion from global address to a pointer to a function is simplified because MCU is able to recognize access to a far function (CALL) if the offset is from a space assigned to a RAM direct addressing space)

 

The approach is the same for S12XD and S12XE families.

Best regards,

Ladislav

View solution in original post

5 Replies
1,167 Views
everkimage
Contributor IV

Is it about memory model?

My project is Banked Memory Model,and get function address shifted left 8bits.

The other project is Small Memory Model,and get function same as the map file.

If it's the answer,why & how does it happen?

0 Kudos
1,167 Views
kef2
Senior Contributor IV

Hi,

my own version of what Lama wrote above:

Native CPU12 far function pointer format 16bits_offset:8bits_ppage. Indirect CALL instruction uses this format. This is why you see something similar to <<8.

Compiler always needs to know function pointer type. Default in banked model is far (CALL). If you want near (JSR), then NON_BANKED placement is not enough. You need either use near keyword or specify __NEAR_SEG area attribute:

#pragma CODE_SEG __NEAR_SEG NON_BANKED

... all functions here are near by default

#pragma CODE_SEG DEFAULT

  

#pragma CODE_SEG NON_BANKED

... all functions here in banked memory model are far by default

#pragma CODE_SEG DEFAULT

If these functions are defined in one source file and should be called from other *.c files, then function prototypes should be visible in all files with the same near attribute or between the same pragmas with __NEAR_SEG:

// in *.h file

#pragma CODE_SEG __NEAR_SEG NON_BANKED

void foo(void); // __NEAR_SEG makes it the same like void near foo(void);

...

#pragma CODE_SEG DEFAULT

1,168 Views
lama
NXP TechSupport
NXP TechSupport

Yes, you are right but some additional should be taken into account which is modifier near or far. It is cause by default function placement. The memory model defines whether function is near (called by JSR and return code is RTS) or it is far function (called by CALL and return code is RTC). Of course you canuse explicit conversion where you will say to compiler hot to exactly process the function (be sure it is placed in the near space if you use near modifier)

(So a "far" function can be placed in a near space. The near function can be place in a far space only and only in the case when such a near space exists (4000~7FFF, C000~FFFF, 2000~3FFF,..se memory maps attached)) In this case the MCU automatically recognizes direct address in an offset of a far function (0xC000_00) and correctly uses it.

Finally,

Direct function address converted to a far space 0xC000 => 0xC000_00.

Something different is to convert far function pointer from far space to global address. Explained below or in attached example.

For example

 

#pragma CODE_SEG NEAR MY_SEG

 

void near fction1(void); // JSR used

void fction2(void);           // JSR used because of near segment ---not sure whether memory model takes precedence

void far fction1(void);     // CALL is used because of explicit conversion. Even the function is, for example placed

                                            // at 0xC000 the far pointer to it will be used with value 0xC000_00

 

#pragma CODE SEG DEFAULT

 

Now I’ll copy here an answer I was preparing on background.

 

Even I do not have full info about your initializations I would like to describe you briefly what you have to keep in mind.

There are different types of addresses near/far global/PPAG_OFFSET/RPAGE_OFFSET/…..

 

The map file shows real addresses (the form of the a classic hexadecimal number).

If you use pointers to a numbers then GLDx, GSTx assembler instructions are used to simplify access so the pointers looks correctly. (different situation is when you use local addressing page_offset form). Pleae lok into attached map files.

However, pointer to a function has different for in Code and environment processing. The address is switched. It makes some issues if you want ot copy some function from flash and you want to use its start and stop address in the copy cycle. In this case you have to transform the number you get as a unsigned long addr = (unsigned long) fction;

It is also good to test wat is difference if you combine variables and fucnctions definitions. I mean far and near.

 

So, if I have pointer to a function then I am able to transform it to a long number:

void far flash_ function(void);

unsigned long addr_of_flash_far_function;

unsigned long  global_addr_of_flash_far_function;

 

addr_of_flash_far_function = unsigned long (far_function);

global_addr_of_flash_far_function = ((addr_of_flash_far_function<<14) & 0x003FC000UL) | ((addr_of_flash_far_function >>8) & 0x00003FFFUL) | 0x00400000;

 

let function is at 0xE08000 (map file) then it is visualized in the debugger 0x8000E0 and to be able to get its correct global address to be able to access individual bytes by data accessing commands you have to transform it by above mentioned formula to get a global address 0x780000: (Gpage_offset)

 

0xE0_8000 => code warrior 0x8000_E0 => global address 0x780000

 

This global address can be used to access bytes of the function in the flash.

 

for ( i =  global_addr_of_flash_far_function, i < end; i++)

{

    unsigned char x;

   

     x = *((unsigned char *far)) i;    // read flash where the  “far_function” is placed

 

}

 

 

If I am working with a near space, for  example function at address 0xC000, then it is near function  (called by JSR and return code is RTS) and it can be called with this address. But when I consider it as a far function (implicit or explicit conversion is applied) then I need a far address of it which means it is converted to 0xC000_00 and it must contains return code RTC because calling assembler instruction is CALL)

 

Confusing? I know but when you try to perform code which copies PIC (position independent) functions from far flash to near or far RAM and then you are able to run them out of the RAM you will understand it perfectly. An example (from the bottom of my old table drawer) of such task is attached. (In the example I use nonpaged RAM for functions placement so backward conversion from global address to a pointer to a function is simplified because MCU is able to recognize access to a far function (CALL) if the offset is from a space assigned to a RAM direct addressing space)

 

The approach is the same for S12XD and S12XE families.

Best regards,

Ladislav

1,167 Views
everkimage
Contributor IV

Hi,lama.Thanks for your reply very much.

In the XDP512 project,there is a function named makePtr2ramFunction().It transforms every function address into form offset:ppage,and the base address is RAM_CODE_START equal to 0x2100.Is it a direct access address?

According to the function codes,finally (i>>16)&0xFF + (i<<8)&0xFFFF00 make the far function pointer value.Does this mean bit0~15 of direct access address is offset,and bit16~23 is ppage?

I mean how to transform memory address to far function invoke address?

0 Kudos
1,167 Views
everkimage
Contributor IV

In another project,i get the right function address,just same to the value listed in map file.

0 Kudos