EmbeddedRelated.com
Forums

RTS problem

Started by nimish_sudan November 21, 2004
At 2004-11-23 14:05, Tony Papadimitriou wrote:
>----- Original Message -----
>From: "Jaap van Ganswijk" <>
>To: <>
>Sent: Tuesday, November 23, 2004 10:09 AM
>Subject: Re: [m68HC11] RTS problem >> At 2004-11-21 19:09, wrote:
>> >I think the rule is: if you push n bytes then call a jsr, the jsr must rts,
>> >then the caller must pull n bytes. One must NEVER jump out of a subroutine
>> >with items on the stack.... unless you are writing a 'kernel' or 'task
>switcher'
>> >or 'coroutines' or other comp-sci. The stack must grow and shrink
>> >symmetrically
>>
>> People that don't understand things like these
>> shouldn't program in assembler but should program
>> in a language like C which will take care of these
>> things.
>
>I'd go further and say people who don't understand such things should not
>program at all until they learn some more about how CPUs work. The notion that
>programming in a higher-level language is OK without sufficient knowledge of the
>underlying CPU is, to me at least, mistaken. Programming, no matter what the
>language, is still based on a machine, and a programmer must know how that
>machine works.

Perhaps for embedded programming, but not in general: Languages
like PHP, Javascript and Java are designed to work on all platforms,
so it wouldn't make sense to study how the CPU's work that they
run on.

>> By the way, nobody should have to program in
>> assembler anymore (unless for fun or to write
>> task switchers etc.) It's a complete waste of
>> human energy and especially in the case of the
>> 6811 you can't write much more effective code
>> than a good compiler can (perhaps you can squeeze
>> out 30% better code, but it will be totally
>> unreadable) and ROM is cheap by now.
>
>Although most will probably agree with you I think your opinion is subjective.
>I think it's like driving. Some truck drivers, for example, may find it easier
>to drive their trucks than their family car because they're on their truck's
>wheel most of their lives and have acquired a 'natural' feel for that vehicle.

You shouldn't assume that because there are two choices
they are equivalent. Programming in a higher level is
programming at a higher level of abstraction, which
has advantages and disadvantages, but it's not a random
choice. Higher level languages allow one to express it's
statements more consize, more powerful and more portable,
but you have to learn a higher level language before you
can use it. This requires at first quite a hefty
investment in learning a higher level language (I
also postponed learning C several years back in the
middle 80's, although I already knew Basic, Algol,
Pascal, Cobol etc.).
But once you have mastered C (of better) you can program
n-times faster (like 4 times faster) and you can handle
n-times bigger/complexer projects (like 8 times).

And you can port tried and tested code from CPU to CPU.

BTW. I'm not talking about small projects of a couple
of hundreds of assembler lines.

>Similar with assembly language. If you've been programming in assembly a great
>deal more than, say, in C, it actually IS easier to program in assembly language
>because you think the solution directly in terms of *that* language.

It's easier for some hardware-oriented people because
they can visualize how the bits go from register to
register through the ALU, affecting the flags etc.

But once you get used to a higher level of abstraction
languages like C are much faster to program in.

(BTW. I currently try to do everything in PHP. C is now
to me what assembler used to be. People still programming
in assembler are now two steps behind... ;-)

>On the
>other hand, if you've been programming mostly in C (or other higher-level
>language), when you get to program in assembly you natually first think in C and
>try to mentally translate the code to assembly. And that doesn't work very well
>so it gives the (I believe) misleading impression that assembly programming is
>harder.

I have programmed in all kinds of assemblers as well and of
course I did't write it in C first and then hand-compiled it,
but it never hurts to use good high-level programming practices
even when it costs a couple of more instructions.

>> I consider writing in assembler a modern form
>> of torture (often self-torture unfortunately ;-).
>
>I understand you completely. I feel the same about C when it comes to
>microcontrollers.

That has more to do with the microcontroller and the
compilers I guess than with C. (I'll go into that in
other reactions on this list).

Greetings,
Jaap


At 2004-11-23 16:36, bart homerson wrote:

