- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
ARM instruction manual referring Cortex-M0 says there is a single instruction possibility muls R0,R1,R0
I can't figure out if it's signed/unsigned operation.
I try to multiply signed char with constant , like (signed_char * 40000 and I got always wrong value.
I tried (int32)signed_char * 40000 and this also give wrong value
I found that regardless of the C formula (int32) or (uint32) the compiler translates it to thumb instruction mul R0,R1
Thanks
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This may be a compiler problem, you could always do inline ASM and
handle the issue yourself.
Consider filing a CASE (and post back what you found out to bebefit the forum) -
“Support”
“Technical Support”
“Create a MyCase”
Regards, Dana.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Do You know about the result of mul instruction? Signed or unsigned?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
According to http://infocenter.arm.com/help/topic/com.arm.doc.dui0497a/BABCFBDJ.html , muls works with signed and unsigned operands.
According to http://infocenter.arm.com/help/topic/com.arm.doc.dui0204f/Cihihggj.html , this is true also for mul. (mul and muls differ only in how flags are updated).
I'm not sure whether the cast in '(int32)signed_char * 40000' is for the result or the first operand. If its the former, than the multiplication is done signed (because you have a signed char) and then casted. This might result in wrong values (depending on what you have in the char).
Can you post a small example where you get wrong results?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
function in C:
void MoveValve(int8 percent){
int32 tmp;
tmp = pDataConfig->SerVoCurrentPWM - ((int32)(percent*(SERVO_MIN_OPEN*(1<<26)/100)) >> 26);
}
SERVO_MIN_OPEN - constant
SERVO_MIN_OPEN*(1<<26)/100 = 1006632960 = 0x3C000000 (6 zero's)
pDataConfig->SerVoCurrentPWM - uint16
why this function produce following code:
ldr r1, .L65
505 0004 084B ldr r3, .L65+4
506 0006 4843 mul r0, r1
507 .LVL49:
508 0008 1B68 ldr r3, [r3]
509 000a 8016 asr r0, r0, #26
510 000c 9A8B ldrh r2, [r3, #28]
511 000e 111A sub r1, r2, r0
I pass percent value of -100 . assembly multiplies (126 * constant) and returns positive output.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Another problem:
1500*(1<<26)/100= 15*(1<<26)=0x3C000000
compiler makes 0x011EB851
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Shifting 100 or -100 left by 26 positions will exceed the 31 bits (one is used for sign) you have got for the intermediate result, so you will ALWAYS get a wrong result. Use the windows calculator, set it to "Programmer's Mode", set the width to DWord and start calculating. Watch the bit patterns.
How to get out of this? First try could be to use float math. If you'd lije to optimize size and speed you will have to arrange your calculation into some statements and group them in a way that no overflow may occure.
As I suspect the value of shifting to improve the precision of the result must be reduced, too
Bob
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks. My calculator calculated wrong value
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
One thing I found awhile ago. I had some code as following
uint32 value;
value = 1<< 24;
and the value is wrong.
needs to be
value = (uint32)1 << 24;
Not sure if that can be problem with GCC now.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Also note that the result of shifting of a signed variable is compiler dependent. So it may not return the value you expected.