Hi, I'm having problems assembling a set of 4 bytes into a long int. My approach has been this:
ulong temp; temp = (temp << SHIFT_BYTE) | getByte(); temp = (temp << SHIFT_BYTE) | getByte(); temp = (temp << SHIFT_BYTE) | getByte(); temp = (temp << SHIFT_BYTE) | getByte(); return temp;
What about this:
union { unsigned long lvar; unsigned char bytes[4]; } v; v.bytes[0]=getByte(); //MSB v.bytes[1]=getByte(); v.bytes[2]=getByte(); v.bytes[3]=getByte(); //LSB return (v.lvar);
0013 120000 R LCALL getByte 0016 8F00 R MOV v,R7 0018 120000 R LCALL getByte 001B 8F00 R MOV v+01H,R7 001D 120000 R LCALL getByte 0020 8F00 R MOV v+02H,R7 0022 120000 R LCALL getByte 0025 8F00 R MOV v+03H,R7
Thanks Jon. I guess I should have done a bit more research before posting. There's a knowledge base article that's almost identical to your reply. It's too bad the compiler won't use the registers instead. I have global register optimization turned on, and the only registers by "getByte()" function uses are A, C and R7. Ideally, I'd like it to produce the assembly code:
; *** v assigned to registers R4-R7 LCALL getByte MOV R4,AR7 LCALL getByte MOV R5,AR7 LCALL getByte MOV R6,AR7 LCALL getByte RET
LCALL getByte MOV R4,A LCALL getByte MOV R5,A LCALL getByte MOV R6,A LCALL getByte MOV R7,A RET
"I guess I should have done a bit more research before posting" yes - it's been discussed on this forum many times before! This is all standard 'C' stuff - the only Keil-specific detail is the byte ordering within a long. Note that your original approach using shifts is independent of the underlying byte order and is, therefore, portable; The union approach relies upon the byte ordering and is, therefore, non-portable. With suitable conditional-compilation directives you can, of course, create a portable union implementation.
I did read back a few months worth of forum discussion before posting, but I didn't search the knowledge base. Thanks for responding anyway. There's more Keil-specific stuff than just the byte ordering in a long. The original purpose of my post was to find out which C code the compiler converted into efficient assembly. An intelligent enough compiler should have produced the same code for both the union approach and the shift approach, in which case, I would have opted for the portable approach. In my pre-purchase testing of the Keil compiler, I had found that it generally was very good at efficient assembly code for constant math such as dividing or multiplying by constant that is a power of 2 (shifting). I guess I was just expecting too much. The Keil tools do generally do a very good job. Thanks, Bob