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.)

Reply via email to