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