RE: [arm-gnu] Access to volatile bit-fields
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: [arm-gnu] Access to volatile bit-fields



Ryan,

Sorry for interfering your communication with CS, but I recently dealt with similar issue where we had handicapped hardware with only 32-bit access to registers area. Probably I shouldn't call it handicapped since it greatly simplifies silicon design and makes hardware folks happy with shorter verification cycle. Shortly, you are absolutely right regarding GCC not honoring specified container for the volatile bitfield and if you will take a look at GCC implementation then you'll see attempt to use best suitable access code based on bitfield offset and length. There is a patch that implements new compiler option -fstrict-volatile-bitfields and Mark Mitchell from CS is the one who tested it, but when the patch will make it to the official release is unknown (at least I didn't get clear answer). If it will help you this is what I did recently:

We had rather large source base with this bitfield access everywhere, so I needed something that will minimize source change. All my registers do look like this template:

typedef volatile union
{
  struct
  {
    unsigned int fieldA : a;
    unsigned int fieldB : b;
    ......
    unsigned int fieldZ : z;
  };

  unsigned int as32BitValue;

} REG_TYPE;

Accessing macros:

#define reg32read(reg,field) \
( (reg.as32BitValue) , (((typeof(reg)*)&(reg.as32BitValue))->field) )

#define reg32write(reg,field,val)			\
do{							\
  uint32_t tmp = reg.as32BitValue;			\
  ((typeof(reg)*)&tmp)->field = (val);			\
  reg.as32BitValue = tmp;				\
}while(0)

A reason to use reference and pointers is that then it compiles nicely with either gcc or g++. reg32write macro is straight forward, reg32read needs some explanation since it was not obvious at first glance. It is comma separated expression macro where expressions will be evaluated from left to right and only last expression will be returned. Since in a heart of each expression is the same variable "reg.as32BitValue" it will be physically read only only once in the first expression as 32 bit value. Try it with your code and you will not see any byte or 16-bit access assembly instructions.

So far it's the best solution that I could come up with. If anybody has some better proposals while we all waiting the patch then please share it in a forum because looks like more and more people assume complete ARM ABI compliance and then spend hours and days with scope attached to the board (like I did) only to figure out later that generated assembly is not in line with ARM ABI standard.

Hope this helps,
Alexander

Quoting Ryan Lishman <ryan@xxxxxxxxxxxxxxx>:

Hi Carlos,

I used the following code:

-- struct TestSt {
--    volatile unsigned long halfword  : 16;
--    volatile unsigned long byte      : 8;
--    volatile unsigned long nybble    : 4;
--    volatile unsigned long tb        : 2;
--    volatile unsigned long bit       : 1;
--    volatile unsigned long           : 1;
-- };
--
--
-- int main( void ) {
--    TestSt test;
--
--    test.halfword = 16;
--    test.byte = 8;
--    test.nybble = 4;
--    test.tb = 2;
--    test.bit = 1;
-- }

This produces the following assembly, which shows that, although accesses to
bit fields which don't have a native instruction of that access size are
correct, accesses to byte and halfword sized bit-fields  are incorrect. This
seems to be the same regardless of what ARM machine the compiler targets.

-- Z:\>arm-none-eabi-gcc -c bf_test.cpp
--
-- Z:\>arm-none-eabi-objdump -d bf_test.o
--
-- bf_test.o:     file format elf32-littlearm
--
--
-- Disassembly of section .text:
--
-- 00000000 <main>:
--    0:   e52db004        push    {fp}            ; (str fp, [sp, #-4]!)
--    4:   e28db000        add     fp, sp, #0
--    8:   e24dd00c        sub     sp, sp, #12
--    c:   e3a03010        mov     r3, #16
--   10:   e14b30b8        strh    r3, [fp, #-8]
--   14:   e3a03008        mov     r3, #8
--   18:   e54b3006        strb    r3, [fp, #-6]
--   1c:   e51b3008        ldr     r3, [fp, #-8]
--   20:   e3c3340b        bic     r3, r3, #184549376      ; 0xb000000
--   24:   e3833301        orr     r3, r3, #67108864       ; 0x4000000
--   28:   e50b3008        str     r3, [fp, #-8]
--   2c:   e51b3008        ldr     r3, [fp, #-8]
--   30:   e3c33201        bic     r3, r3, #268435456      ; 0x10000000
--   34:   e3833202        orr     r3, r3, #536870912      ; 0x20000000
--   38:   e50b3008        str     r3, [fp, #-8]
--   3c:   e51b3008        ldr     r3, [fp, #-8]
--   40:   e3833101        orr     r3, r3, #1073741824     ; 0x40000000
--   44:   e50b3008        str     r3, [fp, #-8]
--   48:   e3a03000        mov     r3, #0
--   4c:   e1a00003        mov     r0, r3
--   50:   e28bd000        add     sp, fp, #0
--   54:   e49db004        pop     {fp}            ; (ldr fp, [sp], #4)
--   58:   e12fff1e        bx      lr
--
-- Z:\>arm-none-eabi-gcc -mthumb -mcpu=cortex-m0 -c bf_test.cpp
--
-- Z:\>arm-none-eabi-objdump -d bf_test.o
--
-- bf_test.o:     file format elf32-littlearm
--
--
-- Disassembly of section .text:
--
-- 00000000 <main>:
--    0:   b580            push    {r7, lr}
--    2:   b082            sub     sp, #8
--    4:   af00            add     r7, sp, #0
--    6:   1d3b            adds    r3, r7, #4
--    8:   2210            movs    r2, #16
--    a:   801a            strh    r2, [r3, #0]
--    c:   1dbb            adds    r3, r7, #6
--    e:   2208            movs    r2, #8
--   10:   701a            strb    r2, [r3, #0]
--   12:   687a            ldr     r2, [r7, #4]
--   14:   4b0b            ldr     r3, [pc, #44]   ; (44 <main+0x44>)
--   16:   401a            ands    r2, r3
--   18:   2380            movs    r3, #128        ; 0x80
--   1a:   04db            lsls    r3, r3, #19
--   1c:   4313            orrs    r3, r2
--   1e:   607b            str     r3, [r7, #4]
--   20:   687a            ldr     r2, [r7, #4]
--   22:   4b09            ldr     r3, [pc, #36]   ; (48 <main+0x48>)
--   24:   401a            ands    r2, r3
--   26:   2380            movs    r3, #128        ; 0x80
--   28:   059b            lsls    r3, r3, #22
--   2a:   4313            orrs    r3, r2
--   2c:   607b            str     r3, [r7, #4]
--   2e:   687a            ldr     r2, [r7, #4]
--   30:   2380            movs    r3, #128        ; 0x80
--   32:   05db            lsls    r3, r3, #23
--   34:   4313            orrs    r3, r2
--   36:   607b            str     r3, [r7, #4]
--   38:   2300            movs    r3, #0
--   3a:   1c18            adds    r0, r3, #0
--   3c:   46bd            mov     sp, r7
--   3e:   b002            add     sp, #8
--   40:   bd80            pop     {r7, pc}
--   42:   46c0            nop                     ; (mov r8, r8)
--   44:   f0ffffff        .word   0xf0ffffff
--   48:   cfffffff        .word   0xcfffffff

Regards,
Ryan