Local Value Corruption on MPC5675K | Stack pointer alignment

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Local Value Corruption on MPC5675K | Stack pointer alignment

Jump to solution
1,620 Views
dhirajshetty
Contributor I

Greetings,

 

We're running uC/OS-II on the MPC5675K and are facing a few issues in development. We're using CW IDE 10.5

 

I have two questions in particular and would greatly appreciate if someone can help us debug or resolve the issue. Thanks in advance!

 

Question 1

 

At some points in task execution, we notice that the values of global variables and local variables are not in agreement.

 

For example, as part of the task, we read the global value and store it into the local variable.

 

However, at certain times, we notice that these values are different from each other.

 

We have ensured that non-atomic accesses are not the issue, since we have kept mutexes in place.

 

Also, this issue occurs when the system is handling a lot of interrupts (FlexCAN, UART).

 

Any pointers on how to debug this?

 

Question 2

 

To comply with the EABI, does the stack pointer need to be 8-byte aligned or 16-byte aligned, for Power e200z760n3?

 

Also, depending on that, could someone provide an example on how to correctly set up the stack frame for context switching?

 

Thanks once again.

 

Any help is much appreciated.

Labels (1)
0 Kudos
1 Solution
1,126 Views
stanish
NXP Employee
NXP Employee

Hi Dhiraj,

Yes, stack frame has to be 16 bytes aligned.

You can inspire by the interrupt prologue/epilogue generated by the compiler:


;   13: 

;   14: __declspec(interrupt) 

;   15: void TestIsr(void) 

