How to define and access a variable in paged ram?

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

How to define and access a variable in paged ram?

1,602 Views
赵子成
Contributor IV

Hi all,

I have a problem. I need to define a variable lager than 4K, if I define as follow:

#pragma DATA_SEG PAGED_RAM
static char astLecuDataPagedRam[7360];
#pragma DATA_SEG DEFAULT

That leads to the complie error:Out of allocatin.

So I divided the variable into 2 halves as  follows:

#pragma DATA_SEG PAGED_RAM
static char astLecuDataPagedRam1[3680];
static char astLecuDataPagedRam2[3680];
#pragma DATA_SEG DEFAULT

Complie OK but access to astLecuDataPagedRam2 will lead to access to astLecuDataPagedRam1,which I use this code:

astLecuDataPagedRam2[1000] = 1;

But infact will lead to: astLecuDataPagedRam1[1000] = 1

My issue is :

1、How can I define a variable lager than 4K?

2、Why access to astLecuDataPagedRam2 will lead to access to astLecuDataPagedRam1?

The paged ram defined in prm file is as follow:

SEGMENTS

RAM_F0 = READ_WRITE DATA_FAR 0xF01000 TO 0xF01FFF;
RAM_F1 = READ_WRITE DATA_FAR 0xF11000 TO 0xF11FFF;
RAM_F2 = READ_WRITE DATA_FAR 0xF21000 TO 0xF21FFF;
RAM_F3 = READ_WRITE DATA_FAR 0xF31000 TO 0xF31FFF;
RAM_F4 = READ_WRITE DATA_FAR 0xF41000 TO 0xF41FFF;
RAM_F5 = READ_WRITE DATA_FAR 0xF51000 TO 0xF51FFF;
RAM_F6 = READ_WRITE DATA_FAR 0xF61000 TO 0xF61FFF;
RAM_F7 = READ_WRITE DATA_FAR 0xF71000 TO 0xF71FFF;

RAM_FC = READ_WRITE DATA_FAR 0xFC1000 TO 0xFC1FFF ALIGN 2[1:1]; /* is also mapped to XGATE: 0xC000..0xCFFF */
RAM_FD = READ_WRITE DATA_FAR 0xFD1000 TO 0xFD1FFF ALIGN 2[1:1]; /* is also mapped to XGATE: 0xD000..0xDFFF */

END

PLACEMENT 

PAGED_RAM INTO  RAM_FD, RAM_FC, RAM_F7, RAM_F6,RAM_F5, RAM_F4, RAM_F3, RAM_F2, RAM_F1, RAM_F0;

END

0 Kudos
12 Replies

1,184 Views
kef2
Senior Contributor IV

Hi John,

Your #pragma only feeds linker with information where to link your struct to. Compiler is left unaware how this thing in paged RAM should be accessed. You either should use far keyword or __RPAGE_SEG / __GPAGE_SEG in your #pragma.

1)

#pragma DATA_SEG PAGED_RAM
far TBatteryInfo BatteryInfo;       // Battery Status information
#pragma DATA_SEG DEFAULT

in case far is used, #pragmas in header won't be necessary, extern far would be enough

extern far TBatteryInfo BatteryInfo;       // Battery Status information

2.a)

#pragma DATA_SEG __RPAGE_SEG PAGED_RAM
TBatteryInfo BatteryInfo;       // Battery Status information

#pragma DATA_SEG DEFAULT

#pragma DATA_SEG ... is information for linker where to place

__RPAGE_SEG is information for compiler, how to access, RPAGE + offset

2.b)

#pragma DATA_SEG __GPAGE_SEG PAGED_RAM
TBatteryInfo BatteryInfo;       // Battery Status information
#pragma DATA_SEG DEFAULT

__GPAGE_SEG tell compiler to use global addressing instructions and GPAGE register

In case far is not used, #pragma with proper __?PAGE_SEG is necessary in header file.

Edward

0 Kudos

1,184 Views
jcdammeyer
Contributor III

Thanks. Many hours later into the early morning, after more research I realized that I was just not seeing the __RPAGE_SEG in the other examples.  It took the step by step instructions in TN238.pdf for it to finally sink in. 

That did create a side effect as several of the buffers I'd created were also in my PAGED_RAM so the first error was that PAGED_RAM was already defined differently elsewhere.  Trouble was, those buffers are used by printf(), memcpy() and my own

PrintString( char devNumber, char * buf);

PrintString is called with both            

PutString(COM1_NDX, "reset\r");

or

PutString(COM1_NDX,(PCHAR)OpenlogFilename);

or

PutString(USB_NDX, (PCHAR)StagingBuffer);

where StagingBuffer was the array of charcters that was declared in the PAGED_RAM.

