This is a technical posting for the firmware readership.
One of the most elegant ways of expressing register bit-fields in C/C++ firmware is using a union of a struct with a register word. The problem with this is that there is no standard way for representing the bit field packing/ordering in C/C++, which restricts portability across compilers and architectures. For the simple traffic light controller (TLC) example with the register-map shown here, the LightState Register’s Green, Amber and Red bit-fields can be represented as shown below, assuming most to least significant bit packing.
union TLC_STATUSREGISTERS_LIGHTSTATE {
struct {
volatile unsigned : 29;
volatile unsigned green : 1;
volatile unsigned amber : 1;
volatile unsigned red : 1;
} fields;
volatile u32 reg;
};
If the bit-order packing is reversed, then it needs to look as follows:
union TLC_STATUSREGISTERS_LIGHTSTATE {
struct {
volatile unsigned red : 1;
volatile unsigned amber : 1;
volatile unsigned green : 1;
volatile unsigned : 29;
} fields;
volatile u32 reg;
};
The reversal of the bit fields can be done using auto-generation based on a bit-ordering condition with a register automation tool like SpectaReg. For non-generated static code, it can be accomplished using #ifdefs, and sometimes compiler pragmas.
The most portable way to deal with register bits in C/C++ is NOT to use this struct/union fanciness — instead do the required masking (and possibly shifting) using bitwise operators. SpectaReg produces both the struct/union format and also the shift/mask format. How does the RegisterBits readership do it?