EmbeddedRelated.com
Forums

mixing C and assembly

Started by Lax April 22, 2008
cbarn24050@aol.com wrote:
>>> I have no idea what kind of person you are. >> That's why I found it odd that you thought referred to "people like >> you". It's a dangerous phrase to use - "people like you" can easily >> sound very insulting (fortunately I'm well used to Usenet, and don't >> take offence easily). > > No offence was mean, perhaps I should have said peaple in your > position. >
I don't think generalisations like that are appropriate, no matter how you phrase them. But don't worry - no offence taken.
>>> Ive never used AVRs tiny or otherwise but I have used PICs >>> extensively. I am convinced that C is pretty much useless on the small >>> devices. If you or anyone else thinks different then post some code >>> for a real project. >> If you want to see real C code for PICs or AVR Tiny's, you'll have to >> search the web. "People like me" have free time enough for some idle >> banter on Usenet, but not nearly enough to waste writing sample >> applications to convince someone who has already made up his mind. > > My mind is quite open to change, this is why I ask for some evidence. > Nobody can ever produce any, I wonder why. Haveing built many projects > in both languages I have seen first hand the differences. >
As I say, you are not likely to get useful direct evidence here. Even if someone posts some code (such as Walter's white paper), it's easy to say "that's just a test case". The same applies the other way too. So all you get is witness declarations, which you can credit or not.
> >>>> No, I can't post my code - it was a project for a paying customer. >>> Allways the same excuse, everyone seems to have a million dollars >>> worth of code on PIC. >> My code is for the AVR Tiny, and it's not worth a million dollars. In >> fact, since the project seems to be stopped (not because of the >> software!), it's probably not worth anything. Nonetheless, I'm a >> professional, and cannot post the code > > You could allways ask for permission.. >
I *could*, but I won't. Again, it would be unprofessional.
>>> Not a chance, challenge me if you want, Walter did but changed his >>> mind after I told him he couldn't have my assembly code untill after >>> he'd done it in C. >> No one has time to take these sorts of challenges seriously, even if it >> were possible to write an application that proves the point. If you >> want to see how well a C compiler will work for *your* sort of programs, >> on *your* chosen target, then *you* can download a trial or demo version >> of the compilers available, and try it out yourself. > > Been there, done it many times, thats why I have this position. >
Choose the tools that work for *you*. But for most people (even good, experienced assembly programmers) and most applications, C is normally a better choice of development language. I'm not making claims that C compilers always generate smaller and faster code than assembly - just that with a good C compiler, C is an appropriate choice of language even on small devices like AVR Tinys. There are some sorts of code that can be coded more compactly in assembly, and other sorts of code where the compiler can optimise better than an assembler programmer writing clear and maintainable assembly code.
> > > As for Walter's claims about his compilers generating code that is >> always smaller and faster than hand-written assembly - it is reasonable >> for him to claim that his compilers will generate smaller and faster >> code for typical applications written in C compared to the same >> applications written by the same people in assembly. > > I dont think it is. > >> >>>>>> Secondly, the AVR Tiny has no ram beyond its 32 cpu registers. �I find >>>>>> it hard to imagine that you could write a program that needed more than >>>>>> 3 levels of calls (including interrupts) and have space in those >>>>>> registers to make a software call stack. >>>>> Exactly! you cant. C is nested language, functions calling functions >>>>> calling functions. Thats one reason why it isn't so good on these >>>>> small chips. >>>> No, calling functions is *one* feature of C. >>> Wrong, thats the whole point of the language, programs within >>> programs. Each block is isolated from the next, self contained, runs >>> in its own space, memory allocated as needed at run time and released >>> when finished with. Anything between braces is independant (or at >>> least sould be). >> That's an amazingly inaccurate way to describe any programming language, >> especially C. > > I think you missed the whole point of the language. >
What you are saying, in a somewhat exaggerated fashion, is that C is a procedural programming language (although it is more correct to say that C *supports* procedural programming). That's true, but it is also an imperative programming language. That is to say, most lines of C code are declarations or statements saying how a task is to be accomplished - function calls are only one type of statement or expression available to the programmer (compare this to Forth, in which a much higher percentage of statements are calls). Splitting your code into separate functions is an important aspect of structured programming in C - but it is not the "whole point of the language". Most assembly programmers divide up their code into functions and procedures in a similar manner to C programming.
> > Have you ever actually written programs in C, or are you >> mixing up C and UNIX? > > >> >> >>> It is not the *only* >>>> feature of C (maybe you're thinking of Forth?). >>> I'm still waiting for Forth on a PIC. >> Try: >> >> http://tutor.al-williams.com/picforth1.htm >> >> or >> >> http://www.ram-tech.co.uk/ >> >> I haven't tried them, but they are the first hits on google for "forth pic". > > > I'll have a look. >
In message <4813CE3E.A2ECC0FD@yahoo.com>, CBFalconer 
<cbfalconer@yahoo.com> writes
>David Brown wrote: >> >... snip ... >> >> As for Walter's claims about his compilers generating code that >> is always smaller and faster than hand-written assembly - it is >> reasonable for him to claim that his compilers will generate >> smaller and faster code for typical applications written in C >> compared to the same applications written by the same people in >> assembly. > >That is due, in part, to the fact that todays programmers have not >had heavy exercise in their chosen assembly language. This, in >turn, follows from the fact that each assembly language has to be >learned on its own. But I still maintain that an expert in assy >language A can always do better than an expert C programmer using a >compiler for A. Note the 'experts'.
Possibly but The C programmer will beat that assembler programmer on all other MCU... He will also be a close second MCU A... More to the point he will be able to turn out reliable, more easily maintainable, applications faster. -- \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ \/\/\/\/\ Chris Hills Staffs England /\/\/\/\/ \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
CBFalconer wrote:
> David Brown wrote: > ... snip ... >> As for Walter's claims about his compilers generating code that >> is always smaller and faster than hand-written assembly - it is >> reasonable for him to claim that his compilers will generate >> smaller and faster code for typical applications written in C >> compared to the same applications written by the same people in >> assembly. > > That is due, in part, to the fact that todays programmers have not > had heavy exercise in their chosen assembly language. This, in > turn, follows from the fact that each assembly language has to be > learned on its own. But I still maintain that an expert in assy > language A can always do better than an expert C programmer using a > compiler for A. Note the 'experts'. >
It took a bit of convincing to make me understand how C could work better than assembly for small processors. Part of that was from my own experience, and part of it was that, until fairly recently, C compilers were not good enough to compete with an experienced assembly programmer. But let me give you a brief example of the sort of thing a C compiler can easily do, that an assembly programmer cannot do while still writing maintainable and legible code. On the COP8 processor, the two most important addressing modes for arithmetic instructions are direct access (in which the memory address is specified in the instruction), and indirect via the B register. Direct access instructions take 3 bytes and 4 cycles, indirect take 1 byte and 1 cycle. (This is from memory, so I might make a few errors here.) Suppose you have a function that adds two global variables, and stores the result in a third. The natural assembly code is something like this: .sect .data var1: .dsb 1 var2: .dsb 1 sum: .dsb 1 .endsect .sect .code AddNumbers: ld a, var1 ; 3 bytes, 4 cycles add a, var2 ; 3 bytes, 4 cycles x a, sum ; 3 bytes, 4 cycles ret ; 1 byte, x cycles .endsect Total: 10 bytes, 12 cycles + ret (I can't remember how many cycles ret takes). C code: uint8_t var1, var2, sum; void AddNumbers(void) { sum = var1 + var2; } Possible compiler-generated assembly code: .sect .data var1: .dsb 1 var2: .dsb 1 sum: .dsb 1 .endsect .sect .code AddNumbers: ld b, #var1 ; 2 bytes, 2 cycles IIRC ld a, [b+] ; 1 bytes, 1 cycles add a, [b+] ; 1 bytes, 1 cycles x a, [b] ; 1 bytes, 2 cycles IIRC ret ; 1 bytes, x cycles .endsect Total: 6 bytes, 6 cycles + ret Obviously, an assembler programmer could write this code directly as well. But it only works as long as var1, var2 and sum are ordered in this manner. If they were spilt up, the assembly code would break - maintainance and legibility suffer greatly. Perhaps you have other routines that could be optimised using [b] mode if the data were in a different order. Writing the assembly by hand, you've got to figure out which ordering works best - and re-write your functions to take advantage of the ordering. A small change to one part of the code means a re-write for other parts of the code - that's not a good plan for software development. Thus in realistic programs, the programmer will go for the pessimistic code that works regardless of the orderings. A compiler, on the other hand, can pick a reasonable (not *optimal* - that is not achievable in polynomial time, but pretty good nonetheless) ordering based on variable usage, and it will make use of that ordering when generating function code.
Walter Banks wrote:
> > CBFalconer wrote: > >> cbarn24050@aol.com wrote: >> >>> No you haven't!! >> Yes he has. In addition, the assembly programmer always has some >> extra tricks available, that result in shorter and faster >> programs. For example, consider a program than needs functions >> foo() and bar(). It turns out that a foo call is always followed >> by a bar call, but that bar needs to be separately callable. As >> an example, write space to stdout, and write char to stdout. The >> assembly programmer can write: >> >> foo: /* foo code */ >> ret >> >> bar: /* bar code */ >> ret >> >> foobar: call foo >> call bar >> ret >> >> but he can combine these, saving a 'ret' execution, some stack >> space, and a call. The result is: >> >> foobar: /* foo code */ >> ; /* fall through */ >> bar: /* bar code */ >> ret >> >> eliminating two calls and two rets from the earlier code. The C >> programmer doesn't have this capability. Believe me, it adds up >> over a medium complicated system. > > You mean something like this? > > void bar (void); > > void foo (void) > { > 0100 9D NOP NOP(); > bar(); > } > > void bar (void) > { > 0101 9D NOP NOP(); > 0102 81 RTS } > > > void main (void) > { > 0103 AD FB BSR $0100 foo(); > 0105 20 FA BRA $0101 bar(); > } > > It does add up.. >
That's just tail call elimination (changing a "call X; ret" into a "jmp X"), which is a standard optimisation technique (some assemblers will do that for you). A better example would be: WriteSpace: ld a, #' ' WriteChar: st a, outputCharacter ret with C code: extern volatile char outputCharacter; void WriteChar(char c) { outputCharacter = c; } void WriteSpace(void) { WriteChar(' '); }
Robert Adsett wrote:
> In article <48135E8A.7BA99BB4@bytecraft.com>, Walter Banks says... >> >> CBFalconer wrote: >> >>>> I think you confusing the limitations of the silicon with the >>>> language tools you are using. Anything that can be written >>>> in asm for a PIC I can write in C in the same space. >>> If you said "Anything you can write ..." I could tentatively >>> agree. But not with "that can be". >> I chose my words carefully I meant "Anything that can be >> written in asm for a PIC I can write in C in the same space" > > I'm curious Walter, how do you deal with the following sequence (for > some mythical processor) in C? > > mul a,b,c ; b * c -> (a,b) 16bit x 16bit -> 32bit multiply > div a,d ; (a,b)/d -> a 32bit / 16bit -> 16bit divide > > It's something I do write in asm to take advantage of a processors > scaling capability. > > > I can see something like the following could work > > long a; > int b, c, d; > > a = (long)b * c; > b = a/d; > > (assuming appropriate initialization is done somewhere). All the > compilers I've seen though aren't smart enough to realize widening isn't > required in this case and perform a 32bit x 32bit multiply. > > Even better would be if the following would work. > > b = ((long)b * c)/d; > > I don't remember it in your paper but I suspect that particular > processors doesn't have the appropriate instructions. > > Robert > ** Posted from http://www.teranews.com **
A quick test on avr-gcc 4.2.2, using 16-bit and 8-bit ints rather than 32-bit and 16-bit (since it's an 8-bit cpu) reveals that avr-gcc is smart enough to do a 8-bit x 8-bit -> 16-bit multiply as desired. It's a little harder to see exactly what is happening for bigger numbers and for division, since these use library calls - certainly the compiler will generalise some of these functions. But for the very common case of the multiply like this, you get optimal code.

Robert Adsett wrote:

> In article <48135E8A.7BA99BB4@bytecraft.com>, Walter Banks says... > > > > > > CBFalconer wrote: > > > > > > I think you confusing the limitations of the silicon with the > > > > language tools you are using. Anything that can be written > > > > in asm for a PIC I can write in C in the same space. > > > > > > If you said "Anything you can write ..." I could tentatively > > > agree. But not with "that can be". > > > > I chose my words carefully I meant "Anything that can be > > written in asm for a PIC I can write in C in the same space" > > I'm curious Walter, how do you deal with the following sequence (for > some mythical processor) in C? > > mul a,b,c ; b * c -> (a,b) 16bit x 16bit -> 32bit multiply > div a,d ; (a,b)/d -> a 32bit / 16bit -> 16bit divide > > It's something I do write in asm to take advantage of a processors > scaling capability.
Robert, A lot of approach depends on processor. We use the "as if" rule a lot in code generation. In general 8*8->16 bits will use a processor 8*8 if we can. Similarly we grab the MS 8bits when we multiply two 8 bit fracts rather than casting and using a 32 bit multiply. Regards -- Walter Banks Byte Craft Limited Tel. (519) 888-6911 http://www.bytecraft.com walter@bytecraft.com

CBFalconer wrote:

> Walter Banks wrote: > > CBFalconer wrote: > > > ... snip ... > > > >> If you said "Anything you can write ..." I could tentatively > >> agree. But not with "that can be". > > > > I chose my words carefully I meant "Anything that can be > > written in asm for a PIC I can write in C in the same space" > > > > Take a look at the white paper. Its examples are for RS08 > > but we have done this with the PIC's as well. > > What white paper? URL please.
http://www.bytecraft.com/C_versus_Assembly Regards -- Walter Banks Byte Craft Limited Tel. (519) 888-6911 http://www.bytecraft.com walter@bytecraft.com

CBFalconer wrote:

> > > It does add up.. > > Well, that looks impressive, but you must be loosing something. > You must be doing something illegal and non-understandable (to a C > programmer) with one or more of indentation, braces placement, > illegal statements (a call to foo should never enter bar). I see > no reason for bar to exit while foo falls through.
I should have used fixed point type to make the listing fragment clearer. This is the source used in the example. void bar (void); void foo (void) { NOP(); bar(); } void bar (void) { NOP(); } void main (void) { foo(); bar(); } Regards -- Walter Banks Byte Craft Limited Tel. (519) 888-6911 http://www.bytecraft.com walter@bytecraft.com
Walter Banks wrote:
> Hans-Bernhard Br&#4294967295;ker wrote:
>> All of that is correct, but beside the point. For *every* piece of C >> code anyone can possibly write, in any C compilers, there's assembler >> code that ends up as the exact same machine code. The same is generally >> not true for the opposite direction. So compilers can't produce faster >> code than assemblers.
> Compilers can produce some machine code that is exceedingly difficult > to write and maintain in asm.
Huh? Is something wrong with my writing or with your reading? Where in the above did you see me talking about maintainability or difficulty? The issue at hand is _speed_ and _size_. No more, no less.
> These are sequences that are data or address specific that are likely > to change or need to be checked each time the code is assembled.
That's why the prudent assembly programmer would secure such tricks with assemlby-time assertions. I.e. make the assumptions explicity, and make sure that the code fails to translate if any of them is no longer true.
> The whole reason for HLL is to aid in making application code easier > to create.
Agreed. But you're still missing the point under discussion.
On Apr 27, 10:23=EF=BF=BDam, David Brown

> > As I say, you are not likely to get useful direct evidence here. =EF=BF=BD=
Even
> if someone posts some code (such as Walter's white paper), it's easy to > say "that's just a test case". =EF=BF=BDThe same applies the other way too=
. =EF=BF=BDSo
> all you get is witness declarations, which you can credit or not.
Walters paper isn't even a test case. Your right that I wont get evidence here, that would require some effort rather than just waffle
> >
> > But for most people (even good, experienced assembly programmers) and > most applications, C is normally a better choice of development language. >
Quite so, I use C most of the time.
> I'm not making claims that C compilers always generate smaller and > faster code than assembly - just that with a good C compiler, C is an > appropriate choice of language even on small devices like AVR Tinys.
Thats a different claim from Walter, not being familiar with AVRs I couldnt say one way or the other but it's no good on small PICs. =EF=BF=BDSplitting your code into separate functions
> is an important aspect of structured programming in C - but it is not > the "whole point of the language". =EF=BF=BDMost assembly programmers divi=
de up
> their code into functions and procedures in a similar manner to C > programming.
A C function is not just a subroutine, It's much more than that. It's a complete stand alone program, has no dependencies on either the calling program or programs it calls. The idea is that each function can be developed, tested and debuged independently.
> >
(maybe you're thinking of Forth?).
> >>> I'm still waiting for Forth on a PIC. > >> Try: > > >>http://tutor.al-williams.com/picforth1.htm
Ive seen that one before gforth! wont run on windows.
> > >> or > > >>http://www.ram-tech.co.uk/
They cant sell this one any more, some european directive, they dont say which one. So I'm still waiting.