Possible to make routine accept near or far pointers? MC9S12XEP100

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

Possible to make routine accept near or far pointers? MC9S12XEP100

2,200 Views
kgkgkg
Contributor I

Hi,

 

I am using MC9S12XEP100 and using the banked memory model in my current project.

 

I recently got paging working in a few projects, but on my current project I now have an issue. Maybe I am asking for the impossible...but I am wondering if there is a way to write a routine such that I can pass in a pointer regardless of whether it is a __near or __far pointer.

 

The reason for this is that we have a lot of legacy code and it uses a lot of "common" code that is shared among many, many different projects. Recently, some of these projects have been converted to use the banked model in order to gain access to additional RAM space. However, most other projects have plenty of RAM and need not use paging. So, it would be nice if these routines would work in either case.

 

Below is an example routine that simply copies a string from ptr1 to ptr2. It has a source pointer and a destination pointer. I would like to be able to call it in various ways. For example, when ptr1is a near pointer and ptr2 is far, or vice versa, or both are near pointers, or both are far pointers, etc...

 

byte CopyString (byte *ptr1, byte *ptr2)
{
    byte count = 0;
    while (*ptr2++ = *ptr1++)

    {

        count++;
    }
    return (count);
}

 

Is what I am asking possible? It would sure make life easier with regard to the enormous amount of legacy code that already uses these common routines. Even casting the parameters when the call is made would require editing  a lot of code in a lot of different projects.

 

Thanks in advance for any helpful advice.

 

KG

Labels (1)
Tags (1)
0 Kudos
Reply
10 Replies

1,065 Views
Lundin
Senior Contributor IV

This is actually one of the main reasons to pick a 32-bit MCU. The addressing system in the S12 is far from pretty. I'm only using 8 and 16 bit micros myself but consider 32 for future projects just to be rid of the horrible banking.

0 Kudos
Reply

1,065 Views
CompilerGuru
NXP Employee
NXP Employee

>these projects have been converted to use the banked model in order to gain access to additional RAM space

 

The banked and the small memory model differ in how they place code, they have the same behavior regarding (nonpaged paged) RAM accesses. In either one, using __far (or __rptr) pointers can be used to access paged RAM.

 

In general, a __far pointer can access anything a __near pointer can, assignment converts them as necessary. Note that the conversion might not be cheap though. Also any code using __far pointers is considerably bigger and slower than __near code, but if you are willing to pay the price, using __far pointers for shared functions should make them work with either kind of input.

 

 

byte CopyString (const byte *__far ptr1, byte *__far ptr2){    byte count = 0;    while (*ptr2++ = *ptr1++)    {        count++;    }    return (count);}

 

 

0 Kudos
Reply

1,065 Views
kgkgkg
Contributor I

I am still having trouble making this work. I had already tried what you suggested, but I revisited it to make sure...unfortunately, still no go.

I wondered if I needed to explicitly cast the "near" parameter to a far pointer, but even that fails.

 

One other piece of info I neglected to mention.One of the buffers is set up to be in global memory (making use of GPAGE register as opposed to the RPAGE reg). I do not manipulate the GPAGE register directly, but rely on the compiler to figure this out.

 

In the prm file, I have the following code:

SEGMENTS

      // For bevity I am not showing all the definitions for paged and non-paged RAM, FLASH, EEPROM, etc....

      GLOBAL_RAM    = READ_WRITE  0x0F0000'G TO 0x0F7FFF'G;    // This is the global memory I will use for my buffer.

END   

 

PLACEMENT

      // For bevity I am not showing all the various placements...

      EXTRA_RAM            INTO GLOBAL_RAM;    // Put buffer here.

END

 

In my source code, I tell the compiler to use GPAGE reg for this buffer and its pointer...as shown:

#define MY_GLOB_TEST_SIZE    20

#pragma push
#pragma DATA_SEG __GPAGE_SEG  EXTRA_RAM
char myGlobalTest[MY_GLOB_TEST_SIZE];
char * __far myGlobalTestPtr;
#pragma pop

 

