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.

ASP and NASP instruction within an assembly routine

Other Parts Discussed in Thread: TMS320F28335

Hi everybody,

I'm using a TMS320F28335 DSP and a TMS320C2000 C/C++ Codegen PC v5.2.1.

Trying to fix a problem in an assembly routine (two different possible solutions), some doubts are now arising on why the second solution doesn't work.

Problem: inside the assembly routine after a PUSH ST0 (16-bit register) there is a PUSH XT (32-bit register). The latter overwrote ST0 on the stack because every 32-bit operation requires the stack to be evenly aligned; if not so, the processor would impose an even alignment storing the register at (SP-1), thus overwriting what was already there.

My first (and working) solution: add a PUSH ST1 after the PUSH ST0 to align the stack.

Second possible solution:

ASP

PUSH XT

...

POP XT

NASP

Unfortunately this doesn't work! The program goes completely crazy causing an "Illegal-instruction TRAP" (in my opinion very likely due to a misaligned stack).

I've been told by someone in TI it should work but I'm convinced it  is dangerous (risky).

My explanation below.

When the compiler generates assembly code for a C-written interrupt routine, it adds an ASP instruction firstly. This is well documented in the manual.

I imagine (please confirm) that in doing so the compiler relies on an even-aligned stack in the following generated assembly code.

Now, let’s suppose that an assembly routine (hand-written),  called from within this interrupt routine, uses in its turn ASP / NASP instructions: here I may see some problems.

_interruptFunction:

ASP

-----------------------------> Here the stack is even-aligned

LCR       #_handWrittenAssemblyFunction

----------------------------------------------------> Returning from the function, SP = 0x4, SPA = 0. The stack is still EVEN-aligned but SPA changed to 0

NASP

 

_handWrittenAssemblyFunction:

----------------------------------------------------> Suppose that here SP = 0x4, SPA = 1 (in ST1 register)

PUSH     ST0

----------------------------------------------------> SP = 0x5, SPA = 1

...

ASP

----------------------------------------------------> SP = 0x6, SPA = 1

PUSH     XT

...

POP       XT

----------------------------------------------------> SP = 0x6, SPA = 1

NASP

----------------------------------------------------> SP = 0x5, SPA = 0

...

POP       ST0

----------------------------------------------------> SP = 0x4, SPA = 0

LRETR

Any ideas / suggestions?

  • What you could do is a PUSH SP at the beginning of your handwritten assembly routine and a POP SP at the very end. This will make sure that the alignment status is consistent when you return to the calling C environment. But please take also into account, that an Interrupt request and service, which breaks into your handwritten assembly code can also mess up your stack treatment.

  • Yes, this is another option actually.

    Shouldn't a C-interrupt routine save the whole context (through the compiler)? A C-coded interrupt routine shouldn't mess up anything! I don't use hand-written assembly interrupt routine but only C-coded interrupt routines...

  • If I understand the function is called from within an ISR.  I think the issue is with nesting ASP/NASP.  The function's NASP may clear the SPA bit, but this is still needed by the interrupt when it performs its NASP.

    I would suggest adding an even number to the stack at the beginning of the function and then deallocating at the end.  This is what the compiler usually does and keeps the stack aligned.  The C  compiler will also keep the stack even aligned and interrupts will use ASP to force even alignment.  If you follow this rule for all functions then the stack will always be aligned.

     

    For example:

    When entering this function, stack is aligned - keep it that way by adding an even number to it then "backfill" into the stack using an offset.

    ;; Stack Usage:
    ;;
    ;;        |----------------| -+
    ;;     -4 |     notused    |  |
    ;;        |----------------|  |
    ;;     -3 |       SP       |  |
    ;;        |----------------| -+      
    ;;     -2 |       XT       |  |
    ;;        |----------------|  |
    ;;     -1 |       XT       |  |
    ;;        |----------------| -+

    _myfunction

         ADDB SP, #4

         MOV16 *-SP[-3], ST0

         MOV32 *-SP[-2], XT

    ...

    ...


        MOV16 ST0, *-SP[-3]

        MOV32 XT, *-SP[-2]

        SUBB SP, #4

            LRETR

     

    Pushing SP1 onto the stack will work also, but may cause confusion later down the line with "why are we saving off ST1" - someone may think it is not needed and remove it from the code.

    Cheers

    Lori

     

     

     

     

     

  • Thanks Lori, I like your way!

    Allow me just to amend your assembly:

    ;; Stack Usage:
    ;;
    ;;        |----------------| -+
    ;;     -4 |     notused    |  |
    ;;        |----------------|  |
    ;;     -3 |       ST0      |  |
    ;;        |----------------| -+      
    ;;     -2 |       XT       |  |
    ;;        |----------------|  |
    ;;     -1 |       XT       |  |
    ;;        |----------------| -+

    _myfunction

    ADDB  SP, #4

    MOV  *-SP[3], ST0

    MOVL *-SP[2], XT

    ...

    ...

    MOV  ST0, *-SP[3]

    MOVL XT, *-SP[2]

    SUBB SP, #4

    LRETR

    I'm a meticulous guy...

    Cheers

    Paolo

  • Paolo Benini said:
    Allow me just to amend your assembly:

    Thanks :) too many different assembly instruction sets in my head :)

    -Lori