News:

Let's find out together what makes a PIC Tick!

Main Menu

Stack Size Declare?

Started by Craig, Nov 04, 2023, 09:01 AM

Previous topic - Next topic

Craig

I was wondering What does the Compiler insert as Default, If the Stack Declare is Not Issued? I have looked in the .PPI Files but, don't find anything.
If I use a Pic 18F47Q10 it has a 31 Level stack, In the past I have declared the stack size as 20 but, what I want to make sure of is it better to declare the stack size as 31 and if I don't declare the Stack Size then what does the compiler insert
if I have selected in the config File  STVREN = On ;Stack full/underflow will Cause Reset ?

Regards
Craig

diebobo

In my understanding the stack is determined by the compiler and that makes an estimate needed depending on the functions and "library's" in use... 

So, if only add and subtracting are used in your program the stack can be very small.. But if u are using command's like Serout the stack required is much bigger..

Sometimes the compiler has is it wrong and determines a to small stack size and then your program might hang or act completely wrong.. Can happen if u are using nested routines, so Gosub in a Gosub in a Gosub . Or in a Proc () to another Proc () etc.. 

In PIC's with enough memory i just delcare stack 400 to be safe.   

top204

#2
I think you are both mixing up a real RAM stack that the 16-bit (PIC24 and dsPIC33) devices have, with the stack available on the 8-bit devices.

The 8-bit devices have different stack sizes depending on the family, and these are hardware stacks for call/returns only, and no software can increase or decrease their size, or, effectively, store data in it, otherwise, the device will overflow its stack and either reset or go crazy. This has always been the problem with the 8-bit devices, and something the compiler tries to minimise by making some call/returns into gotos.

The 16-bit devices have a true RAM stack and the compiler defaults to a size of 120 words. This is held in lower RAM and holds user data and call/return address' and some interrupt contexts. The amount of RAM used for the stack can be increased and decreased with the Declare Stack_Size, and the compiler automatically increases its size when interrupts are used, in order to hold the SFRs and system variables for each interrupt vector because their priorities allow one interrupt to interrupt another.

The Stack I implemented on the 8-bit devices is software only and uses the FSR2L and FSR2H SFRs as the interrupt pointer on 18F devices, and FSR1L and FSR1H on enhanced 14-bit core devices because they do not contain the FSR2L\H SFRs. It can be increased and decreased with the Stack_Size declare, but does not come into play unless a Push or Pop command is used, or the declare is used in the program. Its default is 20 bytes (ten 16-bit values) if the Declare is not used, but a Push command is (just to be on the safe side and help stop other variables being over-written).

When a Push command is used on an 8-bit device without the Stack_Size declare being implemented, the compiler auto creates a very small stack for it:

Create_SoftwareStackArray(10);                  // Create a small stack array, in case the Stack_Size declare has not been used in the program

And to push a variable, it uses one of several functions to create the assembler code depending on its size. For example:

void push_byte(char *pBytein)
{
    if(CORE == 18)
        {
            byte_byte(pBytein, "POSTINC2");
        }
    else if(tEnhancedCore == true)
        {
            word_word("_STK_PTR_", "FSR1L");                              // Load FSR1L\H with the current address held in _STK_PTR_
            byte_byte(pBytein, "INDF1++");
            add_num_byte_byte("1", "_STK_PTR_", "_STK_PTR_");             // Increment the stack pointer address (low byte) by 1
        }
}

On an 8-bit device, you can see the Software Stack RAM if a Push is used without the declare, by pressing the F2 button and viewing the assembler code listing. I have made the assembler code as straightforward as it can be and as readable as it can be, so it can be understood by people also wanting to learn assembler writing, and the Software Stack RAM is created as:

__Sw_Stack equ 0x14
variable __Sw_Stack#0=0x14,__Sw_Stack#1=0x15,__Sw_Stack#2=0x16,__Sw_Stack#3=0x17
variable __Sw_Stack#4=0x18,__Sw_Stack#5=0x19,__Sw_Stack#6=0x1A,__Sw_Stack#7=0x1B
variable __Sw_Stack#8=0x1C,__Sw_Stack#9=0x1D,__Sw_Stack#10=0x1E,__Sw_Stack#11=0x1F
variable __Sw_Stack#12=0x20,__Sw_Stack#13=0x21,__Sw_Stack#14=0x22,__Sw_Stack#15=0x23
variable __Sw_Stack#16=0x24,__Sw_Stack#17=0x25,__Sw_Stack#18=0x26,__Sw_Stack#19=0x27

It is created in high RAM, above user code RAM, so it does not interfere with user RAM and cause more RAM bank mnemonics to be used. However, it has nothing to do with subroutine or procedure calls, because that is, unfortunately, the hardware stack that is set in the 8-bit device's core.

Craig

Thank you Les for the detailed Description it is very much appreciated, it clears things up.