I also have another buffer and accompanying pointer that are NOT in global memory, as shown here (these are file scope variables):

char myDest[MY_GLOB_TEST_SIZE];
char *myDestPtr;

 

 

So far so good. Everything seems to work as expected with regards to reading and writing to both of these buffers, except when using the copy routine to copy between them. The copy routine is as you listed it with both arguments specifiying far pointers.

 

To debug this I print out the pointer values before I call the copy routine, and then inside the copy routine I print the values of the pointers as they are received.  Here are the results:

 

FIRST TEST - I call the copy routine with a source pointer that is a far pointer and a destination pointer that is not.:

debugCnt = CopyString(myGlobalPtr, myDestPtr);

 

RESULT:

Values of pointers before calling:

myGlobalPtr = 000F0000

myDestPtr     = 000031AF

Values of pointers inside CopyString:

ptr1 = 000F0000

ptr2 = 00AF0000  (??? this is no good)

 

2ND TEST - I call the copy routine with a source pointer that is a far pointer and a dest ptr that is cast to a far ptr:

debugCnt = CopyString(myGlobalPtr, (byte* __far)myDestPtr);

 

RESULT:

Values of pointers before calling:

myGlobalPtr = 000F0000

myDestPtr     = 000031AF

Values of pointers inside CopyString:

ptr1 = 000F0000

ptr2 = 00AF31AF   (??? Where did the hex AF come from? I expected the upper byte to be zeroed out)

 

 

Any clues as to what I am doing wrong?

 

Thanks again for your help.

KG

 

0 Kudos
Reply

1,065 Views
kef
Specialist I

What's your compiler version?

What about not printing out pointers, but reading their value in debugger?

 

Did you initialize your source string? If not, then copy routine is copying until it finds first zero byte. It could be a zero in myGlobalTestPtr variable or even many bytes past that.

 

Do you receive this linker warning: "L1128: Cutting value _Range beg data member from 0xF01000 to 0x1000".

It seems linker is having problems initializing copy down structures for this segment:

GLOBAL_RAM    = READ_WRITE  0x0F0000'G TO 0x0F7FFF'G;

I run simulator, and it didn't pass startup routine. It was trying to access unused RAM segments, where I have no variables. Replacing READ_WRITE for 'G segments to NO_INIT solves the problem. But then of course you need to initialize your variables in your code.

 

Your copy routines works well with CW 5.1

 

I think you should move small variables to default segments, making access to them bit faster. I mean myGlobalTestPtr pointer should be moved away from DATA_SEG__GPAGE_SEG, unless you have a lot of such small vars and they don't nonpaged RAM:

#pragma push
#pragma DATA_SEG __GPAGE_SEG  EXTRA_RAM
char myGlobalTest[MY_GLOB_TEST_SIZE];
#pragma pop

char * __far myGlobalTestPtr;

0 Kudos
Reply

1,065 Views
kgkgkg
Contributor I

First of all, thank you for your time in considering my problem.

 

Here are answers to your questions:

 

I am running CW 5.1.

 

Yes, the source string is initialized. (The copy routine will work fine if I make sure the parameters are exactly the same types as the arguments, but it only fails when I try to repy on casting, either explicit or implicit, to convert the parameter into a __far pointer).

 

No, I did not receive linker error L1128.

 

Yes, I too realized that myGlobalTestPtr need not be in the global memory; only the buffer itself needs to be there. I fixed that.

 

Sorry, but I did not follow your discussion about replacing READ_WRITE for 'G segments to NO_INIT...etc., but it may not apply since we do explicitly initialize all of our variables...at least we try :smileyhappy:

 

Just to be clear:

My ulitmate goal is to move a RAM buffer into global memory space because we need this buffer to be much larger than the remaining RAM we have available in local memory. (The example I posted here shows a 20 byte buffer, but in reality I need a much bigger one). Also, we have ruled out using the RPAGE register for getting at more RAM because our design already uses this RPAGE register in an somewhat unconventional way to access some hardware...suffice it to say, the RPAGE register is not available to me to get at more RAM. Hence, my attempt to use th GPAGE register to get at more RAM.

 

