Hi,
I've followed this mailing list time enough to know that is uncommon to find a
bug in the compiler and that the bugs are normally in the developer's code. I
think this is not a bug in GCC (the compiler). This is a bug in the use of
assembler inline to implement a function very specific for the MSP430
microcontroller. Sorry for my English. I usually don't write in English.
My team has find a bug in _BIC_SR_IRQ() (and all the functions that modify data
in the stack using assembler inline) when compiling with optimizations
activated (-O2, -Os) and when we call a function with five or more parameters
in the interrupt service routine where we later call _BIC_SR_IRQ().
Under this circumstances we see that the macro _BIC_SR_IRQ() have overwrite the
incorrect data in the stack instead of the Status Register stored. This is a
simplified version of code that expose the error:
-------------------------------- BEGIN sr_irq.c ------------------------------
int add_all(int a, int b, int c, int d, int e, int f)
{
return a + b + c + d + e + f;
}
volatile int g;
interrupt(TIMERA0_VECTOR) isr(void)
{
g = add_all(1,2,3,4,5,6);
_BIC_SR_IRQ(LPM4_bits);
}//isr
int main()
{
return 0;
}//main
--------------------------------- END sr_irq.c -------------------------------
I compile with this parameters:
$ msp430-gcc -mmcu=msp430x149 -o sr_irq.msp sr_irq.c -Wall -O2
sr_irq.c: In function `isr':
sr_irq.c:17: warning: concatenation of string literals with __FUNCTION__
is deprecated
I've seen in 'iomacros.h' that the macro '_BIC_SR_IRQ(LPM4_bits)' uses
'.L__FrameOffset_isr' to get the position of the Status Register based on the
stack needed by the function 'isr'. But the call 'add_all()' have 6 parameters
and the last two (5 and 6) are pushed in the stack too (4 bytes more). With
optimizations activated, the stack is set to the correct value (the value
coherent with '.L__FrameOffset_isr') after the instruction _BIC_SR_IRQ is
executed (too late). So, the instruction _BIC_SR_IRQ is modifying the incorrect
value in the stack. This is the generated code in assembler for the function 'isr':
.p2align 1,0
.global isr
.global vector_ffec
.type isr,@function
/***********************
* Interrupt Service Routine `isr' at 0xffec
***********************/
vector_ffec:
isr:
/* prologue: frame size = 0 */
.L__FrameSize_isr=0x0
.L__FrameOffset_isr=0x8
push r15
push r14
push r13
push r12
/* prologue end (size=4) */
push #llo(6)
push #llo(5)
mov #llo(4), r12
mov #llo(3), r13
mov #llo(2), r14
mov #llo(1), r15
call #add_all
mov r15, &g
/* #APP */
bic #llo(240), .L__FrameOffset_isr(r1)
/* #NOAPP */
add #llo(4), r1
/* epilogue: frame size=0 */
pop r12
pop r13
pop r14
pop r15
reti
/* epilogue end (size=5) */
/* function isr size 25 (16) */
.Lfe2:
.size isr,.Lfe2-isr
/********* End of function ******/
Here we can see that '.L__FrameOffset_isr' is 0x8 (4 push instructions in the
stack, needed for 'isr'), but the call to 'add_all' insert two push
instructions more. This is not counted in '.L__FrameOffset_isr'. If we don't
use -O2, after the "call #add_all' the compiler insert the 'add #llo(4), r1'
and the stack have again 8 bytes, and everything works ok. But with -O2 the
'add' instruction is inserted later and the macro _BIC_SR_IRQ, expanding to
"bic #llo(240), .L__FrameOffset_isr(r1)", is overwriting the incorrect data in
the stack.
I think that maybe the function _BIC_SR_IRQ() must be an intrinsic function
that can count the correct number of bytes in the stack when using
optimizations, because with assembler inline and '.L__FrameOffset_isr' with a
fixed value the compiler can put the 'ADD' of the stack pointer 'r1' in an
inconvenient place.
I know is unusual call functions inside interrupt service routines and very
unusual to have functions with a lot of parameters, but it is not incorrect
code. We have solved our particular problem reducing the number of parameters
in our function and sometimes using a macro expansion, but I think that is
better to have a correct implementation of _BIC_SR_IRQ() for all the situations
(including calling functions with a lot of parameters inside the interrupt
service routine) like I can see in other compiler implementations for MSP430.
I've tried, but I do not have sufficient skill to correct the code myself. I
hope someone here can do it. Thanks and greetings,
Mario Palomo Torrero