This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Writing a Stack Underflow with the C51 compiler

I am attempting to do something that seemed simple, but it is turning into a mess. I want to write a stack underflow monitor in main that both checks the stack pointer to insure it is at the bottom, and checks a byte under the stack bottom for a pattern (to better insure that the stack never went under when it was outside of main).

I've come to find that you cannot compile the following statement:

unsigned char * data StackPtr _at_ 0x81;
(because it is an sfr address)

It seems like this should be the same thing as:
sfr SP = 0x81;
..but with the added benefit of being able to dereference StackPtr to get at what it is pointing at.

The plan was to enter main at power-up, get the address SP is pointing at, stuff a pattern in there like 0xAA, then increment the SP. Later, when it returns to main, the test verfies the SP is still pointing at the SP++ address, and the original SP pattern is still 0xAA.

Assembler seems my only way out.

Parents
  • Just use SP by name. I'm not at a system with C51 installed at the moment, but something like:

    unsigned char start_SP = SP;
    
    *(unsigned char*)SP = 0xAA;
    ++SP;
    
    /* Do stuff */
    
    if ((SP - 1) != start_SP) {
        /* SP isn't pointing where it should be. */
    } else if (*(unsigned char*)(SP - 1) != 0xAA) {
        /* SP underflowed or something else happened. */
    }
    

Reply
  • Just use SP by name. I'm not at a system with C51 installed at the moment, but something like:

    unsigned char start_SP = SP;
    
    *(unsigned char*)SP = 0xAA;
    ++SP;
    
    /* Do stuff */
    
    if ((SP - 1) != start_SP) {
        /* SP isn't pointing where it should be. */
    } else if (*(unsigned char*)(SP - 1) != 0xAA) {
        /* SP underflowed or something else happened. */
    }
    

Children
  • I should have mentioned that I need to try and maintain MISRA-C compliance.

    unsigned char start_SP = SP;
    MAIN.C(91): error C247: non-address/-constant initializer

    But the typecasting inspired another means.

    void main(void)
    {
      *(uint8_t data *)SP = 0xAAu;
      SP++;
    
      ...
    
      if((SP != &stackbot[0]) || (*(uint8_t data *)(SP-1) != 0xAAu))
      {
        //fail
      }
    }
    

    'stackbot' I stuck in the startup file and defined it in the header file as:

    extern uint8_t const idata stackbot[];
    

    I needed to put the 'data' keyword in there because the compiler must have thought it was generic pointer, and stuffed all sorts of useless instructions in there.

    It compiles and runs like it should. The thing I can't figure out is what is causing the compiler to put in extra instructions...

       267:                 if((SP != &stackbot[0]) || (*(uint8_t data *)(SP-1) != 0xAAu))
    C:0x0264    AF81     MOV      R7,SP(0x81)
    C:0x0266    7E00     MOV      R6,#xFPage(0x00)
    C:0x0268    747E     MOV      A,#STACKBOT(0x7E)
    C:0x026A    B5070D   CJNE     A,0x07,C:027A
    C:0x026D    EE       MOV      A,R6
    C:0x026E    B40009   CJNE     A,#xFPage(0x00),C:027A
    C:0x0271    E581     MOV      A,SP(0x81)
    C:0x0273    14       DEC      A
    C:0x0274    F8       MOV      R0,A
    C:0x0275    E6       MOV      A,@R0
    C:0x0276    64AA     XRL      A,#EMI0CN(0xAA)
    C:0x0278    6007     JZ       C:0281
    

    I'm using the compact memory model

  • if((SP != (uint8_t)&stackbot[0]) || (*(uint8_t data *)(SP-1) != 0xAAu))
    

    That fixed it!
    Thanks for the help.

  • I screwed this up badly.
    I should have incremented SP, then put in the 0xAA pattern. Then the SP-1 down below should have simply been 'SP'.

    The stack pointer always increments before something gets pushed onto the stack.

    (I inadvertently stuffed 0xAA into a variable, instead of onto the actual stack bottom)
    Someday someone will also want to do this, and it would be easier if it were posted correctly.