On 17/08/17 14:24, Walter Banks wrote:
> On 2017-08-17 3:37 AM, David Brown wrote:
>> "IEC/ISO 18037" completely misses the point, and is a disaster for
>> the world of embedded C programming. It is an enormous
>> disappointment to anyone who programs small embedded systems in C,
>> and it is no surprise that compiler implementers have almost entirely
>> ignored it in the 15 years of its existence. Named address spaces
>> are perhaps the only interesting and useful idea there, but the TR
>> does not cover user-definable address spaces properly.
>
>
> Guilty I wrote the section of 18037 on named address spaces based on our
> use in consumer applications and earlier WG-14 papers.
>
> We extended the named address space material to also include processor
> named space N1351,N1386
I don't know the details of these different versions of the papers. I
have the 2008 draft of ISO/IEC TR 18037:2008 in front of me.
With all due respect to your work and experience here, I have a good
deal of comments on this paper. Consider it constructive criticism due
to frustration at a major missed opportunity. In summary, TR 18037 is
much like EC++ - a nice idea when you look at the title, but an almost
total waste of time for everyone except compiler company marketing droids.
The basic idea of named address spaces that are syntactically like const
and volatile qualifiers is, IMHO, a good plan. For an example usage,
look at the gcc support for "__flash" address spaces in the AVR port of gcc:
<
https://gcc.gnu.org/onlinedocs/gcc/Named-Address-Spaces.html>
The AVR needs different instructions for accessing data in flash and
ram, and address spaces provide a neater and less error-prone solution
than macros or function calls for flash data access.
So far, so good - and if that is your work, then well done. The actual
text of the document could, IMHO, benefit from a more concrete example
usage of address spaces (such as for flash access, as that is likely to
be a very popular usage).
The register storage class stuff, however, is not something I would like
to see in C standards. If I had wanted to mess with specific cpu
registers such as flag registers, I would be programming in assembly. C
is /not/ assembly - we use C so that we don't have to use assembly.
There may be a few specific cases of particular awkward processors for
which it is occasionally useful to have direct access to flag bits -
those are very much in the minority. And they are getting more in the
minority as painful architectures like COP8 and PIC16 are being dropped
in favour of C-friendly processors. It is absolutely fine to put
support for condition code registers (or whatever) into compilers as
target extensions. I can especially see how it can help compiler
implementers to write support libraries in C rather than assembly. But
it is /not/ something to clutter up C standards or for general embedded
C usage.
The disappointing part of named address spaces is in Annex B.1. It is
tantalisingly close to allowing user-defined address spaces with
specific features such as neat access to data stored in other types of
memory. But it is missing all the detail needed to make it work, how
and when it could be used, examples, and all the thought into how it
would interplay with other features of the language. It also totally
ignores some major issues that are very contrary to the spirit and
philosophy of C. When writing C, one expects "x = 1;" to operate
immediately as a short sequence of instructions, or even to be removed
altogether by the compiler optimiser. With a user-defined address
space, such as an SPI eeprom mapping, this could take significant time,
it could interact badly with other code (such as another thread or an
interrupt the is also accessing the SPI bus), it could depend on setup
of things outside the control of the compiler, and it could fail.
You need to think long and hard as to whether this is something
desirable in a C compiler. It would mean giving up the kind of
transparency and low-level predictability that are some of the key
reasons people choose C over C++ for such work. If the convenience of
being able to access different types of data in the same way in code is
worth it, then these issues must be made clear and the mechanisms
developed - if not, then the idea should be dropped. A half-written
half-thought-out annex is not the answer.
One point that is mentioned in Annex B is specific little endian and big
endian access. This is a missed opportunity for the TR - qualifiers
giving explicit endianness to a type would be extremely useful,
completely independently of the named address space concept. Such
qualifiers would be simple to implement on all but the weirdest of
hardware platforms, and would be massively useful in embedded programming.
>
> The fixed point material in 18037 is in my opinion reasonable.
No, it is crap.
Look at C99. Look what it gave us over C90. One vital feature that
made a huge difference to embedded programming is <stdint.h> with fixed
size integer types. There is no longer any need for every piece of
embedded C software, every library, every RTOS, to define its own types
u16, u16t, uint_16_t, uWORD, RTOS_u16, and whatever. Now we can write
uint16_t and be done with it.
Then someone has come along and written this TR with a total disregard
for this. So /if/ this support gets widely implemented, and /if/ people
start using it, what types will people use? Either they will use
"signed long _Fract" and friends, making for unreadable code due to the
long names and having undocumented target-specific assumptions that make
porting an error prone disaster, or we are going to see a proliferation
of fract15_t, Q31, fp0_15, and a dozen different incompatible variations.
If this was going to be of any use, a set of specific, fixed-size type
names should have been defined from day one. The assorted _Fract and
_Accum types are /useless/. They should not exist. My suggestion for a
naming convention would be uint0q16_t, int7q8_t, etc., for the number of
bits before and after the binary point. Implementations should be free
to implement those that they can handle efficiently, and drop any that
they cannot - but there should be no ambiguity.
This would also avoid the next point - C99 was well established before
the TR was written. What about the "long long" versions for completeness?
Of course, with a sensible explicit naming scheme, as many different
types as you want could exist.
Then there is the control of overflow. It is one thing to say
saturation would be a nice idea - but it is absolutely, totally and
completely /wrong/ to allow this to be controllable by a pragma.
Explicit in the type - yes, that's fine. Implicit based on what
preprocessing directives happen to have passed before that bit of the
source code is translated? Absolutely /not/.
Equally, pragmas for precision and rounding - in fact, pragmas in
general - are a terrible idea. Should the types behave differently in
different files in the same code?
Next up - fixed point constants. Hands up all those that think it is
intuitive that 0.5uk makes it obvious that this is an "unsigned _Accum"
constant? Write it as "(uint15q16_t) 0.5" instead - make it clear and
explicit. The fixed point constant suffixes exist purely because
someone thought there should be suffixes and picked some letters out of
their hat. Oh, and for extra fun lets make these suffixes subtly
different from the conversion specifiers for printf. You remember?
that function that is already too big, slow and complicated for many
embedded C systems.
Then there is the selection of functions in <stdfix.h>. We have
type-generic maths support in C99. There is no place for individual
functions like abshr, abslr, abshk, abslk - a single type-generic absfx
would do the job. We don't /need/ these underlying functions. The
implementation may have them, but C programmers don't need to see that
mess. Hide it away as implementation details. That would leave
everything much simpler to describe, and much simpler to use, and mean
it will work with explicit names for the types.
And in the thirteen years that it has taken between this TR being first
published, and today, when implementations are still rare, incomplete
and inefficient, we now have microcontrollers that will do floating
point quickly for under a dollar. Fixed point is rapidly becoming of
marginal use or even irrelevant.
As for the hardware IO stuff, the less said about that the better. It
will /never/ be used. It has no benefits over the system used almost
everywhere today - volatile accesses through casted constant addresses.
The TR has failed to give the industry anything that embedded C
programmers need, it has made suggestions that are worse than useless,
and by putting in so much that is not helpful it has delayed any hope of
implementation and standardisation for the ideas that might have been
helpful.
>
> We use both of these a lot especially in programming the massively
> parallel ISA's I have been working on in the last few years.
>
Implementation-specific extensions are clearly going to be useful for
odd architectures like this. It is the attempt at standardisation in
the TR that is a total failure.