C-Function larger as a page

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

C-Function larger as a page

1,600 Views
Boschje
Contributor I

Hello all,

 

I'm new to the S12X and I'm currently generating code from Matlab Simulink for use on an S12X microcontroller. The problem is it generates a function which is larger than a flash-page. Initially I got an error the code could not be located as a result that the function did not fit a page. Then I adapted the prm file to use global addressing on the entire flash:

 

SEGMENTS

    ....

    S12X_FLASH    = READ_ONLY   0x788000'G TO 0x7F3FFF'G;

    ....

END

 

PLACEMENT

    ....

    DEFAULT_ROM             INTO  S12X_FLASH;

    ....

END

 

Well, this compiles, links and runs... However it still does not run the large (the one larger as a page) function correctly. The function is called at the correct address but it fails while executing the function. When I manually adapt the function and decrease the size to a smaller one (so it fits within a page), other assembly is generated and it runs all fine.You can see the difference in the attachments.

 

Not adapted it executes (Dissasembly_Normal.JPG):

JSR         0x0231

GLDAB   0xEC52

GLDAA   0xEA16

...

When it executes the JSR-command it hangs up.

 

Adapted (small size function, see Dissasembly_Adapted.JPG):

LDAB    #15

STAB    0x10

GLDAB   0xEC52

GLDAA   0xEA16

...

Here it loads the correct page normally as I would expect and this runs fine

 

The thing is, it concers generated code so I'm not able to adapt the file/function. Does anyone knows what's going on and how to fix it?

 

Thanks,

Nick

Labels (1)
0 Kudos
11 Replies

886 Views
kef
Specialist I

Nick,

 

I second Deniel's response. CPU program counter can point only into 64k CPU address space and execute code only from what can be accessible in CPU address space. PPAGE window is allocated in CPU address space, what allows CPU to execute banked code. When banked routine is CALL'ed, specified page is mappaed into PPAGE window and CPU can execute code in that window. But CPU can't step from the end of one PPAGE to the beginning of another PPAGE. Isn't it clear? You can execute code in RPAGE window, EPAGE window, PPAGE window, but no page will be switched when PC reaches page coundary.

 

 

But there are ways to have big function. You have two choices. Easy one and harder one. Easy is to choose small memory model and edit PRM file to have single memory segment for ROM from 0x4000 to 0xFFFF. With this easy setup you will have 48kB for code. On S12C family (64k and bigger S12C variants) you can have more than 48k of nonbanked flash, up to 64k minus RAM block minus peripheral registers block.

 

In case simple option is not enough for you, you can proceed with banked memory model with the exception made for your big function. Provided big function doesn't call banked functions (including runtime routines in banked flash) , you can make your big function crossing PPAGE-window boundaries.

0 Kudos

886 Views
CompilerGuru
NXP Employee
NXP Employee

When using the "one big __near function from 0x4000...0xFFFF" approach, load PPAGE at the beginning with the page chosen for the 0x8000..0xBFFF block (naturally 0xFE).

This way the code does not have any limitations in respect to call other banked functions at all.

An alternative would be to use a __far function and make the compiler using PPAGE==0xFE when calling it. This might however cause issues when debugging it as the debugger might not find the function at the address it is looking for it.

 

Anyway, all those things are advanced setups, untested by my. If possible make the function < 16k. When using the large memory model, then the first thing I would check is to allocate often used variables explicitly non banked, that should help the code size quite a bit.

Daniel

0 Kudos

886 Views
kef
Specialist I

Daniel,

 

  • When using the "one big __near function from 0x4000...0xFFFF" approach, load PPAGE at the beginning with the page chosen for the 0x8000..0xBFFF block (naturally 0xFE).

Do you mean setting PPAGE=0xFE at the beginning of big function, before PC reached page window? Wow, that's hard.

 

 

  • This way the code does not have any limitations in respect to call other banked functions at all.

Yes, I was wrong, it's quite safe to call paged functions from big function.

 

 

  • An alternative would be to use a __far function and make the compiler using PPAGE==0xFE when calling it. This might however cause issues when debugging it as the debugger might not find the function at the address it is looking for it.

 

I tried it. Do you mean placing big function to segment like = READ_ONLY   0xFE4000 TO 0xFEBFFF? CW debugger complained it can't load code to FE4000. I think making burner reallocate 0xFE4000-0xFE7FFF to 0xFD8000-0xFDBFFF and loading produced S-records to the target will work. But it's not only hard to debug, but also more difficult to download to the target.

To make CW burning big function, I made it nonbanked, placed in segment 0x4000 TO 0xBFFF. Small nonbanked routine is used to save current PPAGE, switch PPAGE to page of foo(), call big foo() and restore PPAGE. Seems working.

 

 

Nick,

 

Certainly 22k routine will fit small memory model. I think I mentioned you have to edit default PRM file to define single nonbanked segment 0x4000-0xFFFF. Default PRM file defines two 16k segments 0x4000-0x7fff and 0xc000-0xffff. Of course your 22k routine doesn't fit them.

Do you have >12k of RAM variables and stack? If more than that, then you have to use paged RAM.

I think you should either switch to more suitable MCU like Coldfire, ARM etc. 

 

Yes, you can have big function with large model. See my example attached.

 

Modifications made to default XDT512 PRM file:

1) remove 0x4000-0x7fff segment and all references to it.

