EmbeddedRelated.com
Forums

Using Bit Field structures to access LPC-2000 registers

Started by jdauchot May 27, 2009
Hi Jan,

> I just did a quick test ...
>
> Compiled with (OS X, g++ 4.3.3):
>
> Which looks perfectly correct to me and exhibits none of the problems
> that were mentioned.

From my notes:

An example of this nonportability is the compilation of bit-fields
by GCC 3.3.3 on an x86 CPU. Bit-field operations can compile to
byte-wide writes eg. movb %al, (%edx), where byte register al
contains the result of a bit-field manipulation, and edx the
address of the register to write the answer back to. When
this byte operation occurs on a 32-bit wide register that
does not accept byte-wide writes, as is common with PCI memory
mapped registers, the 3 high-bytes of the word will be
overwritten with garbage. So even though bit fields are
defined in terms of 32-bit integers, the assembly output is
not!

The case where I was having issues was with a library defined
on a PCI card processor, that could be recompiled on the PCI host
to access the same registers. However, since the x86 host code
compiled the bit-field code into byte assembly instructions,
the other bytes in the 32-bit access registers were trashed.

If you look at the code generated in your example, each bitfield
operation generates a read-modify-write sequence.

Lets say you have a status register where bits are set to
indicate a change in status, and those bits are cleared
with a write-1 to clear. If you used a bitfield to write-1 to clear
one status bit, the actual sequence of read-modify-write could
read-and-clear additional status bits, and you'd be none the wiser.

Also you cannot simultaneously set multiple fields.

eg.

control.enable_a = 1;
control.enable_b = 1;

requires two writes (actually read-modify-writes), vs

control = ENABLE_A | ENABLE_B;

which requires 1 write. A union with the bitfield definition and
and int can be used to get both methods.

However, I'd still not recommend them :)

Cheers,
Dave

An Engineer's Guide to the LPC2100 Series

Jan Brittenson schrieb:

> I just did a quick test. Code:
> snip
>
> Which looks perfectly correct to me and exhibits none of the problems
> that were mentioned.

So you did test one of millions of possible variations, what does this
prove ?

I've seen weired code generated for bit-fields. But trying to break it
down to a simple example never succeeded.

So again: Never ever use bit fields for hardware-registers.
You'd be warned.

--
42Bastian
------------------
Parts of this email are written with invisible ink.

Note: SPAM-only account, direct mail to bs42@...
David Hawkins wrote:
> If you look at the code generated in your example, each bitfield
> operation generates a read-modify-write sequence.
I doubt the Keil code being ported uses bitfield for registers
with set-reset semantics, or it wouldn't work in the first place.
As long as the registers are declare volatile the code will likely
work just fine with gcc.

Hi

Sounds like this bit field structure thing could work if it is handled
carefully.

Thanks for all the advise and example code I have seen.

I presume that it may be wise to turn off code optimization to make sure
that the does not do anything fanny.

Regards

JJ

_____

From: l... [mailto:l...] On Behalf Of
Jan Brittenson
Sent: 29 May 2009 08:54
To: l...
Subject: Re: [lpc2000] Re: Using Bit Field structures to access LPC-2000
registers

David Hawkins wrote:
> If you look at the code generated in your example, each bitfield
> operation generates a read-modify-write sequence.
I doubt the Keil code being ported uses bitfield for registers
with set-reset semantics, or it wouldn't work in the first place.
As long as the registers are declare volatile the code will likely
work just fine with gcc.



Jean-Jacques Dauchot schrieb:

> Sounds like this bit field structure thing could work if it is handled
> carefully.

Yes. If you look at every assembly output where you use them ...
Is it worth the trouble ? What happens if someone else needs to use your
code ?

--
42Bastian
------------------
Parts of this email are written with invisible ink.

Note: SPAM-only account, direct mail to bs42@...
Hi,

> Sounds like this bit field structure thing could work if it is
> handled carefully.

> I presume that it may be wise to turn off code optimization to make sure
> that the does not do anything fanny.

>From where does this wisdom come? It's a load of baloney. Please, knock
yourself out trying.

--
Paul Curtis, Rowley Associates Ltd http://www.rowley.co.uk
CrossWorks for ARM, MSP430, AVR, MAXQ, and now Cortex-M3 processors

