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.

Interrupting Assembly Function with C Code Interrupt

I am running code on a 5509A, and I am not using DSP/BIOS.

I have a periodic interrupt triggered on the nINT0 pin (external interrupt) that occurs every 256us.  The code in that interrupt runs for about 40us.

I am processing data in between that interrupt.  Part of that processing calls for my code to accumulate a 64-bit value (stored in a struct).  I use an assembly code function to add two 64-bit numbers.  Inevitably, the interrupt eventually fires while I am in this assembly function.  Usually this causes no problem, but it apparently destroys one, or some, of the registers on occasion.  

The result seems to be a return of the same number that was passed (this is an accumulation function) so that that call does not accumulate.  The end result is that if I am accumulating 14 results, my final accumulation includes only 13 of them.

This accum function is called in a for loop to sum up an array for averaging.  I have verified that it has looped in the for loop the correct number of times when it fails, but it is as if one of the 14 values was not accumulated.

It seems that when the C coded interrupt hits, the context save is not quite complete.  I am experimenting with pushing and popping all registers at entrance and exit of the interrupt, but that is an ugly solution.  My understanding of SPRU281f Section 6.6.3 is that a properly declared C interrupt should take care of context saving.

Is there something different when C code interrupts assembly code?

  • Yes, you need to preserve the registers that modified in the ISR.

    Please see the two document for detais 

    1) CPU Reference Guide section 4.4 (http://focus.ti.com/lit/ug/spru371f/spru371f.pdf)

    2) Compiler User's Guide section 6.3 ~ 6.6 (http://focus.ti.com/lit/ug/spru281f/spru281f.pdf)

     

    Regards,

    Peter Chung

  • I do not understand how the answer applies to this specific situation.

    The OP describes a situation in which the interrupt handler is coded in C, and I assume that the interrupt keyword and pragma are being used.  Thus, I would expect the C compiler to preserve all registers modified in the ISR.  In fact, I have witnessed that the code generated by the compiler is quite efficient, because a small ISR that calls nothing else will save minimum state because it alters minimal state, which an ISR that calls other C subroutines will save much more state.  Either way, if the ISR is entirely written in C and does not call assembly, then I do not understand why any extra steps would be needed.

    The OP describes that the assembly code is the "main" code which runs outside the C interrupt.  I also do not understand how the interrupted code can do anything about the ISR besides block interrupts when accessing read/write globals that are not atomic.

    Peter, can to confirm whether a pure C interrupt routine would need to preserve registers, and how this would be done in the C language?

  • As an added bit of information, the C interrupt does call assembly coded functions and all assembly coded functions preserve all registers used.

  • I have been looking at the generated C code for my interrupt (coded in C).  The very first thing that it does, before pushing anything, is set and clear bits in the three status registers.  With these bits changed before any context save, it seems that certain code that depends on non-default bit values will always be at risk when calling C interrupts.

    Is my understanding correct?

    It seems that a workaround might be to interrupt with assembly code and call the C function.  If context saving is left to me, then I can be sure to properly save the context.

    Any thoughts?  If the first point is true, shouldn't this be addressed in the documentation?  I have been unable to find anything about this particular issue.

  • As a follow-up, my point is that the assembly code that was interrupted was performing 40-bit arithmetic and the M40 bit would have been cleared on C code interrupt return.

  • I noticed the same status register issue, but no worries.  Interrupt handling on the C55x will save those status registers on the stack before your interrupt begins executing.  Afterwards, RETI will restore the status register bits perfectly.  This is documented in section 4.4 of the TMS320C55x DSP CPU Reference Guide, SPRU371F.  You'll notice that some status registers are pushed on the stack a few instructions later, and those are status registers which are not automatically saved on the stack.

    I'm not saying there isn't potential for a bug somewhere in here, but the basic fact that certain status register bits are modified without visibly being saved first is not a problem due to the fact that they've already been saved.

  • Brian,

    Thanks for that.  I had missed the ST[0-3] saves in that section.  It certainly helps to eliminate that as an issue.

    Mark

  • Careful, it's not ST[0-3] that are saved, but a subset.  Only ST[0-2]_55 are saved.  If you look again at the C Compiler output for an interrupt routine, you may see that ST3_55 is manually saved on the stack (if it is modified).

  • You are correct sir!  

    Even after all of these years my brain still sees that three status registers are saved and equates that to saving up to ST3; my brain doesn't always like to start at zero!

    Thanks for the catch.