We typically do not use the debugger on our full code, but rather use print statements to a terminal. There is alot of hardware interaction that makes the debugger problematic for me. I suppose I could construct a smaller body of code and see if the debugger reveals anything...

 

However....my printout clearly indicates a problem (2 problems: one for explicit casting and one for implicit conversion):

 

Problem 1:

The value of the pointer (myDestPtr) is wrong once it is received by the Copy routine if I explicitly cast the pointer to char*__far.

 

In 2ND TEST myDestPtr is pointing to 000031AF when the call is made to copy routine.

Inside the routine it becomes 00AF31AF.

 

In 3RD TEST myDestPtr is pointing to 000031B2 when the call is made to copy routine.

Inside the routine it becomes 00B231B2.

 

This indicates to me that the conversion to a __far pointer is not working. The upper byte is simply a duplicate of the lowest byte. This seems like a big clue...to someone who undersands this better than me.

 

Probelm 2:

The value of the pointer (myDestPtr) is wrong once it is received by the Copy routine if I rely on implicit conversion of the pointer.

 

In FIRST TEST myDestPtr is pointing to 000031AF when the call is made to copy routine. Inside the routine it becomes

00AF0000. This is clearly wrong.

 

Once again thank you for slogging thru this with me.

KG

 

0 Kudos
Reply

1,065 Views
CompilerGuru
NXP Employee
NXP Employee

Well, it works for me.

How do you print the far pointers? Far pointers are 3 byte, but you display them as 4 byte entries, so I wonder if the retrieving of the pointers might be problematic.

- Is there a declaration of the function? Does it match the definition? A non matching declaration explains any kind of strange argument passing bugs.

- Are there any implicit declarations warnings? If so, fix them first.

- How is the 4000..0x7FFF area mapped? Default is flash, but the Ep100 supports to map RAM, but this needs some special setup in the linker/compiler/assembler (would not explain the observed behavior though).

 

I've attached a small test app which works for me in the simulator.

 

Daniel

0 Kudos
Reply

1,065 Views
kgkgkg
Contributor I

 

Daniel,

 

You asked the key question....and led me to the solution!

 

During my experimentation I had made a different Copy routine (giving it a unique name) and I had failed to put in a function protoype in the file that called it. Once I put that in it started working!

 

Thank you!!!!

 

KG

0 Kudos
Reply

1,065 Views
CompilerGuru
NXP Employee
NXP Employee

For the future, I would strongly recommend to place all declarations in header files, to include the header files both at where the declaration is needed and where the definition is located. Then make sure there are no implicit declarations (would recommend to map that message to an error).

 

Daniel

0 Kudos
Reply

1,065 Views
CompilerGuru
NXP Employee
NXP Employee

The L1128 linker warning means that there are variables allocated in a paged area which is not supported by default in the chosen memory model. There is a macro which can be defined using -D in order to support this, check the startup code (I', not remembering by heart the macro name).

 

Daniel

0 Kudos
Reply

1,065 Views
kgkgkg
Contributor I

More info regarding my previous post...

 

I repeated the 2nd test after some code changes which happened to move the location of the buffer pointed to by myDestPtr.  Here's what happened when I repeated the 2nd test...

 

3RD TEST - I call the copy routine with a source pointer that is a far pointer and a dest ptr that is cast to a far ptr:

debugCnt = CopyString(myGlobalPtr, (byte* __far)myDestPtr);

 

RESULT:

Values of pointers before calling:

myGlobalPtr = 000F0000

myDestPtr     = 000031B2  (This pointer now has a new value)

Values of pointers inside CopyString:

ptr1 = 000F0000

ptr2 = 00B231B2   (NOTICE that 'B2" seems to be a copy of the lower byte 'B2". This happened in TEST2 also!?)

 

In 2nd test I wondered where the 'AF' came from in the upper byte. Now it appears that it is a copy of the low byte.

 

Any ideas as to what is going on here?

 

Thx again.

KG

 

 

 

 

0 Kudos
Reply