Ok, nobody takes telling do they?

> typedef unsigned int uint;
>
> struct Pinsel {
> uint p0_16:2;
> uint p0_17:2;
> uint p0_18:2;
> uint p0_19:2;
> uint p0_20:2;
> uint p0_21:2;
> uint p0_22:2;
> uint p0_23:2;
> uint p0_24:2;
> uint p0_25:2;
> uint p0_26:2;
> uint p0_27:2;
> uint p0_28:2;
> uint p0_29:2;
> uint p0_30:2;
> uint p0_31:2;
> };
>
> volatile Pinsel& _pinsel1bits = *(volatile Pinsel*)0xe002c004;
>
> int main()
> {
> _pinsel1bits.p0_16 = 0b01; // P0.16 = EINT0 (should: clear+set bits)
> _pinsel1bits.p0_27 = 0b00; // P0.27 = GPIO 0.27 (should: clear
bits)
> _pinsel1bits.p0_21 = 0b11; // P0.21 = Capture 1.3 (should: set bits)
>
> for (;;) ;
> }
>
> Compiled with (OS X, g++ 4.3.3):
> /opt/yagarto/bin/arm-elf-g++ -marm -mcpu=arm7tdmi-s -Os -fno-exceptions
> -fno-rtti -ffunction-sections -ffreestanding -S -c foo.cpp
>
> Resulting code:
>
> .file "foo.cpp"
> .section .text.main,"ax",%progbits
> .align 2
> .global main
> .type main, %function
> main:
> @ args = 0, pretend = 0, frame = 0
> @ frame_needed = 0, uses_anonymous_args = 0
> @ link register save eliminated.
> ldr r3, .L4
> ldr r2, [r3, #0]
> ldr r3, [r2, #0]
> bic r3, r3, #2
> orr r3, r3, #1
> str r3, [r2, #0]
> ldr r3, [r2, #0]
> bic r3, r3, #12582912
> str r3, [r2, #0]
> ldr r3, [r2, #0]
> orr r3, r3, #3072
> str r3, [r2, #0]
> .L2:
> b .L2
> .L5:
> .align 2
> .L4:
> .word _pinsel1bits
> .size main, .-main
> .global _pinsel1bits
> .section .rodata
> .align 2
> .type _pinsel1bits, %object
> .size _pinsel1bits, 4
> _pinsel1bits:
> .word -536690684
> .ident "GCC: (GNU) 4.3.3"
>
> Which looks perfectly correct to me and exhibits none of the problems
> that were mentioned.

And lo, GCC was proclaimed correct.

A slight modification:

typedef unsigned uint;

typedef struct {
uint p0_16:8;
uint p0_20:2;
uint p0_21:2;
uint p0_22:2;
uint p0_23:2;
uint p0_24:2;
uint p0_25:2;
uint p0_26:2;
uint p0_27:2;
uint p0_28:2;
uint p0_29:2;
uint p0_30:2;
uint p0_31:2;
} Pinsel;

volatile Pinsel *_pinsel1bits = (volatile Pinsel*)0xe002c004;
int main1()
{
_pinsel1bits->p0_16 = 1;

for (;;) ;
}

This generates:

E1A0C00D mov r12, sp
E92DD800 stmfd sp!, {r11-r12, lr-pc}
E24CB004 sub r11, r12, #4
E59F300C ldr r3, [pc, #12]
E5932000 ldr r2, [r3]
E3A03001 mov r3, #1
E5C23000 strb r3, [r2]

How about that then?

--
Paul Curtis, Rowley Associates Ltd http://www.rowley.co.uk
CrossWorks for ARM, MSP430, AVR, MAXQ, and now Cortex-M3 processors

You Guys must hate bit fields to bits

JJ

_____

From: l... [mailto:l...] On Behalf Of
Paul Curtis
Sent: 29 May 2009 10:46
To: l...
Subject: RE: [lpc2000] Re: Using Bit Field structures to access LPC-2000
registers

Ok, nobody takes telling do they?

> typedef unsigned int uint;
>
> struct Pinsel {
> uint p0_16:2;
> uint p0_17:2;
> uint p0_18:2;
> uint p0_19:2;
> uint p0_20:2;
> uint p0_21:2;
> uint p0_22:2;
> uint p0_23:2;
> uint p0_24:2;
> uint p0_25:2;
> uint p0_26:2;
> uint p0_27:2;
> uint p0_28:2;
> uint p0_29:2;
> uint p0_30:2;
> uint p0_31:2;
> };
>
> volatile Pinsel& _pinsel1bits = *(volatile Pinsel*)0xe002c004;
>
> int main()
> {
> _pinsel1bits.p0_16 = 0b01; // P0.16 = EINT0 (should: clear+set bits)
> _pinsel1bits.p0_27 = 0b00; // P0.27 = GPIO 0.27 (should: clear
bits)
> _pinsel1bits.p0_21 = 0b11; // P0.21 = Capture 1.3 (should: set bits)
>
> for (;;) ;
> }
>
> Compiled with (OS X, g++ 4.3.3):
> /opt/yagarto/bin/arm-elf-g++ -marm -mcpu=arm7tdmi-s -Os -fno-exceptions
> -fno-rtti -ffunction-sections -ffreestanding -S -c foo.cpp
>
> Resulting code:
>
> .file "foo.cpp"
> .section .text.main,"ax",%progbits
> .align 2
> .global main
> .type main, %function
> main:
> @ args = 0, pretend = 0, frame = 0
> @ frame_needed = 0, uses_anonymous_args = 0
> @ link register save eliminated.
> ldr r3, .L4
> ldr r2, [r3, #0]
> ldr r3, [r2, #0]
> bic r3, r3, #2
> orr r3, r3, #1
> str r3, [r2, #0]
> ldr r3, [r2, #0]
> bic r3, r3, #12582912
> str r3, [r2, #0]
> ldr r3, [r2, #0]
> orr r3, r3, #3072
> str r3, [r2, #0]
> .L2:
> b .L2
> .L5:
> .align 2
> .L4:
> .word _pinsel1bits
> .size main, .-main
> .global _pinsel1bits
> .section .rodata
> .align 2
> .type _pinsel1bits, %object
> .size _pinsel1bits, 4
> _pinsel1bits:
> .word -536690684
> .ident "GCC: (GNU) 4.3.3"
>
> Which looks perfectly correct to me and exhibits none of the problems
> that were mentioned.

And lo, GCC was proclaimed correct.

A slight modification:

typedef unsigned uint;

typedef struct {
uint p0_16:8;
uint p0_20:2;
uint p0_21:2;
uint p0_22:2;
uint p0_23:2;
uint p0_24:2;
uint p0_25:2;
uint p0_26:2;
uint p0_27:2;
uint p0_28:2;
uint p0_29:2;
uint p0_30:2;
uint p0_31:2;
} Pinsel;

volatile Pinsel *_pinsel1bits = (volatile Pinsel*)0xe002c004;

int main1()
{
_pinsel1bits->p0_16 = 1;

for (;;) ;
}

This generates:

E1A0C00D mov r12, sp
E92DD800 stmfd sp!, {r11-r12, lr-pc}
E24CB004 sub r11, r12, #4
E59F300C ldr r3, [pc, #12]
E5932000 ldr r2, [r3]
E3A03001 mov r3, #1
E5C23000 strb r3, [r2]

How about that then?

--
Paul Curtis, Rowley Associates Ltd http://www.rowley.
co.uk
CrossWorks for ARM, MSP430, AVR, MAXQ, and now Cortex-M3 processors



> You Guys must hate bit fields to bits

I've had problems with bit fields in the past. Once bitten twice shy.

Regards,
Richard.

+ http://www.FreeRTOS.org
Designed for Microcontrollers. More than 7000 downloads per month.

+ http://www.SafeRTOS.com
Certified by T as meeting the requirements for safety related systems.
Paul Curtis wrote:
>
> This generates:
>
> E1A0C00D mov r12, sp
> E92DD800 stmfd sp!, {r11-r12, lr-pc}
> E24CB004 sub r11, r12, #4
> E59F300C ldr r3, [pc, #12]
> E5932000 ldr r2, [r3]
> E3A03001 mov r3, #1
> E5C23000 strb r3, [r2]
>
> How about that then?
What about it? The peripheral bus has byte select signaling.