This is what I got when compiling the two code versions (I don't have an MSP 
device with text output capability at hand right now, so I can't confirm that 
the result is different.):



#define PRR_SCALE 255
uint8_t a = 3;
uint8_t b = 4;
uint8_t prr;
prr = (PRR_SCALE * a) / b;
    40ce:       3c 40 fd ff     mov     #-3,    r12     ;#0xfffd
    40d2:       2a 42           mov     #4,     r10     ;r2 As==10
    40d4:       b0 12 fa 6f     call    __divmodhi4     ;#0x6ffa
    40d8:       0f 4c           mov     r12,    r15     ;
printf("prr: %u\n", prr);
    40da:       7f f3           and.b   #-1,    r15     ;r3 As==11
    40dc:       0f 12           push    r15             ;
    40de:       30 12 c0 40     push    #16576          ;#0x40c0
    40e2:       b0 12 9c 67     call    printf          ;#0x679c
    40e6:       21 52           add     #4,     r1      ;r2 As==10



As we can see, the compiler directly calculates the result of 255*3 to -3 
(0xfffd). And here is the problem. Somehow the 255 gets interpreted as -1 
signed 8-bit instead of 255 unsigned 16 bit.
I only wonder why the wrong result of the following division is reported to be 
0. FFFD/4 gives 3FFF (= FF) for me and not 4000 (=00)


uint8_t a = 3;
uint8_t b = 4;
uint8_t c = 255;
uint8_t prr;
prr = (c * a) / b;
    40f2:       02 12           push    r2              ;
    40f4:       32 c2           dint                    
    40f6:       03 43           nop                     
    40f8:       f2 43 30 01     mov.b   #-1,    &0x0130 ;r3 As==11
    40fc:       f2 40 03 00     mov.b   #3,     &0x0138 ;#0x0003
    4100:       38 01 
    4102:       1f 42 3a 01     mov     &0x013a,r15     ;0x013a
    4106:       32 41           pop     r2              ;
    4108:       0c 4f           mov     r15,    r12     ;
    410a:       2a 42           mov     #4,     r10     ;r2 As==10
    410c:       b0 12 fa 6f     call    __divmodhi4     ;#0x6ffa
    4110:       0f 4c           mov     r12,    r15     ;
printf("prr: %u\n", prr);
    4112:       7f f3           and.b   #-1,    r15     ;r3 As==11
    4114:       0f 12           push    r15             ;
    4116:       30 12 c0 40     push    #16576          ;#0x40c0
    411a:       b0 12 9c 67     call    printf          ;#0x679c
    411e:       21 52           add     #4,     r1      ;r2 As==10

Here the multiplication is done first and then the division. Straight and 
correct. And much larger ;)


After re-reading the original post at 'StackOverflow', I noticed that the 
original poster did not mention the compiler he used. All he said was that it 
was an MSP430 compiler used for the contiki(?) os.
It is possible that this whole thing is not MSPGCC related at all. But looking 
at the result above, chances are it is an mspgcc he's using.


p.s.: in theory, the whole calculation could be done at compile time, in both 
cases, since all values are known and no variable is declared volatile.
While the compiler does not bother to load the initial multiplicants into a 
register variable (even in the second version, so the compiler noticed that the 
values are never needed again), it does not go go far enough to 
eliminate the multiplication in the second case and also in both cases the 
following division totally. 

p.p.s.: I'm still using the mspgcc version from 2006-05-02 as most of my code 
base was built on this and I never bothered updating, because I then would have 
to validate all projects again. (I'll do so when I have to 
rebuild most of the libs for the new 54xx processors anyway) So perhaps someone 
can confirm my results with a more recent version.


----- Ursprüngliche Nachricht -----
Von: Hardy Griech
An: [email protected]
Gesendet am: 29 Apr 2009 21:48:11
Betreff: Re: [Mspgcc-users] Fwd: DEFINEd value messes up 8-bit multiplication. 
Why?]

JMGross wrote:
:
> The second approach does an 8x8 bit multiplication, resulting in a 16 bit 
> intermediate result. This delivers the correct value to the following 
> division.
> 
> But in the first approach, the compiler could optimize the whole thing to a 
> 
> ((A<<8)-A)
 >
 > which is faster and smaller than a multiplication with 255.
 > Unfortunately this might be done on 8 bit range, dropping the upper 8
 > bit,
:

Also this seems to be elegant, it is wrong, because uint8_t has to be 
promoted to int, which is 16bit and will yield the correct result in 
both cases.

It seems, that mspgcc is doing something wrong with int promotion!?

Also it seems to be an mspgcc bug, because a native gcc3.2.3 compiler on 
Debian/386 showed the correct results.

Hardy


Reply via email to