I am writing an application that interacts with several registers that are defined in VHDL. The registers are 32 bits wide and are divided into groups. I am given the base address of the group and with 32-bit offsets for each member of the group. The following is an example of one group, a registry within a group, and a register structure.


I / O is currently being processed using the following bitfield structure,
typedef struct { uint32_t data0 : 12; uint32_t data1 : 1; ... }volatile data_port;
and changing fields using a pointer to addresses,
data_port *const p_data = (data_port *)0xc006380;
Although this may work on this platform, with the current compiler, I am worried about portability. I was wondering if there is a better way to handle the hardware interface when it is forced to use these non-traditional data types?
One of the alternatives that I can think of is to create a different level between the hardware and registration structures, volatile unsigned int pointer and use the bitfield structure in the application layer. The problem is that the data still needs to be copied from bit fields that can be aligned differently on another platform, to int, which may be a different topic in general.
Edit:
I think what I'm really looking for is a way to eliminate the use of bit fields. It seems that comparing the structure with the elements of the bit field at the hardware level is bad. So, to exclude this, I will use one of the following instead as a pointer to a volatile memory address,
#define PeripheralBase ((uint32_t volatile *)BASE)
or
uint32_t volatile *const peripheral_base = (uint32_t *) BASE;
Hopefully as soon as I get to this point everything will be well aligned within 32 bits. One of the methods that I was thinking about was to create the same data_port structure, but remove the bitmap, and then directly the function, specifically for each register, to shift the bits into an unsigned int, which can then be transferred to the register. using volatile pointer.
Sort of,
static inline uint32_t struct_to_uint(data_port *data) { return data->data0 + ((uint32_t)data->data1 << 12) + ((uint32_t)data->data2 << 13) + .....; }
I'm not sure if the syntax is correct, but the idea is to bias values โโwithout having to worry about the compiler or the platform. What is the reason for this? Are there any portability issues with this approach?