CVS difference for ai12s/ai12-0363-1.txt
--- ai12s/ai12-0363-1.txt 2020/04/28 03:03:16 1.3
+++ ai12s/ai12-0363-1.txt 2020/06/11 03:11:28 1.4
@@ -1,4 +1,4 @@
-!standard 3.10.2(26/3) 20-04-27 AI12-0363-1/03
+!standard 3.10.2(26/3) 20-06-10 AI12-0363-1/04
!standard 9.10(1/5)
!standard C.6(13.3/5)
!standard C.6(19.1/5)
@@ -7,31 +7,85 @@
!status received 19-11-12
!priority Low
!difficulty Medium
-!subject Fixes for Atomic
+!subject Fixes for Atomic and Volatile
!summary
-We clarify the wording associated with AI12-0128-1.
+We clarify the wording associated with AI12-0128-1 having to do with
+"rounding up" accesses to nonatomic subcomponents of atomic objects. We
+introduce a new boolean aspect "Full_Access_Only" which requires any
+access to any subcomponent to be "rounded up" to the enclosing
+Full_Access_Only object, and disallows having any "full access"
+subcomponents. We indicate that the default for Volatile(_Components)
+and Independent(_Components) is False only if their value is not already
+determined by a corresponding Atomic(_Components) specification. We try
+to clean up the places in the wording of C.6 where changes due to
+multiple partially overlapping AIs have led to inconsistent or unclear
+wording.
!problem
-(1) C.6(13.3/5) allows an *object* of a type that has a (non-atomic) aliased
-(sub)component to be marked atomic, but disallows marking such a type atomic.
-This doesn't make much sense. (We should remove the last two sentences of this
-paragraph.)
-
-(2) C.6(13.3/5) bans independently addressable components of nonatomic
-subcomponents of an atomic type. This seems unnecessary. And shouldn't this say
-"subcomponents"? (We should remove the last two sentences of this paragraph.)
+(1) C.6(13.3/5) disallows marking a type atomic if it has nonatomic
+aliased subcomponents, but says nothing about marking an *object* of such
+type as atomic. This doesn't make much sense, and we can instead solve
+the problem by preventing taking 'Access of a nonatomic subcomponent of
+an atomic object, rather than trying to disallow the existence of
+aliased subcomponents. C.6(13.3/5) also bans independently addressable
+components of nonatomic subcomponents of an atomic type. This seems
+unnecessary, and we can again address this by saying such subcomponents
+cannot be manipulated concurrently. (Net effect is we can eliminate the
+last two sentences of this paragraph, and handle these issues
+elsewhere.)
+
+(2) We have said that nonatomic subcomponents of an atomic object, when
+read or written, will have their access "rounded up" to the nearest
+enclosing atomic object (with a "write" to such a subcomponent typically
+performed as an atomic read followed by an atomic write of the enclosing
+atomic object). However, what about atomic subcomponents of atomic
+objects? It would be incompatible to disallow them completely. Should
+we provide a separate aspect for specifying that no atomic subcomponents
+are permitted of a given atomic type? (Yes).
(3) It is not completely clear whether, in Ada 202X, an assignment to a
nonatomic subcomponent of an atomic object is considered to be a single
-"action," or a sequence of two (sequential) actions, the first an atomic read
-and the second an atomic write. (It should be clarified that they are treated as
-two sequential actions.)
+"action," or a sequence of two (sequential) actions, the first an atomic
+read and the second an atomic write. (It should be clarified that they
+are treated as two sequential actions.)
+
+(4) We disallow having a volatile type used as an actual for a generic
+formal array type, unless the element type of the formal type is
+volatile. Why is that, and why doesn't it mention atomic? (We clarify
+and fix a hole in the rule.)
+
+(5) The current wording implies that Volatile and Independent default to
+False if not specified. But if Atomic is specified True, we want
+Volatile and Independent to default to True (in fact, they are True, and
+that should only allow to be confirmed). We should similarly say that
+Volatile_Components is essentially equivalent to Volatile, and that we
+provide both merely to be consistent with Atomic_Components and
+Independent_Components. (We fix the wording.)
+
+(6) Overall, C.6 has been updated by various different AIs. It would be
+good to scrub the wording to make sure it is consistent and clear. (We
+try to do that in this AI.)
!proposal
-(See Summary.)
+We move the check for not taking 'Access of an aliased subcomponents of an
+atomic object to 3.10.2. We move to 9.10 the rule that says independently
+addressable, but nonatomic subcomponents of an atomic object are *not* safely
+manipulatable concurrently.
+
+We add a Full_Access_Only aspect which can be applied to atomic and
+volatile types and objects to indicate that no atomic (or full access)
+objects are permitted as subcomponents.
+
+We refine the rule relating to generic formal array types, to clarify its
+purpose and fix a hole relating to formal array types with aliased components.
+
+We fix the wording on Volatile and Independent so they properly are
+True if Atomic is specified True. Ditto for Volatile/Independent_Components.
+We make Volatile and Volatile_Components imply one another, since they are
+effectively equivalent (unlike Atomic_Components and Independent_Components).
!wording
@@ -48,27 +102,129 @@
If two different objects, including nonoverlapping parts of the same
object, are independently addressable, they can be manipulated
concurrently by two different logical threads of control without
- synchronization{, unless both are subcomponents of the same atomic
- object, and either is nonatomic}.
+ synchronization{, unless both are subcomponents of the same
+ full access object, and either is nonatomic (see C.6)}.
+Add after C.6(6.4/3):
+
+ Full_Access_Only The type of aspect Full_Access_Only is Boolean.
+
+Modify C.6(6.10/3):
+
+ If any of these aspects are directly specified, the aspect_definition
+ shall be a static expression. If not specified {for a type} (including
+ by inheritance), [each of these]{the Atomic, Atomic_Components, and
+ Full_Access_Only} aspects [is]{are} False. {If any of these aspects
+ are specified True for a type, then the corresponding aspect is True
+ for all objects of the type. If the Atomic aspect is specified True,
+ then the aspects Volatile, Independent, and Volatile_Component (if
+ defined) are True; if the Atomic_Components aspect is specified True,
+ then the aspects Volatile, Volatile_Components, and
+ Independent_Components are True. If the Volatile aspect is specified
+ True, then the Volatile_Components aspect (if defined) is True, and
+ vice versa. When not determined by one of the other aspects, or for an
+ object by its type, the Volatile, Volatile_Components, Independent,
+ and Independent_Components aspects are False.
+
+ AARM Ramification: Aspects Volatile and Volatile_Components (when
+ defined) are equivalent. We provide the Volatile_Components aspect
+ only to give symmetry with Atomic_Components and
+ Independent_Components aspects.
+
+Add after C.6(8.1/4):
+
+ The Full_Access_Only aspect shall not be specified unless the
+ associated type or object is volatile [Reduntant:(or atomic)]. A /full
+ access/ type is any atomic type, or a volatile type for which the
+ aspect Full_Access_Only is True. A /full access/ object (including a
+ component) is any atomic object, or a volatile object for which the
+ aspect Full_Access_Only is True for the object [Redundant: or its
+ type]. A Full_Access_Only aspect is illegal if any subcomponent of
+ the object or type is a full access object.
+
+ AARM Ramification: This last rule breaks privacy, but that is
+ considered OK for representation clauses when there is no clear
+ alternative. Note that atomic objects may be nested, so long as the
+ outer atomic object does not have the Full_Access_Only aspect True.
+
+Modify C.6(12/5):
+
+ If an atomic object is passed as a parameter, then the formal
+ parameter shall either have an atomic type or allow pass by copy. If
+ an atomic object is used as an actual for a generic formal object of
+ mode in out, then the type of the generic formal object shall be
+ atomic. If the prefix of an attribute_reference for an Access
+ attribute denotes an atomic object [Redundant: (including a
+ component)], then the designated type of the resulting access type
+ shall be atomic. Corresponding rules apply to volatile objects{
+ and to full access objects.}
+
+Replace C.6(12.1/5):
+
+ If the Atomic, Atomic_Components, Volatile, Volatile_Components,
+ Independent, or Independent_Components aspect is True for a generic
+ formal type, then that aspect shall be True for the actual type. If a
+ volatile type is used as an actual for a generic formal array type,
+ then the element type of the formal type shall be volatile. If an
+ atomic type is used as an actual for a generic formal derived type,
+ then the ancestor of the formal type shall be atomic. A corresponding
+ rule applies to volatile types.
+
+with:
+
+ If the Atomic, Atomic_Components, Volatile, Volatile_Components,
+ Independent, Independent_Components, or Full_Access_Only aspect is
+ True for a generic formal type, then that aspect shall be True for the
+ actual type. If an atomic type is used as an actual for a generic
+ formal derived type, then the ancestor of the formal type shall be
+ atomic. A corresponding rule applies to volatile types.
+
+ If a type with volatile components is used as an actual for a generic
+ formal array type, then the components of the formal type shall be
+ volatile. Furthermore, if the actual type has atomic components and
+ the formal array type has aliased components, then the
+ components of the formal array type shall also be atomic.
+
+ AARM Reason: The limitations on formal array types are separate for
+ volatile and atomic because of the fact that only volatility is
+ carried down to all subcomponents of a volatile object, while
+ atomicity is not. The goal of both limitations is that we don't want
+ 'Access for an access type to produce a value that designates an
+ object whose atomicity and volatility don't agree with that of the
+ designated type of the access type. The above rules ensure that
+ the generic "sees" the relevant volatility and atomicity.
+
+ [Author's note: The rule on volatility could be relaxed somewhat,
+ to require that only the aliased, tagged, or private subcomponents
+ of the formal type are volatile, but the current rule has been in
+ place since 2012, so we don't see the need to relax it at this
+ point.]
+
Modify C.6(13.3/5):
- If a nonatomic subcomponent of an atomic object is passed as the
- actual parameter in a call then the formal parameter shall allow pass
- by copy (and, at run time, the parameter shall be passed by copy). A
- nonatomic subcomponent of an atomic object shall not be used as an
- actual for a generic formal of mode in out. [A nonatomic subcomponent
- of an atomic type shall not be aliased. A nonatomic subcomponent of an
- atomic type or object shall not have components that are specified to
- be independently addressable.]
+ If a nonatomic subcomponent of [an atomic]{a full access} object is
+ passed as the actual parameter in a call then the formal parameter
+ shall allow pass by copy (and, at run time, the parameter shall be
+ passed by copy). A nonatomic subcomponent of [an atomic]{a full
+ access} object shall not be used as an actual for a generic formal of
+ mode in out. [A nonatomic subcomponent of an atomic type shall not be
+ aliased. A nonatomic subcomponent of an atomic type or object shall
+ not have components that are specified to be independently
+ addressable.]
+
+Modify RM C.6(19.1/5):
+
+ All reads of or writes to any nonatomic subcomponent of [an atomic]{a
+ full access} object are performed by reading and/or writing all of the
+ nearest enclosing [atomic]{full access} object.
Add after AARM C.6(19.1.c/5):
-AARM Discussion: The atomic reads and writes associated with accesses to
-nonatomic components of an atomic object are normal atomic operations -- all of
-the rules that apply to other atomic operations apply to these as well. In
-particular, these atomic reads and writes are sequential if they apply to the
-same object.
+ AARM Discussion: The atomic reads and writes associated with accesses
+ to nonatomic components of a full access object that is atomic are
+ normal atomic operations -- all of the rules that apply to other
+ atomic operations apply to these as well. In particular, these atomic
+ reads and writes are sequential if they apply to the same object.
!discussion
@@ -81,21 +237,56 @@
Z : R with Atomic; -- Legal? (Yes.)
P : access Integer := Z.X'Access -- Legal? (No.)
-We permit the type declaration, but disallow the 'Access. This is necessary in
-general to avoid breaking privacy, since we might actually have an aliased
-component of a component of R, where the component of R is of a private type.
-
-(2) We remove this sentence, and change the rules associated with independent
-addressibility in 9.10 to say that threads can safely manipulate independently
-addressible components, unless they are subcomponents of the same atomic object,
-and either is nonatomic. This also prevents breaking privacy. The existing
-sentence could require breaking privacy in certain cases.
+We permit the type declaration, but disallow the 'Access. This is
+necessary in general to avoid breaking privacy, since we might actually
+have an aliased component of a component of R, where the component of R
+is of a private type.
+
+For the issue of independent addressability, we remove the last sentence
+of (13.3/5), and change the rules associated with independent
+addressibility in 9.10 to say that threads can safely manipulate
+independently addressible components, unless they are subcomponents of
+the same full access object, and either is nonatomic. This also prevents
+breaking privacy. The existing sentence could require breaking privacy
+in certain cases.
+
+(2) We add the Full_Access_Only aspect to control whether nesting of
+atomic objects is permitted. The GNAT aspect Volatile_Full_Access
+is the inspiration for this, but it does not actually imply everything
+that "atomic" implies, so we allow it to be specified as an addition
+to *either* atomic or volatile. Volatile + Full_Access_Only is intended
+to match GNAT's existing pragma. Atomic + Full_Access_Only is
+essentially equivalent to simply "Atomic" but with the added legality
+rule that Full_Access_Only disallows having atomic (or full access)
+subcomponents. This *does* break privacy, but we could not figure
+out anyway to avoid it, and since it is a representation aspect, it
+is something that could be "bubbled up" and across private types.
(3) The AARM note C.6(19.1.c/5) describes the intent that a read-modify-write
cycle is expected and that these are separate atomic reads and writes. As such,
there are two operations and these are sequential with respect to any other
operations on the same object.
+(4) We went back to the original AI that introduced the restriction
+on generic formal array types, and discovered a hole having to do with
+formal arrays with aliased components, which only applies to atomic.
+So we move the formal array restriction into its own paragraph, handle
+both volatile and atomic special cases, and add an AARM note to explain
+what is behind the rules.
+
+(5) There were words that indicated that all atomic objects are also
+volatile, but the defaulting to False of Volatile when not specified
+seemed to contradict that. Similar considerations apply to Independent,
+and the *_Components aspects. So we changed the rules and made
+the defaults match the semantics of atomic implying volatile and
+independent. Finally, Volatile and Volatile_Components
+are equivalent, so we make that explicit, and have one imply the
+other.
+
+(6) We completely replace (12.1/5) because it had been edited so
+often that it didn't seem to end up in a logical sequence. Hopefully
+the new wording is a little clearer.
+
!ASIS
No changes needed.
@@ -556,45 +747,626 @@
From: Randy Brukardt
Sent: Monday, April 27, 2020 10:00 PM
-AI12-0128-1 enhanced the rules for Atomic such that it can be used to
-guarentee that only exact size access is used to access subcomponents of an
+AI12-0128-1 enhanced the rules for Atomic such that it can be used to
+guarentee that only exact size access is used to access subcomponents of an
atomic composite object.
-Recently, a request was made to eliminate some of the requirements of that AI
-in order to allow more uses of atomic subcomponents. These can be seen in the
+Recently, a request was made to eliminate some of the requirements of that AI
+in order to allow more uses of atomic subcomponents. These can be seen in the
attached AI.
-I believe that the changes suggested introduce a major maintenance hazard for
-anyone that requires exact size access to some hardware. I'm posting here in
-order to give people who are more likely to have that sort of requirement
+I believe that the changes suggested introduce a major maintenance hazard for
+anyone that requires exact size access to some hardware. I'm posting here in
+order to give people who are more likely to have that sort of requirement
than me to weigh in on this issue.
-The problem as I see it is that to get exact size access to a hardware
-register, one has to ensure that no subcomponent has an atomic subtype or is
-directly declared atomic. If all of the types involved are declared together,
-that's not hard to ensure, but anyone can change a declaration and break the
-property. The compiler will not care, since there is no legality rule that is
-broken -- just the generated code will change. But of course the generated
+The problem as I see it is that to get exact size access to a hardware
+register, one has to ensure that no subcomponent has an atomic subtype or is
+directly declared atomic. If all of the types involved are declared together,
+that's not hard to ensure, but anyone can change a declaration and break the
+property. The compiler will not care, since there is no legality rule that is
+broken -- just the generated code will change. But of course the generated
code will not work if some smaller access is generated.
-If of course some of the types are declared in other units (even something as
+If of course some of the types are declared in other units (even something as
simple as a status enumeration), then the verification gets even harder.
-Even though the AI worries about breaking privacy, that is irrelevant here as
-representation aspects always break privacy (and Atomic is a representation
+Even though the AI worries about breaking privacy, that is irrelevant here as
+representation aspects always break privacy (and Atomic is a representation
aspect).
-Of course, a need for exact size access is fairly rare, and having rules that
-prevent certain types of subcomponents are likely to get in the way of
-particular uses. Thus, it might be better to have an aspect to require only
-exact size access, and reject any declaration that would violate that.
-Otherwise, it seems to me that any exact size requirement is only going to be
+Of course, a need for exact size access is fairly rare, and having rules that
+prevent certain types of subcomponents are likely to get in the way of
+particular uses. Thus, it might be better to have an aspect to require only
+exact size access, and reject any declaration that would violate that.
+Otherwise, it seems to me that any exact size requirement is only going to be
followed until the first ham-handed maintainer.
Anyone have any informed thoughts on this topic?
+
+P.S. The next ARG meeting is Wednesday, so a quick response would be
+appreciated. If it needs more discussion we can remove it from the agenda of
+that meeting.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Tuesday, April 28, 2020 5:51 PM
+
+>I am confused, Randy. As far as I can tell this AI isn't relaxing the
+>requirements. It is simply moving them to elsewhere in the standard. Can you
+clarify this?
+
+Allowing atomic SUBcomponents makes the bad situation of AI12-0128-1 much worse
+vis-a-vis the original problem of that AI. If one requires exact size access to
+some external device, you have no way to guarantee that is the case short of
+inspecting every subcomponent type to see if anything is declared atomic. Since
+types can be declared atomic, and that can be added after the fact, one has a
+substantial maintenance hazard.
+
+Recall that the original problem occurs rarely but is critical when it happens.
+What sometimes happens is that there is a memory-mapped device that only
+responds to 32-bit read and write cycles (and not to 8-bit read/write cycles).
+[I'm told this is a real problem in practice, I have no direct experience with
+it myself, which is why I posted this here for public comment from those with
+more experience.] We want to be able to use Ada bit-mapped records to access
+this device, rather than have to do bit masking operations to get at the fields.
+But if the Ada compiler generates an 8-bit atomic operation, the device will not
+respond and the program will obviously fail.
+
+We partially solved this problem in AI12-0128-1 by mandating that atomic objects
+with nonatomic components are accessed exactly and one never reads/writes the
+components individually. But this is a maintenance hazard, since if someone
+declares one of the components atomic, the device will stop responding and the
+code will presumably malfunction.
+
+I went along with the original rules because there didn't seem to be a taste for
+a separate aspect and because only the top-level components were allowed to be
+atomic. That meant that one could pretty much inspect and heavily comment those
+components, and maintenance problems would be fairly minimal (but not
+eliminated, as shown below). However, with the elimination of that rule, now any
+components that themselves are composite also would have to be inspected.
+
+It would be best if a program that needs exact-size access but is not going to
+get it gets rejected at compile-time. Otherwise, the code will silently fail as
+the hardware restrictions are not followed and some reads and writes simply do
+nothing (or even read bus noise). Avoiding that would pretty much mean that
+every type used in such a register access has to be declared locally; there
+can't be any reuse as that opens the danger of someone changing it in the future
+and destroying code that they don't even know about.
+
+For instance, imagine the following package exists somewhere in the system owned
+by another group:
+
+ package Register_Info is
+ type Status is (Ready, Full, Empty, Unplugged, Error);
+ for Status use (....);
+ type Data is mod 2**8;
+ end Register_Info;
+
+We need to build access to a 32-bit memory mapped register, and the types above
+are what we need. So we use them so we can better interface with the rest of the
+system:
+
+ with Register_Info; use Register_Info;
+
+ package My_Device is
+ type Device_Register is record
+ Input_Status, Output_Status : Status;
+ Input_Data, Output_Data : Data;
+ Empty : Data;
+ end record with Atomic;
+ -- Record rep. clause here.
+
+ The_Device : Device_Register with Address => ...;
+ end My_Device;
+
+With the rule changes of AI12-0128-1, this does what we want. However, it is
+fragile, because a change in the declaration of either of the imported types
+will break this declaration such that the uses of The_Device will silently
+malfunction.
+
+Remember that I suggested that the type package belongs to another group.
+Perhaps that group decides that the data needs to be Atomic so that they can get
+rid of some error messages from parallel. (Never mind that is a bad idea, people
+do stuff like this all of the time.) If they do that, The_Device will no longer
+work, but it still will compile. If this is maintenance in a long-running
+system, it could take a long time before the maintainers will notice that the
+size guarantee has been lost.
+
+I realize that the rules as given in AI12-0128-1 are limiting for uses that
+don't care about exact size sementics (which will be most of them). So my
+suggestion is to allow the rules to be weakened back to almost no restrictions
+on subcomponents (I don't see the point of distributing this Atomic annex
+special case all over the Standard - it seems to violate our rules about keeping
+the annexes separate from the core), but in addition to add an
+Use_Exact_Size_Only aspect that can be given on an atomic type or object. If the
+new aspect is True, there cannot be any atomic or aliased subcomponents (since
+those would necessarily violate the needed behavior). This would more directly
+meet the need and eliminate any maintenance hazards. (Note: We'd still require
+any atomic object, even without the aspect, to write the exact bits if there are
+no components that require otherwise. We do want to do that expected thing by
+default; it's just that we can't allow some ham-handed maintainer to break that
+if it is in fact an actual hardware requirement.)
+
+Note that I don't see any reason to care about privacy for Atomic's rules. These
+are representation aspects and those never care about privacy. Moreover, I don't
+think people are using many private types in hardware interfacing. So the
+concern is more theoretical than real. I'm suggesting using fewer restrictions
+anyway, unless one gives the new aspect, and that should only be used in the
+relatively rare case of memory mapped hardware that doesn't work with all sizes.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Tuesday, April 28, 2020 7:41 PM
+
+I think the fundamental question is what do you do when you have nested atomic
+objects:
+
+1) Make it illegal
+
+2) Ignore the "atomic" on the components, and only obey atomicity on the
+ outermost atomic object. For everything else you "round up" the load/store
+ size to match the *outermost* enclosing atomic object.
+
+3) Obey atomicity at each level. From a nonatomic subcomponent, round up to the
+ *nearest* enclosing atomic object.
+
+I think each of these are reasonable, depending on the application.
+Unfortunately, we have to pick one.
+
+I would argue (3) gives the programmer the most flexibility, since if they
+actually have a hardware register that allows 32-bit reads, as well as 8-bit
+reads, they can do it with (3) but not with any of the others. If the hardware
+doesn't allow 8-bit reads, then the programmer should not nest an atomic object
+that is 8-bits in size inside the 32-bit atomic object. And as you say private
+types are not that common in such programming, so the programmer can see exactly
+what they are doing. Anyone who is writing a device driver is probably looking
+very carefully at what types they are using.
+
+So for me, (3) gives the programmer the most control, and is to some extent a
+superset of the other capabilities.
+
+I vaguely remember my days of directly addressing hardware registers, and I
+believe there were some that allowed both word and byte access, though who knows
+if that is a real memory, or whether it still applies now.
+
+But the fundamental point is (3) gives the programmer the ability to choose what
+they want to do.
+
+It seems that either approach could introduce a bug if the programmer doesn't
+know what they are doing, or if some change is made in maintenance. But for
+hardware device drivers, my sense is you want to give control, more than you
+want to somehow protect the programmer from themself.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Tuesday, April 28, 2020 9:24 PM
+
+>I think the fundamental question is what do you do when you have nested atomic
+>objects:
+>
+>1) Make it illegal
+>
+>2) Ignore the "atomic" on the components, and only obey atomicity on the
+> outermost atomic object. For everything else you "round up" the load/store
+> size to match the *outermost* enclosing atomic object.
+>
+>3) Obey atomicity at each level. From a nonatomic subcomponent, round up to
+> the *nearest* enclosing atomic object.
+>
+>I think each of these are reasonable, depending on the application.
+>Unfortunately, we have to pick one.
+
+Why do we have to pick only one? The usual case of atomic objects and this
+particular hardware case are very different and there is a much different
+requirement in the latter case. While in the normal case, the exact rule doesn't
+matter and the flexibility seems valuable.
+
+I think it is absolutely necessary for the programmer to tell the compiler when
+this exact size case is required. Then the compiler can (and has to) reject
+anything that doesn't meet the exact size requirements. Anything else is very
+unsafe, since the code can silently get the wrong answer (since the hardware
+will not be read).
+
+>...
+>I vaguely remember my days of directly addressing hardware registers, and I
+>believe there were some that allowed both word and byte access, though who
+>knows if that is a real memory, or whether it still applies now.
+
+I made this point when the subject originally came up, and I was told by a
+number of people that hardware with these sorts of limitations shows up rather
+regularly. A lot of these registers are byte addressed anyway (no larger
+access), so the problem probably doesn't really show up with those.
+
+Anyway, the reason I posted here was to get some feedback from real embedded
+practioners as to whether this is common enough to have a special aspect to
+declare. Silence is a form of an answer, I guess, but we haven't given them
+enough time.
+
+> It seems that either approach could introduce a bug if the programmer doesn't
+> know what they are doing, or if some change is made in maintenance. But for
+> hardware device drivers, my sense is you want to give control, more than you
+> want to somehow protect the programmer from themself.
+
+It's not themself, it's the guy that comes along 5 years from now and knows
+nothing about exact size accesses and little about atomics. You are essentially
+saying that if there is any such exact size access required, you have to write
+it completely self-contained, comment it heavily, and then use other types to
+communicate the results to the rest of the program. There's no possibility of
+reuse or sharing because to have those things greatly increases the chance of a
+change. And the program will silently malfunction if it wrong -- no errors, no
+traps, nothing. That to me is the C approach -- leave it up to the programmer to
+do the right thing - and if they don't, too bad for them (and the people flying
+on their airplane).
+
+If we're not going to solve the original problem at all, then AI12-0128-1 was a
+complete waste of time. Any reasonable compiler would have done the right thing
+most of the time anyway, and since this stuff is untestable, it's highly likely
+that will remain the case. At least having a testable aspect would clue
+implementors into the importance of the issue.
+
+Hopefully some embedded programmers will comment.
+
+****************************************************************
+
+From: Jeff Cousins
+Sent: Wednesday, April 29, 2020 3:11 AM
+
+...
+>> I vaguely remember my days of directly addressing hardware registers, and I
+>>believe there were some that allowed both word and byte access, though who
+>>knows if that is a real memory, or whether it still applies now.
+
+>I made this point when the subject originally came up, and I was told by a
+>number of people that hardware with these sorts of limitations shows up
+>rather regularly. A lot of these registers are byte addressed anyway (no
+>larger access), so the problem probably doesn't really show up with those.
+
+Stretching the memory cells here, but at one time I wrote most of the device
+drivers in the company, and I think you’re correct (i.e. such fussy h/w can
+exist) .
+
+****************************************************************
+
+From: Simon Wright
+Sent: Wednesday, April 29, 2020 6:44 AM
+
+I just checked briefly through the first few peripherals' register descriptions
+in the STM32F4xxx Reference Manual issue 11. Some of them leave it open (I'd
+guess at 32 bit-only), but the ADC says "The peripheral registers must be
+written at word level (32 bits). Read accesses can be done by bytes (8 bits),
+half-words (16 bits) or words (32 bits)." whereas the DAC says 32 bit only.
+
+DCMI says "All DCMI registers have to be accessed as 32-bit words, otherwise a
+bus error occurs." which would at least reduce the chance of missing a
+programming error.
+
+TIM1 & TIM8 say "The peripheral registers must be written by half-words (16
+bits) or words (32 bits). Read accesses can be done by bytes (8 bits), half-word
+(16 bits) or words (32 bits)."
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Wednesday, April 29, 2020 7:08 AM
+
+Another issue worth considering is that Ada 2012 semantics correspond to (3) for
+nested atomic objects. Ada 2012 makes no requirement about "rounding up" of
+nonatomic subcomponents of an atomic object. But for nested atomic objects,
+there is no rounding up in Ada 2012. So we should think about whether
+compatibility should be a relevant concern in this decision.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Wednesday, April 29, 2020 7:25 AM
+
+>>I think the fundamental question is what do you do when you have nested atomic
+>>objects:
+>>
+>>1) Make it illegal
+>>
+>>2) Ignore the "atomic" on the components, and only obey atomicity on the
+>> outermost atomic object. For everything else you "round up" the load/store size to match the *outermost* enclosing atomic object.
+>>
+>>3) Obey atomicity at each level. From a nonatomic subcomponent, round up to
+>> the *nearest* enclosing atomic object.
+>>
+>>I think each of these are reasonable, depending on the application.
+>>Unfortunately, we have to pick one.
+
+>Why do we have to pick only one? The usual case of atomic objects and this
+>particular hardware case are very different and there is a much different
+>requirement in the latter case. While in the normal case, the exact rule
+>doesn't matter and the flexibility seems valuable.
+>
+>I think it is absolutely necessary for the programmer to tell the compiler when
+>this exact size case is required. Then the compiler can (and has to) reject
+>anything that doesn't meet the exact size requirements. Anything else is very
+>unsafe, since the code can silently get the wrong answer (since the hardware
+>will not be read). ...
+
+AdaCore has a separate aspect (Volatile_Full_Access -- VFA) but I believe we
+chose instead to make "atomic" work the "right way." The reason is that you
+still need to address what happens when Atomic objects occur inside of a VFA
+object, and vice-versa. So I don't think having a separate aspect really
+addresses the concern. And based on responses to this, it seems that both sort
+of situations come up, and almost certainly all of them want rounding up of
+*non* atomic subcomponents, so it all comes down to whether atomicity is lost if
+you have an atomic object nested inside something that requires rounding-up. I
+am not seeing a real need to override the atomicicity of a nested object, at
+least not in all cases. What we could add is an aspect that *disallows* nested
+atomic objects. So we would could support both (1) and (3), depending on the
+state of this additional aspect. (2) seems like it is both more error prone and
+less flexible.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Wednesday, April 29, 2020 9:25 AM
+
+That's what I've been suggesting all along.
+
+****************************************************************
+
+From: Richard Wai
+Sent: Wednesday, April 29, 2020 9:04 AM
+
+There is definitely a case these days for requiring atomic word/doubleword-sized
+registers. Most architectures that I’m familiar with, particularly RISC-V and
+ARM require the entire register to be accessed at once.
+
+My two cents is that (2) seems to be the most sane in practice. Since most
+architectures can’t support atomic operations larger than a (double)word
+anyways, the programmer will be restricted to subcomponents that are smaller
+than a (double)word. It wouldn’t make logical sense to have a record, ostensibly
+targeting a single register, to have non-atomic components anyways. From the
+top-down perspective, having a rule that says “if this record is atomic, all
+it’s components are always atomic” makes the most sense. Its an easy rule to
+understand. You’re not likely to have a large record capable of being atomic
+anyways, so I don’t see much use in allowing complex atomic and non-atomic mixes
+allowed by (3). Even huge architectures like the upcoming 128-bit RISC-V ISA,
+one would probably not benefit much from having non-atomic components in your
+128 bit atomic record.
+
+****************************************************************
+
+From: Tero Koskinen
+Sent: Thursday, April 30, 2020 2:20 PM
+
+Sorry, I am little late to this discussion, but I guess I can count as a real
+embedded practitioner.
+
+I usually work with 32-bit ARM Cortex-M{0,4,7,23,33} microcontrollers.
+
+They are quite common and relatively simple 32-bit processors with 4GB flat
+memory map and 16-bit & 32-bit instruction sets.
+
+The 4GB memory map contains various different areas which are mapped to
+different processor peripherals. Normal RAM is one area. GPIO pin control is
+another area. Builtin flash (non-volatile memory) is yet another area, and so
+on.
+
+Some areas, like RAM, do not not have alignment or size requirements/limits for
+access (8-bit, 16-bit, 32-bit read/write operation works - the address can even
+be unaligned in many cases).
+
+However, other areas, like flash, have much stricter alignment and size
+requirements. Some ARM Cortex-M processors have 16-bit write size requirement.
+Also the alignment must be 16-bit (even addresses). ARM Cortex-M processor from
+another vendor on the other hand might have 32-bit write size and alignment
+requirements for flash memory area.
+
+It is also case dependent what happens if you don't follow the requirements. In
+some cases the code fails silently. In other case, the processor goes into a
+failure mode (special interrupt handler for example, or reboot in worst case).
+
+
+In addition to above areas, ARM Cortex-M processors optionally can have so
+called bit-banded memory area. In this kind of area, one 32-bit data access for
+an address is mapped to a single bit in another address.
+
+So, for example, let's assume that 1kB bit-band area starts from 16#0000_F000#
+and is mapped to address 16#0010_0000#.
+
+Writing 16#0000_0001# to address 16#0000_F004# sets the second lowest bit to 1
+at address 16#0010_0000#. (=> 32-bit reading from 16#0010_0000# will get us
+value 16#0000_0002# if the initial value was 0.)
+
+This allows atomic bit operations for certain memory areas.
+
+****************************************************************
+
+From: Weston Pan
+Sent: Wednesday, April 29, 2020 6:05 AM
+
+There was a lot to read, so hopefully I understood it all.
+
+I personally think if an object/type is atomic, there should not be any atomic
+components/subcomponents within it. If a {sub}component is specified to be of an
+atomic type (or is a type that contains some), either it should be rejected or
+the atomicity ignored and a compiler warning is given. I'm agree with Randy that
+to allow atomic {sub}components to be buried within can lead to undesirable
+maintenance issues that would be hard to track. For register level programming,
+I have only needed atomicity for the register as whole (i.e. never for fields
+within a register). Outside of register level programming, I can't think of a
+reason why you would apply Atomic aspect at a higher level and at the same time
+at a piece-meal level too. Atomicity at the higher level is probably the only
+level that matters. For any finer grain of control, I would think it probably
+involves data that is large enough that it cannot be handled with simple CPU
+word read/write access, and instead constructs such as protected types would be
+needed instead. With that in mind, I think A-12-0128-1 should not have
+distinguished between nonatomic/atomic {sub}components and kept it simply as
+"{sub}components".
+
+****************************************************************
+
+From: Bill Wong
+Sent: Wednesday, April 29, 2020 9:53 AM
+
+> I just checked briefly through the first few peripherals' register
+> descriptions in the STM32F4xxx Reference Manual issue 11. ...
+
+I was also going to mention this as I have been trying to get a runtime working
+for TI's chips and it has similar requirements. Hiding access behind a function
+is currently what I was working with but developers often what direct access.
+
+****************************************************************
+
+From: Weston Pan
+Sent: Wednesday, April 29, 2020 2:23 PM
+
+I am surprised by Richard's comment. To me it does *not* make sense to have
+atomic subcomponents in a register. The register as a whole is consider atomic
+for a reason, specifically a hardware restriction. By allowing atomic operations
+on a subcomponent, then the issue that Randy pointed out about violating the
+proper memory access can occur (e.g. Randy's example of a byte read/write access
+being performed on a register that requires a 32-bit read/write).
+
+Regarding Simon's comment about ARM registers allowing different sized read
+access but a 32-bit write restriction, doesn't mean that different sized read
+operations need to be enforced/allowed on the register. I think the flexibility
+on reads is because having multiple read access is safe (e.g. similar to
+multiple readers of a protected object). However, that doesn't mean you have to
+allow all the types of reads on an Ada object that overlays the register. I
+think it makes more sense to go with the highest restriction, in Simon's case a
+32-bit write access, and just apply that for reads as well (i.e. both read and
+write are similar).
+
+Granted, I can only go based on my limited experience at register programming,
+but unless someone can provide a good example of why having atomic subcomponents
+or even a mixture of non-atomic and atomic subcomponents for registers should be
+allowed, I still think atomic objects should be forbidden or removed when
+contained in an atomic object.
+
+****************************************************************
+
+From: Weston Pan
+Sent: Wednesday, April 29, 2020 2:34 PM
+
+Minor correction to my last sentence:
+
+I still think atomic subcomponents at any deeper level should be forbidden or
+the atomic aspect for them should be ignored when contained within an atomic
+object.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Thursday, May 14, 2020 1:05 PM
+
+In C.6(6.10/3) the RM says:
+
+If any of these aspects are directly specified, the aspect_definition shall be a
+static expression. If not specified (including by inheritance), each of these
+aspects is False.
+
+It seems odd that Volatile and independent are False if not specified. We say
+that if you specify something is Atomic, then it is also Volatile. So doesn't
+that mean that specifying something as Atomic implicitly also specifies it to be
+Volatile? We certainly don't want to allow someone to specify Atomic => True,
+Volatile => False. It feels like the wording of this paragraph needs some work,
+or we need to establish a stronger rule that specifying Atomic => True implies
+both Volatile=>True and Independent=>True.
+
+****************************************************************
+
+From: Jeff Cousins
+Sent: Thursday, May 14, 2020 1:34 PM
+
+Seems a good point.
+
+****************************************************************
+
+From: Richard Wai
+Sent: Thursday, May 14, 2020 7:28 PM
+
+> It seems odd that Volatile and independent are False if not specified.
+> We say that if you specify something is Atomic, then it is also Volatile. So
+> doesn't that mean that specifying something as Atomic implicitly also
+> specifies it to be Volatile?
+
+That was certainly my expectation of Atomic.. I'm actually stunned that C.6
+doesn't make this explicit anywhere.
+
+> We certainly don't want to allow someone to specify Atomic => True,
+> Volatile => False.
+
+I can imagine cases where you know that an atomic value is being changed
+synchronously, but yet you want any actual writes or reads to be atomic.
+For example, you are inside of an ISR that is reading some kind of buffer
+register. That would allow the user to map an object directly to the address
+of that register with Atomic => True, Volatile => False, and the compiler could "correctly" optimize-out multiple reads, thus avoiding the need to copy values. But this seems to be such a corner case, and such an insignificant advantage that it's hardly a
n argument to allow it. OTOH, this seems to create the potential for implementation-defined funny business. If we let users have Atomic => True, Volatile => False entities, then the user would need to make correct assumptions about how the compiler might o
ptimize reads and writes. That seems pretty dangerous and un-Ada-like. It's even worse if we look at the write-side of the equation, where you probably don't want the compiler deciding if multiple writes of the same value to a register should be "optimized
".
+
+Incidentally, I tested it and GNAT (GCC 9.2.0) accepts this:
+
+type My_ATM is mod 2**8 with Atomic => True, Volatile => False;
+
+It gave me no complaints.
+
+> It feels like the wording of this paragraph needs some work, or we
+> need to establish a stronger rule that specifying Atomic =>
+> True implies both Volatile=>True and Independent=>True.
+
+Agreed.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Thursday, May 14, 2020 8:00 PM
+
+I think that the original pragmas were defined independently of each other, so
+the wording was written such that only one was specified. We probably left the
+wording that way.
+
+Even so, I agree that keeping Volatile and Independent matching Atomic might
+make more sense. However, in that case, I'd guess that some of the rules are
+redundant when they say that the same rule applies to Atomic as to Volatile.
+Especially the rule that says all atomic entities are volatile.
+
+Are you proposing wording changes and an AI write-up? :-) [How are you going to
+have time to do AdaCore work before the next meeting?? :-)]
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Thursday, May 14, 2020 8:07 PM
+
+Yes, I'll take a shot at it. Steve and I are debating the rule about formal
+array types and volatility as well, which I might fold into yet another C.6
+fix-up. I think we still are debating the one having to do with atomicity and
+nesting. I wonder whether we ultimately need two aspects, Atomic which works
+the way the current one does, which allows nesting, and "Atomic_Full_Access" or
+equivalent which disallows any nested Atomic (or Atomic_Full_Access)
+subcomponents. Both of them would require rounding up of non-atomic
+subcomponents, but one would disallow having nested atomic subcomponents.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Thursday, May 14, 2020 9:38 PM
+
+I think Atomic_Full_Access would work; I've always viewed it as an option on the
+existing Atomic (I'd expect the rules would require far less change that way)
+but I don't think that it would be a problem to do it the other way (just more
+change is needed).
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Friday, May 15, 2020 9:09 AM
+
+We could have a separate "Full_Access_Only" or "No_Nested_Atomic" or something
+like that, which would only be meaningful in conjunction with Atomic.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Friday, May 15, 2020 12:42 PM
-P.S. The next ARG meeting is Wednesday, so a quick response would be
-appreciated. If it needs more discussion we can remove it from the agenda of
-that meeting.
+Yup, that's what I was thinking. Didn't have a good name for it though.
****************************************************************
Questions? Ask the ACAA Technical Agent