What should the stack size be for my application?

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

What should the stack size be for my application?

8,084 Views
BasePointer
Contributor II
Hi,
 
I'm come here from pic world and new at freescale.
How can I indicate stack size that my application needs?
My application start exhibiting some interesting behaviours and I'm doubting that it needs more stack. But I don't know what it exactly should be.
 
Here is my actual prm file.
 
Code:
SEGMENTS
    ROM                      =  READ_ONLY    0x1870 TO 0xFFAF;    Z_RAM                    =  READ_WRITE   0x0060 TO 0x00FF;    RAM                      =  READ_WRITE   0x0100 TO 0x0C5F;    NO_INIT_RAM_SEG          =  NO_INIT      0x0C60 TO 0x105F;    ROM1                     =  READ_ONLY    0x1060 TO 0x17FF;    ROM2                     =  READ_ONLY    0xFFC0 TO 0xFFD1;ENDPLACEMENT
    DEFAULT_RAM                         INTO  RAM;    NO_INIT_RAM                         INTO  NO_INIT_RAM_SEG;    DEFAULT_ROM, ROM_VAR, STRINGS       INTO  ROM;    _DATA_ZEROPAGE, MY_ZEROPAGE         INTO  Z_RAM;ENDSTACKSIZE 0x50

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

3,402 Views
BasePointer
Contributor II
My application is for MC9S08LC60. I changed the stack size with 0x200. It seems working well for now. I still wonder if there is a way to detect stack overflow condition for the future?
 
Here is my new prm file:
Code:
/* This is a linker parameter file for the mc9s08lc60 */NAMES END SEGMENTS         Z_RAM                    =  READ_WRITE   0x0060 TO 0x00FF;  // 160 byte    RAM                      =  READ_WRITE   0x0100 TO 0x0A5F;  // 2400 byte    NO_INIT_RAM_SEG          =  NO_INIT      0x0A60 TO 0x0E5F;  // 1024 byte    MY_STK                   =  NO_INIT      0x0E60 TO 0x105F;  // 512 byte    ROM1                     =  READ_ONLY    0x1060 TO 0x17FF;    ROM                      =  READ_ONLY    0x1870 TO 0xFFAF;    ROM2                     =  READ_ONLY    0xFFC0 TO 0xFFD1;ENDPLACEMENT     _DATA_ZEROPAGE, MY_ZEROPAGE         INTO  Z_RAM;    DEFAULT_RAM                         INTO  RAM;    NO_INIT_RAM                         INTO  NO_INIT_RAM_SEG;    SSTACK                              INTO  MY_STK;    DEFAULT_ROM, ROM_VAR, STRINGS       INTO  ROM;         ENDSTACKSIZE 0x200VECTOR 0 _Startup

 
0 Kudos
Reply

3,402 Views
Lundin
Senior Contributor IV
You do it the same way on any micro. Start the debugger, set the whole stack segment to zero, let the program run for a while. Then check how much of it that is still zero.

A more serious approach would be to record the SP through for example an emulator, but that is probably overkill for most apps. Perhaps there are some debuggers that support this, but Codewarrior doesn't.

Another method you can use on some Freescale micros is to map the stack just above a segment that isn't used, then run the program for a while. If the stack tries to write to the memory area that isn't used, you will get "software interrupt" or similiar.
0 Kudos
Reply

3,402 Views
igorstravinsky
Contributor I
Hi,

I didn't originate this thread,but it interests be nonetheless. I am also new to
this micro. I am more familiar with the TI 16 bit DSP micros where I typically do what you suggest and map the stack in memory so that a stack overflow will attempt to write to an illegal address. On the TI architecture this asserts an NMI which I use to report debugging info.

Could you be more specific about how this might work on the freescale micro, or point me to the proper documentation. I've gone through the documentation and have not located any section where it mentions what happens when you attempt to read from an illegal address. All I see is the interrupt for "Illegal Opcode" (also quite useful).

I am more than happy to RTFM if someone can point me at the correct one ;^).

Thanks,



Igor
0 Kudos
Reply

3,402 Views
Alban
Senior Contributor II
Hello Igor,

It depends on the architectures.
On Freescale MCUs = HC08, S08, HC12, S12 and S12XD, there isn't any Illegal memory read.
Reading from reserved or un-implemented locations will return garbage.

On the S12XE, you can declare descriptors to protect different areas of memory from read and/or write.