>I would have to agree with you Tony. When I write the few programs that I do write, for a microcontroller, I always write them in assembly. Just as you said, it's just natural. I once took a look at some C-code and I simply could not figure it out! To me, it wasn't intuitive such as Assembly and Visual Basic are; it didn't "Flow". I am attempting to learn Assembly for X86 processors, yes, your PC. I have been told that it is more efficient than using Visual Basic. This should be interesting. Just my thoughts.

I can write in x86 assembler and even know a
lot of the differences between all of the
architectures by heart:
8086, 8088, 80186, 80286, 80386, i486, pentium etc.
and wrote in assembler for most of them, but I really
can't recomment it unless you have to write drivers
that have to be very small (but they don't have to
be anymore). C can be compiled quite efficiently
to x86 binary code and it runs perhaps at 50% of it's
speed.

And then there is always the trick of just
hand-optimising those few loops that the processor
spends the most time in. A rule of thumb says that
every program spends 90% of it's time in just 10%
of the code, so when you speed that up with the factor
two the total code runs about twice as fast.
(I have actually used this technique way back,
but why bother on CPU's with the current speeds?)

Greetings,
Jaap


At 2004-11-23 20:35, Paul B. Webster wrote:
>On Wed, 2004-11-24 at 02:36, bart homerson wrote:
>> I would have to agree with you Tony. When I write the few programs that
>> I do write, for a microcontroller, I always write them in assembly.
>
> My sentiments entirely.

Why are you indenting your text?

>> I am attempting to learn Assembly for X86 processors, yes, your PC. I
>> have been told that it is more efficient than using Visual Basic. This
>> should be interesting. Just my thoughts.
>
> Again, you would be in good company FWIW, that of the few people who
>*actually* know how PCs work, viz. Steve Gibson.

I'm sure that Steve Gibson has studied the architecture
of the x86 quite thoroughly but in the field of
computer protection he is considered to be a loud
fraud by people knowing more about these things than I.

> I had to chuckle where a previous critique stated:
>
>> It's perfectly legal (but usually bad practice) to push something onto
>> the stack before doing the JSR, and have the subroutine reference it.
>
>... as this is of course, *exactly* how C, Pascal and such function.

Indeed, whereby Pascal traditionally uses the reverse order of C ;-)

>It went on to say:
>
>> Advanced programmers sometimes -do- intentionally mess up the stack,
>> but they will take additional steps to handle the situation.
>
>... such as, by using such a language.
>
> However, I wonder whether (many of) those who malign the use of
>assembler, understand or recognise the distinction between "raw" and
>*macro* assembler,

Of course. I wrote my own assembler (the program that translates
the assembler source code) and it had very powerful macro abilities,
However I have never used them much, because a macro mainly results
in a lot of instructions repeated over and over again all over the
code. That isn't what I call byte-efficiency.

BTW. In an assembler I wrote for the Zilog Super8 processor I also
built a lot of pseudo instructions, like 32-bits adds, composed
of several 16 and 8 bit adds. That saved a lot of assembler lines
and you can't do that very flexible using macro's.

>which latter is I hope, our point of reference and
>the use of which begins to resemble "C"?

I wouldn't go as far that a macro assembler begins to resemble C.

Greetings,
Jaap



At 2004-11-23 20:52, Mark Schultz wrote:
>--- In , "Tony Papadimitriou" <tonyp@m...>
>wrote:
>>> I consider writing in assembler a modern form
>>> of torture (often self-torture unfortunately ;-).
>
>> I understand you completely. I feel the same about C when it comes
>> to microcontrollers.
>
>Ahh, the classic "C vs. asm" argument that tends to pop up in groups
>like this periodically.
>
>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.

Most 6811's had 4K internal (EP)ROM already 10 years ago, I think,
and a good compiler won't produce much more than 30% extra code
for the 6811, so where is the gain?

>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?

> 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 probably intended to write:

