Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2013-12

Problem with bitpacked records and STM32F107 Controller

7 messages · 5 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Michael Ring

Hi, while playing arround I found a strange behaviour that seems to have to do with the fact that writes to bitpacked records are byte aligned.

Here are the details:

I have create a bitpacked record set for the GPIO Registers of the processor. On Port D of the processor I have 16 LED's, one for each bit.

   TGPIO_ODR_bits = bitpacked record
     ODR0  : 0..1;
     ODR1  : 0..1;
     ODR2  : 0..1;
     ODR3  : 0..1;
     ODR4  : 0..1;
     ODR5  : 0..1;
     ODR6  : 0..1;
     ODR7  : 0..1;
     ODR8  : 0..1;
     ODR9  : 0..1;
     ODR10 : 0..1;
     ODR11 : 0..1;
     ODR12 : 0..1;
     ODR13 : 0..1;
     ODR14 : 0..1;
     ODR15 : 0..1;
     RESERVED : 0..65535;
   end;

When I now access the bits via:

     GPIOD_B.ODR.ODR0 := 0;
     GPIOD_B.ODR.ODR0 := 1;

not only the LED for ODR0 lights up, also the one connected to ODR8 !!??!!

When I access the Port without the bitset:
     GPIOD.ODR := 0;
     GPIOD.ODR := 1;
only the LED attached to ODR0 lights up.

Looking at the assembler code I see the following:

.Ll5:

         ldr     r0,.Lj19         //Code for GPIOD_B.ODR.ODR0 := 0;

*ldrb* r0,[r0]
bic r0,r0,#1
and r0,r0,#255
ldr r1,.Lj19
*strb* r0,[r1]
.Ll6:

         ldr     r0,.Lj19       //Code for GPIOD_B.ODR.ODR0 := 1;

*ldrb* r0,[r0]
orr r0,r0,#1
and r0,r0,#255
ldr r1,.Lj19
*strb* r0,[r1]
.Ll7:

         mov     r0,#0           //Code for GPIOD.ODR := 0;
         ldr     r1,.Lj19

*str* r0,[r1]
.Ll8:

         mov     r0,#1           //Code for GPIOD.ODR := 1;
         ldr     r1,.Lj19

*str* r0,[r1]

The strb command seems to be the problem, documentation from STM states:

Each I/O port bit is freely programmable, however the I/O port registers have to be accessed as 32-bit words (half-word or byte accesses are not allowed).

So, is there some way to make the bitset operations word-aligned? Are there any good reasons for not doing so?

Michael

STM32F101xx, STM32F102xx, STM32F103xx, STM32F105xx and STM32F107xx advanced ARM-based 32-b

Reply by email

Sven Barth
to Michael Ring
Michael Ring wrote 7 lines
The strb command seems to be the problem, documentation from STM states: Each I/O port bit is freely programmable, however the I/O port registers have to be accessed as 32-bit words (half-word or byte accesses are not allowed). So, is there some way to make the bitset operations word-aligned?

Better say 32-bit aligned to avoid confusion. Words in Pascal are 16-bit although I know that you are talking about the CPUs word size...

Are there any good reasons for not doing so?

What when you really have a byte that you want ot access? Then using 32-bit writes/reads could(*) result in unnecessary cycles.

* I don't know about ARM especially, but I know that for e.g. the m68k a 32-bit store is more expensive than a 16-bit or 8-bit store

That said I don't have a solution for your specific problem except by doing it by hand.

Regards,
Sven

Reply by email

Sergei Gorelkin
to Sven Barth

11.12.2013 12:28, Sven Barth пишет:

Show quoted text 18 lines
Am 11.12.2013 08:43, schrieb Michael Ring: > The strb command seems to be the problem, documentation from STM states: > > Each I/O port bit is freely programmable, however the I/O port registers have to be accessed as > 32-bit words (half-word or byte accesses are not allowed). > > So, is there some way to make the bitset operations word-aligned? Better say 32-bit aligned to avoid confusion. Words in Pascal are 16-bit although I know that you are talking about the CPUs word size... > Are there any good reasons for not doing so? What when you really have a byte that you want ot access? Then using 32-bit writes/reads could(*) result in unnecessary cycles. * I don't know about ARM especially, but I know that for e.g. the m68k a 32-bit store is more expensive than a 16-bit or 8-bit store That said I don't have a solution for your specific problem except by doing it by hand.

Maybe size of memory access must be guided by size of record? For ARM the record will be 32-bit, and for m68k it can be 8 or 16-bit.

Regards,
Sergei

Reply by email

