From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=unavailable autolearn_force=no version=3.4.4 Path: eternal-september.org!reader01.eternal-september.org!reader02.eternal-september.org!news.eternal-september.org!news.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: Simon Clubley Newsgroups: comp.lang.ada Subject: Re: Forcing GNAT to use 32-bit load/store instructions on ARM? Date: Tue, 1 Jul 2014 12:03:30 +0000 (UTC) Organization: A noiseless patient Spider Message-ID: References: <0e0b9ac2-e793-4cc5-8d8d-d3441ca28a58@googlegroups.com> Injection-Date: Tue, 1 Jul 2014 12:03:30 +0000 (UTC) Injection-Info: mx05.eternal-september.org; posting-host="e458ff8b81bc0c159989eb0e36c6e372"; logging-data="8130"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1//pfCj4DYATt4ngNfWNBOyHQRkn6wIxQY=" User-Agent: slrn/0.9.8.1 (VMS/Multinet) Cancel-Lock: sha1:m/rf7sPM9z6ANdmuygi4Y1ReDek= Xref: news.eternal-september.org comp.lang.ada:20660 Date: 2014-07-01T12:03:30+00:00 List-Id: On 2014-06-30, 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