if ((ch=getch())=='\n') {

Which makes perfect sense since your read a character
into the variable ch and check if it's a newline character.

>And this is just a simple example (intended to be
>comprehensible while still making my point) of much more complex
>assignments-within-expressions-within-evaluations that I see all too
>often in "professionally developed" C source.

It saves repeating terms from expressions.

You could have written the previous expression as:

ch=getch();
if (ch=='\n') {

But I prefer the concisely written version, because it only
once has the term 'ch' in it.

>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.

The first cast-iron bridges in England were build like they
were build from wood. It's a phenomenon often seen when new
technology arises: Managers who needed a company WWW site
often thought it needed to look like an old medium like a
TV-program or a brochure. The true acceptance of new
technology goes very slowly and may take a generation
change (sorry guys...)

>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.

>A properly commented, intelligently
>structured C program can be a joy to behold - just as a properly
>aligned, well structured assembly program with good label/variable
>names can be. Organization, clarity, and consistency in style are
>the keys to readability in ANY language.

Yes, but you still shouldn't compare programming in a low level
language with that in a higher level language. It just isn't the
same. And it isn't just a choice. It's like saying that the
Quakers (?) in Pennsylvania Dutch Country are also developing
technology but in another direction.

>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 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 ...

etc. in the end I identified about 16 different spaces.

A next obstacle is BTW. the communication between the downloader
and the project to download it to.

>This issue has been the single greatest obstacle that I've
>encountered in my attempts to utilize the GNU HC11/12 toolset for my
>own projects based on these parts.

I can imagine that very well...

BTW. Anyone want to help make my 6811 compiler, assembler, linker and
downloader public (under GPL)?

The assembler is actually a family of assemblers and I also have
a similar family of disassemblers.

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.

BTW. For a sample of code that I write in PHP:
http://www.chipdir.nl/amazon/

(But it's a bit over-commented, because the code is explicitly
meant to be used by others.)

Greetings,
Jaap



At 2004-11-23 21:54, Donald E Haselwood 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.
>
>Quite true. Over the years the technique I've found most useful is to keep
>asm routines small and C-callable (and before C, FORTRAN callable). By
>making them C-callable, 1) I can use a quick 'n dirty C mainline to test
>them, 2) it forces a uniform organization for passing arguments, stack
>useage, and saving registers (which saves
>frustration/self-cursing/sanity/...).
>
>Also, whenever I start to write an asm routine I find there is a temptation to
>keeping add more to the routine, which can lead to a monstrosity that is
>difficult to debug/test, and has limited reusability.

But why still write big subroutines in assembler?
With the 6811 the code size of compiled code doesn't
have to be much bigger than 30% more so it will also
not take 30% more cycles.

You shouldn't choose a certain processor when it's
speed margin is within the 50% range. Always choose
a processor that is at least twice or four times as
fast as you think you need. You never know what will
turn out to be too slow and you never know what
extra functions management and users may want added
later.

The 30% extra that the compiler add's is much less
than what you need to add as a safety margin for the
uncertainty.

BTW. I have programmed very large projects on
microcontrollers like the 6811 and as long as you
understand timing issues that extra 30% is never
an issue.

Greetings,
Jaap


On Thu, 2004-11-25 at 15:40, Jaap van Ganswijk wrote:

> Why are you indenting your text?

Because it looks and reads better that way.

As someone who has gone on to state that you "can't indent assembler",
which is in itself, certainly news to me, I can only assume that you
agree that indenting makes computer code more readable, and so it is for
English prose.

> I'm sure that Steve Gibson has studied the architecture
> of the x86 quite thoroughly but in the field of
> computer protection he is considered to be a loud
> fraud by people knowing more about these things than I.

But the question remains, do those critics *actually* know more about
these things than Steve Gibson, or are they in turn, merely a further
group of equally loud frauds? Wannabees and Know-it-alls are never in
short supply, wherever they occur in the food chain.

> Of course. I wrote my own assembler (the program that translates
> the assembler source code) and it had very powerful macro abilities,
> However I have never used them much, because a macro mainly results
> in a lot of instructions repeated over and over again all over the
> code. That isn't what I call byte-efficiency.

Where the alternative is subroutines, extra stack operations and
consumption of stack space, it may *well* be byte-efficiency. The first
use of macros is to concisely represent code which is *going to be* used
again and again. If it was not *necessary* to repeat the code pattern,
then you wouldn't *need* the macro. The code comes first, the macro
embodies the code.