Sven Barth
to Sergei Gorelkin
Sergei Gorelkin wrote 27 lines
11.12.2013 12:28, Sven Barth пишет: > Am 11.12.2013 08:43, schrieb Michael Ring: >> The strb command seems to be the problem, documentation from STM >> states: >> >> Each I/O port bit is freely programmable, however the I/O port >> registers have to be accessed as >> 32-bit words (half-word or byte accesses are not allowed). >> >> So, is there some way to make the bitset operations word-aligned? > Better say 32-bit aligned to avoid confusion. Words in Pascal are > 16-bit although I know that you > are talking about the CPUs word size... >> Are there any good reasons for not doing so? > What when you really have a byte that you want ot access? Then using > 32-bit writes/reads could(*) > result in unnecessary cycles. > > * I don't know about ARM especially, but I know that for e.g. the > m68k a 32-bit store is more > expensive than a 16-bit or 8-bit store > > That said I don't have a solution for your specific problem except by > doing it by hand. > Maybe size of memory access must be guided by size of record? For ARM the record will be 32-bit, and for m68k it can be 8 or 16-bit.

The problem for ARM is that byte sized accesses for bitfields are done correctly except if it's an I/O port where 32-bit accesses are required. Let's assume that ARM also has different cycle times for different sizes then it would be overkill to change EVERY bitfield access to 32-bit. Maybe a local compiler directive would be better that tells the compiler what size it should use? Then Michael could use it like this:

=== code begin ===

{$push}
{$bitaccesssize 4} // in Byte
   TGPIO_ODR_bits = bitpacked record
     ODR0: 0..1;
     // ...
   end;
{$pop}
   TSomeNonIOStruct = bitpacked record
     Field1: 0..1;
     // ...
   end;

=== code end ===

For TGPIO_ODR_bits the compiler would then use 32-bit writes and for TSomeNonIOStruct it would continue to use 8-bit writes.

Regards,
Sven

Reply by email

Jonas Maebe
to Michael Ring: Hi, while playing arround I found a strange behaviour that seems to have to do with the…
Michael Ring wrote 5 lines
The strb command seems to be the problem, documentation from STM states: Each I/O port bit is freely programmable, however the I/O port registers have to be accessed as 32-bit words (half-word or byte accesses are not allowed). So, is there some way to make the bitset operations word-aligned?

No. In C, you can control the access size by using "int ODR0:1;" instead of "char ODR0:1;", but there is no equivalent in Pascal. This functionality was not introduced with direct hardware access in mind, but for compatibility with the way it's implemented in Mac Pascal compilers and GPC/GCC (the last one with "__attribute__((__packed__))", which is what GPC implicitly uses).

Are there any good reasons for not doing so?

Bitpacked records are considered to be byte-aligned by the compiler. That means that if we would use 16bit or 32bit loads stores, they would actually be split up in multiple byte stores on ARM, which is definitely not what you would want here. The alignment of such records could change if we did have a way to specify the access size of individual elements, but in past discussions nobody ever came up with a nice syntax for this. I'm personally also not interested in working on this.

Jonas

Reply by email

Michael Ring
to Jonas Maebe

Could you give me a hint on where this is handled in code-generator? (I never wanted to touch this beast so I do not know which files are relevant)

Could it be acceptable to change behaviour of the Code-Generator when compiling for arm-embedded? (or by implementing {$bitaccesssize 4}, which looks like a nice syntax for this to me)?

What I have in Mind is that arm seems to support unaligned access, so it might for a first step be good enough to replace the byte load/store with 32bit load/store (yes, when crossing a boundary on 32bit access there's a performance hit, but this should get evened out by not doing the 'and $ff' in generated code.). It would of course be better to always do aligned access but to be able to do this I would first need to understand how the whole mechanism works in general in the code generator, for example for cornercases where a huge number of bits (>8) gets modified at the same time)

What do you think?

Michael

Jonas Maebe wrote 17 lines
On 11 Dec 2013, at 08:43, Michael Ring wrote: > The strb command seems to be the problem, documentation from STM states: > > Each I/O port bit is freely programmable, however the I/O port registers have to be accessed as 32-bit words (half-word or byte accesses are not allowed). > > So, is there some way to make the bitset operations word-aligned? No. In C, you can control the access size by using "int ODR0:1;" instead of "char ODR0:1;", but there is no equivalent in Pascal. This functionality was not introduced with direct hardware access in mind, but for compatibility with the way it's implemented in Mac Pascal compilers and GPC/GCC (the last one with "__attribute__((__packed__))", which is what GPC implicitly uses). > Are there any good reasons for not doing so? Bitpacked records are considered to be byte-aligned by the compiler. That means that if we would use 16bit or 32bit loads stores, they would actually be split up in multiple byte stores on ARM, which is definitely not what you would want here. The alignment of such records could change if we did have a way to specify the access size of individual elements, but in past discussions nobody ever came up with a nice syntax for this. I'm personally also not interested in working on this. Jonas_______________________________________________ fpc-devel maillist - http://lists.freepascal.org/mailman/listinfo/fpc-devel

Reply by email

Bernd Mueller
to Michael Ring
Michael Ring wrote 7 lines
Could it be acceptable to change behaviour of the Code-Generator when compiling for arm-embedded? (or by implementing {$bitaccesssize 4}, which looks like a nice syntax for this to me)? What I have in Mind is that arm seems to support unaligned access, so it might for a first step be good enough to replace the byte load/store

at least ARMv4T architecture, which is also covered by arm-embedded does not support unaligned accesses.

Regards, Bernd.

Reply by email