* Forcing GNAT to use 32-bit load/store instructions on ARM? @ 2014-06-30 22:11 daniel.dmk 2014-06-30 23:41 ` Jeffrey Carter ` (4 more replies) 0 siblings, 5 replies; 51+ messages in thread From: daniel.dmk @ 2014-06-30 22:11 UTC (permalink / raw) Hello, I've started using GNAT GPL for ARM (hosted on Windows) and I'm working on some code in SPARK 2014 to interface to memory-mapped registers to control registers on the STM32 F4 microcontroller, however I'm having trouble where GNAT is using byte loads/stores to the registers, instead of word load/stores (32-bit). For a lot of registers on the STM32 it is necessary to always access the registers using 32-bit load/store instructions. Using half-word (16-bit) or byte (8-bit) accesses generates a CPU fault with these registers. I'm representing the 32-bit register as a record as follows: type Bits_1 is mod 2**1 with Size => 1; type CR_Register is record RNGEN : Bits_1; IE : Bits_1; end record; for CR_Register use record RNGEN at 0 range 2 .. 2; -- bits 0 .. 1 are reserved IE at 0 range 3 .. 3; -- bits 4 .. 31 are reserved end record; for CR_Register'Size use 32; I then define the register of type CR_Register at the peripheral's base address: CR : CR_Register with Size => 32, Volatile, Async_Readers, Async_Writers, Address => System'To_Address(Base_Address); I'm using a record instead of a simple Unsigned_32 type so that: 1) I can hide access to the "reserved" parts of the register, 2) The code to modify the register is straightfoward. For example, enabling the peripheral is done by setting the RNGEN bit to 1: CR.RNGEN := 1; However, the GNAT compiler uses the ARM instruction ldrb to load the lower 8 bits of the register, modify the byte (or 16#40#), then use strb to write the lower 8-bits back to memory. This causes a fault since the register must be accessed using a 32-bit load/store instructions (the ldr and str instructions). Does anyone know how I can force GNAT to generate the appropriate instructions? Things I have tried: 1) Using the Atomic aspect on the record type and CR object had no effect on the code generated. 2) Using Pack. 3) Declaring the bits inside the register as: Bits_32 range 0 .. 1; So far, I am able to get GNAT to use 32-bit load/stores only when I read the entire record into a temporary variable, as follows: declare Temp : CR_Register; begin Temp := CR; Temp.RNGEN := 1; CR := Temp; end; However, this makes it more "clunky" to use in my opinion. I would prefer to be able to modify the bits directly, and have the compiler always use 32-bit load/store instructions. Does anyone else have any ideas that I could try? Thanks, Dan ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-06-30 22:11 Forcing GNAT to use 32-bit load/store instructions on ARM? daniel.dmk @ 2014-06-30 23:41 ` Jeffrey Carter 2014-07-01 12:06 ` Simon Clubley 2014-07-01 0:55 ` anon ` (3 subsequent siblings) 4 siblings, 1 reply; 51+ messages in thread From: Jeffrey Carter @ 2014-06-30 23:41 UTC (permalink / raw) On 06/30/2014 03:11 PM, daniel.dmk@googlemail.com wrote: > > Does anyone know how I can force GNAT to generate the appropriate > instructions? If you need specific machine instructions, you should use a machine-code insertion. -- Jeff Carter "Now look, Col. Batguano, if that really is your name." Dr. Strangelove 31 ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-06-30 23:41 ` Jeffrey Carter @ 2014-07-01 12:06 ` Simon Clubley 2014-07-01 15:44 ` Niklas Holsti ` (2 more replies) 0 siblings, 3 replies; 51+ messages in thread From: Simon Clubley @ 2014-07-01 12:06 UTC (permalink / raw) On 2014-06-30, Jeffrey Carter <spam.jrcarter.not@spam.not.acm.org> wrote: > On 06/30/2014 03:11 PM, daniel.dmk@googlemail.com wrote: >> >> Does anyone know how I can force GNAT to generate the appropriate >> instructions? > > If you need specific machine instructions, you should use a machine-code insertion. > The issue here is that Pragma Atomic should have given him the guarantee he needs. There is a place for specific assembly language insertions (for example, on ARM when you need to access the CPSR register), but that should not be required here. Simon. -- Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP Microsoft: Bringing you 1980s technology to a 21st century world ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-01 12:06 ` Simon Clubley @ 2014-07-01 15:44 ` Niklas Holsti 2014-07-01 17:26 ` Simon Clubley 2014-07-01 17:18 ` Simon Wright 2014-07-01 17:28 ` Jeffrey Carter 2 siblings, 1 reply; 51+ messages in thread From: Niklas Holsti @ 2014-07-01 15:44 UTC (permalink / raw) On 14-07-01 15:06 , Simon Clubley wrote: > On 2014-06-30, Jeffrey Carter <spam.jrcarter.not@spam.not.acm.org> wrote: >> On 06/30/2014 03:11 PM, daniel.dmk@googlemail.com wrote: >>> >>> Does anyone know how I can force GNAT to generate the appropriate >>> instructions? >> >> If you need specific machine instructions, you should use a machine-code insertion. >> > > The issue here is that Pragma Atomic should have given him the guarantee > he needs. Perhaps pragma Atomic did not work because the record actually had only 2 significant bits, fitting in one octet, and the Size = 32 bits clause did not make GNAT treat all 32 bits as atomic? I'm not sure if that would be a bug -- does a Size clause determine the extent of pragma Atomic? The OP should try to add components to fill all 32 bits, and also use pragma Atomic. If that doesn't work, then it is a GNAT bug, methinks. -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-01 15:44 ` Niklas Holsti @ 2014-07-01 17:26 ` Simon Clubley 0 siblings, 0 replies; 51+ messages in thread From: Simon Clubley @ 2014-07-01 17:26 UTC (permalink / raw) On 2014-07-01, Niklas Holsti <niklas.holsti@tidorum.invalid> wrote: > On 14-07-01 15:06 , Simon Clubley wrote: >> On 2014-06-30, Jeffrey Carter <spam.jrcarter.not@spam.not.acm.org> wrote: >>> On 06/30/2014 03:11 PM, daniel.dmk@googlemail.com wrote: >>>> >>>> Does anyone know how I can force GNAT to generate the appropriate >>>> instructions? >>> >>> If you need specific machine instructions, you should use a machine-code insertion. >>> >> >> The issue here is that Pragma Atomic should have given him the guarantee >> he needs. > > Perhaps pragma Atomic did not work because the record actually had only > 2 significant bits, fitting in one octet, and the Size = 32 bits clause > did not make GNAT treat all 32 bits as atomic? I'm not sure if that > would be a bug -- does a Size clause determine the extent of pragma Atomic? > I suppose it's possible, but then again according to the OP it did work when using a temporary record. > The OP should try to add components to fill all 32 bits, and also use > pragma Atomic. If that doesn't work, then it is a GNAT bug, methinks. > Filling out to 32-bits would be an interesting test (and allows the OP to set them to a known value if performing a simple 32-bit store instead of a R/M/W operation.) Simon. -- Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP Microsoft: Bringing you 1980s technology to a 21st century world ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-01 12:06 ` Simon Clubley 2014-07-01 15:44 ` Niklas Holsti @ 2014-07-01 17:18 ` Simon Wright 2014-07-01 19:43 ` Simon Wright 2014-07-01 17:28 ` Jeffrey Carter 2 siblings, 1 reply; 51+ messages in thread From: Simon Wright @ 2014-07-01 17:18 UTC (permalink / raw) Simon Clubley <clubley@remove_me.eisner.decus.org-Earth.UFP> writes: > On 2014-06-30, Jeffrey Carter <spam.jrcarter.not@spam.not.acm.org> wrote: >> On 06/30/2014 03:11 PM, daniel.dmk@googlemail.com wrote: >>> >>> Does anyone know how I can force GNAT to generate the appropriate >>> instructions? >> >> If you need specific machine instructions, you should use a >> machine-code insertion. >> > > The issue here is that Pragma Atomic should have given him the guarantee > he needs. > > There is a place for specific assembly language insertions (for example, > on ARM when you need to access the CPSR register), but that should not > be required here. Just for fun I tried this on Intel (x86_64) with GNAT GPL 2014 and GCC 4.9.0 on this: procedure Atom is type R is record A : Boolean; B : Boolean; end record with Size => 32; for R use record A at 0 range 0 .. 0; B at 0 range 31 .. 31; end record; V : R with Atomic, Import, Convention => C, External_Name => "foo"; begin V := (A => True, B => True); V.A := False; end Atom; and found that the compiler did a reaonable thing: movl _T3b.2569(%rip), %edx movq _foo@GOTPCREL(%rip), %rax movl %edx, (%rax) mfence movq _foo@GOTPCREL(%rip), %rax movl (%rax), %edx andl $-2, %edx movl %edx, (%rax) .const .align 2 _T3b.2569: .byte 1 .space 2 .byte 128 ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-01 17:18 ` Simon Wright @ 2014-07-01 19:43 ` Simon Wright 0 siblings, 0 replies; 51+ messages in thread From: Simon Wright @ 2014-07-01 19:43 UTC (permalink / raw) Simon Wright <simon@pushface.org> writes: > and found that the compiler did a reaonable thing: I forgot to say that, _without_ the Atomic aspect and with -O0, the compiler used byte operations; any higher optimisation and the compiler used the longword access as with Atomic. ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-01 12:06 ` Simon Clubley 2014-07-01 15:44 ` Niklas Holsti 2014-07-01 17:18 ` Simon Wright @ 2014-07-01 17:28 ` Jeffrey Carter 2 siblings, 0 replies; 51+ messages in thread From: Jeffrey Carter @ 2014-07-01 17:28 UTC (permalink / raw) On 07/01/2014 05:06 AM, Simon Clubley wrote: > > The issue here is that Pragma Atomic should have given him the guarantee > he needs. I think I agree with Holsti that the lack of reference to the other 30 bits results in the compiler concluding that it can satisfy the pragma with 8-bit loads and stores. > There is a place for specific assembly language insertions (for example, > on ARM when you need to access the CPSR register), but that should not > be required here. A machine-code insertion seems to be required to obtain the machine-code instructions he desires with the type definition he is using. Generally one wants to define the reserved fields so one can control what values they have, but if he doesn't want to do that, he'll probably need a machine-code insertion. -- Jeff Carter "C++ is like giving an AK-47 to a monk, shooting him full of crack and letting him loose in a mall and expecting him to balance your checking account 'when he has the time.'" Drew Olbrich 52 ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-06-30 22:11 Forcing GNAT to use 32-bit load/store instructions on ARM? daniel.dmk 2014-06-30 23:41 ` Jeffrey Carter @ 2014-07-01 0:55 ` anon 2014-07-01 4:30 ` Niklas Holsti ` (2 subsequent siblings) 4 siblings, 0 replies; 51+ messages in thread From: anon @ 2014-07-01 0:55 UTC (permalink / raw) ... -- other Ada instructions -- tells assembler to use 32-bit coding -- Must be before insert 32-bit instructions or the -- assembler will try to decode the 32-bit Ada in 64-bit mode Asm ( Template => ".code32", Volatile => True ) ; --- 32-bit assembly instructions. -- go here -- just an example: A 32-bit 'nop' -- In this case, only a single instruction -- but could be more than 1 Asm ( Template => " nop", Volatile => True ) ; -- go here --- 32-bit assembly instructions -- tells assembler to switch back to 64-bit coding -- Must be after insert 32-bit instructions or the -- assembler will try to decode the 64-bit Ada in 32-bit mode Asm ( Template => ".code64", Volatile => True ) ; ... -- other Ada instructions In <0e0b9ac2-e793-4cc5-8d8d-d3441ca28a58@googlegroups.com>, daniel.dmk@googlemail.com writes: >Hello, > >I've started using GNAT GPL for ARM (hosted on Windows) and I'm working on = >some code in SPARK 2014 to interface to memory-mapped registers to control = >registers on the STM32 F4 microcontroller, however I'm having trouble where= > GNAT is using byte loads/stores to the registers, instead of word load/sto= >res (32-bit). > >For a lot of registers on the STM32 it is necessary to always access the re= >gisters using 32-bit load/store instructions. Using half-word (16-bit) or b= >yte (8-bit) accesses generates a CPU fault with these registers. > >I'm representing the 32-bit register as a record as follows: > > type Bits_1 is mod 2**1 with Size =3D> 1; > > type CR_Register is > record > RNGEN : Bits_1; > IE : Bits_1; > end record; > for CR_Register use > record > RNGEN at 0 range 2 .. 2; -- bits 0 .. 1 are reserved > IE at 0 range 3 .. 3; > -- bits 4 .. 31 are reserved > end record; > for CR_Register'Size use 32; > >I then define the register of type CR_Register at the peripheral's base add= >ress: > > CR : CR_Register > with Size =3D> 32, > Volatile, > Async_Readers, Async_Writers, > Address =3D> System'To_Address(Base_Address); > >I'm using a record instead of a simple Unsigned_32 type so that: >1) I can hide access to the "reserved" parts of the register, >2) The code to modify the register is straightfoward. > >For example, enabling the peripheral is done by setting the RNGEN bit to 1: > > CR.RNGEN :=3D 1; > >However, the GNAT compiler uses the ARM instruction ldrb to load the lower = >8 bits of the register, modify the byte (or 16#40#), then use strb to write= > the lower 8-bits back to memory. This causes a fault since the register mu= >st be accessed using a 32-bit load/store instructions (the ldr and str inst= >ructions). > >Does anyone know how I can force GNAT to generate the appropriate instructi= >ons? > >Things I have tried: >1) Using the Atomic aspect on the record type and CR object had no effect o= >n the code generated. >2) Using Pack. >3) Declaring the bits inside the register as: Bits_32 range 0 .. 1; > >So far, I am able to get GNAT to use 32-bit load/stores only when I read th= >e entire record into a temporary variable, as follows: > > declare > Temp : CR_Register; > begin > Temp :=3D CR; > Temp.RNGEN :=3D 1; > CR :=3D Temp; > end; > >However, this makes it more "clunky" to use in my opinion. I would prefer t= >o be able to modify the bits directly, and have the compiler always use 32-= >bit load/store instructions. > >Does anyone else have any ideas that I could try? > >Thanks, >Dan ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-06-30 22:11 Forcing GNAT to use 32-bit load/store instructions on ARM? daniel.dmk 2014-06-30 23:41 ` Jeffrey Carter 2014-07-01 0:55 ` anon @ 2014-07-01 4:30 ` Niklas Holsti 2014-07-01 8:11 ` Dmitry A. Kazakov 2014-07-01 12:03 ` Simon Clubley 4 siblings, 0 replies; 51+ messages in thread From: Niklas Holsti @ 2014-07-01 4:30 UTC (permalink / raw) On 14-07-01 01:11 , daniel.dmk@googlemail.com wrote: > Hello, > > I've started using GNAT GPL for ARM (hosted on Windows) and I'm > working on some code in SPARK 2014 to interface to memory-mapped > registers to control registers on the STM32 F4 microcontroller, > however I'm having trouble where GNAT is using byte loads/stores > to the registers, instead of word load/stores (32-bit). > > For a lot of registers on the STM32 it is necessary to always > access the registers using 32-bit load/store instructions. Using > half-word (16-bit) or byte (8-bit) accesses generates a CPU fault > with these registers. > > I'm representing the 32-bit register as a record as follows: > > type Bits_1 is mod 2**1 with Size => 1; > > type CR_Register is > record > RNGEN : Bits_1; > IE : Bits_1; > end record; > for CR_Register use > record > RNGEN at 0 range 2 .. 2; -- bits 0 .. 1 are reserved > IE at 0 range 3 .. 3; > -- bits 4 .. 31 are reserved > end record; > for CR_Register'Size use 32; > > I then define the register of type CR_Register at the peripheral's > base address: > > CR : CR_Register > with Size => 32, > Volatile, > Async_Readers, Async_Writers, > Address => System'To_Address(Base_Address); > > I'm using a record instead of a simple Unsigned_32 type so that: > 1) I can hide access to the "reserved" parts of the register, > 2) The code to modify the register is straightfoward. > > For example, enabling the peripheral is done by setting > the RNGEN bit to 1: > > CR.RNGEN := 1; > > However, the GNAT compiler uses the ARM instruction ldrb to > load the lower 8 bits of the register, modify the byte (or > 16#40#), then use strb to write the lower 8-bits back to memory. > This causes a fault since the register must be accessed > using a 32-bit load/store instructions (the ldr and str > instructions). > > Does anyone know how I can force GNAT to generate the > appropriate instructions? > > Things I have tried: > 1) Using the Atomic aspect on the record type and CR object > had no effect on the code generated. > 2) Using Pack. > 3) Declaring the bits inside the register as: Bits_32 range 0 .. 1; I agree in general with Jeff's answer that if you need specific machine instructions, and the compiler documentation does not promise to generate such instructions under certain conditions, you should use assembly language. But if you are willing to take the risk of not being sure, have you tried to define "Reserved" components for bits 0..1 and 4..31 to fill the gaps in the record type? Filling the gaps with named components would also be safer from the HW point of view, because any 32-bit store into the register necessarily must write the reserved bits too, and usually the HW documentation says that one should write zero to reserved bits. Your current, gappy record type may write anything to those bits. -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-06-30 22:11 Forcing GNAT to use 32-bit load/store instructions on ARM? daniel.dmk ` (2 preceding siblings ...) 2014-07-01 4:30 ` Niklas Holsti @ 2014-07-01 8:11 ` Dmitry A. Kazakov 2014-07-01 12:09 ` Simon Clubley 2014-07-01 12:03 ` Simon Clubley 4 siblings, 1 reply; 51+ messages in thread From: Dmitry A. Kazakov @ 2014-07-01 8:11 UTC (permalink / raw) On Mon, 30 Jun 2014 15:11:31 -0700 (PDT), daniel.dmk@googlemail.com wrote: > I've started using GNAT GPL for ARM (hosted on Windows) and I'm working on > some code in SPARK 2014 to interface to memory-mapped registers to control > registers on the STM32 F4 microcontroller, however I'm having trouble > where GNAT is using byte loads/stores to the registers, instead of word > load/stores (32-bit). There is a middle way between assembly insertion and pure Ada. You could try GCC's __sync_fetch_and_or and __sync_bool_compare_and_swap for atomic load/store. https://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html > Things I have tried: > 1) Using the Atomic aspect on the record type and CR object had no effect > on the code generated. Yes, I hope they will fix this for this and other platforms, e.g. 64-bit atomic load/store for i686. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-01 8:11 ` Dmitry A. Kazakov @ 2014-07-01 12:09 ` Simon Clubley 2014-07-01 12:20 ` Dmitry A. Kazakov 0 siblings, 1 reply; 51+ messages in thread From: Simon Clubley @ 2014-07-01 12:09 UTC (permalink / raw) On 2014-07-01, Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote: > On Mon, 30 Jun 2014 15:11:31 -0700 (PDT), daniel.dmk@googlemail.com wrote: >> Things I have tried: >> 1) Using the Atomic aspect on the record type and CR object had no effect >> on the code generated. > > Yes, I hope they will fix this for this and other platforms, e.g. 64-bit > atomic load/store for i686. > Are you saying Pragma Atomic is known to be broken in GNAT ? (I wasn't aware of that if so.) Simon. -- Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP Microsoft: Bringing you 1980s technology to a 21st century world ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-01 12:09 ` Simon Clubley @ 2014-07-01 12:20 ` Dmitry A. Kazakov 2014-07-01 17:00 ` Simon Clubley 0 siblings, 1 reply; 51+ messages in thread From: Dmitry A. Kazakov @ 2014-07-01 12:20 UTC (permalink / raw) On Tue, 1 Jul 2014 12:09:36 +0000 (UTC), Simon Clubley wrote: > On 2014-07-01, Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote: >> On Mon, 30 Jun 2014 15:11:31 -0700 (PDT), daniel.dmk@googlemail.com wrote: >>> Things I have tried: >>> 1) Using the Atomic aspect on the record type and CR object had no effect >>> on the code generated. >> >> Yes, I hope they will fix this for this and other platforms, e.g. 64-bit >> atomic load/store for i686. > > Are you saying Pragma Atomic is known to be broken in GNAT ? It is not broken. The problem I know is that it is rejected on machines that do support atomic load and store. In a wider language design perspective, yes, it is broken because IMO either the language shall require the pragma accepted for all scalar types or else a system package for atomic operations must be provided. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-01 12:20 ` Dmitry A. Kazakov @ 2014-07-01 17:00 ` Simon Clubley 2014-07-01 19:36 ` Dmitry A. Kazakov 0 siblings, 1 reply; 51+ messages in thread From: Simon Clubley @ 2014-07-01 17:00 UTC (permalink / raw) On 2014-07-01, Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote: > On Tue, 1 Jul 2014 12:09:36 +0000 (UTC), Simon Clubley wrote: > >> On 2014-07-01, Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote: >>> On Mon, 30 Jun 2014 15:11:31 -0700 (PDT), daniel.dmk@googlemail.com wrote: >>>> Things I have tried: >>>> 1) Using the Atomic aspect on the record type and CR object had no effect >>>> on the code generated. >>> >>> Yes, I hope they will fix this for this and other platforms, e.g. 64-bit >>> atomic load/store for i686. >> >> Are you saying Pragma Atomic is known to be broken in GNAT ? > > It is not broken. The problem I know is that it is rejected on machines > that do support atomic load and store. > That's not great, but at least you know there's a problem at compile time. In the OP's case (according to the problem description), pragma Atomic was been accepted, but the generated code was not using a 32-bit store and was using an 8-bit store into a 32-bit field instead. If for some reason the compiler could not generate a 32-bit str opcode instead of an 8-bit strb opcode, the pragma Atomic should have caused an error during compilation. Simon. -- Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP Microsoft: Bringing you 1980s technology to a 21st century world ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-01 17:00 ` Simon Clubley @ 2014-07-01 19:36 ` Dmitry A. Kazakov 2014-07-01 20:08 ` Simon Clubley 0 siblings, 1 reply; 51+ messages in thread From: Dmitry A. Kazakov @ 2014-07-01 19:36 UTC (permalink / raw) On Tue, 1 Jul 2014 17:00:45 +0000 (UTC), Simon Clubley wrote: > On 2014-07-01, Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote: >> On Tue, 1 Jul 2014 12:09:36 +0000 (UTC), Simon Clubley wrote: >> >>> On 2014-07-01, Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote: >>>> On Mon, 30 Jun 2014 15:11:31 -0700 (PDT), daniel.dmk@googlemail.com wrote: >>>>> Things I have tried: >>>>> 1) Using the Atomic aspect on the record type and CR object had no effect >>>>> on the code generated. >>>> >>>> Yes, I hope they will fix this for this and other platforms, e.g. 64-bit >>>> atomic load/store for i686. >>> >>> Are you saying Pragma Atomic is known to be broken in GNAT ? >> >> It is not broken. The problem I know is that it is rejected on machines >> that do support atomic load and store. >> > > That's not great, but at least you know there's a problem at compile > time. > > In the OP's case (according to the problem description), pragma Atomic > was been accepted, but the generated code was not using a 32-bit store > and was using an 8-bit store into a 32-bit field instead. Yes, my case was different. The pragma was rejected. > If for some reason the compiler could not generate a 32-bit str opcode > instead of an 8-bit strb opcode, the pragma Atomic should have caused > an error during compilation. Well, pragmas are permitted to be ignored. Atomic should never be a pragma. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-01 19:36 ` Dmitry A. Kazakov @ 2014-07-01 20:08 ` Simon Clubley 2014-07-02 22:24 ` Randy Brukardt 0 siblings, 1 reply; 51+ messages in thread From: Simon Clubley @ 2014-07-01 20:08 UTC (permalink / raw) On 2014-07-01, Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote: > On Tue, 1 Jul 2014 17:00:45 +0000 (UTC), Simon Clubley wrote: >> If for some reason the compiler could not generate a 32-bit str opcode >> instead of an 8-bit strb opcode, the pragma Atomic should have caused >> an error during compilation. > > Well, pragmas are permitted to be ignored. Atomic should never be a pragma. > I thought that only applied to unrecognised pragmas. OTOH, going back a couple of versions to the Ada 95 RM (the version I have to hand and also the pragma only days), C.6(10) makes it clear that an Atomic pragma is illegal if the implementation cannot support the indivisible accesses required. Simon. -- Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP Microsoft: Bringing you 1980s technology to a 21st century world ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-01 20:08 ` Simon Clubley @ 2014-07-02 22:24 ` Randy Brukardt 2014-07-06 20:40 ` MatthiasR 0 siblings, 1 reply; 51+ messages in thread From: Randy Brukardt @ 2014-07-02 22:24 UTC (permalink / raw) "Simon Clubley" <clubley@remove_me.eisner.decus.org-Earth.UFP> wrote in message news:lov4ga$3v9$1@dont-email.me... > On 2014-07-01, Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote: >> On Tue, 1 Jul 2014 17:00:45 +0000 (UTC), Simon Clubley wrote: >>> If for some reason the compiler could not generate a 32-bit str opcode >>> instead of an 8-bit strb opcode, the pragma Atomic should have caused >>> an error during compilation. >> >> Well, pragmas are permitted to be ignored. Atomic should never be a >> pragma. >> > > I thought that only applied to unrecognised pragmas. Correct. Pragma Atomic should be illegal if it is not supported. But Dmitry is right, it should never have been a pragma. (Pragmas should only have been used for global configuration, never on individual entities, IMHO.) > OTOH, going back a couple of versions to the Ada 95 RM (the version > I have to hand and also the pragma only days), C.6(10) makes it clear > that an Atomic pragma is illegal if the implementation cannot support > the indivisible accesses required. Right. If the OP really did exactly as he said, then GNAT has a bug (no matter what his declaration was). [But I've seen plenty of cases where someone (including me) thought they'd tried something when they really had not for one reason or another.] Randy. ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-02 22:24 ` Randy Brukardt @ 2014-07-06 20:40 ` MatthiasR 2014-07-07 0:25 ` Simon Clubley 2014-07-07 22:38 ` Randy Brukardt 0 siblings, 2 replies; 51+ messages in thread From: MatthiasR @ 2014-07-06 20:40 UTC (permalink / raw) Randy Brukardt wrote: > Right. If the OP really did exactly as he said, then GNAT has a bug (no > matter what his declaration was). [But I've seen plenty of cases where > someone (including me) thought they'd tried something when they really had > not for one reason or another.] According to the RM, the compiler must not divide a read or write from/to a variable with pragma/aspect 'atomic' into multiple reads/writes. There is nothing said, that the variable always has to be read/written as a whole. So it seems to be perfectly OK to write only one byte of a 32 bit variable, if a value has been assigned to only a part of a record which is contained in this byte. There is something said about this topic in the latest GNAT docs: https://docs.adacore.com/gnat-unw-docs/html/gnat_ugn_8.html#SEC97 They recommend to use a temporary variable to ensure an access to the record variable as a whole. That is not really elegant, because records with representation clauses, directly mapped onto hardware registers, look like the most natural way to access these registers. Reading Ada books, one even could get the impression that record represenation clauses are made primarily for this purpose. Unfortunately there seem to be no way to force a specific access width, so this feature is not really useable (without the mentioned workaround with the temporary variable) on architectures where the allowed access width is not uniform over the whole address range. Matthias ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-06 20:40 ` MatthiasR @ 2014-07-07 0:25 ` Simon Clubley 2014-07-07 22:38 ` Randy Brukardt 1 sibling, 0 replies; 51+ messages in thread From: Simon Clubley @ 2014-07-07 0:25 UTC (permalink / raw) On 2014-07-06, MatthiasR <MatthiasR@invalid.invalid> wrote: > They recommend to use a temporary variable to ensure an access to the record > variable as a whole. > > That is not really elegant, because records with representation clauses, > directly mapped onto hardware registers, look like the most natural way to > access these registers. Reading Ada books, one even could get the impression > that record represenation clauses are made primarily for this purpose. > Unfortunately there seem to be no way to force a specific access width, so > this feature is not really useable (without the mentioned workaround with > the temporary variable) on architectures where the allowed access width is > not uniform over the whole address range. > Totally agree. In addition, Ada needs syntax/semantics to update multiple bitfields within a record as one write operation without having to use a temporary. The size of the write (assuming the record itself was marked as Atomic) would be the size of the record. In that way, you could (finally) get rid of temporary variables and C style bitmasks when updating registers. Simon. -- Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP Microsoft: Bringing you 1980s technology to a 21st century world ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-06 20:40 ` MatthiasR 2014-07-07 0:25 ` Simon Clubley @ 2014-07-07 22:38 ` Randy Brukardt 2014-07-08 6:51 ` Simon Wright ` (3 more replies) 1 sibling, 4 replies; 51+ messages in thread From: Randy Brukardt @ 2014-07-07 22:38 UTC (permalink / raw) "MatthiasR" <MatthiasR@invalid.invalid> wrote in message news:lpcck1$vtv$1@dont-email.me... > Randy Brukardt wrote: > >> Right. If the OP really did exactly as he said, then GNAT has a bug (no >> matter what his declaration was). [But I've seen plenty of cases where >> someone (including me) thought they'd tried something when they really >> had >> not for one reason or another.] > > According to the RM, the compiler must not divide a read or write from/to > a > variable with pragma/aspect 'atomic' into multiple reads/writes. There is > nothing said, that the variable always has to be read/written as a whole. > So > it seems to be perfectly OK to write only one byte of a 32 bit variable, > if > a value has been assigned to only a part of a record which is contained in > this byte. No. C.6(22/2) surely applies. (All atomic objects are also volatile objects.) Anyone claiming that C.6(22/2) does not apply to a load/store of part of an object is seeing what they want - that would be inconsistent with the way such wording is intepreted in the rest of the standard. But any attempt to write of a record component of an atomic object necessarily must violate either C.6(20) or C.6(22/2). (Either you don't access all of the bits, or you have to have a read not in the source code to read the bits that you aren't going to write.) From that I conclude that Ada doesn't (really) support atomic composite types (and any attempt to declare such a thing ought to be rejected, since the language provides no other possibilities). I doubt any compiler will do that for practical reasons. Since C.6(22/2) is Implementation Advice, a compiler is allowed to ignore it if it documents that it does so. That's probably what GNAT is doing here, but clearly that's harmful (as noted by this discussion). I'd rather that the implementation reject any assignments for which it cannot make this guarantee, but I suppose the language gives no justification for doing so. (That's a common problem in Chapter 13/Annex C features.) Does GNAT at least give a warning? Clearly, we need a partial aggregate syntax (it's the only way for an atomic record write to make sense), and that needs to be clear that it includes both a read and a write of the object for the purposes of volatile variables. Probably someone should submit this problem to Ada-Comment for study in the next version of Ada (whenever that might be). > There is something said about this topic in the latest GNAT docs: > https://docs.adacore.com/gnat-unw-docs/html/gnat_ugn_8.html#SEC97 > > They recommend to use a temporary variable to ensure an access to the > record > variable as a whole. Right. Partial writes of atomic objects shouldn't be allowed at all, and thus the programmer should never write one. > That is not really elegant, because records with representation clauses, > directly mapped onto hardware registers, look like the most natural way to > access these registers. That *is* the most natural way to access those registers. But you can never access a *part* of a register, you always have to read or write the entire register at a time. Ada makes you make that explicit in your code, thus a temporary is required (pending new syntax). > Reading Ada books, one even could get the impression > that record represenation clauses are made primarily for this purpose. It is. > Unfortunately there seem to be no way to force a specific access width, so > this feature is not really useable (without the mentioned workaround with > the temporary variable) on architectures where the allowed access width is > not uniform over the whole address range. No, you're looking at this the wrong way. If you write this in C, you read the entire register and then do some sort of bit-mask, and then write the thing back. You have to do that same thing in Ada, just using the record type instead of the bit mask. Ada replaces the bit masking operations by more readable record component accesses; it doesn't suddenly allow you to write something that you couldn't possibly write in C [a direct write of part of a register]. (Whether Ada *should* have allowed you do to that is a totally different question and relatively irrelevant at the moment because the language isn't likely to support anything new in the near future.) Randy. ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-07 22:38 ` Randy Brukardt @ 2014-07-08 6:51 ` Simon Wright 2014-07-10 11:47 ` Simon Wright 2014-07-08 8:50 ` Brian Drummond ` (2 subsequent siblings) 3 siblings, 1 reply; 51+ messages in thread From: Simon Wright @ 2014-07-08 6:51 UTC (permalink / raw) "Randy Brukardt" <randy@rrsoftware.com> writes: > No. C.6(22/2) surely applies. (All atomic objects are also volatile > objects.) Anyone claiming that C.6(22/2) does not apply to a > load/store of part of an object is seeing what they want - that would > be inconsistent with the way such wording is intepreted in the rest of > the standard. I don't quite understand the conclusion of AI95-00272 in the light of this! (It's expressed in terms of slices of an (atomic) array object, but it would surely apply also to record components if anyone had thought of that). I don't understand why anyone would say that an object was atomic if they didn't want it to be always addressed as a whole (and the prime reason for that must be memory-mapped I/O, given we now have protected objects for inter-task communication). See also the AARM ramification for C6(7), "A slice of an atomic array object is not itself atomic. That's necessary as executing a read or write of a dynamic number of components in a single instruction is not possible on many targets." which strikes me as being back-to-front reasoning. See also C.6(15), "For an atomic object (including an atomic component) all reads and updates of the object as a whole are indivisible.". I can't help wondering whether "as a whole" was a mistake, given that the IA in the AARM, back as far as Ada95, includes "The presumption is that volatile or atomic objects might reside in an ``active'' part of the address space where each read has a potential side-effect, and at the very least might deliver a different value.". > I doubt any compiler will do that for practical reasons. Since > C.6(22/2) is Implementation Advice, a compiler is allowed to ignore it > if it documents that it does so. That's probably what GNAT is doing > here, but clearly that's harmful (as noted by this discussion). I'd > rather that the implementation reject any assignments for which it > cannot make this guarantee, but I suppose the language gives no > justification for doing so. (That's a common problem in Chapter > 13/Annex C features.) Does GNAT at least give a warning? The GNAT RM doesn't contain notes on C.6 IA, and GNAT doesn't give a warning. FSF GCC 4.9.0 and GNAT GPL 2014 (Mac, x86_64) are both (IMO) a little confused (maybe just legalistic) about this: procedure Atom is type R is record A : Boolean; B : Boolean; end record with Size => 32; for R use record A at 0 range 0 .. 0; B at 0 range 31 .. 31; end record; V : R with Import, Atomic, Convention => C, External_Name => "foo"; begin V := (A => True, B => True); V.A := False; V.B := False; V := (A => True, B => True); end Atom; in that the whole-record assignments are followed by an mfence instruction while the component assignments (implemented by a read V, modify, write V sequence of 3 instructions) are not; I think this means that the component assignments are just treated as volatile, borne out by the fact that the -gnatw.d switch (turn on info messages for atomic synchronization) only reports 'info: atomic synchronization set for "V"' for the whole-record assignments. The x86_64 code accesses all 32 bits of V. If it is more efficient on arm to access the relevant bytes for the component assignments, I expect that's what would happen (as reported). ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-08 6:51 ` Simon Wright @ 2014-07-10 11:47 ` Simon Wright 2014-07-10 13:06 ` Simon Clubley 0 siblings, 1 reply; 51+ messages in thread From: Simon Wright @ 2014-07-10 11:47 UTC (permalink / raw) Simon Wright <simon@pushface.org> writes: > The x86_64 code accesses all 32 bits of V. If it is more efficient on > arm to access the relevant bytes for the component assignments, I > expect that's what would happen (as reported). Just tried this on Raspberry Pi (GCC 4.6.3): yes, it only accesses the relevant bytes. ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-10 11:47 ` Simon Wright @ 2014-07-10 13:06 ` Simon Clubley 2014-07-11 18:05 ` Simon Wright 0 siblings, 1 reply; 51+ messages in thread From: Simon Clubley @ 2014-07-10 13:06 UTC (permalink / raw) On 2014-07-10, Simon Wright <simon@pushface.org> wrote: > Simon Wright <simon@pushface.org> writes: > >> The x86_64 code accesses all 32 bits of V. If it is more efficient on >> arm to access the relevant bytes for the component assignments, I >> expect that's what would happen (as reported). > > Just tried this on Raspberry Pi (GCC 4.6.3): yes, it only accesses the > relevant bytes. Just to make sure: you mean it uses ldrb/strb instead of ldr/str in the generated code ? Thanks, Simon. -- Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP Microsoft: Bringing you 1980s technology to a 21st century world ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-10 13:06 ` Simon Clubley @ 2014-07-11 18:05 ` Simon Wright 2014-07-11 20:22 ` Simon Clubley 0 siblings, 1 reply; 51+ messages in thread From: Simon Wright @ 2014-07-11 18:05 UTC (permalink / raw) Simon Clubley <clubley@remove_me.eisner.decus.org-Earth.UFP> writes: > On 2014-07-10, Simon Wright <simon@pushface.org> wrote: >> Simon Wright <simon@pushface.org> writes: >> >>> The x86_64 code accesses all 32 bits of V. If it is more efficient on >>> arm to access the relevant bytes for the component assignments, I >>> expect that's what would happen (as reported). >> >> Just tried this on Raspberry Pi (GCC 4.6.3): yes, it only accesses the >> relevant bytes. > > Just to make sure: you mean it uses ldrb/strb instead of ldr/str > in the generated code ? Yes. I don't understand all the asm, but that part is clear! _ada_atom: @ args = 0, pretend = 0, frame = 0 @ frame_needed = 0, uses_anonymous_args = 0 @ link register save eliminated. ldr r2, .L2 ldr r3, .L2+4 ldmia r2, {r1, r2} str r1, [r3, #0] ldrb r1, [r3, #0] @ zero_extendqisi2 bic r1, r1, #1 strb r1, [r3, #0] ldrb r1, [r3, #3] @ zero_extendqisi2 bic r1, r1, #128 strb r1, [r3, #3] str r2, [r3, #0] bx lr ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-11 18:05 ` Simon Wright @ 2014-07-11 20:22 ` Simon Clubley 0 siblings, 0 replies; 51+ messages in thread From: Simon Clubley @ 2014-07-11 20:22 UTC (permalink / raw) On 2014-07-11, Simon Wright <simon@pushface.org> wrote: > Simon Clubley <clubley@remove_me.eisner.decus.org-Earth.UFP> writes: > >> On 2014-07-10, Simon Wright <simon@pushface.org> wrote: >>> Simon Wright <simon@pushface.org> writes: >>> >>>> The x86_64 code accesses all 32 bits of V. If it is more efficient on >>>> arm to access the relevant bytes for the component assignments, I >>>> expect that's what would happen (as reported). >>> >>> Just tried this on Raspberry Pi (GCC 4.6.3): yes, it only accesses the >>> relevant bytes. >> >> Just to make sure: you mean it uses ldrb/strb instead of ldr/str >> in the generated code ? > > Yes. I don't understand all the asm, but that part is clear! > > _ada_atom: > @ args = 0, pretend = 0, frame = 0 > @ frame_needed = 0, uses_anonymous_args = 0 > @ link register save eliminated. > ldr r2, .L2 > ldr r3, .L2+4 > ldmia r2, {r1, r2} > str r1, [r3, #0] > ldrb r1, [r3, #0] @ zero_extendqisi2 > bic r1, r1, #1 > strb r1, [r3, #0] > ldrb r1, [r3, #3] @ zero_extendqisi2 ^^^ Eeeek! :-) That's an "interesting" variant I have not seen before. It looks like gcc is generating code to do a byte offset load directly from the top byte of the 32-bit word. In my bitfield struct experiments in C I only ever saw gcc use ldrb when the bitfield was in the low 8 bits of the 32-bit word. I never managed to get gcc to do the above. Congratulations on finding yet another variant to this. :-) > bic r1, r1, #128 > strb r1, [r3, #3] > str r2, [r3, #0] > bx lr Simon. -- Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP Microsoft: Bringing you 1980s technology to a 21st century world ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-07 22:38 ` Randy Brukardt 2014-07-08 6:51 ` Simon Wright @ 2014-07-08 8:50 ` Brian Drummond 2014-07-08 12:12 ` Simon Clubley 2014-07-20 11:35 ` MatthiasR 3 siblings, 0 replies; 51+ messages in thread From: Brian Drummond @ 2014-07-08 8:50 UTC (permalink / raw) On Mon, 07 Jul 2014 17:38:54 -0500, Randy Brukardt wrote: > "MatthiasR" <MatthiasR@invalid.invalid> wrote in message > news:lpcck1$vtv$1@dont-email.me... >> That is not really elegant, because records with representation >> clauses, directly mapped onto hardware registers, look like the most >> natural way to access these registers. > > That *is* the most natural way to access those registers. But you can > never access a *part* of a register, you always have to read or write > the entire register at a time. Ada makes you make that explicit in your > code, thus a temporary is required (pending new syntax). There are exceptions to this. Some embedded CPUs (and even the old Z80) have atomic "bit test, set, clear" instructions. Where a register is represented in Ada as a packed array of booleans, setting one component of the array does actually compile down to a single "bit set" instruction. (I do not have a worked example with a record of packed booleans, but would expect the same). (Except for bit 7 on the MSP430 gcc4.9 back end where you get a shift instead, which expands to about 30 instructions! Must report that one...) But the bit access exception doesn't fundamentally change the argument : there are no access levels between the bit and the byte (or 32-bit word on some architectures) so there are no general hardware means for atomically accessing arbitrary sizes or alignments of record components. And thus, I see no way to coherently offer such facility in Ada with a guarantee of atomicity. One of Ada's strengths is that, however abstract the syntax and semantics may be, it is always close to the hardware in terms of the underlying operations it offers. - Brian ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-07 22:38 ` Randy Brukardt 2014-07-08 6:51 ` Simon Wright 2014-07-08 8:50 ` Brian Drummond @ 2014-07-08 12:12 ` Simon Clubley 2014-07-08 13:26 ` G.B. ` (2 more replies) 2014-07-20 11:35 ` MatthiasR 3 siblings, 3 replies; 51+ messages in thread From: Simon Clubley @ 2014-07-08 12:12 UTC (permalink / raw) On 2014-07-07, Randy Brukardt <randy@rrsoftware.com> wrote: > > Clearly, we need a partial aggregate syntax (it's the only way for an atomic > record write to make sense), and that needs to be clear that it includes > both a read and a write of the object for the purposes of volatile > variables. Probably someone should submit this problem to Ada-Comment for > study in the next version of Ada (whenever that might be). > What are the submission details for Ada-Comment ? (Searching for Ada Comments just points to links about using comments in Ada code.) What is the level of formality and problem detail required in the submission ? I also wonder if "Atomic" is the correct word here; perhaps something like "Non_Segmented_Access" would be a better attribute name when we _must_ access the register in units of the record size and don't really care about the Read-Modify-Write sequence itself being indivisible. _We_ "know" that Atomic in this case really only means there's a single, full-sized read and a single full-sized write of the register and that the whole Read-Modify-Write sequence itself isn't really indivisible. However, it's reasonable for a newcomer to Ada to wonder if Atomic really does mean the whole Read-Modify-Write sequence itself is indivisible. One of the goals of Ada is to express clarity when writing code and "Non_Segmented_Access" expresses the intent here better than Atomic does. Simon. -- Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP Microsoft: Bringing you 1980s technology to a 21st century world ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-08 12:12 ` Simon Clubley @ 2014-07-08 13:26 ` G.B. 2014-07-08 17:13 ` Simon Clubley 2014-07-08 15:36 ` Adam Beneschan 2014-07-08 20:34 ` Randy Brukardt 2 siblings, 1 reply; 51+ messages in thread From: G.B. @ 2014-07-08 13:26 UTC (permalink / raw) On 08.07.14 14:12, Simon Clubley wrote: > What are the submission details for Ada-Comment ? (Searching for Ada > Comments just points to links about using comments in Ada code.) Searching the LRM for "ada-comment" uses prior knowledge which, by narrowing, is superior to anything that the WWW's Search AI can possibly produce ;-) ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-08 13:26 ` G.B. @ 2014-07-08 17:13 ` Simon Clubley 0 siblings, 0 replies; 51+ messages in thread From: Simon Clubley @ 2014-07-08 17:13 UTC (permalink / raw) On 2014-07-08, G.B. <rm-dash-bau-haus@dash.futureapps.de> wrote: > On 08.07.14 14:12, Simon Clubley wrote: >> What are the submission details for Ada-Comment ? (Searching for Ada >> Comments just points to links about using comments in Ada code.) > > Searching the LRM for "ada-comment" uses prior knowledge > which, by narrowing, is superior to anything that the WWW's > Search AI can possibly produce ;-) > My copy of the LRM is safely at home in my library. :-) (Ada is not a part of my day job.) Since I only tend to study it when needing to resolve a specific issue (and look at the specific sections around that issue only) I had overlooked this. I knew about the Ada Issues database, but I didn't realise the initial submission was via an address starting with ada-comment. Thanks to you and Adam. Simon. -- Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP Microsoft: Bringing you 1980s technology to a 21st century world ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-08 12:12 ` Simon Clubley 2014-07-08 13:26 ` G.B. @ 2014-07-08 15:36 ` Adam Beneschan 2014-07-08 15:40 ` Adam Beneschan 2014-07-08 20:34 ` Randy Brukardt 2 siblings, 1 reply; 51+ messages in thread From: Adam Beneschan @ 2014-07-08 15:36 UTC (permalink / raw) On Tuesday, July 8, 2014 5:12:22 AM UTC-7, Simon Clubley wrote: > What are the submission details for Ada-Comment ? http://www.ada-auth.org/standards/12aarm/html/AA-0-2.html, paragraph 58ff. -- Adam ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-08 15:36 ` Adam Beneschan @ 2014-07-08 15:40 ` Adam Beneschan 0 siblings, 0 replies; 51+ messages in thread From: Adam Beneschan @ 2014-07-08 15:40 UTC (permalink / raw) On Tuesday, July 8, 2014 8:36:03 AM UTC-7, Adam Beneschan wrote: > On Tuesday, July 8, 2014 5:12:22 AM UTC-7, Simon Clubley wrote: > > What are the submission details for Ada-Comment ? > http://www.ada-auth.org/standards/12aarm/html/AA-0-2.html, paragraph 58ff. Actually, http://www.ada-auth.org/standards/12rm/html/RM-0-2.html is slightly better. (I tend to consult the AARM first always, so that's why I came up with that link.) -- Adam ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-08 12:12 ` Simon Clubley 2014-07-08 13:26 ` G.B. 2014-07-08 15:36 ` Adam Beneschan @ 2014-07-08 20:34 ` Randy Brukardt 2014-07-09 7:31 ` Dmitry A. Kazakov 2 siblings, 1 reply; 51+ messages in thread From: Randy Brukardt @ 2014-07-08 20:34 UTC (permalink / raw) "Simon Clubley" <clubley@remove_me.eisner.decus.org-Earth.UFP> wrote in message news:lpgn76$u7h$1@dont-email.me... > On 2014-07-07, Randy Brukardt <randy@rrsoftware.com> wrote: >> >> Clearly, we need a partial aggregate syntax (it's the only way for an >> atomic >> record write to make sense), and that needs to be clear that it includes >> both a read and a write of the object for the purposes of volatile >> variables. Probably someone should submit this problem to Ada-Comment for >> study in the next version of Ada (whenever that might be). >> > > What are the submission details for Ada-Comment ? (Searching for Ada > Comments just points to links about using comments in Ada code.) Others have answered this. > What is the level of formality and problem detail required in the > submission ? Well, it's English, so there's no way to enforce anything. :-) The expectation is that people report the problems they have, that are either hard or impossible to solve with Ada as it stands. A sufficient level of detail is needed so that we can understand the problem. It's not necessary to provide solutions (although few people can resist offering up their pet ideas). > I also wonder if "Atomic" is the correct word here; perhaps something like > "Non_Segmented_Access" would be a better attribute name when we > _must_ access the register in units of the record size and don't really > care about the Read-Modify-Write sequence itself being indivisible. We discussed that years ago, that's why C.6(22/2) was added. And the answer was, yes, "Atomic" is the concept that we want to use for this. It's essentially the same idea. As far as the "Read-Modify-Write" sequence being indivisble, that definitely is *not* the purpose of Atomic. It just makes Read indivisible (and the same for Write, of course). To make "Read-Modify-Write" indivisible, you'd need a test-and-set instruction, which would require far more restrictions than Atomic does. (I don't see any way to make a general Read-Modify-Write to be indivisible on Windows or Linux, for instance, as that requires shutting off interrupts.) I think the only reason that we'd consider adding yet another classification would be in case we were worried about compatibility (which certainly is possible) with the previous definition of Atomic. Randy. ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-08 20:34 ` Randy Brukardt @ 2014-07-09 7:31 ` Dmitry A. Kazakov 2014-07-10 0:11 ` Simon Clubley 0 siblings, 1 reply; 51+ messages in thread From: Dmitry A. Kazakov @ 2014-07-09 7:31 UTC (permalink / raw) On Tue, 8 Jul 2014 15:34:04 -0500, Randy Brukardt wrote: > To make > "Read-Modify-Write" indivisible, you'd need a test-and-set instruction, > which would require far more restrictions than Atomic does. (I don't see any > way to make a general Read-Modify-Write to be indivisible on Windows or > Linux, for instance, as that requires shutting off interrupts.) I don't think this should be the semantics of "indivisible". Because as you said it incredibly difficult to ensure, but more importantly is that this is mot what programmers actually need. They need it rather be logically indivisible from the process' point of view. If the process could lose the processor in between would be no problem for most if not all applications. If anybody wanted on top of that to block all other processes, system kernel, interrupts and the very memory bus itself, he would do this by other means. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-09 7:31 ` Dmitry A. Kazakov @ 2014-07-10 0:11 ` Simon Clubley 0 siblings, 0 replies; 51+ messages in thread From: Simon Clubley @ 2014-07-10 0:11 UTC (permalink / raw) On 2014-07-09, Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote: > On Tue, 8 Jul 2014 15:34:04 -0500, Randy Brukardt wrote: > >> To make >> "Read-Modify-Write" indivisible, you'd need a test-and-set instruction, >> which would require far more restrictions than Atomic does. (I don't see any >> way to make a general Read-Modify-Write to be indivisible on Windows or >> Linux, for instance, as that requires shutting off interrupts.) > > I don't think this should be the semantics of "indivisible". Because as you > said it incredibly difficult to ensure, but more importantly is that this > is mot what programmers actually need. They need it rather be logically > indivisible from the process' point of view. If the process could lose the > processor in between would be no problem for most if not all applications. > Oh, I agree with this. :-) I was just wondering if a newcomer to Ada might be confused by the use of the word Atomic. BTW, I'm planning on writing up the partial aggregate submission sometime at the weekend (spare time permitting :-)). I'm also planning on a second submission which is a request for a formal decision regarding if Atomic on a record applies to the access of a individual record component or not. The wording identified by Niklas ("as a whole") would suggest not but Randy appears to think it does. I think we need a firm decision one way or another so we know for sure. Simon. -- Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP Microsoft: Bringing you 1980s technology to a 21st century world ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-07 22:38 ` Randy Brukardt ` (2 preceding siblings ...) 2014-07-08 12:12 ` Simon Clubley @ 2014-07-20 11:35 ` MatthiasR 2014-07-20 15:49 ` Simon Clubley 3 siblings, 1 reply; 51+ messages in thread From: MatthiasR @ 2014-07-20 11:35 UTC (permalink / raw) Randy Brukardt wrote: > [...] > >> Unfortunately there seem to be no way to force a specific access width, >> so this feature is not really useable (without the mentioned workaround >> with the temporary variable) on architectures where the allowed access >> width is not uniform over the whole address range. > > No, you're looking at this the wrong way. If you write this in C, you read > the entire register and then do some sort of bit-mask, and then write the > thing back. You have to do that same thing in Ada, just using the record > type instead of the bit mask. Ada replaces the bit masking operations by > more readable record component accesses; it doesn't suddenly allow you to > write something that you couldn't possibly write in C [a direct write of > part of a register]. (Whether Ada *should* have allowed you do to that is > a totally different question and relatively irrelevant at the moment > because the language isn't likely to support anything new in the near > future.) > > Randy. Ironically, there *is* another possibility, just in C. In principle, 'Volatile Bitfields', mapped to the register via a pointer, can be used. Bitfields are avoided by most C programmers because their layout is generally not well defined. Means to control the layout (like representation clauses in Ada) do not exist. At least for the ARM platform, the situation is more convenient: There are rules for the layout of bitfields given in the AAPCS (ABI specification for ARM, 'Procedure Call Standard for the ARM Architecture'). So, if the compiler is AAPCS-compliant, the layout of the bitfield records is exactly defined. Additionaly, the AAPCS requires in chapter 7.1.7.5 (http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042e/IHI0042E_aapcs.pdf) that all reads or writes from/to volatile bitfields must be done 'using the access width appropriate to the type of the container'. The 'container' is not the record/struct as a whole, it is a type specifier given with each of the bitfields (this concept of a 'container type' is somewhat strange, I needed some time to get the idea of this...) Example: struct s { volatile int a:8; volatile char b:2 }; 'int' and 'char' are the 'container types' of the bitfields 'a' and 'b'. A AAPCS-compliant compiler must read or write 's.a' using a 32-bit access (assuming 'int' is 32 bit wide). Accesses to 's.b' must be 8 bit wide. So, if a C compiler is AAPCS-compliant, volatile bitfields should have the desired behaviour. Whether a compiler is *really* AAPCS-compliant, is another question. A well-known open source C compiler had bugs in this area in several releases. Last year, attempts were made to repair it. I don't know the current status. Matthias ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-20 11:35 ` MatthiasR @ 2014-07-20 15:49 ` Simon Clubley 2014-07-26 11:05 ` MatthiasR 0 siblings, 1 reply; 51+ messages in thread From: Simon Clubley @ 2014-07-20 15:49 UTC (permalink / raw) On 2014-07-20, MatthiasR <MatthiasR@invalid.invalid> wrote: > > So, if a C compiler is AAPCS-compliant, volatile bitfields should have the > desired behaviour. Whether a compiler is *really* AAPCS-compliant, is > another question. A well-known open source C compiler had bugs in this area > in several releases. Last year, attempts were made to repair it. I don't > know the current status. > That open source C compiler wouldn't be called gcc by any chance would it ? :-) I did some experiments with using bitfields instead of bitmasks in some bare metal ARM target C code a couple of years ago and ran into the exact same problems as the OP's Ada code, with gcc's generated code using ldrb instead of ldr. I haven't tried building a ARM cross compiler using the very latest versions of gcc however. Simon. -- Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP Microsoft: Bringing you 1980s technology to a 21st century world ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-20 15:49 ` Simon Clubley @ 2014-07-26 11:05 ` MatthiasR 2014-08-10 11:20 ` MatthiasR 0 siblings, 1 reply; 51+ messages in thread From: MatthiasR @ 2014-07-26 11:05 UTC (permalink / raw) Simon Clubley wrote: > On 2014-07-20, MatthiasR <MatthiasR@invalid.invalid> wrote: >> >> So, if a C compiler is AAPCS-compliant, volatile bitfields should have >> the desired behaviour. Whether a compiler is *really* AAPCS-compliant, is >> another question. A well-known open source C compiler had bugs in this >> area in several releases. Last year, attempts were made to repair it. I >> don't know the current status. >> > > That open source C compiler wouldn't be called gcc by any chance > would it ? :-) How did you guess that? ;-) > I did some experiments with using bitfields instead of bitmasks in > some bare metal ARM target C code a couple of years ago and ran into > the exact same problems as the OP's Ada code, with gcc's generated > code using ldrb instead of ldr. 'strict volatile bitfields' are good keywords to find some informations about the bugs in this area - and the recent attempts to fix them. > I haven't tried building a ARM cross compiler using the very latest > versions of gcc however. > > Simon. It looks like there are indeed some changes in the latest versions: In http://www.lpcware.com/content/forum/volatile-preventing-ldrb-byte-access someone complains that the compiler does *not* use ldrb on a volatile struct... Matthias ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-26 11:05 ` MatthiasR @ 2014-08-10 11:20 ` MatthiasR 0 siblings, 0 replies; 51+ messages in thread From: MatthiasR @ 2014-08-10 11:20 UTC (permalink / raw) Latest GNAT Pro emits a warning on accesses to components of atomic records: http://www.adacore.com/developers/development-log/NF-73-M715-002-gnat/ At least, one knows that something can go wrong here... Some background story: We stumbled upon this problem some time ago. After I had realised that the RM doesn't give any guarantees in this case (at least the RM can be interpreted in this way...), I filed an enhancement request to Adacore. I proposed to add a (implementation specific, since there isn't anything in standard and I didn't want to wait until Ada 202x) pragma and/or aspect which should enforce a specific access width. That's basically the same as Simon Clubleys proposal in his second issue for 'Ada-comments'. After some discussions, the proposal was rejected, because - there is a working way to solve the problem (the temporary variable) - 'no one would know this implementation specific pragma/aspect' - there is little chance to get this in the standard The new warning is apparently the result of these discussions. Matthias ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-06-30 22:11 Forcing GNAT to use 32-bit load/store instructions on ARM? daniel.dmk ` (3 preceding siblings ...) 2014-07-01 8:11 ` Dmitry A. Kazakov @ 2014-07-01 12:03 ` Simon Clubley 2014-07-01 19:52 ` daniel.dmk 4 siblings, 1 reply; 51+ messages in thread From: Simon Clubley @ 2014-07-01 12:03 UTC (permalink / raw) On 2014-06-30, daniel.dmk@googlemail.com <daniel.dmk@googlemail.com> wrote: > Hello, > > I've started using GNAT GPL for ARM (hosted on Windows) and I'm working on > some code in SPARK 2014 to interface to memory-mapped registers to control > registers on the STM32 F4 microcontroller, however I'm having trouble where > GNAT is using byte loads/stores to the registers, instead of word load/stores > (32-bit). > This is both a GNAT front end problem and a GCC ARM code generator problem. A couple of years ago, I tried to use bitfields in C code instead of bitmasks (which I don't like) in the same way you are using them here in Ada and I ran into the same ldrb/strb problem. At the time I could not find a reliable solution to this and I went back to using bitmasks in my C code. However, we had a discussion in a related area on comp.lang.ada recently and, in Ada, the conclusion was that the Atomic pragma should indeed either give you the guarantee you seek or GNAT should reject the code during compilation. If this isn't happening then I regard that as a major GNAT bug if Pragma Atomic is indeed being ignored. > For a lot of registers on the STM32 it is necessary to always access the > registers using 32-bit load/store instructions. Using half-word (16-bit) or > byte (8-bit) accesses generates a CPU fault with these registers. > > I'm representing the 32-bit register as a record as follows: > > type Bits_1 is mod 2**1 with Size => 1; > > type CR_Register is > record > RNGEN : Bits_1; > IE : Bits_1; > end record; > for CR_Register use > record > RNGEN at 0 range 2 .. 2; -- bits 0 .. 1 are reserved > IE at 0 range 3 .. 3; > -- bits 4 .. 31 are reserved > end record; > for CR_Register'Size use 32; > In the general case, you need to initialise those reserved bits to known values; to not do this is too dangerous. I always do this in C and if I was doing embedded code in Ada I would do the same thing in Ada as well. > I then define the register of type CR_Register at the peripheral's base > address: > > CR : CR_Register > with Size => 32, > Volatile, > Async_Readers, Async_Writers, > Address => System'To_Address(Base_Address); > > I'm using a record instead of a simple Unsigned_32 type so that: > 1) I can hide access to the "reserved" parts of the register, > 2) The code to modify the register is straightfoward. > > For example, enabling the peripheral is done by setting the RNGEN bit to 1: > > CR.RNGEN := 1; > > However, the GNAT compiler uses the ARM instruction ldrb to load the lower 8 > bits of the register, modify the byte (or 16#40#), then use strb to write the > lower 8-bits back to memory. This causes a fault since the register must be > accessed using a 32-bit load/store instructions (the ldr and str instructions). > > Does anyone know how I can force GNAT to generate the appropriate > instructions? > > Things I have tried: > 1) Using the Atomic aspect on the record type and CR object had no effect on > the code generated. That absolutely should have worked or GNAT should have raised a error during compilation. > 2) Using Pack. > 3) Declaring the bits inside the register as: Bits_32 range 0 .. 1; > > So far, I am able to get GNAT to use 32-bit load/stores only when I read the > entire record into a temporary variable, as follows: > > declare > Temp : CR_Register; > begin > Temp := CR; > Temp.RNGEN := 1; > CR := Temp; > end; > FYI, if you need to set more than one bitfield at the same time (as part of an atomic register update) this is the only way you can do this in Ada unless you resort to using C style bitmasks. > However, this makes it more "clunky" to use in my opinion. I would prefer to > be able to modify the bits directly, and have the compiler always use 32-bit > load/store instructions. > > Does anyone else have any ideas that I could try? > Pragma Atomic _should_ have given you the guarantee you needed. Are you double checked how it's being used in the code ? Simon. -- Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP Microsoft: Bringing you 1980s technology to a 21st century world ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-01 12:03 ` Simon Clubley @ 2014-07-01 19:52 ` daniel.dmk 2014-07-01 20:40 ` Simon Clubley 2014-07-02 7:30 ` Simon Wright 0 siblings, 2 replies; 51+ messages in thread From: daniel.dmk @ 2014-07-01 19:52 UTC (permalink / raw) Thank you everyone for your suggestions and comments. On Tuesday, 1 July 2014 13:03:30 UTC+1, Simon Clubley wrote: > > In the general case, you need to initialise those reserved bits to known > > values; to not do this is too dangerous. I always do this in C and if I > > was doing embedded code in Ada I would do the same thing in Ada as well. Thanks for this suggestion, I'll define the reserved bits in the register, and use static checks to enforce that they are not modified from their reset value in the code. > > However, this makes it more "clunky" to use in my opinion. I would prefer to > > > be able to modify the bits directly, and have the compiler always use 32-bit > > > load/store instructions. > > > > > > Does anyone else have any ideas that I could try? > > > > > > > Pragma Atomic _should_ have given you the guarantee you needed. > > Are you double checked how it's being used in the code ? So I've set up a project to demonstrate only this problem. I've created a package called "Test" which contains the structure definition, and the definition of the register itself at the fixed address: with System; package Test is type Bits_1 is mod 2**1 with Size => 1; type Bits_2 is mod 2**2 with Size => 2; type Bits_28 is mod 2**28 with Size => 28; type CR_Register is record Reserved_1 : Bits_2; RNGEN : Bits_1; IE : Bits_1; Reserved_2 : Bits_28; end record; for CR_Register use record Reserved_1 at 0 range 0 .. 1; RNGEN at 0 range 2 .. 2; IE at 0 range 3 .. 3; Reserved_2 at 0 range 4 .. 31; end record; for CR_Register'Size use 32; CR : CR_Register with Volatile, Atomic, Address => System'To_Address(16#5006_0800#); end Test; So I've now defined the reserved bits in the register, and I have added "Atomic" to the CR register. In my main procedure I have the following: with System; with Test; procedure Main with SPARK_Mode => On is pragma Priority(System.Priority'First); begin Test.CR.RNGEN := 1; loop null; end loop; end Main; The line where I assign the RNGEN bit produces the following assembly code (using no optimization: -O0): mov.w r3, #2048 ; 0x800 movt r3, #20486 ; 0x5006 ldrb r2, [r3, #0] orr.w r2, r2, #4 strb r2, [r3, #0] As you can see, it is using byte load/store instructions. So even when using Atomic, and when defining the other bits in the register it is still using the byte load/store instructions. The same assmebly code is generated at all optimization levels. For reference, here's the code when I use a temporary copy of the register: declare Temp : Test.CR_Register; begin Temp := Test.CR; Temp.RNGEN := 1; Test.CR := Temp; end; produces the following assembly code (the 3 segements of asm correspond to each of the 3 lines of code): mov.w r3, #2048 ; 0x800 movt r3, #20486 ; 0x5006 ldr r3, [r3, #0] str r3, [r7, #4] ldr r3, [r7, #4] orr.w r3, r3, #4 str r3, [r7, #4] mov.w r3, #2048 ; 0x800 movt r3, #20486 ; 0x5006 ldr r2, [r7, #4] str r2, [r3, #0] In this case, it is always using the word load/store instructions (ldr and str). Here is the same code when optimization is enabled (-O1): mov.w r3, #2048 ; 0x800 movt r3, #20486 ; 0x5006 ldr r2, [r3, #0] orr.w r2, r2, #4 str r2, [r3, #0] So could there be a problem with GNAT's Atomic on ARM? I think the approach that I will take for the time being is to always use a temporary when reading/writing the registers. I can hide the registers behind procedures to enforce this access, and to also add pre/post conditions to enforce that the reserved bits are not modified from their reset value. I would like to avoid machine code insertions if possible, since I would like to remain inside SPARK 2014 as much as possible (machine code insertions are not in SPARK 2014). ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-01 19:52 ` daniel.dmk @ 2014-07-01 20:40 ` Simon Clubley 2014-07-01 20:55 ` Simon Clubley 2014-07-01 21:01 ` Niklas Holsti 2014-07-02 7:30 ` Simon Wright 1 sibling, 2 replies; 51+ messages in thread From: Simon Clubley @ 2014-07-01 20:40 UTC (permalink / raw) On 2014-07-01, daniel.dmk@googlemail.com <daniel.dmk@googlemail.com> wrote: > Thank you everyone for your suggestions and comments. > > On Tuesday, 1 July 2014 13:03:30 UTC+1, Simon Clubley wrote: >> >> Pragma Atomic _should_ have given you the guarantee you needed. >> >> Are you double checked how it's being used in the code ? > > So I've set up a project to demonstrate only this problem. I've created a package called "Test" which contains the structure definition, and the definition of the register itself at the fixed address: > > with System; > > package Test is > type Bits_1 is mod 2**1 with Size => 1; > type Bits_2 is mod 2**2 with Size => 2; > type Bits_28 is mod 2**28 with Size => 28; > > type CR_Register is > record > Reserved_1 : Bits_2; > RNGEN : Bits_1; > IE : Bits_1; > Reserved_2 : Bits_28; > end record; > for CR_Register use > record > Reserved_1 at 0 range 0 .. 1; > RNGEN at 0 range 2 .. 2; > IE at 0 range 3 .. 3; > Reserved_2 at 0 range 4 .. 31; > end record; > for CR_Register'Size use 32; > > CR : CR_Register with > Volatile, > Atomic, > Address => System'To_Address(16#5006_0800#); > end Test; > > So I've now defined the reserved bits in the register, and I have added "Atomic" to the CR register. > > In my main procedure I have the following: > > with System; > with Test; > > procedure Main > with SPARK_Mode => On > is > pragma Priority(System.Priority'First); > > begin > > Test.CR.RNGEN := 1; > > loop > null; > end loop; > > end Main; > > The line where I assign the RNGEN bit produces the following assembly code (using no optimization: -O0): > > mov.w r3, #2048 ; 0x800 > movt r3, #20486 ; 0x5006 > ldrb r2, [r3, #0] > orr.w r2, r2, #4 > strb r2, [r3, #0] > This is the exact same issue I encountered when I tried to use bitfields in C instead of bitmasks. The difference here is that Ada's Atomic pragma is supposed to stop this type of code from being generated. > As you can see, it is using byte load/store instructions. > > So even when using Atomic, and when defining the other bits in the register > it is still using the byte load/store instructions. The same assmebly code is > generated at all optimization levels. > > For reference, here's the code when I use a temporary copy of the register: > > declare > Temp : Test.CR_Register; > begin > Temp := Test.CR; > Temp.RNGEN := 1; > Test.CR := Temp; > end; > > produces the following assembly code (the 3 segements of asm correspond to > each of the 3 lines of code): > > mov.w r3, #2048 ; 0x800 > movt r3, #20486 ; 0x5006 > ldr r3, [r3, #0] > str r3, [r7, #4] > > ldr r3, [r7, #4] > orr.w r3, r3, #4 > str r3, [r7, #4] > > mov.w r3, #2048 ; 0x800 > movt r3, #20486 ; 0x5006 > ldr r2, [r7, #4] > str r2, [r3, #0] > This is exactly the kind of ARM code I would expect to see generated. > In this case, it is always using the word load/store instructions (ldr and str). Here is the same code when optimization is enabled (-O1): > > mov.w r3, #2048 ; 0x800 > movt r3, #20486 ; 0x5006 > ldr r2, [r3, #0] > orr.w r2, r2, #4 > str r2, [r3, #0] > > So could there be a problem with GNAT's Atomic on ARM? > Yes, big time. The Atomic pragma is making a guarantee which is not being honoured by the gcc ARM code generator. > I think the approach that I will take for the time being is to always use a > temporary when reading/writing the registers. I can hide the registers behind > procedures to enforce this access, and to also add pre/post conditions to > enforce that the reserved bits are not modified from their reset value. > You would need to use a temporary variable anyway if you need to update multiple bitfields at the same time as part of an atomic register update. > I would like to avoid machine code insertions if possible, since I would like > to remain inside SPARK 2014 as much as possible (machine code insertions are > not in SPARK 2014). If you need to do things like manipulate the CPSR or the ARM coprocessor registers, then this might not be possible. Simon. -- Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP Microsoft: Bringing you 1980s technology to a 21st century world ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-01 20:40 ` Simon Clubley @ 2014-07-01 20:55 ` Simon Clubley 2014-07-01 21:01 ` Niklas Holsti 1 sibling, 0 replies; 51+ messages in thread From: Simon Clubley @ 2014-07-01 20:55 UTC (permalink / raw) On 2014-07-01, Simon Clubley <clubley@remove_me.eisner.decus.org-Earth.UFP> wrote: > On 2014-07-01, daniel.dmk@googlemail.com <daniel.dmk@googlemail.com> wrote: >> >> So could there be a problem with GNAT's Atomic on ARM? >> > > Yes, big time. > > The Atomic pragma is making a guarantee which is not being honoured by > the gcc ARM code generator. > And before anyone pulls me up on it :-), I know it's not a pragma any more, but Ada 2012 is still on my list to things to look at (along with lots of other projects all competing for my spare time. :-)) Simon. -- Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP Microsoft: Bringing you 1980s technology to a 21st century world ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-01 20:40 ` Simon Clubley 2014-07-01 20:55 ` Simon Clubley @ 2014-07-01 21:01 ` Niklas Holsti 2014-07-01 21:20 ` Simon Clubley 2014-07-01 21:55 ` daniel.dmk 1 sibling, 2 replies; 51+ messages in thread From: Niklas Holsti @ 2014-07-01 21:01 UTC (permalink / raw) On 14-07-01 23:40 , Simon Clubley wrote: > On 2014-07-01, daniel.dmk@googlemail.com <daniel.dmk@googlemail.com> wrote: >> Thank you everyone for your suggestions and comments. >> >> On Tuesday, 1 July 2014 13:03:30 UTC+1, Simon Clubley wrote: >>> >>> Pragma Atomic _should_ have given you the guarantee you needed. Unfortunately not, see below. >>> Are you double checked how it's being used in the code ? >> >> So I've set up a project to demonstrate only this problem. I've >> created a package called "Test" which contains the structure >> definition, and the definition of the register itself at the >> fixed address: >> >> with System; >> >> package Test is >> type Bits_1 is mod 2**1 with Size => 1; >> type Bits_2 is mod 2**2 with Size => 2; >> type Bits_28 is mod 2**28 with Size => 28; >> >> type CR_Register is >> record >> Reserved_1 : Bits_2; >> RNGEN : Bits_1; >> IE : Bits_1; >> Reserved_2 : Bits_28; >> end record; >> for CR_Register use >> record >> Reserved_1 at 0 range 0 .. 1; >> RNGEN at 0 range 2 .. 2; >> IE at 0 range 3 .. 3; >> Reserved_2 at 0 range 4 .. 31; >> end record; >> for CR_Register'Size use 32; >> >> CR : CR_Register with >> Volatile, >> Atomic, >> Address => System'To_Address(16#5006_0800#); >> end Test; >> >> So I've now defined the reserved bits in the register, and I have >> added "Atomic" to the CR register. >> >> In my main procedure I have the following: >> >> with System; >> with Test; >> >> procedure Main >> with SPARK_Mode => On >> is >> pragma Priority(System.Priority'First); >> >> begin >> >> Test.CR.RNGEN := 1; >> >> loop >> null; >> end loop; >> >> end Main; >> >> The line where I assign the RNGEN bit produces the following >> assembly code (using no optimization: -O0): >> >> mov.w r3, #2048 ; 0x800 >> movt r3, #20486 ; 0x5006 >> ldrb r2, [r3, #0] >> orr.w r2, r2, #4 >> strb r2, [r3, #0] >> > > This is the exact same issue I encountered when I tried to use bitfields > in C instead of bitmasks. The difference here is that Ada's Atomic pragma > is supposed to stop this type of code from being generated. Actually not... as I also forgot... because the Ada rule is RM C.6(15): "For an atomic object (including an atomic component) all reads and updates of the object as a whole are indivisible." Note the part "as a whole". If you access a component of an atomic record, that is not accessing the record "as a whole". >> For reference, here's the code when I use a temporary copy of the register: >> >> declare >> Temp : Test.CR_Register; >> begin >> Temp := Test.CR; >> Temp.RNGEN := 1; >> Test.CR := Temp; >> end; This code accesses the record as a whole, and therefore... > This is exactly the kind of ARM code I would expect to see generated. > >> In this case, it is always using the word load/store instructions >> (ldr and str). >> So could there be a problem with GNAT's Atomic on ARM? >> > > Yes, big time. No. The Atomic guarantee only applies to read/write of the whole record. My earlier post in this thread was in error. -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-01 21:01 ` Niklas Holsti @ 2014-07-01 21:20 ` Simon Clubley 2014-07-01 22:38 ` Niklas Holsti 2014-07-01 21:55 ` daniel.dmk 1 sibling, 1 reply; 51+ messages in thread From: Simon Clubley @ 2014-07-01 21:20 UTC (permalink / raw) On 2014-07-01, Niklas Holsti <niklas.holsti@tidorum.invalid> wrote: > On 14-07-01 23:40 , Simon Clubley wrote: >> On 2014-07-01, daniel.dmk@googlemail.com <daniel.dmk@googlemail.com> wrote: >>> So could there be a problem with GNAT's Atomic on ARM? >>> >> >> Yes, big time. > > No. The Atomic guarantee only applies to read/write of the whole record. > My earlier post in this thread was in error. > That's interesting, and depressing, as it reduces the usefulness of Atomic hugely. When c.l.a talked a few weeks ago about syntax for the atomic update of multiple bitfields at the same time, I had thought the general view was that Atomic on a record resulted in register updates in units of the record size when updating a single bitfield, but that's clearly not the case as you have just pointed out. I think this whole area of the atomic updating of multiple bitfields is something which needs work in Ada especially now the above revelation means Ada is even weaker in this specific area than I thought it was. Thanks for the interesting (if depressing :-)) insight. Simon. -- Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP Microsoft: Bringing you 1980s technology to a 21st century world ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-01 21:20 ` Simon Clubley @ 2014-07-01 22:38 ` Niklas Holsti 2014-07-02 16:49 ` Simon Clubley 0 siblings, 1 reply; 51+ messages in thread From: Niklas Holsti @ 2014-07-01 22:38 UTC (permalink / raw) On 14-07-02 00:20 , Simon Clubley wrote: > On 2014-07-01, Niklas Holsti <niklas.holsti@tidorum.invalid> wrote: >> On 14-07-01 23:40 , Simon Clubley wrote: >>> On 2014-07-01, daniel.dmk@googlemail.com <daniel.dmk@googlemail.com> wrote: >>>> So could there be a problem with GNAT's Atomic on ARM? >>>> >>> >>> Yes, big time. >> >> No. The Atomic guarantee only applies to read/write of the whole record. >> My earlier post in this thread was in error. >> > > That's interesting, and depressing, as it reduces the usefulness of > Atomic hugely. > > When c.l.a talked a few weeks ago about syntax for the atomic update > of multiple bitfields at the same time, I had thought the general > view was that Atomic on a record resulted in register updates in units > of the record size when updating a single bitfield, but that's clearly > not the case as you have just pointed out. As I remember, the new syntax ideas in that discussion were meant to update some bitfields in an atomic record as part of a read, modify, write sequence, accessing the whole record without using a temporary variable to hold the value. So Ada's rule for Atomic was included and assumed in that discussion. I am ashamed for forgetting it... maybe there have been too many midnight-football-viewing sessions lately :-) > I think this whole area of the atomic updating of multiple bitfields is > something which needs work in Ada especially now the above revelation > means Ada is even weaker in this specific area than I thought it was. I don't think the weakness is serious. Using a temporary variable to ensure whole-record access is a pretty clean work-around, IMO. But the new aggregate-like syntax suggested in the earlier discussion could be used for other things, too, so I am still in favour of it. -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-01 22:38 ` Niklas Holsti @ 2014-07-02 16:49 ` Simon Clubley 0 siblings, 0 replies; 51+ messages in thread From: Simon Clubley @ 2014-07-02 16:49 UTC (permalink / raw) On 2014-07-01, Niklas Holsti <niklas.holsti@tidorum.invalid> wrote: > On 14-07-02 00:20 , Simon Clubley wrote: >> >> When c.l.a talked a few weeks ago about syntax for the atomic update >> of multiple bitfields at the same time, I had thought the general >> view was that Atomic on a record resulted in register updates in units >> of the record size when updating a single bitfield, but that's clearly >> not the case as you have just pointed out. > > As I remember, the new syntax ideas in that discussion were meant to > update some bitfields in an atomic record as part of a read, modify, > write sequence, accessing the whole record without using a temporary > variable to hold the value. So Ada's rule for Atomic was included and > assumed in that discussion. Yes, you are correct. Thinking about it, this interpretation of Ada's Atomic rule is still consistent with that discussion because the underlying reference is to the _full_ record in those proposals. > I am ashamed for forgetting it... maybe > there have been too many midnight-football-viewing sessions lately :-) > :-) Simon. -- Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP Microsoft: Bringing you 1980s technology to a 21st century world ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-01 21:01 ` Niklas Holsti 2014-07-01 21:20 ` Simon Clubley @ 2014-07-01 21:55 ` daniel.dmk 1 sibling, 0 replies; 51+ messages in thread From: daniel.dmk @ 2014-07-01 21:55 UTC (permalink / raw) On Tuesday, 1 July 2014 22:01:35 UTC+1, Niklas Holsti wrote: > On 14-07-01 23:40 , Simon Clubley wrote: > > > >> On Tuesday, 1 July 2014 13:03:30 UTC+1, Simon Clubley wrote: > > >>> > > >>> Pragma Atomic _should_ have given you the guarantee you needed. > > > > Unfortunately not, see below. > > > > >>> Are you double checked how it's being used in the code ? > > >> > > >> So I've set up a project to demonstrate only this problem. I've > > >> created a package called "Test" which contains the structure > > >> definition, and the definition of the register itself at the > > >> fixed address: > > >> > > >> with System; > > >> > > >> package Test is > > >> type Bits_1 is mod 2**1 with Size => 1; > > >> type Bits_2 is mod 2**2 with Size => 2; > > >> type Bits_28 is mod 2**28 with Size => 28; > > >> > > >> type CR_Register is > > >> record > > >> Reserved_1 : Bits_2; > > >> RNGEN : Bits_1; > > >> IE : Bits_1; > > >> Reserved_2 : Bits_28; > > >> end record; > > >> for CR_Register use > > >> record > > >> Reserved_1 at 0 range 0 .. 1; > > >> RNGEN at 0 range 2 .. 2; > > >> IE at 0 range 3 .. 3; > > >> Reserved_2 at 0 range 4 .. 31; > > >> end record; > > >> for CR_Register'Size use 32; > > >> > > >> CR : CR_Register with > > >> Volatile, > > >> Atomic, > > >> Address => System'To_Address(16#5006_0800#); > > >> end Test; > > >> > > >> So I've now defined the reserved bits in the register, and I have > > >> added "Atomic" to the CR register. > > >> > > >> In my main procedure I have the following: > > >> > > >> with System; > > >> with Test; > > >> > > >> procedure Main > > >> with SPARK_Mode => On > > >> is > > >> pragma Priority(System.Priority'First); > > >> > > >> begin > > >> > > >> Test.CR.RNGEN := 1; > > >> > > >> loop > > >> null; > > >> end loop; > > >> > > >> end Main; > > >> > > >> The line where I assign the RNGEN bit produces the following > > >> assembly code (using no optimization: -O0): > > >> > > >> mov.w r3, #2048 ; 0x800 > > >> movt r3, #20486 ; 0x5006 > > >> ldrb r2, [r3, #0] > > >> orr.w r2, r2, #4 > > >> strb r2, [r3, #0] > > >> > > > > > > This is the exact same issue I encountered when I tried to use bitfields > > > in C instead of bitmasks. The difference here is that Ada's Atomic pragma > > > is supposed to stop this type of code from being generated. > > > > Actually not... as I also forgot... because the Ada rule is RM C.6(15): > > > > "For an atomic object (including an atomic component) all reads and > > updates of the object as a whole are indivisible." > > > > Note the part "as a whole". If you access a component of an atomic > > record, that is not accessing the record "as a whole". > Aha, this clarifies it all perfectly. Thank you. I'll avoid modifying these registers in part, and make sure that the registers are always accessed in whole. ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-01 19:52 ` daniel.dmk 2014-07-01 20:40 ` Simon Clubley @ 2014-07-02 7:30 ` Simon Wright 2014-07-02 18:52 ` daniel.dmk 2014-07-04 23:51 ` Niklas Holsti 1 sibling, 2 replies; 51+ messages in thread From: Simon Wright @ 2014-07-02 7:30 UTC (permalink / raw) daniel.dmk@googlemail.com writes: > Thanks for this suggestion, I'll define the reserved bits in the > register, and use static checks to enforce that they are not modified > from their reset value in the code. You could use something like type Reserved_Bit is range 0 .. 0 with Size => 1; type Reserved is array (Natural range <>) of Reserved_Bit with Component_Size => 1; ... type T is record A : Boolean; -- at bit 0 Res : Reserved (1 .. 6); B : Boolean; -- at bit 7 end record with Size => 8; (with representation clauses as indicated) ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-02 7:30 ` Simon Wright @ 2014-07-02 18:52 ` daniel.dmk 2014-07-04 23:51 ` Niklas Holsti 1 sibling, 0 replies; 51+ messages in thread From: daniel.dmk @ 2014-07-02 18:52 UTC (permalink / raw) On Wednesday, 2 July 2014 08:30:44 UTC+1, Simon Wright wrote: > > You could use something like > > > > type Reserved_Bit is range 0 .. 0 with Size => 1; > > type Reserved is array (Natural range <>) of Reserved_Bit > > with Component_Size => 1; > > > > ... > > > > type T is record > > A : Boolean; -- at bit 0 > > Res : Reserved (1 .. 6); > > B : Boolean; -- at bit 7 > > end record with Size => 8; > > > > (with representation clauses as indicated) That's quite elegant, I like it. Thanks! ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-02 7:30 ` Simon Wright 2014-07-02 18:52 ` daniel.dmk @ 2014-07-04 23:51 ` Niklas Holsti 2014-07-05 0:18 ` Niklas Holsti 1 sibling, 1 reply; 51+ messages in thread From: Niklas Holsti @ 2014-07-04 23:51 UTC (permalink / raw) On 14-07-02 09:30 , Simon Wright wrote: > daniel.dmk@googlemail.com writes: > >> Thanks for this suggestion, I'll define the reserved bits in the >> register, and use static checks to enforce that they are not modified >> from their reset value in the code. > > You could use something like > > type Reserved_Bit is range 0 .. 0 with Size => 1; > type Reserved is array (Natural range <>) of Reserved_Bit > with Component_Size => 1; > > ... > > type T is record > A : Boolean; -- at bit 0 > Res : Reserved (1 .. 6); > B : Boolean; -- at bit 7 > end record with Size => 8; > > (with representation clauses as indicated) That has two potential problems... - First, even if Reserved_Bit is constrained to a single value (0), that does not mean that an uninitialized variable or component of this type will have that value. It will still have to be assigned the value zero, to be sure of having that value. - Second, if you read the value of the control register into a variable of type T, and some of the reserved bits read as 1 (which is not quite possible), these Reserved_Bit components will now, very probably, have an invalid representation, which is a nasty state. For these reasons, I would define Reserved_Bit as range 0 .. 1 and perhaps provide the default value (others => 0) for the Res component. -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Forcing GNAT to use 32-bit load/store instructions on ARM? 2014-07-04 23:51 ` Niklas Holsti @ 2014-07-05 0:18 ` Niklas Holsti 0 siblings, 0 replies; 51+ messages in thread From: Niklas Holsti @ 2014-07-05 0:18 UTC (permalink / raw) On 14-07-05 01:51 , Niklas Holsti wrote: > On 14-07-02 09:30 , Simon Wright wrote: >> daniel.dmk@googlemail.com writes: >> >>> Thanks for this suggestion, I'll define the reserved bits in the >>> register, and use static checks to enforce that they are not modified >>> from their reset value in the code. >> >> You could use something like >> >> type Reserved_Bit is range 0 .. 0 with Size => 1; >> type Reserved is array (Natural range <>) of Reserved_Bit >> with Component_Size => 1; >> >> ... >> >> type T is record >> A : Boolean; -- at bit 0 >> Res : Reserved (1 .. 6); >> B : Boolean; -- at bit 7 >> end record with Size => 8; >> >> (with representation clauses as indicated) > > That has two potential problems... > > - First, even if Reserved_Bit is constrained to a single value (0), that > does not mean that an uninitialized variable or component of this type > will have that value. It will still have to be assigned the value zero, > to be sure of having that value. > > - Second, if you read the value of the control register into a variable > of type T, and some of the reserved bits read as 1 (which is not quite ^^^ (Delete the word "not", above -- it is quite possible that some reserved bits read as 1, although they should be written with zero.) > possible), these Reserved_Bit components will now, very probably, have > an invalid representation, which is a nasty state. > > For these reasons, I would define Reserved_Bit as range 0 .. 1 and > perhaps provide the default value (others => 0) for the Res component. > -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 51+ messages in thread
end of thread, other threads:[~2014-08-10 11:20 UTC | newest] Thread overview: 51+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2014-06-30 22:11 Forcing GNAT to use 32-bit load/store instructions on ARM? daniel.dmk 2014-06-30 23:41 ` Jeffrey Carter 2014-07-01 12:06 ` Simon Clubley 2014-07-01 15:44 ` Niklas Holsti 2014-07-01 17:26 ` Simon Clubley 2014-07-01 17:18 ` Simon Wright 2014-07-01 19:43 ` Simon Wright 2014-07-01 17:28 ` Jeffrey Carter 2014-07-01 0:55 ` anon 2014-07-01 4:30 ` Niklas Holsti 2014-07-01 8:11 ` Dmitry A. Kazakov 2014-07-01 12:09 ` Simon Clubley 2014-07-01 12:20 ` Dmitry A. Kazakov 2014-07-01 17:00 ` Simon Clubley 2014-07-01 19:36 ` Dmitry A. Kazakov 2014-07-01 20:08 ` Simon Clubley 2014-07-02 22:24 ` Randy Brukardt 2014-07-06 20:40 ` MatthiasR 2014-07-07 0:25 ` Simon Clubley 2014-07-07 22:38 ` Randy Brukardt 2014-07-08 6:51 ` Simon Wright 2014-07-10 11:47 ` Simon Wright 2014-07-10 13:06 ` Simon Clubley 2014-07-11 18:05 ` Simon Wright 2014-07-11 20:22 ` Simon Clubley 2014-07-08 8:50 ` Brian Drummond 2014-07-08 12:12 ` Simon Clubley 2014-07-08 13:26 ` G.B. 2014-07-08 17:13 ` Simon Clubley 2014-07-08 15:36 ` Adam Beneschan 2014-07-08 15:40 ` Adam Beneschan 2014-07-08 20:34 ` Randy Brukardt 2014-07-09 7:31 ` Dmitry A. Kazakov 2014-07-10 0:11 ` Simon Clubley 2014-07-20 11:35 ` MatthiasR 2014-07-20 15:49 ` Simon Clubley 2014-07-26 11:05 ` MatthiasR 2014-08-10 11:20 ` MatthiasR 2014-07-01 12:03 ` Simon Clubley 2014-07-01 19:52 ` daniel.dmk 2014-07-01 20:40 ` Simon Clubley 2014-07-01 20:55 ` Simon Clubley 2014-07-01 21:01 ` Niklas Holsti 2014-07-01 21:20 ` Simon Clubley 2014-07-01 22:38 ` Niklas Holsti 2014-07-02 16:49 ` Simon Clubley 2014-07-01 21:55 ` daniel.dmk 2014-07-02 7:30 ` Simon Wright 2014-07-02 18:52 ` daniel.dmk 2014-07-04 23:51 ` Niklas Holsti 2014-07-05 0:18 ` Niklas Holsti
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox