C for embedded controllers (was Re: Timed mechanical fuel injection )

Ed Lansinger elansi01 at mpg.gmpt.gmeds.com
Wed Nov 22 17:07:44 GMT 1995


I support the use of assembly language, C, and C++ for embedded systems.
I have some nits to pick with statements made.

John Gwynne wrote:

>| C is easier to program
>
>Absolutely.

With all due respect, I think this statement is, well, hogwash.

>From conception to the final debugged program, assembly
>language takes ****me**** at least 4 times longer to develope for *small*
>programs (YMMV, the ratio is worse for RISC).

(****emphasis**** added)

That's better.

I have yet to see a meaningful difference in productivity for small
projects such as I believe we are discussing here which is the
result of language alone, assuming equal familiarity and practice with
two languages in question.  The real differences seem to come through
design tools, support tools such as simulators and debuggers, code re-use,
and (for larger projects) effective project management.  But note that
assembly language precludes none of that.

What is unfortunately true for embedded systems programming is, as a general
statement, assembly language programming is being marginalized or dropped
from CompSci and Computer Engineering curricula.  It's getting harder
to find new people with assembly language experience.  If you are
building programming teams there's pressure to use C because of this
simple fact.

> Once you get used to
>using a high level debugger, like gdb, its very hard to revert back
>(and unnecessary) to a low level monitor.

I agree with the sentiment that a high level debugger is a Good Thing,
but I disagree with "unnecessary" and I don't find it "very hard".
When debugging EFI in C or C++ I find I often go down to the assembly
language level.  There's a big, implicit leap of faith when you decide
to use a high-level language, which is that you trust that the compiler.
Actual compiler bugs aside, there is absolutely no guarantee that
the compiler interprets your code the way you think it will.  Does
it move a word to an I/O address 16 bits at a time or with separate
byte moves?  Is it really performing atomic operations on your data
to avoid coherency problems the way you think it is?  Just how efficient
is it?  What evaluation order did it end up using for that expression?
How nasty is the jump through the virtual table?

No matter how you slice it, using a high-level language further removes
you from knowing exactly what the processor is doing.  For critical
embedded systems (and anything that can stall on a railroad track
is critical), this is cause for being cautious.

>| machine code is more direct to the point
>
>I don't understand this comment... do not the two programs (C vs
>assembly) do the same thing?

I don't understand the original comment, either.  However, I contend
that there are certain things that are easier to express in assembler
than in C and vice versa.  I find complicated decision logic to be
easier to express and follow in assembler than in horrific &&-||-!
combinations with umpteen levels of nested parentheses (even better
is relay-ladder logic).  Conversely, I much prefer to write
PulseWidth = k * MAP() * VE(RPM()) than the equivalent in assembler
(although I can't say that the assembler really takes me any longer to
write and debug).

>
>| requires less memory
>
>True, but maybe only by 10-20% with a good optimizing C compiler (gcc
>for the 68k is a good example. Optimization is cpu dependent.). With
>larger programs it is conceivable the C will be smaller since it
>generally promotes better structure.

Like art, the medium affects the expression.  No self-respecting
assembly language programmer writing anything more than a trivial
program would use a whole word to represent a boolean value, much
less 16Kb to hold an 8,000-element boolean array.  The same programmer
automatically uses a "walking pointer" to search an array rather than
indexing because it's the most obvious thing (or uses
the built-in search instruction if a CISC machine).  He or she doesn't
need to count on the compiler to be smart enough to return a value as the
carry flag rather than on the stack because why would you waste the
time and space?

That same programmer would retch knowing that linking in sprintf() pulls
in umpteen K of routines to convert %g,%e,%G,%E,%f,%x,%X,... formats
when all that is needed is %s and %d.

I really don't think the statement that C beats assembler for code space
as programs get larger is supportable.  We're moving to C right now
from assembler at GM.  The code does the same things (i.e. the car
runs with all the same features) but we're looking at a huge increase
in ROM space (much more than 10-20%).

I have no problem with the overhead typically found in C programs if
memory and CPU power is cheap.  But sometimes it isn't.  If you are truly
going to optimize for time and space, you need to have
control over every aspect of the code.  You can only do this with
assembly language, or if you have source for the compiler and are willing
to mess with it.

>| hardware often can be made simpler
>
>This is nonsense.

I agree 100% with John.

>Remember, assembly can easily be placed in-line
>within any C code.

As an aside, I personally don't like in-line assembler.  I find I get
greater flexibility when I link the assembler separately, especially when
using a source-level debugger that has no problem switching languages
midstream.

I am arguing to shore up support for paying continued attention to
assembler for this type of programming.  I think it can help us build
better systems.  I am not advocating using it preferentially to C or other
languages, which I feel can be justifiable choices.

The GE Software Engineering Handbook classifies embedded systems programming,
especially real-time mission-critical systems, as the toughest kind of all.
I much prefer having ALL of the tools available.

Ed Lansinger
GM Powertrain Premium V (Northstar/Aurora) Software & Calibration Group






More information about the Diy_efi mailing list