Folks,
I'm using CW7.1 for codefire 5225x to generate some byte streams. in the definition document, it asks for 2 consecutive 12 bit numbers that takes 3 bytes. so i used the code below (simplified) but it seems the sizeof is 4 bytes instead of 3. if I assign foo and bar with 0x1111, they show up in the stream as 0x1110, which means a padding nibble is added to each var..
any recommendations other than split the 2 vars into 2 int8 + 2 nibbles?
#pragma options align=packed
typedef struct
{
int16_t foo:12 ;
int16_t bar:12 ;
}
expect_3_byte_t;
thanks in advance.
Leong
Solved! Go to Solution.
Hello Leong,
I think that the main issue here is that there are no 12-bit or 24 bit types in C. Therefore either 16-bit or 32-bit types need to be used to fit the data, and will obviously include padding bits. Since the C standard does not define how a compiler should pack the bits within a bitfield, the current packing arrangement by the CW compiler, within a 16 bit multiple, would seem to make a lot of sense because it would produce the most efficient access to each bitfield element, with no compromise on the total size of the bit field. Any other arrangement, such as your packing requirement, would involve additional implicit arithmetic to access each element, with a reduction of efficiency.
My understanding is that the MISRA standard does also not condone the use of bitfields. This would mean that you will need to provide either a function or a macro that uses explicit arithmetic to pack the data in the required manner. In your case, the 24 bits could be either left-aligned or right-aligned within the 32 bit type. The following functions do not use either a bitfield or a union.
dword packR24( word high12, word low12) // Right aligned result
{
return ((dword)high12 << 12) | (low12 & 0x0FFF);
}
dword packL24( word high12, word low12) // Left aligned result
{
return packR24( high12, low12) << 8;
}
result = packL24( foo, bar);
result = packR24( foo, bar);
#define get_fooR(x) (word)((x) >> 12)
#define get_barR(x) (word)((x) & 0x0FFF)
#define get_fooL(x) (word)((x) >> 20)
#define get_barL(x) (word)((x) >> 8) & 0x0FFF
foo = get_fooR( result);
bar = get_barR( result);
Regards,
Mac
Hello Leong!
How is the project going, were you able to try that suggestion?
Please keep us posted, we'd like to know! :smileywink:
Best regards,
Monica
Hello Leong,
The padding bits inserted into a bit field will be compiler dependent. See if the following alternative method, using a union, will work for you.
typedef union {
byte array[3];
struct {
word high16;
byte low8;
} seq16_8;
struct {
byte high8;
word low16;
} seq8_16;
} PACK24;
word foo = 0x0ABC;
word bar = 0x0DEF;
PACK24 three_byte;
three_byte.seq16_8.high16 = foo << 4;
three_byte.seq16_8.low8 = 0;
three_byte.seq8_16.low16 |= bar & 0x0FFF;
Regards,
Mac
Mac,
Thanks for the reply. Yes this would work but there are 2 reasons that I can not use this in the code: 1 no direct reference to foo or bar in the code, it would always require arithmetic before referencing to the variables. 2. MISRA C does not like the usage of union.... (misra is an automotive programming standard)...
so i've been negotiating with the other party to change the protocol.... in case there is no direct solution to this issue...
any one from the freescale compiler team can verify if this is a limitation or there is a way to get around in the code generation?
Thanks
Leong
Hello Leong,
I think that the main issue here is that there are no 12-bit or 24 bit types in C. Therefore either 16-bit or 32-bit types need to be used to fit the data, and will obviously include padding bits. Since the C standard does not define how a compiler should pack the bits within a bitfield, the current packing arrangement by the CW compiler, within a 16 bit multiple, would seem to make a lot of sense because it would produce the most efficient access to each bitfield element, with no compromise on the total size of the bit field. Any other arrangement, such as your packing requirement, would involve additional implicit arithmetic to access each element, with a reduction of efficiency.
My understanding is that the MISRA standard does also not condone the use of bitfields. This would mean that you will need to provide either a function or a macro that uses explicit arithmetic to pack the data in the required manner. In your case, the 24 bits could be either left-aligned or right-aligned within the 32 bit type. The following functions do not use either a bitfield or a union.
dword packR24( word high12, word low12) // Right aligned result
{
return ((dword)high12 << 12) | (low12 & 0x0FFF);
}
dword packL24( word high12, word low12) // Left aligned result
{
return packR24( high12, low12) << 8;
}
result = packL24( foo, bar);
result = packR24( foo, bar);
#define get_fooR(x) (word)((x) >> 12)
#define get_barR(x) (word)((x) & 0x0FFF)
#define get_fooL(x) (word)((x) >> 20)
#define get_barL(x) (word)((x) >> 8) & 0x0FFF
foo = get_fooR( result);
bar = get_barR( result);
Regards,
Mac
Mac,
Thanks for diving into this... I will buy that explanation on the C intrinsic types only has 8 16 32 64 bits now that i think about the compiler complexity if they were to support nibbles... I've seen some other compiler does have 12 bit or 24 bit internal alignment (may be TI?) but mw may not... I wouldn't call this a bug but need to confirm with some documentation (could not find the exact compiler behavior in such case under the #pragma packed doc)....
Yes Misra is ok with bit-field just not with the union type. I would need to write a couple of accessors to do a 'simple get/set' to the vars as you suggested. At the same time, i have explained to the customer and see if they can move around other bit field definitions to fill the nibbles instead of using 3 consecutive 12bits..
Thanks again
leong