Hello!
First of all - I am only a C-newbie. Please keep your answers easy.
Ich found a bug in the compiler MSP430-GCC: The software multiplication (16bits
* 16 bits = 32 bits) produces wrong results. The point, where the
error occurs is located and a hint for the solution will be presented.
The used operating system is Solaris 5.7, the version of msp430-gcc is 3.2.2.
The target is any MSP430 without hardware multiplier - e.g.
MSP430x311-series.
A minimal example:
////////////////////////////////////////
#include <msp430x31x.h>
int main(void)
{
long int multi(int a, int b);
int a = 0x1234;
int b = 0xabcd;
long int res;
/*hide the multiplication in a function
otherwise the compiler optimizes it away*/
res = multi(a,b);
/*dummy-operations - otherwise the result would have been never used
and would be optimized away*/
*((unsigned int*)0x200) = res;
*((unsigned int*)0x202) = res >> 16;
return 0;
}
long int multi(int a, int b)
{
return (long int)a * b;
}
////////////////////////////////////////
The used Makefile:
////////////////////////////////////////
NAME=mspgcc_mulbug
CPU = msp430x311 #no hardware multiplier
ASMOPT = -mmcu=${CPU}
COPT = -mmcu=${CPU} -O2 -Wall -g
CC = msp430-gcc
${NAME}.elf: ${NAME}.o
$(CC) -mmcu=${CPU} -g -o $@ $^
msp430-objcopy -O ihex $@ ${NAME}.a43
msp430-objdump -DS ${NAME}.elf >${NAME}.lst
${NAME}.o: ${NAME}.c
msp430-gcc ${COPT} -c $<
clean:
rm -f ${NAME}.elf ${NAME}.a43 ${NAME}.lst ${NAME}.ini *.o
////////////////////////////////////////
The point, where the bug occurs is marked in the source code. During "make" a
list file is created. An extract of the buggy code follows:
////////////////////////////////////////
return (long int)a * b;
f862: 0a 4f mov r15, r10 ;
f864: 0c 4e mov r14, r12 ;
f866: 0b 43 clr r11 ;
f868: 0a 93 cmp #0, r10 ;subst r3 with
As==00
f86a: 01 34 jge $+4 ;abs dst addr
0xf86e
f86c: 3b 43 mov #-1, r11 ;subst r3 with
As==11
f86e: 0c 43 clr r12 ;
f870: 0c 93 cmp #0, r12 ;subst r3 with
As==00
f872: 01 34 jge $+4 ;abs dst addr
0xf876
f874: 3d 43 mov #-1, r13 ;subst r3 with
As==11
f876: b0 12 84 f8 call #-1916 ;#0xf884
////////////////////////////////////////
The final "call" on address 0xF876 is the jump to the software multiplication
routine. The listed code shows both conversions of "a" (register R10)
and "b" (register R12) from type "int" to "long int". ("b" is converted
automatically.)