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

Problem:- Calling a subroutine that did NOT return to original caller

Hi all,

I am cracking my head to see why Keil's uVision2 has this problem?

Calling a subroutine callee on the first time, returned to the original Caller with no problem.

Calling it 2nd time and follows, caused a critical fault of NOT returning to original caller's address

SP_max: 032

I have a mixture of C & Assembly coding. where Timer interrupts happen under C and most logical functions are done under .A51s.

What could be the cause of calling a subroutine which doesn't return to the original caller's address?

Please advise.

Head scratching,
James

  • Either you don't execute the RET instruction, or the return value has been corrupted. The return addresses are stored on the (real, hardware, internal) stack. Are you sure they don't get trampled?

    Where does your program go on the RET, if not to the proper spot?

    Does your program actually execute this procedure, or is it already off doing something odd (running wild, stuck in an interrupt handler, etc)?

    Is your program memory space writable? Could the code itself actually get trampled?

  • "The return addresses are stored on the (real, hardware, internal) stack. Are you sure they don't get trampled?"

    This can easily happen with bad or uninitialised Generic Pointers in C51: the 1st byte of a Generic pointer identifies the target memory type, and a value of zero indicates IDATA...
    Need I say more?

  • "What could be the cause of calling a subroutine which doesn't return to the original caller's address?"

    Also check those assembly functions, ensuring that every PUSH has a matching POP.

  • I said "every PUSH has a matching POP"

    ...and that there is balance in all operations that are equivalent to PUSH/POP from the perspective of adjusting the stack pointer.

  • ---> Andy Neil wrote:-
    "The return addresses are stored on the (real, hardware, internal) stack. Are you sure they don't get trampled?"

    This can easily happen with bad or uninitialised Generic Pointers in C51: the 1st byte of a Generic pointer identifies the target memory type, and a value of zero indicates IDATA...
    Need I say more?

    ### Thanks for the reply guys. Where do I check on the Simulated Debugger of uV2 if my generic pointers are not well initialized, and the location of IDATA? I believe this is possible due to some unseen real address values declared under Main.c. The wrong return address seemed to bring the so called corrupted SP back to a similar wrong spot all the time even if I add in some redundant NOPs in between the lines of code. I'm using P87LPC767 with 4K OTP ROM size by the way.

    Cheers,
    James

  • "Where do I check on the Simulated Debugger of uV2 if my generic pointers are not well initialized"

    You do that by looking at your source code, and making sure that every variable is initialised before it is used!
    Unfortunately, C51 does not give any warnings on this - you could try compiling with MSVC or Borland, or use a checker such as lint

    When the uVision displays a pointer value, it will use a prefix to indicate what memory type it points to - D: for DATA, X: for XDATA, I: for IDATA, etc

    "Where do I check ... the location of IDATA"

    You don't.
    You are concerned about whether your pointer is incorrectly addressing it; not about where it is!

    The question suggests, however, that you need to review the 8051's memory architecture:
    http://www.semiconductors.philips.com/acrobat/various/80C51_FAM_ARCH_1.pdf

    and read the C51 Manual sections abou Keil's extensions to handle it.

    See also the other Required Reading in this thread:
    http://www.keil.com/forum/docs/thread3387.asp

  • Another possibility is that your stack is overflowing, particularly if you are using a significant amount of idata as variable storage. You could try filling the top few bytes of the stack with some known value right at the beginning of your program, check to see if these have been overwritten when your function fails to return.

    Stefan

  • Dear all,

    Thanks for all the kind advice. Very useful.

    found the problem cause. In fact, it is really the stack overflowing into my own data registers which caused the wrongly returned address.

    Well... I didn't know that 8051's stack 'eats' down from 00 of RAM instead of 'eating' upwards like MOT's. For Microchip, there is a separate set of memory for stacks??? That's what I remember.

    Thanks again guys!

    Cheers,
    James

  • "Well... I didn't know that 8051's stack 'eats' down from 00 of RAM instead of 'eating' upwards like MOT's."

    The stack grows up from wherever you set the stack pointer. When it passes 0xff it wraps to zero and overwrites the register banks.

    Stefan

  • "For Microchip, there is a separate set of memory for stacks???"

    No matter how you implement the stack, you will have problems if it overflows!