Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Compiler doesn't respect 'Size for atomic object

97 views
Skip to first unread message

Simon Wright

unread,
Dec 20, 2017, 7:35:54 AM12/20/17
to
The code below is an abstract of one for a Cortex-M processor; it
generates an external interrupt, useful for testing.

All released GNAT compilers I have access to and which accept the syntax
(GPL 2015+, FSF GCC 5+) produce the result that the hardware needs and
that I intended, i.e. 16#1#.

GCC 8, which is still under development, produces 16#FFFFFF01#, i.e. has
only written the least significant byte.

I'm pretty sure this is an error, rather than an unhelpful
interpretation: can anyone confirm one way or the other, before I raise
a bug, please?

========================================================================
with Ada.Text_IO;
with Interfaces;

procedure Full_Word is

Register : Interfaces.Unsigned_32;

type Interrupt_ID is range 0 .. 44;

procedure Trigger_Interrupt (IRQ : Interrupt_ID) is
-- The Software Trigger Interrupt Register.
NVIC_STIR : Interrupt_ID
with
Import,
Atomic,
Size => 32,
Address => Register'Address;

begin
NVIC_STIR := IRQ; -- h/w requires 32-bit write
end Trigger_Interrupt;

package Unsigned_32_IO
is new Ada.Text_IO.Modular_IO (Interfaces.Unsigned_32);

begin
Register := 16#ffff_ffff#;
Trigger_Interrupt (1);
Unsigned_32_IO.Put (Register, Base => 16);
Ada.Text_IO.New_Line;
end Full_Word;

Simon Clubley

unread,
Dec 20, 2017, 2:23:34 PM12/20/17
to
On 2017-12-20, Simon Wright <si...@pushface.org> wrote:
> The code below is an abstract of one for a Cortex-M processor; it
> generates an external interrupt, useful for testing.
>
> All released GNAT compilers I have access to and which accept the syntax
> (GPL 2015+, FSF GCC 5+) produce the result that the hardware needs and
> that I intended, i.e. 16#1#.
>
> GCC 8, which is still under development, produces 16#FFFFFF01#, i.e. has
> only written the least significant byte.
>
> I'm pretty sure this is an error, rather than an unhelpful
> interpretation: can anyone confirm one way or the other, before I raise
> a bug, please?
>

And an old friend (for various values of "friend" :-)) has raised
its head again.

A skim through AI12-0128 might be useful although my AI only
refers to components within an atomic composite object.

My instinct is that this is a compiler problem although I don't
know if something is going on due to you extending the underlying
data type to 32 bits.

If you use a naturally 32-bit variable instead of your Interrupt_ID
data type, does it work ok ?

Simon.
--
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP
Microsoft: Bringing you 1980s technology to a 21st century world

Simon Wright

unread,
Dec 20, 2017, 3:19:13 PM12/20/17
to
Simon Clubley <clubley@remove_me.eisner.decus.org-Earth.UFP> writes:

> If you use a naturally 32-bit variable instead of your Interrupt_ID
> data type, does it work ok ?

Yes. My workround is to declare the atomic object as Integer, and
convert the Interrupt_ID to Integer (the ARM says only that Interrupt_ID
is discrete, but that's a bridge to cross when we come to it; it's
naturally an Integer on Cortex-M).

Simon Clubley

unread,
Dec 20, 2017, 3:45:54 PM12/20/17
to
On 2017-12-20, Simon Wright <si...@pushface.org> wrote:
Unless Randy and company come up with something around the use of
Size to extend the size of the base data type[*], I would consider
this to be a compiler bug.

[*] That qualifier is there because I seem to have a vague
recollection of previous discussions around problems that
occurred when Size was used to extend a data type but I can't
remember the details.

Simon.

Simon Wright

unread,
Dec 20, 2017, 4:20:22 PM12/20/17
to
I meant, naturally an integral type. The RM description of the NVIC's
STIR indicates that the IRQ fits in 8 bits; the top 24 bits are reserved
(write as 0).

Robert Eachus