On 32-Bit MCU, DSP and everything else, I have no clue.

Cheers,
Alban.
0 Kudos
Reply

3,398 Views
igorstravinsky
Contributor I
Hi Alban,

Thanks, you have answered my question. I was referring to the post #3 wherein it is stated: "Another method you can use on some Freescale micros is to map the stack just above a segment that isn't used, then run the program for a while. If the stack tries to write to the memory area that isn't used, you will get "software interrupt" or similiar.

Apparently the S12 does not have this feature. Do you know of any way on the S12 to do run-time detection of stack overflow?

Thanks again,



Igor
0 Kudos
Reply

3,397 Views
Alban
Senior Contributor II
Hi again Igor,

Well, the post #3 is also right.
There is nothing by default.

Using the Break module is a good idea. I did that on HC08 for "defensive programming" and it also works on S12.

The Break module can generate a Software Interrupt on Address Match.

You leave a word (S12 does 16-Bit accesses) between the bottom of your stack and the top of the variables.
Then, you set up the break module to trigger on that address.
If the Stack overflows, the break will detect it.

The only "native" access control on S12 is **executing** from reserved/un-implemented memory.

Cheers,
Alban.
0 Kudos
Reply

3,397 Views
igorstravinsky
Contributor I
Alban,

That looks like it will do the trick.

Thanks again,


Igor
0 Kudos
Reply

3,396 Views
bigmac
Specialist III
Hello BasePointer,
 
While not directly related to detecting the required stack size, it has occurred to me that a few stack locations are being unnecessarily consumed when the main() function is called.  Since this function never exits, there is no need for a return address, nor for CPU register values to be pushed onto the stack, as this memory will never be released.  I suspect this RAM usage can be eliminated using suitable pragmas.  While saving only a few bytes of RAM, this could be critical to low end applications, perhaps with as little as 128 bytes of RAM available.
 
Another consideration for minimising stack size is not to declare any local variables within main() - these again represent stack allocations that will never be released.  Any variables directly required by main() should be global.  However, this will not reduce total memory usage.
 
To further minimize stack usage, limit the number of variables passed to each function - don't use int values where a char values will suffice.  If a large number of different parameters are required by a function, consider use of a global structure (not static), eliminating any recursive calls.
 
Otherwise, I would agree with others that the stack should be utilised as much as possible for local variables, as this will give more efficient RAM utilisation.
 
Regards,
Mac
 
0 Kudos
Reply

3,397 Views
CompilerGuru
NXP Employee
NXP Employee
For the HC08, the current startup code does not push the return address of _Startup to the stack before calling main, so that optimization is done.
There are no CPU registers put on the stack for a HC08/HC12 for main at all.
Using globals instead of locals for main does only help in some setups to reduce the RAM usage. In others it will use more memory.
With locals there is a chance that the compiler can keep them in registers and does not have to allocate them at all, that wont happen with globals.
For a HC08, using globals may be beneficial if they are allocated DIRECT and the compiler can use cheaper access methods than when accessing the stack (but this is not about the needed RAM space tough).
Another point where globals could theoretically help is if they are not used just in main, but instead also in called function and would have to be passed as arguments otherwise.
In general I would not propose to use globals to use RAM. I would use locals whenever reasonable and only use globals in the exceptional cases.

Daniel
0 Kudos
Reply

3,402 Views
BasePointer
Contributor II
I have found a compiler parameter "-Ll: Statistics about Each Function" , but it gives stack size at only function level. I saw that this kind of stack usage is very dangerous and hard to debug for my application.
 
Is there any way to tell compiler not to use stack area for local variables? For example, hitech picc18 doesn't use pic's limited stack area for local variables. Instead of that, It automatically allocates global ram area for them and optimizes their size according to call-graph of functions and their local ram requirements. You only care nested  called function counts. I think this way is more programmer friendly.
 
Do you know codewarrior support this?
 
Thanks.
0 Kudos
Reply

3,402 Views
Lundin
Senior Contributor IV
Since C is so very focused at stack usage, it is probably wise to keep as much locals as possible on the stack, if you have enough RAM for it.

In ANSI C, you allocate variables with the keyword "static" to prevent them from ending up on the stack. Global variables will not be placed on the stack either. If you wish to place a global variable at a certain location, use the Codewarrior #pragma DATA_SEG.
0 Kudos
Reply

3,402 Views
rocco
Senior Contributor II
Of course, defining variables as static or global will "dedicate" ram locations to those variables, so it will use more ram than if they "shared" space on the stack.

