Reply by frikkiethirion●January 13, 20092009-01-13
Good day,
I've created patches for GCC 4.3.2 and GCC 4.4.0 to honor the specified
container type of the bitfield when
1) The variable is declared volatile and
2) The gcc internal: TARGET_NARROW_VOLATILE_BITFIELD is '0'
(Needs to be set at compile time for GCC. For 'arm' architecture, it is
currently the default setting)
I've posted the patches to
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=23623
If anybody is interested in this, please test it and give me some feedback
if it is working for you. I've tested the patches on actual hardware (ST
STR912FW44) and it works fine. The included disassembly listings also
confirm the correct accesses.
Regards,
Frikkie
Reply by Arie●July 27, 20082008-07-27
"frikkiethirion" ...
> I wonder if somebody has managed to create a structured way of accessing
> the memory mapped IO attached to the STR912 [ARM9] via bitfields.
>
> I can manipulate the members of a union that is declared in main(), bus as
> soon as I make a pointer type of my union and point it to the memory bus,
> I
> get unexpected results.
I know from bad experience that (at least some) GCC compilers do minimize
the access - for a bitfield in a 32-bit word it only does a byte
read-modify-write, which is deadly for the other bits if you are accessing
an I/O register that can only be accessed 32-bits wide.
For memory it's OK, so I update a RAM based copy, then write the result to
the I/O register. Use a critical section or mutex around the whole operation
if other drivers use the other bits...
Arie de Muynck
Reply by Robert Adsett●July 25, 20082008-07-25
In article <XZidnecSAIgQcxTVnZ2dnUVZ_hudnZ2d@giganews.com>,
frikkiethirion says...
> I wonder if somebody has managed to create a structured way of accessing
> the memory mapped IO attached to the STR912 [ARM9] via bitfields.
>
> My test code is as follow:
>
> main()
> {
> uint32_t uwI;
> uint32_t *pwPointer;
>
> typedef struct
> {
> volatile uint32_t PLL_MDIV:8; // [7:0] PLL Pre-divider
> volatile uint32_t PLL_NDIV:8; // [15:8] PLL Feedback divider
> volatile uint32_t PLL_PDIV:3; // [18:16] PLL Post-divider
Don't do that, it's a bad idea. Seductively bad. Why? you might ask.
- Well first it's both compiler and architecture dependant. That
means you cannot tell what's happening in the code by reading it making
future maintenance a nightmare. Anyone maintaing the code is going to
have to look up the details on how this particular compiler deals with
bitfield layout.
- Also I suspect that the use of uint32_t in a bit field is not
fully defined. IIRC only int and unsigned int are allowed. On an ARM
they happen to map to the same thing but... Of course that's particular
to this example.
But, you respond, I will only ever be working with a single compiler and
architecture.
- Have you no sympathy for anyone else who has to maintain the
project? Maybe you are developing something that doesn't need to be
maintained if you are not around?
If that doesn't convince you consider that what happens when you access
a bitfield isn't fully specified. As a for instance consider accessing
PLL_MDIV above, the access could be via an 8, 16 or 32bit set of
operations (and the 16 and 32 bit methos would require some sort of
read-modify-write operation). It is possible (and yes some hardware
does have these restrictions) that all access's to this hardware must be
made only via 32bit read/writes or maybe only via 8 bit read/writes.
It's also possible that a RMW sequence will not work due to harware
restrictions. And, yes there are compilers that will optimize the
access to 8 bits.
Bitfields on I/O are seductive (i've been seduced by them a time or two
myself) but ultimately they cause more problems than they solve.
Bitfields are only usefule to reduce in memory storage at the expense of
access time.
Robert
** Posted from http://www.teranews.com **
Reply by Anton Erasmus●July 25, 20082008-07-25
On Fri, 25 Jul 2008 10:17:33 -0500, "frikkiethirion"
<frikkie@zitera.co.za> wrote:
>Good day,
>I wonder if somebody has managed to create a structured way of accessing
>the memory mapped IO attached to the STR912 [ARM9] via bitfields.
>
>I can manipulate the members of a union that is declared in main(), bus as
>soon as I make a pointer type of my union and point it to the memory bus, I
>get unexpected results.
>
>The following two posts, from 2000 and 2005, make it seem asif it is only
>possible to access 4 byte values on the ARM memory architecture at a time
>and that bitfield accesses won't work:
>http://gcc.gnu.org/ml/gcc/2000-05/msg00776.html
>
>http://archives.devshed.com/forums/development-94/new-volatile-keyword-changes-bitfield-access-size-from-32bit-to-1322941.html
>
>
>My test code is as follow:
>
[code snipped]
>
>I'm running gcc 4.3.1, compiled for target: arm-elf, with newlib. If it
>will help, I could supply the detailed configure switches when I build the
>toolchain and CFLAGS/LDFLAGS of my Makefile.
>
>Any help will be much appreciated.
It is an extremely bad idea to use bitfields to access hardware
registers. There is absolutely no guarantee about how the actual
accesses wil be handled by the compiler. Handle the bits by
reading/writing the register with required size, and mask the bits
as required.
Regards
Anton Erasmus
Reply by frikkiethirion●July 25, 20082008-07-25
Good day,
I wonder if somebody has managed to create a structured way of accessing
the memory mapped IO attached to the STR912 [ARM9] via bitfields.
I can manipulate the members of a union that is declared in main(), bus as
soon as I make a pointer type of my union and point it to the memory bus, I
get unexpected results.
The following two posts, from 2000 and 2005, make it seem asif it is only
possible to access 4 byte values on the ARM memory architecture at a time
and that bitfield accesses won't work:
http://gcc.gnu.org/ml/gcc/2000-05/msg00776.htmlhttp://archives.devshed.com/forums/development-94/new-volatile-keyword-changes-bitfield-access-size-from-32bit-to-1322941.html
My test code is as follow:
main()
{
uint32_t uwI;
uint32_t *pwPointer;
typedef struct
{
volatile uint32_t PLL_MDIV:8; // [7:0] PLL Pre-divider
volatile uint32_t PLL_NDIV:8; // [15:8] PLL Feedback divider
volatile uint32_t PLL_PDIV:3; // [18:16] PLL Post-divider
volatile uint32_t PLL_EN:1; // [19] PLL Enable (0=off, 1=on)
volatile uint32_t uwPAD:12; // [31:20] -PADDING-
} mySCU_PLLCONF_t;
typedef union
{
volatile uint32_t ALL;
volatile mySCU_PLLCONF_t BITS;
} mySCU_PLLCONF_u;
mySCU_PLLCONF_u umyPLLCONF;
volatile mySCU_PLLCONF_u *pPLLCONF;
umyPLLCONF.BITS.PLL_MDIV = 0x80;
umyPLLCONF.BITS.PLL_NDIV = 0x10;
umyPLLCONF.BITS.PLL_PDIV = 0x2;
umyPLLCONF.BITS.PLL_EN = 1;
uwI=umyPLLCONF.ALL;
The value in uwI is 0x000a1080, as expected.
// ON SCU bus
pwPointer = (uint32_t *)(AHB_NB_APB1_BASE + SCU_OFST); //5c00 2000
pwPointer++; //increment one word, to get aligned with PLL //5c00 2004
pPLLCONF = (mySCU_PLLCONF_u *)pwPointer;
pPLLCONF->BITS.PLL_MDIV = 0x80;
uwI=pPLLCONF->ALL;
//Value is 0x8080-->Both 'MDIV' and 'NDIV'altered...
pPLLCONF->BITS.PLL_NDIV = 0x10;
uwI=pPLLCONF->ALL;
//Value is 0x1010-->Both 'MDIV' and 'NDIV'altered...
}
I'm running gcc 4.3.1, compiled for target: arm-elf, with newlib. If it
will help, I could supply the detailed configure switches when I build the
toolchain and CFLAGS/LDFLAGS of my Makefile.
Any help will be much appreciated.
Regards,
Frikkie Thirion