unread,
Dec 21, 2017, 12:55:59 AM12/21/17
to
On Wednesday, December 20, 2017 at 4:20:22 PM UTC-5, Simon Wright wrote:

> I meant, naturally an integral type. The RM description of the NVIC's
> STIR indicates that the IRQ fits in 8 bits; the top 24 bits are reserved
> (write as 0).

A language lawyer reading: If the hardware specifies that those bit must be zero? Then it is definitely a bug. But if all the hardware says is that the positions are reserved, I would expect the compiler to pass whatever junk happened to be in the register. (In other words, move the IRQ as eight-bits to a register, then pass the register to the hardware.)

Should the address of Register in your example be set to 16#E000EF00#? Also should your type Interrupt_ID be given a size? If so I would expect the new behavior with Interrupt_ID'Size set to 8, and the old behavior when it is set to 32.

I am certainly not an expert on the Cortex-M CPUs, but as I read the documentation, the STIR is write-only, and the upper 24-bits of the value written there are ignored. If so, no bug, but probably worth a comment IF the behavior of the compiler has changed, not just the bits you are passing..

Randy Brukardt

unread,
Dec 21, 2017, 2:10:42 AM12/21/17
to
"Simon Clubley" <clubley@remove_me.eisner.decus.org-Earth.UFP> wrote in
message news:p1ei5v$fqc$1...@dont-email.me...
> On 2017-12-20, Simon Wright <si...@pushface.org> wrote:
>> Simon Clubley <clubley@remove_me.eisner.decus.org-Earth.UFP> writes:
>>
>>> If you use a naturally 32-bit variable instead of your Interrupt_ID
>>> data type, does it work ok ?
>>
>> Yes. My workround is to declare the atomic object as Integer, and
>> convert the Interrupt_ID to Integer (the ARM says only that Interrupt_ID
>> is discrete, but that's a bridge to cross when we come to it; it's
>> naturally an Integer on Cortex-M).
>
> Unless Randy and company come up with something around the use of
> Size to extend the size of the base data type[*], I would consider
> this to be a compiler bug.

I tend to agree. The reason is 13.1(7/2). The extra bits in this case are
defined to be "padding bits", and 13.1(7/2) says that "padding bits are
normally read and updated along with the others".

