Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Force GCC to access structs with words

Tags:

c

gcc

arm

On an ARM processor (HT32F1655), a specific section of registers requires word accesses. From the user manual:

Note that all peripheral registers in the AHB bus support only word access.

But gcc is generating some ldrb (load byte) and strb (store byte) instructions on packed structs. The structs look something like this:

typedef union {
    struct {
        uint32_t CKOUTSRC    : 3;    //!< CKOUT Clock Source Selection
        uint32_t             : 5;
        uint32_t PLLSRC      : 1;    //!< PLL Clock Source Selection
        uint32_t             : 2;
        uint32_t CKREFPRE    : 5;    //!< CK_REF Clock Prescaler Selection
        uint32_t             : 4;
        uint32_t URPRE       : 2;    //!< USART Clock Prescaler Selection
        uint32_t USBPRE      : 2;    //!< USB Clock Prescaler Selection
        uint32_t             : 5;
        uint32_t LPMOD       : 3;    //!< Lower Power Mode Status
    } __attribute__((packed)) __attribute__ ((aligned(4)));
    uint32_t word;
} reg;

Example usage:

(*(volatile uint32_t*)0x40088000)->CKOUTSRC = 1;

Produces something similar to:

 ldrb r2, [r1]
 orr r2, r2, #1
 strb r2, [r1]

When I need:

 ldr r2, [r1]
 orr r2, r2, #1
 str r2, [r1]

Is there any way to force gcc to only generate instructions that access the whole word? Some options (-mno-unaligned-access) make gcc generate word accesses, but only when the byte is not 4-word aligned.

There is a -mslow-bytes which should do the right thing, however it seems that option does not exist for arm-none-eabi-gcc.

Ideally, there would be a way to force this only on the affected structs.

Please, no "don't use bitfields" answers. I know the drawbacks, but I have the ability here to control the compiler(s) used, so I am not worried about portability.

like image 642
Shade Avatar asked Mar 09 '23 21:03

Shade


1 Answers

What you're looking for is GCC's -fstrict-volatile-bitfields option:

This option should be used if accesses to volatile bit-fields (or other structure fields, although the compiler usually honors those types anyway) should use a single access of the width of the field's type, aligned to a natural alignment if possible. For example, targets with memory-mapped peripheral registers might require all such accesses to be 16 bits wide; with this flag you can declare all peripheral bit-fields as unsigned short (assuming short is 16 bits on these targets) to force GCC to use 16-bit accesses instead of, perhaps, a more efficient 32-bit access.

If this option is disabled, the compiler uses the most efficient instruction. In the previous example, that might be a 32-bit load instruction, even though that accesses bytes that do not contain any portion of the bit-field, or memory-mapped registers unrelated to the one being updated.

In some cases, such as when the packed attribute is applied to a structure field, it may not be possible to access the field with a single read or write that is correctly aligned for the target machine. In this case GCC falls back to generating multiple accesses rather than code that will fault or truncate the result at run time.

Note: Due to restrictions of the C/C++11 memory model, write accesses are not allowed to touch non bit-field members. It is therefore recommended to define all bits of the field's type as bit-field members.

The default value of this option is determined by the application binary interface for the target processor.

along with use of the volatile keyword. See: https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html

like image 118
R.. GitHub STOP HELPING ICE Avatar answered Mar 21 '23 07:03

R.. GitHub STOP HELPING ICE