> BTW. In an assembler I wrote for the Zilog Super8 processor I also
> built a lot of pseudo instructions, like 32-bits adds, composed
> of several 16 and 8 bit adds. That saved a lot of assembler lines
> and you can't do that very flexible using macro's.

I begin to wonder what you think macros are? What you describe is
*exactly* what macros do - the second use of macros is to generate
parametric code (often using macros within macros), that is code using
similar patterns of instructions which differ by parameter - the actual
values or addresses which they contain. Also, using conditional
directives, a given macro expansion can contain (entirely) different
instructions on different invocations.

> I wouldn't go as far that a macro assembler begins to resemble C.

Well, macros can build hierarchical structures, which seems to have a
lot to do with what C is about. A macro assembler can most certainly
build a higher level language, and can like C, be used to generate
CPU-independent code. In fact, a properly-constructed macro assembler
*is* CPU-independent because at the lowest level it contains only
definitions of all the instructions - as macros!

One simple little "gadget" that I build some time back - when I *was*
actually building things(!) - was a State Machine - a clock, an octal
D-latch, and an EPROM. Now the "program" was written in AS09 (MAS09?
The host machine - 6809 Exorciser variant - has subsequently died) which
was rather funny, as it had *no* microprocessor! Of course, now I would
use a 16F84 or an AT90S1200 (because they are still a lot cheaper than
an HC05K2).

--
Cheers,
Paul B.


----- Original Message -----
From: "Jaap van Ganswijk" <>
To: <>

> Perhaps for embedded programming, but not in general: Languages
> like PHP, Javascript and Java are designed to work on all platforms,
> so it wouldn't make sense to study how the CPU's work that they
> run on.

You missed my point. Yes, high-level languages have the benefit of being less
platform dependent. But, in most systems, e.g., PCs, mainframes, etc. there is
a hefty Operating System in the background doing all the dirty work for you.
That's what gives you the freedom to use the language without having to know
much about the CPU architecture. (Although you still should know, for example,
what size integers the host machine has or else porting may be puzzlingly
unsuccessful.) With most microcontroller projects, this isn't the case. It's
just you (with your C compiler friend at best) and the machine. Not the same
scenario.

Also, I never claimed higher-level languages should be abolished, on the
contrary, I'm a firm believer in their use being increased as nobody seems to
use them anymore. But, I'm referring to truly high-level languages. And C
isn't it. It wasn't designed to be.

My 'complaint' is C, to many, is meant to be the cure to all diseases. As you
probably know, C started out as (and still really is) a 'medium-level' language
to address a specific problem, in short, to give as much as possible the
capabilities of an assembler (which has no restrictions found in nearly all
high-level languages) yet have the look-and-feel of a high-level language (e.g.,
with loop contructs, structured IF-THEN-ELSEs, etc.). That was, so people could
write middle-ware like Operating Systems or Compilers (which often need to get
down close to the hardware) in that language. Initially, it was never meant to
be for writing end-user applications.