AI12-0128-1 adds some rules for non-atomic subcomponents of atomic objects,
but it shouldn't change the behavior of an *elementary* atomic object, like
this one. Perhaps GNAT is treating this like a record type with two
components, the actual integer value, and some padding bits. Then it would
be right. (But that's not how the language defines this object.)

Still, you'll always have less issues if you avoid padding bits and have the
subtype Object_Size (this is now in Ada 2020, so we can talk about it) be
32.

Which is something you (Simon Wright, not Simon Clubley) might try, since
Object_Size can be specified for any subtype. So try declaring:

subype Simons_Interrupt_Id is Interrupt_Id with Object_Size => 32;

and declare your object of that subtype. Then there are no padding bits (as
defined by 13.1(7.2)).

Randy.


Simon Wright

unread,
Dec 21, 2017, 9:02:52 AM12/21/17
to
Robert Eachus <riea...@comcast.net> writes:

> On Wednesday, December 20, 2017 at 4:20:22 PM UTC-5, Simon Wright wrote:
>
>> I meant, naturally an integral type. The RM description of the NVIC's
>> STIR indicates that the IRQ fits in 8 bits; the top 24 bits are reserved
>> (write as 0).

> Should the address of Register in your example be set to 16#E000EF00#?
> Also should your type Interrupt_ID be given a size? If so I would
> expect the new behavior with Interrupt_ID'Size set to 8, and the old
> behavior when it is set to 32.

This was an example to demo the behaviour on the desktop, mimicing the
real code as far as possible; I wouldn't expect the compiler to behave
differently as far as assign-to-atomic is converned between arm-eabi &
x86_64-apple-darwin. STIR is indeed at 16#E000EF00#.

Looking at Adacore's RTS ravenscar-sfp-stm32f4 in GNAT GPL 2017, I see
(after delving through several layers of package) in
System.BB.Parameters

subtype Interrupt_Range is Integer
range -1 .. MCU_Parameters.Number_Of_Interrupts;

so if I'd followed this style Interrupt_ID would have been 32-bits from
the start.

In my defence, in e.g. GNAT GPL 2015 I see in System.Interrupts

type Ada_Interrupt_ID is range 0 .. System.OS_Interface.Max_Interrupt;

> I am certainly not an expert on the Cortex-M CPUs, but as I read the
> documentation, the STIR is write-only, and the upper 24-bits of the
> value written there are ignored. If so, no bug, but probably worth a
> comment IF the behavior of the compiler has changed, not just the bits
> you are passing..

I was taught that if the specification says a bit is reserved you
need to ensure that you never write a 1 to it (in case some later
revision should assign a meaning to that).

Simon Wright

unread,
Dec 21, 2017, 9:08:40 AM12/21/17
to
"Randy Brukardt" <ra...@rrsoftware.com> writes:

> Still, you'll always have less issues if you avoid padding bits and
> have the subtype Object_Size (this is now in Ada 2020, so we can talk
> about it) be 32.
>
> Which is something you (Simon Wright, not Simon Clubley) might try,
> since Object_Size can be specified for any subtype. So try declaring:
>
> subype Simons_Interrupt_Id is Interrupt_Id with Object_Size => 32;
>
> and declare your object of that subtype. Then there are no padding
> bits (as defined by 13.1(7.2)).

Works a treat! Thanks!

(and Object_Size is available in GNAT back to at least 2015)

Simon Wright

unread,
Dec 21, 2017, 5:02:07 PM12/21/17
to
Robert Eachus <riea...@comcast.net> writes:

> I am certainly not an expert on the Cortex-M CPUs, but as I read the
> documentation, the STIR is write-only, and the upper 24-bits of the
> value written there are ignored.

It turns out that declaring NVIC_STIR as Unsigned_32 and writing

NVIC_STIR := 16#ffff_ff00# or Interfaces.Unsigned_32 (IRQ);

doesn't generate an interrupt.

Robert Eachus

unread,
Dec 21, 2017, 11:51:56 PM12/21/17
to
On Thursday, December 21, 2017 at 5:02:07 PM UTC-5, Simon Wright wrote:
> Robert Eachus <riea...@comcast.net> writes:

> It turns out that declaring NVIC_STIR as Unsigned_32 and writing
>
> NVIC_STIR := 16#ffff_ff00# or Interfaces.Unsigned_32 (IRQ);
>
> doesn't generate an interrupt.

It took me a while to figure out what you were saying. I really need to find a way to post here that will allow things like boldfacing Ada reserved words. After I parsed the or as Ada not English, I still have a problem. that I don't know the value passed as IRQ. I assume it is a valid interrupt number for an unprivileged program.

You should report this to Ada Core as a bug. I'm just not convinced it is an Ada bug or a compiler front end bug, not a Cortex-M code generator bug.

Simon Wright

unread,
Dec 22, 2017, 5:21:27 AM12/22/17
to
Robert Eachus <riea...@comcast.net> writes:

> On Thursday, December 21, 2017 at 5:02:07 PM UTC-5, Simon Wright wrote:
>> Robert Eachus <riea...@comcast.net> writes:
>
>> It turns out that declaring NVIC_STIR as Unsigned_32 and writing
>>
>> NVIC_STIR := 16#ffff_ff00# or Interfaces.Unsigned_32 (IRQ);
>>
>> doesn't generate an interrupt.
>
> It took me a while to figure out what you were saying. I really need
> to find a way to post here that will allow things like boldfacing Ada
> reserved words. After I parsed the or as Ada not English, I still
> have a problem. that I don't know the value passed as IRQ. I assume
> it is a valid interrupt number for an unprivileged program.

In the example I posted upthread,

type Interrupt_ID is range 0 .. 44;

> You should report this to Ada Core as a bug. I'm just not convinced
> it is an Ada bug or a compiler front end bug, not a Cortex-M code
> generator bug.

Reported (via GCC bugzilla, since we're talking GCC 8); accepted; fixed
(r255958).
0 new messages