;   16: {

//interrupt prolog

stwu     rsp,-160(rsp)

stw      r0,36(rsp)

mfmsr    r0

oris     r0,r0,0x0200

mtmsr    r0

evmergelohi r0,r0,r0

stw      r0,32(rsp)

mfctr    r0

stw      r0,16(rsp)

mfxer    r0

stw      r0,20(rsp)

mfcr     r0

stw      r0,24(rsp)

mflr     r0

stw      r0,28(rsp)

evstdd   r3,40(rsp)

evstdd   r4,48(rsp)

evstdd   r5,56(rsp)

evstdd   r6,64(rsp)

evstdd   r7,72(rsp)

evstdd   r8,80(rsp)

evstdd   r9,88(rsp)

evstdd   r10,96(rsp)

evstdd   r11,104(rsp)

evstdd   r12,112(rsp)

li       r0,152

evstddx  r31,rsp,r0

li       r0,144

evstddx  r30,rsp,r0

li       r0,136

evstddx  r29,rsp,r0


//...jump to a ISR or execute ISR code here


//interrupt epilog

li       r0,152

evlddx   r31,rsp,r0

li       r0,144

evlddx   r30,rsp,r0

li       r0,136

evlddx   r29,rsp,r0

evldd    r3,40(rsp)

evldd    r4,48(rsp)

evldd    r5,56(rsp)

evldd    r6,64(rsp)

evldd    r7,72(rsp)

evldd    r8,80(rsp)

evldd    r9,88(rsp)

evldd    r10,96(rsp)

evldd    r11,104(rsp)

evldd    r12,112(rsp)

lwz      r0,16(rsp)

mtctr    r0

lwz      r0,20(rsp)

mtxer    r0

lwz      r0,24(rsp)

mtcrf    0xff,r0

lwz      r0,28(rsp)

mtlr     r0

evldd    r0,32(rsp)

addi     rsp,rsp,160

rfi


Hope it helps.

Stan

View solution in original post

0 Kudos
10 Replies
1,126 Views
stanish
NXP Employee
NXP Employee

Hello,

SPE/SPE2 instructions are described in SPE2PIM document available here:

http://cache.nxp.com/files/32bit/doc/ref_manual/SPE2PIM.pdf?fpsp=1&WT_TYPE=Reference%20Manuals&WT_VE...

The issue you observe is caused by the fact that  R0 has special meaning in most of store instructions - destination address is 0x0 instead of a real register value.

See the instruction description:

evstdd_instruction.png

So the solution is easy - use other register then R0 as a destination address register

Hope it helps.

Stan

0 Kudos
1,126 Views
stanish
NXP Employee
NXP Employee

Hello,

regarding Q#1:

If SPE compiler support is enabled the compiler might use optimization which takes advantage of the unused high half of the gpr vectors as storage and therefore avoids loading and storing to the stack.


It may cause some problems if interrupt prolog/epilog does not save/restore entire 64bit GPRs.

So it would be worth trying to disable this optimization by pragma below:

#pragma spill_to_spe off

or you can pass it via command line:

-pragma "spill_to_spe off"

Stan

0 Kudos
1,126 Views
dhirajshetty
Contributor I

Hi Stan,

Our interrupt prologue/epilogue is saving and restroring the entire 64-bit GPRs.

I took a look at the stack frame defined as part of the "Stack Frame Requirements" under "Function Calling Sequence" in the document Power-Arch-32-bit-ABI-supp-1.0-Embedded .

Do you have any suggestions/pointers about the rules to be followed for stack frame population by Interrupt handlers?

Are we expected to adhere to the stack frame requirements mentioned in the above document? Or does it just suffice that we save and restore all the register values, but using a stack frame not as defined by the document above?

Thanks in advance.

0 Kudos
1,127 Views
stanish
NXP Employee
NXP Employee

Hi Dhiraj,

Yes, stack frame has to be 16 bytes aligned.

You can inspire by the interrupt prologue/epilogue generated by the compiler:


;   13: 

;   14: __declspec(interrupt) 

;   15: void TestIsr(void) 

;   16: {

//interrupt prolog

stwu     rsp,-160(rsp)

stw      r0,36(rsp)

mfmsr    r0

oris     r0,r0,0x0200

mtmsr    r0

evmergelohi r0,r0,r0

stw      r0,32(rsp)

mfctr    r0

stw      r0,16(rsp)

mfxer    r0

stw      r0,20(rsp)

mfcr     r0

stw      r0,24(rsp)

mflr     r0

stw      r0,28(rsp)

evstdd   r3,40(rsp)

evstdd   r4,48(rsp)

evstdd   r5,56(rsp)

evstdd   r6,64(rsp)

evstdd   r7,72(rsp)

evstdd   r8,80(rsp)

evstdd   r9,88(rsp)

evstdd   r10,96(rsp)

evstdd   r11,104(rsp)

evstdd   r12,112(rsp)

li       r0,152

evstddx  r31,rsp,r0

li       r0,144

evstddx  r30,rsp,r0

li       r0,136

evstddx  r29,rsp,r0


//...jump to a ISR or execute ISR code here


//interrupt epilog

li       r0,152

evlddx   r31,rsp,r0

li       r0,144

evlddx   r30,rsp,r0

li       r0,136

evlddx   r29,rsp,r0

evldd    r3,40(rsp)

evldd    r4,48(rsp)

evldd    r5,56(rsp)

evldd    r6,64(rsp)

evldd    r7,72(rsp)

evldd    r8,80(rsp)

evldd    r9,88(rsp)

evldd    r10,96(rsp)

evldd    r11,104(rsp)

evldd    r12,112(rsp)

lwz      r0,16(rsp)

mtctr    r0

lwz      r0,20(rsp)

mtxer    r0

lwz      r0,24(rsp)

mtcrf    0xff,r0

lwz      r0,28(rsp)

mtlr     r0

evldd    r0,32(rsp)

addi     rsp,rsp,160

rfi


Hope it helps.

Stan

0 Kudos
1,126 Views
zhouxian
Contributor III

Hi .Where can I find the manual for the spe instructions like evstdd / evldd. I cannot get evstdd r4, 8(r0) to work when r0 points to memory area.  But it passes compiling and linking process.I use MPC5675K evb and booke instruction set.

0 Kudos
1,126 Views
dhirajshetty
Contributor I

Hi Stan,

Thanks very much for this.

I also tried to let the compiler generate the prolog/epilog for me by using __declspec(interrupt) but I do not see the vector instructions (evstdd/evldd) like yours.

I am seeing se_stw and se_lwz in my compiler generated code.

Any pointers?

Thanks once again.

0 Kudos
1,126 Views
stanish
NXP Employee
NXP Employee

Other option is to declare interrupt routine with "save_spe" option:

__declspec(interrupt save_spe)

void testIsr()

{

...

}

Stan

0 Kudos
1,126 Views
dhirajshetty
Contributor I

Hi Stan,

Thank you very much for your help and patient support.

We seemed to have found the problem.

In our ISR Prolog/Epilog, some instructions (e_add2i.) were modifying the state of the Condition Register CR0 just after the interrupt arrived. This effectively changed the task's state from the time that it was interrupted.

We were then saving the wrong CR value in the task's context.

So, when we restored the tasks context, maybe it was branching absurdly due to wrong CR0, leading to strange code behaviour.

After accounting for the CR0 change in our Prolog/Epilog, it looks like the problem seems to have been solved.

Please do let us know what you think about this.

Thank you once again for your continued support.

Regards,

Dhiraj

0 Kudos
1,126 Views
stanish
NXP Employee
NXP Employee

Hi Dhiraj,

This prolog/epilog is generated by the compiler automatically e.g. if it detects usage of 64bit SPE  vector data type:

#include <spe.h>

__ev64_opaque__ ev64SaveReg;

void test()

{

  asm("nop");   

}

__declspec(interrupt)

void TestIsr(void)

{

ev64SaveReg = __ev_create_u64(0); 

test();   

}

Stan

0 Kudos
1,126 Views
dhirajshetty
Contributor I

Hi Stan,

Thank you very much for your reply.

We will try this and update you.

Regards,

Dhiraj

0 Kudos