Each language has its place. With C, somewhere it took the wrong path. From a
computer science standpoint, C is actually a bad language for writing high-level
applications. Pascal, Modula, and others are far better choices. Unfortunately
though, early (mostly) student programmers' show-off attitutes made them use C
from their early university years to prove to fellow students that they can do
it, i.e., program in a language, which at that time, was considered harder
(correctly so) than BASIC or COBOL or FORTRAN or Pascal or Lisp or whatever else
was available, just like assembly is still today considered 'harder' than C.
(And I'm talking before the time C became a requirement in most CS curricula.)
Then inevitably, what most learn in school, they try to stick with for the rest
of their lives, so we got a whole generation of C coders many of whom didn't
even realize there were other tools for the jobs they were asked to do. And
that 'foolishness' spread. The more the people that use a language, the greater
the numbers of projects written in it, the greater the demand for new people to
learn it to support older projects, and so on. So, today, it's gotten to the
point that if you don't know C you're hardly considered a programmer! Amazing!
(And in case you wonder, I do know C, I just don't like it for the reasons I
mention here, and I avoid it whenever it's in my hand to do so, unless of course
there truly is a reason to use it, e.g. modify a Linux kernel or something of
that nature!)

> >Although most will probably agree with you I think your opinion is
subjective.
> >I think it's like driving. Some truck drivers, for example, may find it
easier
> >to drive their trucks than their family car because they're on their truck's
> >wheel most of their lives and have acquired a 'natural' feel for that
vehicle.
>
> You shouldn't assume that because there are two choices
> they are equivalent. Programming in a higher level is
> programming at a higher level of abstraction, which

Sorry, abstraction is NOT related to language (although it is more easily
implemented with certain high-level languages designed specifically for this
purpose). Even if it were, it certainly wouldn't be close to the middle-level C
language. Abstraction is conceptual and, as such, it is related to programming
methodologies, not language. You can be very abstract in assembly language just
as you can be very nonsensical (is that a real word?) or 'spaghetti-like' in C
(or BASIC or Pascal or whatever) which are supposed to protect you from
programming 'atrocities'.

> has advantages and disadvantages, but it's not a random
> choice. Higher level languages allow one to express it's
> statements more consize, more powerful and more portable,
> but you have to learn a higher level language before you
> can use it. This requires at first quite a hefty
> investment in learning a higher level language (I
> also postponed learning C several years back in the
> middle 80's, although I already knew Basic, Algol,
> Pascal, Cobol etc.).

Almost 25 years, three University degrees strictly in Computer Science, and a
large assortment of projects in more computer languages than most people would
be able to enumerate in a pop-quiz, is more than enough investment to know a
little what I'm talking about, even if I can't get others to always agree.
We're all entitled to our opinions.

> But once you have mastered C (of better) you can program
> n-times faster (like 4 times faster) and you can handle
> n-times bigger/complexer projects (like 8 times).

Again, you fail to understand that what you claim is subjective. It's because
YOU can program faster or more easily in C, you think this is a universal rule.
Not so. (Example: Can you or I speak Chinese? No! But 5-year Chinese can!
Does that make the Chinese language easy or hard?) It doesn't automatically
mean your knowledge of C is greater than someone else's who also happens to know
assembly language equally well, and *still* find it easier (and possibly faster)
to program in assembly, even though s/he know enough C to not 'have to'
(according to you it's a self-torture) write in assembly language.

> And you can port tried and tested code from CPU to CPU.

True to the extent I mentioned earlier, i.e., code depends on an underlying OS
or something equivalent, not stand-alone. Raw hardware and just your code will
never port as easily as recompiling for the new target processor, except for
trivial applications.

> BTW. I'm not talking about small projects of a couple
> of hundreds of assembler lines.

Me neither, I'm talking about complex well-structured thousands-of-lines-of-code
programs.

> >Similar with assembly language. If you've been programming in assembly a
great
> >deal more than, say, in C, it actually IS easier to program in assembly
language
> >because you think the solution directly in terms of *that* language.
>
> It's easier for some hardware-oriented people because

Again, having a heavy Computer Science background, I'm not hardware-oriented in
the sense most EE people on this list are (I can't hardly design even the
simplest circuits). Of course, I do know all I need to know about CPU internals
to the extent that I can design my own CPU from scratch (but then I *must* take
it to an EE professional to maybe optimize it and turn it into an actual circuit
that works).

> they can visualize how the bits go from register to
> register through the ALU, affecting the flags etc.
>
> But once you get used to a higher level of abstraction
> languages like C are much faster to program in.

> (BTW. I currently try to do everything in PHP. C is now
> to me what assembler used to be. People still programming
> in assembler are now two steps behind... ;-)

To me, C is actually a *very rich* macro-assembler! So, our views our coming
closer here, from different ends, but closer none-the-less.

> I have programmed in all kinds of assemblers as well and of
> course I did't write it in C first and then hand-compiled it,
> but it never hurts to use good high-level programming practices
> even when it costs a couple of more instructions.

I didn't say that you must actually write in another language (I said 'mentally
translate'). To give an example, I say that just like when your native tongue
is English you think in English no matter how well you have been trained in
another foreign language. You still think in your mother language. And it is
possible for someone who lives abroad for a long-long time to master another
language better than his own, but then this new language becomes your main
language, so all your thinking is in that language, and your original language
still needs a little work when you try to speak it. (This is actually based on
personal experience.) So, it takes extra 'thinking' to speak anything other
than your 'currently' native language, it doesn't come out as effortlessly.
Similar with programming languages. You tend to think a solution in terms of
your favorite or better mastered language, and then mentally 'translate' to the
language you must actually use for the project at hand. And this doesn't yield
the best results. So, you end up blaming the language instead of the author.

> >> I consider writing in assembler a modern form
> >> of torture (often self-torture unfortunately ;-).
> >
> >I understand you completely. I feel the same about C when it comes to
> >microcontrollers.
>
> That has more to do with the microcontroller and the
> compilers I guess than with C. (I'll go into that in
> other reactions on this list).

It is precisely with microcontrollers that this holds, so we agree on that.
Like I said earlier, PCs have a rich OS so in a sense your code is really not
much more than a series of calls to that OS (I exaggerate a little but I'm
trying to get my point across about not being the same scenario with PCs and
microcontrollers). Not much 'original' work in PCs in the sense you find in
microcontroller projects! With PCs, if the OS can't support it, or else, let
you bypass it to do it yourself, you're pretty much stuck! See what I mean?
Hope so.

To conclude:

I'm not bashing C unconditionally, I just think it's the wrong language for
certain jobs, one of them being microcontroller code writing (*especially* when
we're talking about 8-bit controllers which are small enough to be completely
manageable fully in assembly language even by non-expert assembly coders).

I wouldn't write a multi-tier airline reservation database application with
assembly language (or even C). But I also wouldn't write a 68HC08QT4
application with C, either. Each language has its place.

The reason for programmers turning to C originally was to gain the added power
high-level languages didn't provide when dealing with hardware or lower level
software functions. This is the same reason that drives many of us assembly
language proponents to assembly language FOR MICROCONTROLLER JOBS, not
everything. We need the extra power that C can't offer to a microcontroller
project.

> Greetings,
> Jaap




--- 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




On Nov 25, 2004, at 12:37 PM, Mark Schultz wrote:

> 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 don't know what C compiler your statements are based upon but only
poor implementations have a "runtime (crt0)" such as you describe. This
relates right back to my earlier statement that if one sees stdio.h
that one can expect to find the code written by the clueless.

My use of embedded C has mostly been with the Introl C-11 compiler.
Other than rare situations where it re-reloads a register with the same
value it loaded a moment earlier there is not much it does which I
would do differently by hand in assembly. In other words I don't
usually bother to pass arguments on the stack in assembly. Introl C-11
puts all it can in registers then stacks the rest.

Introl's startup code is quite reasonable. Any HC11 has a few
housekeeping chores which must be done early such as position the I/O
registers and set the stack pointer. If one preloads variables with
data then these must be copied from ROM to RAM. Introl goes a bit
farther and by default routes IRQ vectors thru a RAM vector table and
provides a wrapper so that nonspecial subroutines may be called. A
provided library function inserts your subroutine into the vector table
and wraps it. If one reads the source code and understands it then
there is no problem replacing the actual ROM vector table with
addresses of one's actual routines. And no problem defining them with a
special function type so that they behave during IRQ and properly RTI.

Have recently been looking at avr-gcc in quite some detail. One fairly
simple example found in the avr-libc documentation had very little code
out of RESET before main() was called.

One could do lots of real work in 1k of ROM with avr-gcc. But one
probably couldn't get printf() to fit if one insists on writing C the
Microsoft Way.

I agree with all the bad things Mark says about C if one limits the
discussion to C compilers I have seen for the 8051, PIC 16, and 68HC05
products. The Metrowerks HC908 C compiler appears to be acceptable. But
recently made the selection of Atmel AVR and avr-gcc for future
products. Only time will tell.

--
David Kelly N4HHE,
========================================================================
Whom computers would destroy, they must first drive mad.