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