To make the code compile I had to remove StagingBuffer from PAGED_RAM and make it much smaller to remove the out of ram memory error.

I've not yet tried changing the function definition to be PrintString( char devNumber, char * __rptr buf); but I don't see how that will work for printf() nor for the literal strings.

I'll check that out this morning. Do you have a suggestion for printf()?  I use sprint() to the output_buffer which was in PAGED_RAM is done quite a bit.  But as it turned out it wasn't stepping on anything.

Thanks

John

0 Kudos

1,184 Views
kef2
Senior Contributor IV

Hi John,

It depends. You may like to recompile library with, IIRC, LIBDEF_PRINTF_FAR_PTR defined, which will add new %S format specifier... You may also consider large memory model, in which everything is far. You may also set RPAGE somehow and call printf ignoring warning about pointer conversion, like below

#pragma DATA_SEG __RPAGE_SEG PAGED_RAM
char str1[0x1000] = "abcd\r";
char str2[0x1000] = "efgh\r";

#pragma DATA_SEG DEFAULT

    

#define SetRPAGE(str) asm("LDAB \043PAGE(" #str ")"); asm STAB RPAGE

{

  SetRPAGE(str1);
  printf(str1);


  SetRPAGE(str2);
  printf(str2);

}

Regards

Edward

0 Kudos

1,184 Views
jcdammeyer
Contributor III

Thank you.  I've been playing around with that idea and looking at the compiled code.  I'm caught between the proverbial rock and a hard place though.  There isn't a budget to upgrade to the full compiler so I'm stuck with 64K.   But I'm also running at about 60.5K worth of code. 

One option is to return to the approach I had when I used the free 32K compiler for this project.  Five CAN bus channels, one for each ring.  My own PutDec, PutHex, PutString, PutBuffer.  Then as we repurposed the hardware I took the easy way and changed to using sprintf since suddenly the extra 32K was a massive amount of extra flash.(150 CAN based lamps per ring, 5 CAN channels)

Now as the client keeps adding features the battle to keep it under 64K is becoming more work and it's likely the full compiler with the interrupt routines and buffers in direct memory and the less important diagnostic and logging strings put in paged memory accessed with far pointers.

If I strip all sprintf and printf out, I then can force page operations without the warning which I don't want to ignore.

You've been very helpful. Thank you.

John

0 Kudos

1,184 Views
kef2
Senior Contributor IV

Hi

  • without the warning which I don't want to ignore.

CW compiler is good in that each warning can be disabled or even turned into an error if you wish. Either globally or for just a few lines of code:

#pragma push
#pragma MESSAGE DISABLE C1860
  printf(str1);
#pragma pop

I've lost your point about why 64K limit would matter here. Do you mean it doesn't allow you to recompile library for LIBDEF_PRINTF_FAR_PTR? Or you mean that code with RPAGE pointers is much bigger?

BTW what about putting your big data into asm files? CW 64K limit applies only to C files and o(bject) files made from C files.

Regards

Edward

0 Kudos

1,184 Views
jcdammeyer
Contributor III

Thanks.  I'm going to guess that once I change over to FAR that the overall program will become too large.  I think I need to lobby my client to just bite the bullet and buy the full compiler.

0 Kudos

1,184 Views
kef2
Senior Contributor IV

Hi,

To use bigger arrays than can fit in 4K R-page window, you need to use global addressing. To be to allocate >4K data you would need to edit PRM file and for example comment out two RAM_F0 and RAM_F1 segments and create one bigger and continuous segment in global address space. 'G tells linker it's global address:

RAM_F0F1 = READ_WRITE DATA_FAR 0xF0000'G TO 0xF1FFF'G;

Then you would need to comment out all occurrences of F0 and F1 in PLACEMENT, create new PLACEMENT like

mybigpagedram INTO RAM_F0F1;

Then you would need to use __GPAGE_SEG with your DATA_SEG. BTW you code should always specify which way you would like to access your paged RAM, RPAGE + 16 offset or GPAGE + global addressing instructions. For global addressing (you have no choice for big array in paged RAM, only __GPAGE_SEG, not RPAGE_SEG):

#pragma DATA_SEG __GPAGE_SEG mybigpagedram
static char astLecuDataPagedRam[7360];
#pragma DATA_SEG DEFAULT

If you would need to share your non static scope paged variables, you had to round you paged vars declarations in header file with correct #pragma DATA_SEG __GPAGE_SEG. __GPAGE_SEG or __RPAGE_SEG have to be shared, else compiler may fail using proper addressing.

Regarding splitting your big array into two smaller. It fails because you need to add -PSegObj to compiler command line. See compiler options->code generation->assume objects are in same page for:. Placing all paged RAM's into same placement doesn't provide compiler with what page particular variable is placed in. You either need to use different PLACEMENT's for each R-page, so that compiler would be right assuming that one PLACEMENT never crosses R-page boundary and all objects from the same PLACEMENT are in the same RPAGE. Or, you may keep using PAGED_RAM placement but tell compiler it should always reload RPAGE accessing different paged variables. You decide what is better for You.

