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 20:40:31 +0000 (UTC) Organization: A noiseless patient Spider Message-ID: References: <0e0b9ac2-e793-4cc5-8d8d-d3441ca28a58@googlegroups.com> Injection-Date: Tue, 1 Jul 2014 20:40:31 +0000 (UTC) Injection-Info: mx05.eternal-september.org; posting-host="e458ff8b81bc0c159989eb0e36c6e372"; logging-data="19484"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18kdSb1VM9v7W/vtEIqr7vmpXNX4znk/7A=" User-Agent: slrn/0.9.8.1 (VMS/Multinet) Cancel-Lock: sha1:3E50lGG93m5qo1hxO1Nr+La5HzY= Xref: news.eternal-september.org comp.lang.ada:20674 Date: 2014-07-01T20:40:31+00:00 List-Id: On 2014-07-01, 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