So having automatic variables on the stack is a form of optimizing for ram space.
0 Kudos
Reply

3,402 Views
BasePointer
Contributor II
I don't want to use local variables in stack unless the compiler automatically control stack size. Instead of that, the compiler should reserve a shared area globally for them and optimize size of the area itself. Does the compiler do this automatically?
 
What is the "OVERLAP" segment and How does it work? Can I use it for this purposes?
 
Thank you.
0 Kudos
Reply

3,402 Views
Lundin
Senior Contributor IV
Why not? It is simple enough to check how much you are using. And you could for example set stack size to be RAM size minus the size of the globals. The latter can be found in the .map file.
0 Kudos
Reply

3,402 Views
BasePointer
Contributor II


Lundin wrote:
Why not? It is simple enough to check how much you are using. And you could for example set stack size to be RAM size minus the size of the globals. The latter can be found in the .map file.


Actually the problem exactly is this. The compiler doesn't tell me how much stack my application is using. I can't calculate manually this value by using function call-graph. The compiler should do this automatically for me. Even I allocate whole empty ram space for stack, the application may need more. We can't know this. So I personally don't preffer this method unless the compiler checks it.
0 Kudos
Reply

3,402 Views
Lundin
Senior Contributor IV
I didn't say you should use the function call graph, I said that you should check how much of the RAM that is used by globals and statics which can be found in the .map file.

I assume that you intend to use your whole RAM. Then you can set your stack size according to:

RAM_size - globals_size = stack_size.


Further, keeping track of the stack size is the programmer's responsibility. Unless your system is totally deterministic, with no I/O or interrupts what-so-ever, then the compiler CAN'T know the stack size. For example, how exactly do you expect the compiler to calculate how many nested interrupts that your program will receive? How can the compiler know if a certain function will be called or not if the condition for calling the function depends on a run-time variable, like a port register?
0 Kudos
Reply

3,402 Views
bigmac
Specialist III
Hello all,
 
I totally agree that the compiler cannot know the stack size required.  However, I would argue that the debugger should be aware, at least in full chip simulation mode.  Since the stack pointer is being simulated, I might have expected the debugger to issue a warning in the event that the allocated stack size is exceeded during the simulation process.
 
The 8-bit debugger does not appear to provide any warnings of this nature.  I have had instances where global variables residing immediately underneath the allocated stack have been over-written by the stack - without any warning being issued.
 
Perhaps it would also not be unreasonable to expect the debugger to keep track of the lowest stack pointer value achieved during simulation.  But this is probably wishful thinking.
 
Regards,
Mac
 
0 Kudos
Reply

3,402 Views
BasePointer
Contributor II
All the problem here is local variables stored in stack. Stack area is mostly consumed by local variables for applications. Not recursive functions nor nested interrupts. Of course the compiler exactly can't know count of recursive functions or nested interrupts or called functions via function pointers. These are exceptions, I think. But it can simply calculate total stack size of main function according to functions call-graph by summing stack size necessary for the each functions. I'm doing this manually and the compiler can do this automatically. This value will be the *minimum stack* necessary that the programmers must be aware of. This does not mean it will be enough. If you use recursive functions or nested interrupts, of course, you must grow up the minimal stack size calculated by the compiler according to your application, the compiler can't know or simulate when your this kind of algorithms stop in real.
0 Kudos
Reply

3,402 Views
CompilerGuru
NXP Employee
NXP Employee
About the automatic stack size computation.
This is really THE feature I miss most. I really suggested this many times in the past.
The computation has to be done with the call graph in mind, so not actually in the compiler, but in the linker. The compiler should be extended to provide more accurate information about the function tough. Its not just adding the frames of all functions, its really computing a pessimistic max stack size considering a static call graph.
In general there are case where this is not doable completely, like with function pointers, recursion, assembly code, inline assembly code. Interupts are not that hard though as they just can be considered with a separate call graph.
0 Kudos
Reply

3,402 Views
StephenRussell
Contributor I
The competition has been doing it for years!
 
The Cosmic linker analyzes the call graph and outputs the maximum stack usage for each function, including all called functions. 
 
Of course, it doesn't work for recursive functions.
 
This is relatively easy for them. The linker is already aware of the call graph because they have an option to optimize storage of locals in a shared fixed RAM area rather than on the stack.
 
0 Kudos
Reply