Embedded
Lingos
Copyright 1995,
Jack G. Ganssle
Abstract
How do you pick
a programming language? Here's some thoughts on C++.
Published in
Embedded Systems Programming, June 1995
How do you go
about selecting a language for an embedded application? Each has it's ups
and downs: APL's conciseness comes at the cost of
being infinitely cryptic. Forth's extensibility requires a tremendous amount
of documentation to back up the meaning of each word. ADA's
complexity makes a programmer focus on syntax to the point where, if the program
compiles, it will probably run. (ADA, however, seems to
be in the early stages of becoming a Latin - a dead or dying language spoken
only by a few high priests).
In the embedded
world the language debate is largely between C and C++. The magazine pages
are crammed with ads from compiler companies
offering the latest in OOP products, yet my informal surveys indicate that
few in this industry write real C++ code. A recent debate in
comp.realtime seems to confirm this observation.
Though C++ scares
me (are the compilers be reliable? can we find programmers who really live
and breathe it?), I see it as a critical step
in promoting software packaging. And, I do believe that reusability is the
only reason for migrating to C++.
Someday our mantra
will be "inheritance, encapsulation, polymorphism". Why
rewrite the same routines time after time? C++, and a
strong armed programming discipline, just might make the concept of reusable
packages a reality.
I believe that
reusable software is our only hope of dealing with increasing software complexity.
Let's face it: at some point our own
code will be simply too convoluted for anyone, including ourselves, to understand.
It's naive to expect that, by itself, a new language
will create some magic ability to handle bigger systems.
Why is it so
much easier to design an embedded system's hardware than its code? Though
programming surely is hard, don't forget that your
30,000 lines of code might be running in a system with over 200 million transistors.
Which is more complicated? Which would you expect to
be harder to design?
In fact, the
hardware community is much better than we are at defining, and living with,
levels of abstraction. No one designs a computer
for an embedded system. We use an off the shelf processor. Need some memory?
Pick one of thousands of standard chips. I/O is just as
simple - hundreds of different kinds of peripherals lie at our fingertips,
with yet more hundreds of variations of each type. Any one chip
might be supremely complex, but each is easy to use.
Programmers decompose
a problem into its functional blocks and then laboriously code each block.
The hardware engineer also partitions the
problem into functional blocks. Then, he uses a few standard parts to implement
that section.
The problem of
hardware complexity has been mastered by standard parts and a will to use
them, even if the design must be altered to fit
the available parts. Software folks simply must reach the same mastery of
complexity to deal with the larger programs looming in the
future.
Every chip comes
with a well defined interfaced bounded by some number of pins. Voluminous
data books describe the action of the device in
gory detail. While the unit's internal operation might be glossed over, its
interface is well defined with timing diagrams, input and
output levels, and the like. Doesn't this sound a bit like the OOP nirvana
we're all seeking?
C++, by itself,
will not create massive software reuse. It's but one ingredient in a larger
recipe. Just as knowing how to use Corel won't
make you a graphic artist, the tool itself can greatly aid in achieving an
objective. Management Issues
Programming is
like accounting. It's not an end in itself; it's merely one necessary function
performed by a company in pursuit of
profits. Select a programming language that fits the organization's goals
and objectives; not one that just fits your own style.
Though we're
technologists infatuated with technology, don't pick a lingo solely on technical
merits. Poor language selection can
dramatically effect a company's viability, so make sure your choice is based
on sound business thinking.
Can you get competent
programmers familiar with the language? Will you be able to get people with
this knowledge way out at the project's
projected end of life? The latest fad could be tomorrow's bit of history,
leaving the company in dire straits when looking for someone to
make a few patches.
This sort of
implies that a "safe" strategy is to follow the herd. If
the whole world is using Modula 2, then Modula is probably
a safe bet in terms of finding people to do the work. Surely, C fits this
bill now. I would bet that C++ will have a large enough
installed base in a few years that plenty of adept people will be available.
The management
ranks in high tech organizations often suffer from a fear of change - an appalling
thought considering that most of the
whirlwind of societal change we've seen in the last generation springs from
the electronics industry. A fact of software engineering is
that relatively young engineers quickly find their way into mid-level roles
of responsibility, and quickly start losing touch with state-
of-the-art technology as their jobs require more personnel work and less techie
stuff. A manager comfortable with assembly will naturally
encourage his folks to use assembly, and will be a bit afraid of any language
of which he is not a master. This slows the adoption of all
sorts of new technologies, languages being one. Perhaps there is a benefit
to this, as the inertia helps avoid erratic pursuit of new
fads. Surely there's a lot of evil as well.
The C versus
C++ debate is especially sensitive to this. You don't gain the benefits of
object oriented programming without adopting a new
way of looking at solving software problems. C is more like assembly, at heart,
than C++ is like C. It's hard to make the inductive leap
an OOP requires. As a middle-aged manager, I know!
But, the manager's
role is to insure that his people are doing the right things, in addition
to doing things right. Picking a language is
taking a leap of faith into the future. Select one that builds the company's
core competencies, that stretches the team in the direction
that the organization should be headed.
The only constant
is change, so you've got to develop a strategy that elegantly waltzes with
change rather than resists it. The clever
manager never views a project as an end in itself. Though the immediate goal
is generally nothing more than building a product, you've got
to use each and every engineering effort as a training camp for every member
of the team. Move the team's competencies ever forward,
always gaining experience as well as a product.
Now, an assembly-only
shop should probably not make a sudden leap to 100,000 lines of C++. You have
to balance the risk of being late with
the need to try new things. Constant incremental improvements are good. Radical
surgery is something a company can tolerate only
occasionally.
We can all learn
from consultants McKinsey & Company. They'll turn down dead-end jobs
that bring no more benefit for the company than
cash. Projects are selected and planned to insure that each one improves the
business's competencies. This is long range planning and
investment at its best!
Every company
needs a certain amount of leading edge work designed to push the envelope.
Mitigate risk by limiting the scope or importance
of these projects, but do try different things. Even if your group has no
use for C++, run a small effort using it to increase the skill
levels of your workers, and to learn important new things.
Now, going back
to a comment I made earlier, I believe the primary reason to use C++ is for
software reuse. Period. C++ has all of C's
wonderful ability to control any bit in the system, yet comes equipped for
serious encapsulation and subsequent routine reuse. Go to C++
if reuse is your god. This means that everyone involved is committed to code
recycling, from the CEO to the janitor. If your manager is
not beating a reuse drum, keeping the entire team's vision focused on this
critical goal, then reuse will be abandoned the first time a
ship date nears.
Don't assume
management has your best interests at heart. If you are caught in an intellectual
backwater, work hard outside of the
business to stay up to snuff on all of the latest technology, since today's
whiz bang idea will be the base level of competition tomorrow.
Any engineer who stops aggressively learning and experimenting condemns himself
to technical obscurity. Efficiency
The holy grail
of language and compiler debates is efficiency. How fast is the compiled code?
How big is it? Software folks love to debate
how one runtime package searches strings a few microseconds faster than another.
Select a language
(and compiler) based on your real size and speed constraints. Is it efficient
enough for your application? When the
crummiest compiler in the world is perfectly adequate, don't torment yourself
with debates over unimportant microseconds.
In a high volume
tiny application, like the PIC-controlled blinking lights on kids' sneakers,
assembly language may be the only
appropriate choice. Larger projects, especially those produced in small quantities,
should be language insensitive: crank up the clock
speed or get a larger CPU in the interest of reducing software development
costs.
Counting T states
is a terrible waste of a programmer's mind. Avoid it in any but the most cost-sensitive
applications.
Modern C and
C++ compilers generate high quality code. Trust your compiler. Most overhead
problems come from weaknesses in the processor's
architecture, like poor stack handling abilities. Recently I saw this graphically
when comparing real time trace data on a Z80 to the
original C source: ++I (with I a 16 bit signed integer) generated about 25
instructions. Changing I from an automatic to a static variable
cut out 75% of the overhead.
Crummy code problems
come mostly from programming without thinking. Don't force the compiler to
optimize your program for you. Fold
constants yourself, remove unneeded code from loops, and minimize conversions
between types. This is just good programming style.
Interrupt and Device Handlers
Select a language
that is complete enough, and efficient enough, to handle all aspects of your
task, including real time interrupt
handling. Sure, there may be one or two ISRs that simply must be coded in
assembly, but remember that assembly is a productivity disaster.
C compilers are
now so efficient that I recommend writing all but the most critical ISRs in
this language. Assembly is simply too tedious,
and linking assembly to C is sometimes an art - particularly if you have to
pass data between languages.
Be sure your
compiler has built-in support for writing ISRs. We've found that even Microsoft
and Borland's DOS compilers do a great job in
interrupt intensive embedded systems. True embedded compilers, like those
from Software Development Systems, Microtec Research, Avocet,
and a host of others all include ISR-specific keywords.
The compilers
will take care of pushing, popping, reenabling interrupts, and the return.
Frequently the linker will even set up the vector
table for you as well. A few low-level OUTs, issued from your C code will
program the external controllers and other devices with the
proper vectors.
If your tentative
language choice is a loser in the real time segments of code, reject it. You
don't use COBOL in embedded systems; why
pick some equally inappropriate lingo for your application? Conclusion
Sometimes you
just can't make a rational language decision. All too often the contract mandates
details down to the toolchain. It's noble
to wage a holy war against the use of FORTRAN-60, but be prepared to lose
gracefully. Swallow hard, search your soul to see just how badly
you want to stick with that job, and get the work done or start circulating
resumes.
Never forget
that you can write crummy code in any language. Conversely, no mainstream
lingo will prevent you from writing software as
beautiful as that crafted with any other tool.
I do believe
we'll all eventually migrate to C++, but am afraid that the driving force
will be language lust (the "this is the new
cool thing" factor), not a commitment to recycling code. Yet you
can make a choice today to start reusing code, no matter what
language you're working in. Your productivity increase will earn you fame
as the master software guru... and maybe even some fame and
riches.