This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Setting stack pointer

Hi,

I'm new to the C6727 (and TI chips in general) and I was really hoping not to have to code any assembly on this platform as it seems a bit tricky, but here I am!

Our C-code runs as a module that gets called from a system which we have no control over. It is uncertain how much stack memory is available to us, and since we need quite a bit of stack I would like to set the stack pointer to a place in memory which is allocated for us. In pseudocode it would look like so:

void ModuleEntry(void* pOurMemory) {

// Save stack pointer (B15) somewhere and point B15 to pOurMemory

asm("...");

// Call our code

DoStuffThatPutsLotsOf MemOnStack(); 

// Restore B15

asm("...");

}

Are there any pitfalls on doing this on the C6727? Also, if someone would be so kind as give me some pointers on how to write this in assembly I'd appreciate it. Especially on how to access C variables from asm() since it does not seem to have the option to take C variables as input and output parameters, as is possible with asm() statements on some other compilers.   

Thanks,

TINewbie

  • TINewbie,

    In general, it's a very bad idea to do inline assembly.  If you are going to take this type of approach, you should implement it as a full assembly language function, not as a C function with inline assembly calls.  When you put a asm(" "); statement in your C code, the compiler just pastes in the ASM instruction wherever that asm(" "); statement appears. In the best case, this places an optimization barrier in your code, so you might consume more cycles than necessary.  In the worst case, it will get moved by the optimizer to a location that is slightly different than where you think it should go.  This can be catastrophic.

    With that being said, let's try to avoid assembly language altogether, if we can.  Let me make sure I fully  understand your use case. As I understand it, you're responsible for a function in a larger application.  The top level application calls you at certain times, but you don't know how much memory will be available on the system stack when you are executed, so you have your own memory that you want your code, and the stuff it calls to be able to use as stack.  Please let me know if I have misunderstood this, so far.  Here are some follow-up questions:

    • Doesn't the overall system have to have some max limit of stack space it uses, otherwise, it crashes?  I'm just curious about what the advantages are of segmenting your memory in this way. For example,  Say the top level application has allocated 4 K of memory for it's stack, and you have 1 K for your function .  (The actual values may be much larger or much smaller, I'm just using these as an example.)  This means that the max stack usage by the to level application never exceeds 4K.  So, why not just tell the top level application to allocate 5K of memory for the stack?  The top level app still won't exceed using 4K, which means, in the worst case, your function would have at least 1K of stack space left when it executes. You may have a valid reason for doing it this way.  Maybe these different stack sections have different memory characteristics.  I'm just trying to be sure I understand the overall view.
    • There will be issues with debugging this code, if you ever have to.  The call stack won't work, because it uses SP relative access to determine the calls on the stack.  If your stack is segmented in this way, there's no way for the debugger to resolve the entire call stack.
    • Is this a multithreaded application?  If so, how do the threads use the stack?  I'm worried about a case where your code is entered, and the stack pointer is moved, and then a thread switch occurs without the stack pointer being set back to whatever the new thread expects it to be.

    In response to your question about how to read variables from assembly, it somewhat depends on the type of variables. For a global variable, in an assembly file, you can just use the .global identifier.  Local variables are stored on the stack, so you have to know the offset of from the stack pointer to the variable.  If the values are function parameters, their location is determined by the Register Argument conventions.  All of these are discussed in the C6000 Compiler Guide.  See the links below.

    Here are a few links:

    C6000 Compiler Guide: http://www.ti.com/litv/pdf/spru187t

    C6000 Assembly Language Tools User's Guide http://www.ti.com/litv/pdf/spru186v

    Regards,
    Dan

     

     

     

     

     

     

     

  • Hi Dan,

    Thanks a lot for your answer.

    "In general, it's a very bad idea to do inline assembly.  If you are going to take this type of approach, you should implement it as a full assembly language function, not as a C function with inline assembly calls."

    Yes, an assembly function may be preferable here. I've actually had better performance on other platforms (but with the optimization issues you mention) using inline assembly, so that's why I considered it to begin with. Performance is not as big of an issue here so an assembly wrapper for my c code sounds better.

    "As I understand it, you're responsible for a function in a larger application.  The top level application calls you at certain times, but you don't know how much memory will be available on the system stack when you are executed, so you have your own memory that you want your code, and the stuff it calls to be able to use as stack."

    Exactly.

    "Doesn't the overall system have to have some max limit of stack space it uses, otherwise, it crashes?"

    It most certainly must have. Problem is, we don't know how much stack memory is available and we can't tell the top level app to allocate stack memory for us. The provider of the top level app does not encourage using the stack at all and recommends that all variables should be put in a memory space that we can request from the top level app. The issue with this is that the code I'm moving to this platform is a whole framework which run on several platforms using standard C, and then of course also use the stack. So that's no real alternative.

    "There will be issues with debugging this code, if you ever have to."

    Good point. I had not considered that. Hopefully no big deal though.  

    "Is this a multithreaded application?  If so, how do the threads use the stack?"

    I've also worried about this. The application may very well be multithreaded as we're not the only module running on the system. However, I would guess that all registers are preserved at a context switch, no? I know that may be more of a question for the top level app people...

    "In response to your question about how to read variables from assembly, it somewhat depends on the type of variables."

    This would be another advantage with using an assembly function instead I guess. Then I won't have to reach those variables directly but as input variables as determined by the calling convention.

    I guess my problem is that I'm sandwiched between a platform I know very little about and an application which I also know very little about... Thanks for the links, I'll look into them and get started on writing that assembly function.

    Cheers,

    TINewbie

     

     

  • Just one additional comment about your statement  "However, I would guess that all registers are preserved at a context switch, no? I know that may be more of a question for the top level app people..."


    I think that a multi-threaded application probably uses separate "stacks" for each thread, and the registers are preserved on each.  The "stacks" that I am referring to are different than the one that we are discussing.  Now that I think about it, what you are asking about doing is similar to what an OS would do when it switches contexts.  It would likely save the context on a stack, and then in the context switch, change the stack pointer to pint to the stack for the next thread, and then restore the register context that is stored there.  So, it sounds reasonable to do what you are wanting to do. 

    Regards,

    Dan

     

  • Yep, sounds reasonable. Thanks Dan.

    Cheers,

    TINewbie