Perhaps try using search on top right corner and look for -PSegObj, 'G and similar topics. Perhaps this will help

https://community.nxp.com/message/611605?commentID=611605#comment-611605

Regards,

Edward

0 Kudos

1,184 Views
赵子成
Contributor IV

Hi Edward, 

 Thanks for your detail explaination.

I still have some doubts about paged ram.

1、I split the big array into 2 smaller arraies, it seems that I must use __RPAGE_SEG(or maybe I can use __far when I define the var), if I define the 2 arraies like this:

 #pragma DATA_SEG PAGED_RAM
static char astLecuDataPagedRam1[3680];
static char astLecuDataPagedRam2[3680];
#pragma DATA_SEG DEFAULT

Even if I add the "-PSegObj" to the Command Line, I still get the error: Access to astLecuDataPagedRam2 will lead to access to astLecuDataPagedRam1.

If I define like this:

 #pragma DATA_SEG __RPAGE_SEG PAGED_RAM
static char astLecuDataPagedRam1[3680];
static char astLecuDataPagedRam2[3680];
#pragma DATA_SEG DEFAULT

I don't need to add  the "-PSegObj" to the Command Line, I can get the right result.

2、If I use the global addressing, your advise is merging the RAM_F0 and RAM_F1 and create one bigger and continuous segment in global address space. 'G tells linker it's global address:

RAM_F0F1 = READ_WRITE DATA_FAR 0xF0000'G TO 0xF1FFF'G;

My question is Can I use others address like this:

RAM_F0F1 = READ_WRITE DATA_FAR 0xF01000'G TO 0xF02FFF'G;?

0 Kudos

1,184 Views
kef2
Senior Contributor IV

Hi 赵子成,

  • #pragma DATA_SEG PAGED_RAM
    static char astLecuDataPagedRam1[3680];
    static char astLecuDataPagedRam2[3680];
    #pragma DATA_SEG DEFAULT
  • Even if I add the "-PSegObj" to the Command Line, I still get the error: Access to astLecuDataPagedRam2 will lead to access to astLecuDataPagedRam1.

Do you mean linker error 

L1128: Cutting value _Range beg data member from 0xFB1000 to 0x1000 ?

startup.c without __FAR_DATA defined assumes all data to be initialized are "near" and all data addresses are <0x10000. It is bit faster and OK until you use paged RAM. And once you start using paged RAM, you need to make __FAR_DATA defined, please add -D__FAR_DATA to compiler command line. 

  • If I define like this:
  •  #pragma DATA_SEG __RPAGE_SEG PAGED_RAM
    static char astLecuDataPagedRam1[3680];
    static char astLecuDataPagedRam2[3680];
    #pragma DATA_SEG DEFAULT
  • I don't need to add  the "-PSegObj" to the Command Line, I can get the right result.

No, you can't. astLecuDataPagedRam1[0] = 5 followed by astLecuDataPagedRam2[0]=5 will write to the same location! Just try it. It may seem being OK if you interleave accesses to astLecuDataPagedRam1 and astLecuDataPagedRam2 with some other code, ot use astLecuDataPagedRam1 and astLecuDataPagedRam2 in different routines, so compiler may decide it is unsafe to assume RPAGE didn't change and will reload RPAGE with correct setting...

  • My question is Can I use others address like this:
  • RAM_F0F1 = READ_WRITE DATA_FAR 0xF01000'G TO 0xF02FFF'G;?

0xF01000'G is non existing global address. See Figure 1-2. MC9S12XE100 Global Memory Map in S12XE datasheet. Top global address is 0x7FFFFF'G.

Regards,

Edward

0 Kudos

1,184 Views
赵子成
Contributor IV

Hi Edward,

Do you mean linker error 

L1128: Cutting value _Range beg data member from 0xFB1000 to 0x1000 ?

My comment: NO, there is no compile or link error. What I means is I want to:

astLecuDataPagedRam2[1000] = 1, but infact make astLecuDataPagedRam1[1000] equal 1;

startup.c without __FAR_DATA defined assumes all data to be initialized are "near" and all data addresses are <0x10000. It is bit faster and OK until you use paged RAM. And once you start using paged RAM, you need to make __FAR_DATA defined, please add -D__FAR_DATA to compiler command line. 

My comment:Yes, I have added  -D__FAR_DATA to command line at the original time.

