Hello
I'm using: mcb32stmf103rb6t The uvision3 V3.62c Realview MDK-ARM Version 3.23
In my program i need to multiply a series of 32bit ints. Very simple code:
int test1 = 0x01002000; int test2 = 0x03004000; test1 = test2*test1;
When i compile it and view the disassembly in debug mode is says: 129: int test1 = 0x01002000; 0x08004788 4D3F LDR r5,[pc,#252] 130: int test2 = 0x03004000; 131: 0x0800478A 4C40 LDR r4,[pc,#256] 132: test1 = test2*test1; 133: 0x0800478C 4365 MULS r5,r4,r5
The question then is: Why does it use "MULS" when the instruction does not exits in the cortex-m3? And why does it choose an instruction where the MSB are thrown away when when I need the MSB?
An explanation will be very much appreciated Regards Henrik
S is an optional suffix. If S is specified, the condition code flags are updated on the result of the operation.
The MULS is a valid thumb instructions (in some cases). Thumb2 includes all thumb instructions.
MULS Rd, Rd, Rm is allowed. MULS Rd, Rm, Rd as shown in your listing is not allowed.
The instruction 4354 decodes to thumb
MULS R5, R4 (notice only 2 registers are defined) this is
R5 = R5 * R4
This sort of looks like a decoding error on the listing except that the ASSEMBLER will generate a valid instruction for MULS Rd, Rm, Rd since it is equivalent to MULS Rd, Rd, Rm and it will not generate an error. (It generates to 2 operand version of the thumb instruction)
This is a full 32 x 32 multiple with a full 32-bit result. Not bytes are dropped, save the excess over 32-bits. If you want a larger result, you will need to define 64-bit variables.
"I tried typecasting with "long long" which is 64bit, same result. The LSB are put into the register instead of the MSB."
Typecasting from 32-bit to 64-bit is only meaningful when you have two variables who are _both_ less than 64-bit and you have a target variable that is of 64-bit (or larger) size.
Then the type cast of one (or both) of the input arguments will force a 64-bit multiplication.
Without a type-cast, but with a 64-bit target variable, the compiler will use a 32-bit multiplication (32-bit in and 32-bit out) and then sign-extend (or zero-extend) the result to 64 bits.
In your case, where you place the result in the same variable, that variable must be larger than 32 bits. A type cast of one or more of the inputs will still only store the low 32 bits - nothing more fits. All a type cast could give you is a warning that the result of the expression (of 64-bit size) will be truncated when stored back into the 32-bit variable.
I have now tried to declare two "long" variabels, multiply them and then store the result in a variable which is a "long long".
typedef signed int INT32S;
typedef signed long long INT64S;
INT32S test1 = 0x40002000; INT32S test2 = 0x30004000; INT64S test3;
test3 = test2*test1;
0x08004788 4D41 LDR r5,[pc,#260] ; @0x08004890 133: INT32S test2 = 0x30004000; 134: INT64S test3; 135: 0x0800478A 4C42 LDR r4,[pc,#264] ; @0x08004894 136: test3 = test2*test1; 137: 0x0800478C FB04F005 MUL r0,r4,r5 0x08004790 17C1 ASRS r1,r0,#31 0x08004792 E9CD0100 STRD r0,r1,[sp,#0]
In this code it still only stores the lower 16 bit. The value in r0 should be 0x00C001600 but the actual value is 0x08000000.That or it should use a instruction where both are stored.
Just stop it!
If you multiply 2 32-bit values, the result will be 32-bits. Converting that 32-bits to 64-bits will just result in a 32-bit sign extended to 64-bits. YOU MUST MAKE SURE THAT THE MULTIPLY IS DONE IN 64-bit PRECISION.
INT64S test1 = n; INT64S test2 = y; INT64S test3;
test3 = test1 * test2;
or you could do
test3 = (INT64S) test1 * test2;
with the original declarations. The typecast of test1 will force a 64-bit multiplication.
Do not ask the compiler to do something and expect it to do something different. It is supposed to do what you ask, not what you want it to do.
Okay. This is what i would like. I want to multiply to 32bit signed ints, and get this 32MSB. How do make the compiler do this for me?
I want to multiply to 32bit signed ints, and get this 32MSB.
Unfortunately you've been remarkably good at hiding that intent from the compiler and everybody else.
How do make the compiler do this for me?
Get the full 64-bit result, then shift & mask out the part of it you want.
INT32 test1; INT32 test2; INT32 upper32; upper32 = ((long long) test1 * test2) >> 32;
View all questions in Keil forum