--- In , Jaap van Ganswijk <ganswijk@x> wrote:
>> At 2004-11-23 20:52, Mark Schultz wrote:
>> FWIW, my own personal preference is to do smaller and/or more
>> cost-critical, resource-constrained applications in assembly
>> language. Even the best C compiler cannot produce code to match
>> expertly hand-optimized assembly code.
>
> I assumed that ROM space wasn't a problem and usually it
isn't.
That's a very poor assumption to make.
There are still a lot of *current* microcontrollers on the market
that are very code- or RAM-size constrained. This is particularily
true for 8-bit families such as the lower-end PIC and AVR devices,
as well as half a dozen other MCU families I could cite if asked.
There are parts in the aforementioned families that I've encountered
that have less than 1K of ROM space, and only 32 bytes of
RAM/register space! For such devices, C is not really an option -
the overhead imposed by the C runtime (crt0) alone would consume
half your program storage! For such ultra low-end devices, assembly
language is still the best choice, IMO.
I also believe that Jaap mentioned in one of his responses that one
should select a device that is at least 2x as "powerful" (~= RAM/ROM
space, CPU speed, etc.) as the anticipated need. As an engineer, I
would be inclined to agree with that statement, but if I put on
my 'managers' hat and look at the project from a marketability and
cost-control standpoint, I'd be inclined to argue that assertion. I
have been compelled to do firmware design for projects where
decisions such as which microcontroller to utilize or how the
external support hardware is designed have been made with little or
no input from myself. When faced with a situation where the
hardware design is just barely sufficient to get the job done, I'll
go for the design option that lets me get the most from the
hardware - and that almost always means "write it in assembly
language". Either that, or throw up my hands, say "it can't be
done", and resign.
>> Some C-only proponents often use as an
argument that asm is
>> cryptic...
> No it's too wordy. The language is very
hardware idiocyncrasies
> dependent.
>> ...whereas C tends to be more "self
documenting". I could not
>> DISAGREE more.
> C is more abstract so the programmer can more
exactly express
> what the more abstract meaning of the program is without having
> to use the assembler instructions that happen to be available.
> When you know 6811 as you probably do, you will probably easily
> read a 6811 assembler program by another programmer, but when I
> would present you with some Super8, Z80, x86, Alpha, R3000
> assembler code?
>
> Compare:
>
> if (x) {
> ..do this..
> }
> else {
> ..do that..
> }
>
> isn't this code very clear?
>
> Now in assembler:
>
> lda _x
> tsta
> jr z,1f
> ..do this..
> jr 2f
> 1
> ..do that..
> 2
>
> (I would have properly indented it, but most programmers probably
> don't do that...)
>
> Anyway, which code is the clearest?
While your point has some validity, your example/contrast is not
very fair. I *NEVER* write assembly code in the style you
demonstrated. For one thing, any asm program I write almost always
has a comment-per-line. I could attempt to illustrate my style
here, but the Yahoo message formatter will mess it up, so I have to
resort to a textual description. My asm programs always use labels
of medium length (typically 10 char max), and jump-points within a
given subroutine are always sequentially (or occasionally, alpha)
numbered. Almost every statement has a end-of-line comment. I use
indentation in the comment field and liberal use of vertical
whitespace to illustrate blocking. Every subroutine I write has a
standard comment header that describes input and output parameters,
variables referenced, estimated stack usage, registers affected,
etc. Major sub-sections of code within a routine have one or more
lines of block comments that describe overall function. A typical
source file generated by myself will consist of more comments
(measured in terms of space consumed by the source file) than code.
Some of the code that I have recently uploaded to the files section
of this group illustrates my asm style; I invite you and others to
review it and reach your own conclusions.
I should point out that I follow many of the commenting/style rules
(with appropriate modifications due to the different environment) in
my C (or other HLL) programs.
My point in mentioning all of this is that asm source CAN be made to
be quite readable - and conversely, C source can be made to be
totally unintelligible, a point that I will address in a moment...
>> The sad tendency of your typical C programmer
to write gawd-
>> awful constructs like this:
>>
>> if (ch=getch()=='\n') {
>>
>> drives me nuts.
> It shouldn't drive you nuts. Just learn the
associativity
> rules: '==' is more associative than '=' so I
immediatily
> see that your code can be rewritten as:
>
> if (ch=(getch()=='\n')) {
>
> Which is probably not what you intended to write because
> you are assigning a boolean value to a variable called 'ch'.
You make my point for me. Writing constructs like the one above is
a common (and difficult to locate!) source of bugs in a typical C
program. And, while I do not disagree with your point that a good
programmer should familiarize themselves with the rules of
assocativity and precedence in the language they are utilizing,
parsing expressions like the one above (for a human) is a lot more
difficult than parsing the equivalent:
ch = getch();
if (ch == '\n') {
The difference in readability is not as easy to see in this trivial
example, but it is much more pronounced in more complex expressions.
>> When I write programs in C, I try to avoid
complex expressions,
>> or at least break them up into multiple lines, assembly-
>> language-style.
>
> You suffer from what also happens a lot with artists who produce
> kitsch: They partly adopt a new technology but can't sever the
> links with past technologies and therefore combine them.
Perhaps I should have omitted (or replaced) the phrase "assembly-
language style" with something like "...to make the code easier to
read". While I can, given time, deduce the operation of a long,
complex expression, the time this takes as compared to the lesser
time and effort required to figure out the operation of a complex
operation broken down into smaller, more discrete steps is
considerable. This has less to do with "assembly style" vs "HLL
style" and much more to do with "readability".
Note that I'm not advocating a reducto ad absurdum approach to this;
I have no problems with an expression such as:
Scaled = (Sample1 + Sample2) * Slope + Offset;
Although I might use a few more ()'s even if they are redundant:
Scaled = ((Sample1 + Sample2) * Slope) + Offset;
The ()'s make the precedence of operations explicit TO THE READER;
they are redundant as far as the compiler is concerned.
Mind you, I *would* have a problem with this:
Scaled = ((RawValue = (Sample1 + Sample2)) * Slope) + Offset;
Assignments don't belong in expressions. Period.
Of course, any one of the above (even the one with the stupid
assignment-within-expression) is quite readable because I used
meaningful variable names; it is fairly obvious what I'm trying to
do (scale raw measurements into [presumably] standard units using
the classic linear equation y = mx + b). I mention this to make
another point about what distinguishes good from bad code -
selection of variable names.
Also note that I do not 'crowd' the operators right up against the
variable names; judicious use of whitespace goes a long way towards
enhancing readability.
>> Ok, I'm ranting here, so let me get to my
point: I am of the
>> opinion that the language is not as important as is the style in
>> which one writes code in any language.
>
> Yes, but you can't use bracketing, indentation, local variables,
> dynamical expressions etc. in assembler.
True, but I can use whitespace, end-of-line comments (which can be
indented), and stack-allocated local variables (if the CPU offers
direct access to the stack pointer, which the HC11 does but the HC05
and PIC do not) to achieve similar results.
Obviously, a HLL will offer better tools for block-structuring than
assembly will - that's one of the aspects that makes a HLL a HLL
after all. I'm simply trying to reiterate my point that good style -
in any language - is the single most important factor in
readability.
>> One last comment on C in
embedded/microcontroller systems - one
>> of the things I dislike most about your typical C compiler is the
>> complex (and usually poorly documented) procedure one has to
>> figure out to get the various memory regions and areas, or even
>> individual variables, mapped to where you want them to go.
>
> Yes, I fully agree with you on this and that is also why I
> wrote my own assemblers and linker.
>
>> The C language standard does not do a good job of allowing one to
>> attach attributes to variables (or subroutines - Ed.) indicating
>> where in memory they should go. This task usually falls to the
>> linker, and of course there is no standard for linker
>> control 'languages' which means that it differs for every
>> compiler.
>
> Indeed. And it's doubtful if it should be done within the C code
> itself because it might kill the portability of the code. In C
> there might be hints (just as with the register 'class') like:
> Put this in EEPROM, this in battery RAM, this in memory that
> is still available when the program starts again, this on disk,
> this in literal space, this ...
Many 'better' relocating assemblers support a "section"
directive
(or equivalent) that allows the programmer to specify, in a fairly
portable and abstract way, what region a given block of code should
be mapped to. The physical address of each section is still
(usually) specified at link-time, but one can create sections with
names such as "Page0RAM", "ExternalRAM", "EEPROM",
"PrimaryFlash",
"BackupFlash", etc. that make it clear where things go. Some C
compilers I have encountered provide non-standard #pragma's or even
linguistic extensions that allow this sort of control at the source-
code (rather than linker) level. I would personally like to see
extensions of this nature added to the C standard, or perhaps as
an "addendum" to the standard that would be optional and probably
only implemented by developers of cross-target compilers.
> BTW. Anyone want to help make my 6811 compiler,
assembler, linker
> and downloader public (under GPL)?
Wish I could help, but I got out of the 'application' side of things
around the time that Windows became popular. I have made some
progress in learning the *nix/posix API's, but I've got a while to
go before I could call myself 'proficient'. I suspect that
attempting to comprehend Microsoft's (Windows) API's would lead to a
nervous breakdown.
> BTW. In PHP the problem with assignments within
expressions is
> more or less solved by adding 'and' and 'or' as having
the same
> function as '&&' and '||' but with a lower
priority as '=',
> so you can write:
>
> if (ch=getch() and ch=='\n') {
>
> In a lot of the code that I write, it's a big improvement.
Yes, I agree. The first HLL I learned (after BASIC) was (Borland's
implementation of) Pascal. I only wish that Pascal, or a language
similar in structure to it, had become the de-facto HLL standard.
Borland's implementation of Pascal offered ways to do almost all of
the 'low level' stuff that C is capable of, but with a much less
ambiguous syntax. To this day, I still have trouble remembering
which of C's operators are bit-wise and which ones are logical (e.g.
& vs. &&, | vs. ||, etc.). Borland did away with the
'logical'
operators entirely, and opted to make AND, OR, XOR bit-wise, while
specifying the value of "TRUE" for relational operators to be -1
(all bits set). This choice eliminated the need for ambiguous bit-
wise vs. logical operators. Couple that in with Pascal's usage of
English words (AND, OR, XOR) instead of symbols (&, |, ^) for the
operators themselves, the end result was a lot more readable.
From what little I've seen of PHP, it would seem as if what the
designers have done is take C and move it a bit in the Pascal-ish
direction. That's a Good Thing in my book. Unfortunately, I've not
seen very many PHP compilers made available for microcontroller
targets :(. Also, isn't it true (I honestly do not know) that PHP
is tokenized/interpreted rather than compiled? If so, this is a Bad
Thing, at least as it applies for it's use in embedded systems.
Despite all the industry talk about use of Java in embedded systems,
it's use is pretty much constrained to high-end systems running
almost desktop-PC-capable microprocessors due to the twin overhead-
bloaters: object-oriented data dynamisim (-> large RAM requirements)
and it's interpreted nature (-> high CPU load).
-- Mark
|