No, you can't. astLecuDataPagedRam1[0] = 5 followed by astLecuDataPagedRam2[0]=5 will write to the same location! Just try it. It may seem being OK if you interleave accesses to astLecuDataPagedRam1 and astLecuDataPagedRam2 with some other code, ot use astLecuDataPagedRam1 and astLecuDataPagedRam2 in different routines, so compiler may decide it is unsafe to assume RPAGE didn't change and will reload RPAGE with correct setting...

My comment: I just access astLecuDataPagedRam1 and astLecuDataPagedRam2 in the initial code, It is OK.

For example, I make astLecuDataPagedRam2[1000] equal 5, it is really become 5, and the astLecuDataPagedRam1[1000] is 0, so I said I could get the right result.

0xF01000'G is non existing global address. See Figure 1-2. MC9S12XE100 Global Memory Map in S12XE datasheet. Top global address is 0x7FFFFF'G.

My question is why we can use 0xF01000、0xF11000、0xF21000、0xF31000......if we use RPAGE, I can't see these addresses in Figure 1-2.

Thanks.

0 Kudos

1,184 Views
kef2
Senior Contributor IV

Hi

  • Do you mean linker error 

    L1128: Cutting value _Range beg data member from 0xFB1000 to 0x1000 ?

    My comment: NO, there is no compile or link error. What I means is I want to:

    astLecuDataPagedRam2[1000] = 1, but infact make astLecuDataPagedRam1[1000] equal 1;

OK. Since data has no far keyword and page access type (__RPAGE_SEG / __GPAGE_SEG) is not specified, top part of address is ignored, instead of 0xFB1000 you compiler uses 0x1000. Most likely both ..Ram1[] and ..Ram2[] have same lower 16bits of address.

-PSegObj is indeed required for __RPAGE_SEG and all paged variabels placed in the same placement PAGED_RAM. Please double check your observation. Perhaps my compiler is older than yours and -PSegObj is default behavior when -P switch is not specified. I'm using compiler version 5.0.45

0xF01000 address is paged address, 0xF0 - page and 0x1000 - offset. Now, when talking about paged RAM, which page do you mean? R-page or G-page? And how compiler should know it, maybe you meant P-page? Global address is unique for each particular location, there's no ambiguity.

Problem with paged RAM segments is that you can't specify contiguous segment using paged address. There's a gap between 0xF01000..0xF01FFF segment and 0xF11000..0xF11FFF segment! In global address space there's no gap between them! First is 0F0000'G..0x0F0FFF'G  and second is 0x0F1000'G..0x0F1FFF'G . No gap between 0x0F0FFF and 0x0F1000.

In mentioned figure is specified only global address of top of RAM (0x0F_FFFF = 0x0FFFF'G).

Nonpaged 0x2000 (rpages 0xFE, 0xFF) -> 0x0FE000'G

Rpage 0xFD -> 0x0FD000'G

Rpage 0xFC -> 0x0FC000'G

..

Rpage 0xF1 -> 0x0F1000'G

..

Edward

0 Kudos

1,184 Views
jcdammeyer
Contributor III

I'm having a similar problem with accessing paged ram.  In my prm file I have

      PAGED_RAM         INTO  /* when using banked addressing for variable data, make sure to specify
                                 the option -D__FAR_DATA on the compiler command line */
                              RAM_F8, RAM_F9, RAM_FA, RAM_FB, RAM_FC, RAM_FD;

where

/* paged RAM:                       0x1000 TO   0x1FFF; addressed through RPAGE */
      RAM_F8        = READ_WRITE  0xF81000 TO 0xF81FFF;
      RAM_F9        = READ_WRITE  0xF91000 TO 0xF91FFF;
      RAM_FA        = READ_WRITE  0xFA1000 TO 0xFA1FFF;
      RAM_FB        = READ_WRITE  0xFB1000 TO 0xFB1FFF;
      RAM_FC        = READ_WRITE  0xFC1000 TO 0xFC1FFF;
      RAM_FD        = READ_WRITE  0xFD1000 TO 0xFD1FFF;

I have the -D __FAR_DATA declared in the compiler command line.

The structure is declared like this:

#pragma DATA_SEG PAGED_RAM
TBatteryInfo BatteryInfo;       // Battery Status information
#pragma DATA_SEG DEFAULT

and in the .h file as

#pragma DATA_SEG PAGED_RAM
extern TBatteryInfo BatteryInfo; // Battery Status information
#pragma DATA_SEG DEFAULT

Once compiled and programmed into the 9S12xdp512 using the debugger I see that the BatteryInfo structure is located at 0xF81200, size 379.  A right click on the variable and show location brings up that area in the memory debug window.  A breakpoint at the point where I access it shows the correct 0x1206 offset to access a structure element but the code isn't using RPAGE which happens to be set at FD.

How do I tell the compiler I want it to load the RPAGE register?

Thanks

John

0 Kudos