2) remove 0xFE8000-0xFEBFFF segment and all references to it

3) create segment for big function 0x4000-0xBFFF. Currently 32k. If that won't suffice later, try moving upper end of this big segment up, along with moving bottom end of 0xC000-0xFxxx segment.

4) define placement into segment 0x4000-0xBFFF

5) In the code you have  to use pragma CODE_SEG to place big function in segment defined at step 4.

 

Since you are trying to not touch generated code and since some #pragmas are unavoidable, you may remove generated code from project tree and #include it in small C file, like this:

 

--- some C file

#pragma push
#pragma CODE_SEG __NEAR_SEG BIGFUNC

#include "generated.c"

 

#pragma pop

----------

 

Code, which is calling big function must either see big function declared with near keyword, or, you may include generated

header file the same like above in your own header file, and include it in calling code.

 

Small function is required to save/restore PPAGE when calling big function from banked routine.

0 Kudos

886 Views
Boschje
Contributor I

I managed to get this working! Perfectly!

 

However, the function size will increase that much it won't fit the 48KB... So I will need the banked flash (globally accessed). Could the same "trick" be repeated but then allocate it to global FLASH addressing?

 

Thanks again,

Nick

0 Kudos

886 Views
kef
Specialist I

No, you can't cross 48k function size limit with S12X. Start looking for suitable 32bit MCU.

 

Well, you can, but at the cost of RAM. Your big function could start in RAM page window, at 0x1000. But you need some stack space, so your function could start somewhere between 0x1000 and 0x2000. But you said you have tons of RAM variables and need paged RAM. So your stack has to be above 0x2000, say 0x2000-0x2100, and then you big function could start at 0x2100. But that's 100% overkill, you should really switch to right for the task MCU.

0 Kudos

886 Views
Boschje
Contributor I

You're probably right.

 

We're currently investigating how to setup Matlab in order to create separate functions. It seems to be possible with using atomic subsystems.  We're using somewhere about 68 KB where the Matlab step-function is 58KB!

 

Switching to another MCU is not an option for now because we created an S12X Matlab target which we intend to use.

 

Thanks for your help man, you've been very helpful!

 

Nick

0 Kudos

886 Views
Boschje
Contributor I

Thanks Kef,

 

I will try it right away and post the outcome tomorrow. Very much appreciated!

 

Nick

0 Kudos

886 Views
CompilerGuru
NXP Employee
NXP Employee

Don't use global to cross page boundaries.

 

Don't. Basically this will cause  that the linker allocates functions ignoring page boundaries. So functions get allocated across page boundaries, then at runtime when the CPU executed across such a page boundary it does not continue on the next page, but instead at the next local address, (say 0xC000). and the code will crash horribly. So again, don't....

 

 

The best way would obviously be to reduce the function size to be below 16k.

how far are you off?

 

Apparently the code is using the large memory model, necessary?

Eventually some of the vars the generated code is using could be allocated explicitly non banked? That could reduce the function size considerably.

How many huge functions do have?

 

Daniel

0 Kudos

886 Views
Boschje
Contributor I

Daniel,

 

I'm at 22K now and increasing and it's only one big function now. I might be able to tune some stuff from within Matlab Simulink though and I am investigating that option as well. It has to be integrated into the environment so when press the build-key in Matlab, no manual editing should be needed. It's generated C-code.

 

Yep, I'm using the large memory model. I was already having problems with that as well. Matlab generates enormous data structures (which we already optimized to be as small as possible) so we needed to put some of them in paged RAM (which I managed to do with a self-coded parser at the declaration). This can be done from within Matlab (you can make it generate the #pragma-statements).

 

However, the generated code does not use far pointers within these structures and passes the data to functions illegaly (as char *) and I can't change that. Therefore I changed to the large memory model in order to be sure far pointers are always used. This works fine. (I did make an option within my build environment to simply change from small to large to banked).

 

Kef, I tried to put it within the small memory model, but that won't fit.... I don't completely understand your second solution. I see the point, but I'm not sure how to technically accomplish that. Daniel's last respond does already give some valuable tips but could you give a few more hints? I'n not an S12X expert yet :smileywink: .

 

Thanks,

Nick

0 Kudos

886 Views
Boschje
Contributor I

As an addition which I just realized, I'm afraid I need the large memory model because the gererated Matlab code does not use far-pointers for the banked RAM (in function calls etc.) and my RAM-usage is quite extensive so I will definely need paged RAM. By using the large memory model (and using far pointers by default) these function calls are executed well (but hang due to the large function).

 

Am I still able to create one large FLASH block from 0x4000 to 0xFFFF?

 

Thanks again,

Nick

 

 

0 Kudos

886 Views
Lundin
Senior Contributor IV

You cannot make functions larger than 16k (one page). You have one flash page from 4000 to 7FFF and one from C000 to FF7F (non-banked pages). This is regardless of large or banked model. FF80 to FFFF is reserved for the vector table.

 

One thing you should be aware of is that by default, the startup code, constants in flash, string tables etc are all stored together with your code. Unless you edit the .prm file, they will be in the same page. You could possibly toss some those things into one of the non-banked pages, and keep the actual code in the other.

 

Also, library calls like all the floating point stuff will end up in "default rom". But your own code you can place in any segement, using #pragma CODE_SEG. The float stuff will no doubt take up several kb alone.

 

 

0 Kudos