Assembler and C - not a war

Go To Last Post
130 posts / 0 new

Pages

Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In another thread the posts drifted towards a discussion on C v/s assembler. I tossed in the post below looking for a serious discussion, but as it was an obvious thread-jack I am now breaking that sub-thread out here.

The original thread is here: https://www.avrfreaks.net/index.p...

There was talk about Smileys book(s), and things like "C is easier".

My post in it read:

Quote:

"Easier" than what?

This either war stuff, or a very interesting discussion emerging. It is quite obvious that some here argue that "assembler is easier than C", while there are others that argue the exact opposite.

Highly intelligent and educated people are present at both sides of the fence.

Me I'm on the "C is easier" side of the fence. I speak both languages pretty well, but things are much more easily expressed in C. Not to mention that rather C makes for rather more compact source as well. This in itself is of high value.

Example (just tossing something up):
uint16_t i;
i = 19876 + PORTB;

For me that is quite clear, short and concise. The same thing in assembler is not obvious by looking at it for two seconds. Not to mention when we get into control structures. A simple if-else-statement with largeish block in both "legs" takes me one or several minuters to analyze, whereas the C counterpart takes a moment or two.

This is from my point of view. It seems to me that both John and Jim, who over and over again post top-notch and smart posts here, have real tough struggles with C from time to time. I'm interested in why that is. Some kind of "difference in way of thinking" is involved. Some lack of knowledge also (I seem to recall the discussion we had when Jim first had to face and understand a separate compiling and linking tool chain, and how his posts in that discussion revealed a totally different background).

So, if we can avoid the pie-throwing for a while: Could you in some way, on some very concrete or more abstract level, describe what you find confusing/strange/obscure/totally-whacko etc with C? Could you relate to such things matching or not matching stuff in your background? Etc.

Again, I am seriously interested in this. I am in no way hunting a C v/s assembler argument. I am trying to understand how things look from your side of the fence.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Johan,

I'm fairly agnostic either way. But your short example is interesting:

uint16_t i; 
i = 19876 + PORTB;

reading posts from Asm folks who are trying to migrate to C here I think one of the stumbling blocks is TYPEs. Not just the confusing jumble of punctuation and characters in the "uint16_t" itself but the same applies if you had said "unsigned int".

An Asm programmer is possibly even more aware of the 127/8,256,32767/8,65536 boundaries but posts here seem to show that it's knowing which types are available, how wide they are, and when is the best time to use one of them (char / signed char / unsigned char / unint8_t / int8_t for example) that flummoxes asm programmers.

Of course they've been considering exactly the same things previously in deciding how to store stuff but maybe have never formalised it in the way that C typing does.

Anyway, just an observation, perhaps there are other reasons?

(BTW how many posts have you seen where a Asm programmer has wondered how you associate a variable with a fixed register (pair)? While some C compilers allow this and come C programmers (LT!) advocate it, I think it's hard for the Asm programmer to make the break and let the C compiler and linker take charge of what's allocated where and whether it lives in SRAM or R0..R31)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, Cliff. The concept of types is one of the things I am speculating about.

From my side of the fence types makes things easier. The compiler know all about how a two-byte unsigned integer is to be added. I don't have to care at all about ADD and ADC or any other low level stuff. When I say "I don't have to care" I mean that I, when writing that C code can be confident that the compiler will generate the correct code, not that I don't understand the details of adding on an unsigned two byte variable, handling carry and stuff. I know how to write that in assembler, but am rather happy being relieved of having to concentrate on such detail.

I really, really would like John and Jim to come over here and comment on this. The thing that is a relief to me might well be a hindrance to them. I'd like to understand the underlying reasons and mechanisms for that. Still NOT looking for a war.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think it is a fear of surrendering control to some unknown power (the C compiler).

They no longer control where they store things, and worst of all the Compiler may even remove unreachable or ineffective code.

Most microcontroller code consists of setting / clearing / waiting for bits. This is often more intuitive in ASM.

From my point of view, when you start doing any math
that is more complex than adding a constant, ASM starts to get fiddly.

My other problem is that the AVR gives you too much choice of registers!! When I used a 6502, you passed all the arguments in A, X, Y and returned in CY, A, X, Y.

There appear to be no conventions at all used by AVR asm programs, principally because there is too much choice.

I can fully understand people's difficulties with pointers, structures etc. But in all truth, you use exactly the same ideas in an asm program. They are just not formalised.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I think it is a fear of surrendering control to some unknown power (the C compiler).

That's a good point. Before I understood C run times, when I first moved from Asm to C I though the compiler wasd doing all sorts of unknown things behind my back. Part of the problem I guess is that C compiler manuals very rarely describe exactly what it is that goes on between the reset vector and the main()/main: entry point.

As it happens it turns out that it's a whole bunch of things you would be doing at a start of an Asm program anyway and it's all very sensible. But it does seem "black magic" when you first start to use C.

The provision of a fully populated vector table that on a big AVR like a 1280 or Xmega can mean that even before you've written one line of C you have several hundred bytes of apparent "hidden code" is also a bit disconcerting.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
So, if we can avoid the pie-throwing for a while: Could you in some way, on some very concrete or more abstract level, describe what you find confusing/strange/obscure/totally-whacko etc with C? Could you relate to such things matching or not matching stuff in your background? Etc.

I will start with a comparison.
Been playing music for decades.
During those years I've made several serious attempts to learn notes. Never managed to feel comfortable at this.
Play me a melody and I'll learn it in a few moments. Hand me the notes of that melody and it will take me the whole day to figure it out.
Some people I've met especially at music schools can be real good at reading notes.
Tell the same people to improvise over that song and 9 of 10 are clueless. Tell me the same thing and I can go on for ever inventing variants.
Is anyone to be called a better musician?
I realize that notes can be useful but in my way of approaching music it just don't fit.

I've done several similar attempts to learn C, always fail.
When I started with µC the program I wrote was in machine code.
This might be a reason why moving on to write assembler for AVR felt intuitive and easy to grasp for me.
Confront me with some C code and I get same awkward feeling as looking at notes.
The feeling makes my thoughts scatter and block any successful understanding/performing.
OTOH I know that many of the members of this forum started out with machine code and now do it all in C.
I strongly believe it's a matter of different mindsets.
Just as with music, then there's this 10th guy who can do both things fluid.
The only C-programmers that impress on me are those that know what assembler will be produced from a certain C code. Or change C code so that the desired assembler is produced.

As a sidenote I've met two people lately that work with programming. They both used assembler. One of them made life-supporting devices and wanted to have full control of any instruction placed in code.
The other guy worked for Ericsson, writing algoritms for base stations. He stated it must be done in assembler to be fast and accurate.
Claiming that any professional programming must be done in C or similar just ain't correct.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I like to think I'm competent at assembler and like it as I'm in complete control of what's going on and can make absolute minimalist code and fastest, which is important in my apps.

I really want to learn C but I struggle big time:
- yep, all that uint16_t stuff makes me glaze over
- C documentation makes me glaze over
- Whilst happy with LD X, type asm, all those &'s and *'s make me glaze over
- I'm a happy ASM2/AVR Studio user oblivious to make files, optimisation levels and all that other complexity that seems to get in the way of putting machine code into flash

I really don't understand why I can't get on with C and TBH it's a bit disappointing. What I'd really like is to be able to embed some C capabilities (floating point, (s)printf etc) in ASM so that I can do the hard ASM bits easier ;)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK, so let's pick one of those "glazings over". In fact, the thing I already used in the OP: uint16_t .

I am curious as to what actually makes you glaze over with that? I realize that read with the wrong tone that might sound like the first bullet from the C trench, but that is not my intention with the question. For me, handling rather simple arithmetics on a multi-byte variable is more complicated in assembler than in C. As I hinted at above, I eg need to know and place the ADD and ADCs correctly. I also realize that this "generation of code" is similar for every time I do that operation on that type of data. So for me it makes perfect sense that someone has automated it for me. I'm not saying that this is my complete view of what a compiler / high-level language is, but it is a part of it.

When I program(med) in assembly I try to follow strict patterns. I actually try to code if-else stuff, and code it following the same idiom every time. My assembly loops are (ok, "where") almost always a disguised "while". Does this sound odd to a "hard core" assembly programmer?

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Whilst happy with LD X, type asm, all those &'s and *'s make me glaze over

Interesting how this parallels that other thread just started about the barrier between C and C++. It's the syntactical structure of C++ that just makes me "glaze over". Presumably this is actually a psychological barrier of some sort?

(BTW you can get an awful lot done in C without ever venturing near & and * - they are the "power tools" that set C apart from other languages but often they are used as "short cuts" to achieve the same things that could be done in other ways. A lot of &/* stuff can be achieved simply using arrays (pointers just point to blocks of data in memory) which may be familiar to anyone who's dabbled in BASIC)

Actually, talking about BASIC, I remember when I first started C that the obvious:

FOR A=1 to 7

became:

unsigned char A;
for (A=1; A<8; A++) {..

which on the surface looks completely impenetrable and all those seemingly pointless punctuation characters create a real WTF moment!

I always find this page interesting:

http://helloworldsite.he.funpic....

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

...there you go again - I'm happy with the for loop syntax, but using an unsigned char to hold a (presumably 8-bit) number is the silly part :D I suppose you just get used to it.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

unsigned char

Does it help you if those rather leading type names are hidden behind:

typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef signed int int16_t;
typedef unsigned int uint16_t;
typedef signed long int int32_t;
typedef unsigned long int uint32_t;
typedef signed long long int int64_t;
typedef unsigned long long int uint64_t;

Now the types are given generic (and portable!) names where a leading ui or i says whether it should be used unsigned or signed (0..(2^n)-1 or -2^(n-1)..+(2^(n-1))-1) and the number 8/16/32/64 says how wide it is in bits (i.e. 1/2/4/8 bytes). So my for() loop is really:

uint8_t A; 
for (A=1; A<8; A++) {.. 

No mention of "char" suggesting that these are characters or anything. Just an 8 bit wide integer being used unsigned (so 0..255 rather than -128..+127)

BTW if you didn't already know it you just learned a new C keyword: typedef which basically means:

typedef  

It just helps to make code more readable really. Especially when you get into the realms of:

typedef mystruct * (*function_type) ( mystruct *, char **, int, long *);

Unfortunatelyly this particular example breaks the rule of what I just said in that the new type is "function_type" and it's a pointer to a function that returns a pointer to a type called mystruct (almost certainly another typedef) and takes as parameters a pointer to that struct type, a double indirect pointer to char, an int and a long. But these kind of typedefs even make professionals wince a bit!

(Actually I think I can see how people can be put off by C ;-))

Last Edited: Tue. Mar 30, 2010 - 01:12 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I like programming in C, even on the small AVRs (ATTiny13), it saves many time.
Neverthelesee I understand assembler and look on the list file to see, how many time and Flash
a certain code sequence need.

Peter

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

C works for me. I feel like I am on the outside looking in at the ASM. The compiler provides a list file showing C statements and ASM. I seem to follow what is going on, however find few thoughts on how to improve the ASM code. It is possible to use inline ASM or ASM functions, in a way C provides it all.
I learned early on that it is very important to keep in mind what the processor does to complete programming tasks. Writing efficient code is possible with C. Sometimes it might be necessary to time routines and adjust methods.
What I like most are the libraries. They seem to help do things in a fairly standard manner, and save development time.
I learned to like structures. Here is an example:
I defined a data stucture with a few hundred bytes of setup information. EEprom and RAM are then declared using the structure. It is then possible to use a single line "ramdata = eepromdata;" to copy the contents of the eeprom structure to ramdata or go the other way "eepromdata = ramdata;". The structure helps organize the data components, and indexes provide a means to modify them. It provides a way to read the program, in a way understood by many. To me this helps, and I can use my skills to do more tasks.

It all starts with a mental vision.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The C and ASM are just two different tools serving the same purpose. The C can be compared to some power tool like an electric nut driver with a bit set, the ASM - to a precise hand toolset.

Whereas the electric nut driver can be more convenient in some cases such as screwing on or off many medium sized bolts at once, the properly collected, sharpened and adjusted hand toolset can be just indispensable in other cases.

Just a small and simple example - try to do this in C:

Unpack a contiguous 56-bit long, 7-bit per field bitstream to an 8-bit (1 byte) per field data array.

Bitstream as received: aaaaaaabbbbbbbcccccccdddddddeeeeeeefffffffggggggghhhhhhh (aaaaaaa..hhhhhhh = any bit sequences).
Input array = [aaaaaaab, bbbbbbcc, cccccddd, ddddeeee, eeefffff, ffgggggg, ghhhhhhh].
Output array = [0aaaaaaa, 0bbbbbbb, 0ccccccc, 0ddddddd, 0eeeeeee, 0fffffff, 0ggggggg, 0hhhhhhh].

After I see the properly working (in simulation) C code, I will supply my ASM implementation.

Warning: Grumpy Old Chuff. Reading this post may severely damage your mental health.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I will start with a comparison.
Been playing music for decades.
During those years I've made several serious attempts to learn notes. Never managed to feel comfortable at this.
Play me a melody and I'll learn it in a few moments. Hand me the notes of that melody and it will take me the whole day to figure it out.
Some people I've met especially at music schools can be real good at reading notes.
Tell the same people to improvise over that song and 9 of 10 are clueless. Tell me the same thing and I can go on for ever inventing variants.
Is anyone to be called a better musician?
I realize that notes can be useful but in my way of approaching music it just don't fit.

A rather interesting comparison. Some people DO play music just by throwing out chords. You can earn a living as a lounge pianoist this way. Most folk or rock guitar players do the same. Guess that's like writing a "C" program that mostly calls library routines. OTHO writing in assembler gets you down in the dirt with all the details. In music that's having to sight read the piece. Most people are taught piano this way.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would love to be able to program in C. My experience has all been assemly. I started with 8080/Z80 assembly many years ago then did no programming for many of those years. I finally came up with an idea for a project and decided an AVR device was a perfect fit. This was partially due to the 8080 and AVR instructions were quite similar to me. As my my project has morphed over time, I have come to see the advantages that C would provide. One example is I would like to implement a USB host. In assembly that would be more than my skills and time could accomodate. Dean's LUFA package would be the answer and if I ever learn C wiould probably be the incentive I need. Assembly seems like an intuitive way for me to program, it just seems to flow. While I can see the definate advantages of C, I have a hrd time wraping myself around the overall structure of how a program is written. (Old dog new tricks?) I've had several false starts and seem to make more progress each time I try. I just have to be able to sit down and write some excercises in C but life keeps getting in the way and is not as easy to drop and pick up as assembly is. This I'm sure has to do more with familiarity than the differences. I'm not sure if this addresses the OP but it sure felt good to express my frustration.

SOMEDAY I WILL PROGRAM IN C!

Roger

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've never understood why there should ever be a "war" between the C and ASM advocates. They are both tools one carries in one's belt, each appropriate for a given task. I believe the true power comes from understanding both sides of the equation, having both tools in one's belt.

For many years, my father had only a jigsaw. He did everything with that jigsaw: remodeled the basement, built cabinets, on and on. Seemed to work just fine.

Then he broke down and got a table saw. New things started coming from his shop, things he would not have tried before. His new tool gave him the ability to do different things than he did before.

I feel the same way about C and ASM. There are some tasks I would not contemplate in ASM. Others, are clearly not cut out for C.

I freely admit that I am far more comfortable in C than in ASM. On the other hand, if I were tackling a project that started with a Tiny9 (the original root of this thread), I would not think twice: I would use ASM.

As an aside: John Samperi posted some of his boilerplate library code a while back. I grabbed it immediately and started to learn from a master. Just as a long timer ASM writer would feel uncomfortable with the "magic" C compiler, I am uncomfortable building my own library of utility routines in ASM. If I were to do a really big ASM project, I might take the avr-libc code as a starting point for some of my routines.

Funny how C leads to ASM leads to C leads to...

Stu

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

On the other hand, if I were tackling a project that started with a Tiny9 (the original root of this thread), I would not think twice: I would use ASM.

Sigh--now THAT one leads dangerously close to the edge of the warring cliff. (Or the docile Cliff; whichever Clawson is around today.)

By the nature of the Tiny10 family, the app structure will be simple. I'd see no reason why the C program for the Tiny9, written with the constraints of the very-limited register set and SRAM, would necessarily be precluded.

As it is a limited-flash device, one could certainly pose the 6-million-microwave-ovens-saving-10-cents-on-each case. But that can be done with Mega48 vs. 88 vs. 168 as well--it is worth the time to save 5% if that means use the smaller & cheaper model. It might come down to the two-word catch loop added to main() by most compilers. Custom prologue can take care of most of the rest.

The Tiny10 family will actually be interesting once they are more widespread. Most models still seem to be unobtanium. Perhaps there are apps where dedicating a couple of the index registers during operation will make lie to my claim. I can't envision that app as the limited SRAM would make that of doubtful utility.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I've never understood why there should ever be a "war" between the C and ASM advocates.

Me neither. I'm trying to get a grip on the obstacles an assembler programmer encounters when he tries to use C.

The other way around, C to assembler, I think I have a better clue. C programmers, coming from eg desktop programming, need not care about hardware issues. The lowest level of abstraction they need to understand is the operating system level. With AVRs there is no such level. The closest we come is the run-time support level (eg avr-libc for avr-gcc). What is new wfor them with AVRs is the hardware stuff, something they need to understand even if programing in C only. As soon as they start to debug, some knowledge of assembler comes in real handy. When there, or even trying to write some assembly themselves, they encounter for the first time those rudimentary assembler instructions, need to understand the general purpose registers, and how eg a simple addition needs several instructions that are far less generic than they think. Remember just the other day when someone tried to do a MOV from a general purpose register to a register in I/O-space. It took that programmer a while to understand that this could not be done in one instruction. He was thinking something like

GeneralPurposeRegister = Rn;

and possibly thought that every "basic C construct" has more or less one assembler instruction counterpart.

So again, for me the interest in this discussion lies in what "bumps off" seasoned assembler programmers trying to use C.

Let me pose a specific question to those who has done the journey in that direction:

Can you name three things that you struggled with, or where you misunderstood something etc, when you went from assembler to C?

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I find the music analogy an interesting one.

I played the trumpet, briefly, while in school. (Very briefly, really...). While I could easily learn the notes and play back what I heard, I couldn't get the hang of reading the notes off the page. And to make it worse, they threw in all of those sharp and flat squiggly markers that changed the rules on the fly... Good thing I'm not a musician.

I did a lot of 8080 Asm long ago, but now I am stuck with Basic. Nice thing is it lets me focus on the conceptual part of the project at hand. I don't have to care about how to implement the square root of a floating point number... X = Sqr(Y) Done, move on.

The point not yet made, however, is that I do projects mostly for myself, for fun, and rarely for others. To be marketable in this day and age, as a programmer or an embedded engineer, I would think that knowing C would pretty much be a requirement to get hired in a "large" company. If, however, you are the master of your own ship, (e.g. JS), run your own company, and work for yourself, then you have the option to select which is the "right" tool for you, to get the job done.

At the end of the day the primary objective is to get the job done, working, error free. There are many ways to get there. Efficiency of writing, re-useabilty of code, readability of code, maintainability of code, portability of code, consistency within the group/company, all come into play as external factors impacting how one elects themself, or is ordered, to code. Fortunately I get to assign my own priority values to all of those factors and use what is right for me.

Johan, I think there is a big difference in how different individual's brains function. The classic right brain vs left brain arguments, only to a finer degree. It doesn't mean you can't "train your brain" to do something, it just means that for certain individuals certain tasks may come naturally, while for others it will be a challenge.

I still have Teach your C in 21 days sitting right next to Teach yourself Java in 21 days sitting on the shelf, collecting dust. They just didn't click like Asm and Basic did.

JC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I'm trying to get a grip on the obstacles an assembler programmer encounters when he tries to use C.

Oh, that. There is indeed a learning curve. In the last millennium when I started in C, circa 1985, I was a seasoned professional [ ;) 'cause I'd been paid for it] programmer for nearly 15 years. Lots of COBOL and ALGOL and proprietary block-structured languages at a major computer manufacturer. Lots of FORTRAN and other stuff on VAX/VMS.

Yet it still took me some time o get my head around C. Not the syntax per se, but using pointers in a most appropriate way. I find I actually use pointers much less on AVR than on my early C work on DOS and VMS--the interfaces to the operating system(s) required it. And the nature of the apps had a lot of strcat() and the like. And even on DOS an app would have malloc()/free() and then casting those pointers to the appropriate struct etc.

I've never used a malloc() on an AVR, and of course there are no "system calls". On Mega88-class apps I find I use few pointers and data structures. On bigger class (e.g. Mega64) of apps I will then have more but the overall app structure and the coding style is still simpler than back in the DOS days.

So I'd agree that there is a hump in the learning curve to be able to read and understand an arbitrary C app for the AVR ASM programmer--primarily if data structures and pointers are heavily used. Other than that the standard library functions should be fairly straightforward given a decent reference and a read-through.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Can you name three things that you struggled with, or where you misunderstood something etc, when you went from assembler to C?

1. The structure of code with brackets and a few words on each line.
2. Operators
3. Declaring variables and other stuff.

Like Cliff suggested in C++ thread, I think it's a mental block. Where this block come from I do not know.
First encounter?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hmmmm.. I'll have to think about that before drilling deeper into your brain, Lennart.
The stuff that you point out as "akwardnesses" is all stuff that I see as making things clearer. As I said, I don't want to argue - to avoid that I have to think of some smart questions which I cant formulate right now.

(One small argument though: In general assembler has fewer words per line than C code if you don't count comments. Depending on commenting style, this might hold or not, even when counting comments).

Thanks for the answers, Lennart!

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Just a small and simple example - try to do this in C:

Unpack a contiguous 56-bit long, 7-bit per field bitstream to an 8-bit (1 byte) per field data array.

Bitstream as received: aaaaaaabbbbbbbcccccccdddddddeeeeeeefffffffggggggghhhhhhh (aaaaaaa..hhhhhhh = any bit sequences).
Input array = [aaaaaaab, bbbbbbcc, cccccddd, ddddeeee, eeefffff, ffgggggg, ghhhhhhh].
Output array = [0aaaaaaa, 0bbbbbbb, 0ccccccc, 0ddddddd, 0eeeeeee, 0fffffff, 0ggggggg, 0hhhhhhh].

After I see the properly working (in simulation) C code, I will supply my ASM implementation.


OK but remember this was not supposed to be a C vs Asm contest?

But one thing about this C solution (are we allowed to look behind the scenes and see the Asm?) is that once I wrote the first 2 or three rules of what you suggested then the "pattern" became obvious and I wrote the rest of the lines by a simple copy/paste and then editing the 1,2,3,4,5,6's (actually when I first tested the code against my test data the only bug was because I'd missed a couple of fixups after pasting!):

#include 

extern uint8_t in_data[7];
extern uint8_t out_data[8];

int main(void) { 

	out_data[0] = in_data[0] >> 1;
	out_data[1] = ((in_data[0] & 1) << 6) | (in_data[1]>>2);
	out_data[2] = ((in_data[1] & 3) << 5) | (in_data[2]>>3);
	out_data[3] = ((in_data[2] & 7) << 4) | (in_data[3]>>4);
	out_data[4] = ((in_data[3] & 15) << 3) | (in_data[4]>>5);
	out_data[5] = ((in_data[4] & 31) << 2) | (in_data[5]>>6);
	out_data[6] = ((in_data[5] & 63) << 1) | (in_data[6]>>7);
	out_data[7] = in_data[6] & 0x7F;

   while(1) {
   } 

}

and so the compiler didn't simply optimise the whole thing away or do all the bit manipulation at compilation rather than run time (it has a rather useful habit of doing this!) I have to put my test data in a separate file so it was extern to the code above (and hence not known at compile time). Within this I wrote out the bit patterns of the randomly picked input bytes then manually worked out what the expanded data should be. After a bit of debugging this is exactly what I got in the simulator. If Studio had not been "playing up" on my machine I would have had this solution MUCH sooner which (if we're on he warpath?) which proves another of C's useful features (very quick and easy to get to a solution given your specification!):

#include 

uint8_t in_data[] = { 0x37, 0xBf, 0x27, 0xAE, 0x09, 0xB3, 0x4F };
// 00110111 10111111 00100111 10101110 00001001 10110011 01001111
uint8_t out_data[8];
//****************************************************************************
// 00011011 01101111 01100100 01111010 01110000 00100110 01100110 01001111
//    1B       6F       64       7A       70       26       66       4F

I (honestly!) have not yet stopped to look at the Asm this generated. I rather imagine it could be horrendous as I've spent no time analysing it and maybe adding typecasts to persuade the compiler to try and use 8 bit wide entities where I imagine it may be using 16 (or more) bits unnecessarily.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I like both C and Asm, but I guess my OCD side prefers Asm and the absolute, complete control it affords. Sort of like playing with Legos instead of TinkerToys.

I personally think C is a magnificent language, elegant, clear, concise, and lean. Like Lee, I learned it after I had done many years of programming, so it just sort of fell into place without much difficulty. I am sometimes confused about how much trouble some obviously smart people have in grasping it.

One of the things that may be off-putting are the header files, especially when nested with embedded conditionals and the like. It all makes perfect sense when it has become second hand, but initially it gets a little intimidating. Same with declarations and suchnot. And GCC's versions and extras make my eyes glaze over, which is why I use one of the less popular options.

And then there are the devil's spawn (programmers, that is) who use the flexibilty of C to deliberately obfuscate. Fortunately this doesn't happen much on this forum, but for some it's a form of malicious and torturous entertainment.

I would suggest to anyone wanting to learn C that they read K&R and initially ignore all their other books. And ignore all the "big system" stuff in K&R. The language itself is tiny and simple, a piece of rope with which you can do anything, including making a noose. Therein lies the rub.

Chuck Baird

"I wish I were dumber so I could be more certain about my opinions. It looks fun." -- Scott Adams

http://www.cbaird.org

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK I had a look at the Asm - not great. For one thing there's a whole bunch of numeric sequences in the middle 6 statements and the shifts using integer constants were being promoted to 16 bit. So I made some 8 bit shift counters and wrapped the middle 6 statements into one loop. This cut more than 100 bytes and a chunk of machine cycles out of it. Though it's no longer as "readable" as the previous so if time/space weren't a consideration I'd actually stick with the above (maintainability for me is far more important than anything else!). Anyway...

int main(void) { 
	uint8_t temp1, temp2, temp3, i;

	out_data[0] = in_data[0] >> 1;
	temp1 = 1;
	temp2 = 6;
	temp3 = 2;
	i = 0;
	for (;temp3<8; temp1 = temp1<<1 | 1, temp2--, temp3++, i++) {
		out_data[i+1] = ((in_data[i] & temp1) << temp2) | (in_data[i+1]>>temp3);
	}
	out_data[7] = in_data[6] & 0x7F;

   while(1) {
   } 

}

EDIT:

Quote:
who use the flexibilty of C to deliberately obfuscate.

Oops! what were you saying? ;-)

Attachment(s): 

Last Edited: Tue. Mar 30, 2010 - 05:14 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
(One small argument though: In general assembler has fewer words per line than C code if you don't count comments. Depending on commenting style, this might hold or not, even when counting comments).

I probably spend equal time and twice or trice as many letters on commenting, so it's not a lazy approach on my side to use ASM.

Here's a farfetched theory:
I HATE formulas.
I'm really good at head-counting, normally beat the person with a calculator.
But when I see a formula I get the chills.
I think the way C is constructed reminds me of formulas,
I HATE FORMULAS.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok then.

Here is an assembly solution:

;----------------------------------------------------------------------------------------------------------------
; Recursively unpacks a received contiguous 7-bit per field bitstream to an 8-bit (1 byte) per field data array.
;
; Bitstream as received: aaaaaaabbbbbbbcccccccdddddddeeeeeeefffffffggggggghhhhhhh (xxxxxxx = any bit sequence)
; Input = r16:aaaaaaab r17:bbbbbbcc r18:cccccddd r19:ddddeeee r20:eeefffff r21:ffgggggg r22:ghhhhhhh r23:00000000
; Output= r16:0aaaaaaa r17:0bbbbbbb r18:0ccccccc r19:0ddddddd r20:0eeeeeee r21:0fffffff r22:0ggggggg r23:0hhhhhhh
; 15 code words, 84 cycles (4.2 uS @20 MHZ)
;
unpack:
        ldiw    Z,iter1         ; Initialize the iteration entry address pointer
        ldi     r24,low(it_lim) ; Set recursion limit checkpoint

                        ; Iter1:   Iter2:   Iter3:   Iter4:   Iter5:   Iter6:   Iter7:   Iter8:
                        ;------------------------------------------------------------------------
iter1:  lsr     r16     ; 0aaaaaaa Intact   Intact   Intact   Intact   Intact   Intact   Intact
iter2:  ror     r17     ; bbbbbbbc 0bbbbbbb Intact   Intact   Intact   Intact   Intact   Intact
iter3:  ror     r18     ; ccccccdd cccccccd 0ccccccc Intact   Intact   Intact   Intact   Intact
iter4:  ror     r19     ; dddddeee ddddddee ddddddde 0ddddddd Intact   Intact   Intact   Intact
iter5:  ror     r20     ; eeeeffff eeeeefff eeeeeeff eeeeeeef 0eeeeeee Intact   Intact   Intact
iter6:  ror     r21     ; fffggggg ffffgggg fffffggg ffffffgg fffffffg 0fffffff Intact   Intact
iter7:  ror     r22     ; gghhhhhh ggghhhhh gggghhhh ggggghhh gggggghh gggggggh 0ggggggg Intact
iter8:  ror     r23     ; h0000000 hh000000 hhh00000 hhhh0000 hhhhh000 hhhhhh00 hhhhhhh0 0hhhhhhh

it_lim: adiw    Z,1     ; Advance the recursive iteration entry pointer
        cpse    ZL,r24  ; Check for recursion limit, exit if reached
        ijmp            ; Do the next iteration (iterN+1) recursively. Hint: iter8 always rolls out CY = 0

        ret
;----------------------------------------------------------------------------------------------------------------

And the test caller if anybody wants to simulate and/or check:

;----------------------------------------------------------------------------------------------------------------
; UNPACK function test.
; Stuff the input bitstream registers with a 7-bit ASCII coded word "Keyboard" for easy watching in AVR Studio:
;
test_unpack:
        ldi     r16,0xFF & ('K'<<1)|('e'>>6)
        ldi     r17,0xFF & ('e'<<2)|('y'>>5)
        ldi     r18,0xFF & ('y'<<3)|('b'>>4)
        ldi     r19,0xFF & ('b'<<4)|('o'>>3)
        ldi     r20,0xFF & ('o'<<5)|('a'>>2)
        ldi     r21,0xFF & ('a'<<6)|('r'>>1)
        ldi     r22,0xFF & ('r'<<7)|('d'>>0)
        ldi     r23,0                           ; needed for CY = 0 rollout from every last iteration in a loop

        rcall   unpack
        rjmp    test_unpack                     ; Loop again
;----------------------------------------------------------------------------------------------------------------

Any comments please?

(Below is a simulation result - the ASCII "Keyboard" is restored from the bitstream:)

Attachment(s): 

Warning: Grumpy Old Chuff. Reading this post may severely damage your mental health.

Last Edited: Tue. Mar 30, 2010 - 05:48 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Looks like Duff's device :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ah now you didn't say recursion was a possible part of the solution. It obviously relies on a recurrent pattern in the algorithm and there's no reason why this same technique and recurrent pattern should not be implemented in C just as much as in Asm. But personally for me recursion gives me the screaming habdabs in terms of readability, maintainability. Like so many programming techniques it may be a "good trick" and it might even save cycles or space but unless those things are at a premium I'd trade them for easily readable/maintainable source (which is why I'd use the first main() above, not the second)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I can't find anything unreadable/unmaintainable in my code - can you? If the recursion makes you screaming - here is a straightforward, non-recursive version of the same code:

;----------------------------------------------------------------------------------------------------------------
; Unpacks a contiguous 7-bit per field bitstream to an 8-bit (1 byte) per field data array.
;
; Bitstream as received: aaaaaaabbbbbbbcccccccdddddddeeeeeeefffffffggggggghhhhhhh (xxxxxxx = any bit sequence)
; Input = r16:aaaaaaab r17:bbbbbbcc r18:cccccddd r19:ddddeeee r20:eeefffff r21:ffgggggg r22:ghhhhhhh
; Output= r16:0aaaaaaa r17:0bbbbbbb r18:0ccccccc r19:0ddddddd r20:0eeeeeee r21:0fffffff r22:0ggggggg r23:0hhhhhhh
; 37 code words, 40 cycles (2.0 uS @20 MHZ)
;
unpack_inline:
; Iter1
        lsr     r16     ; 0aaaaaaa
        ror     r17     ; bbbbbbbc
        ror     r18     ; ccccccdd
        ror     r19     ; dddddeee
        ror     r20     ; eeeeffff
        ror     r21     ; fffggggg
        ror     r22     ; gghhhhhh
        ror     r23     ; h0000000

; Iter2
        lsr     r17     ; 0bbbbbbb
        ror     r18     ; cccccccd
        ror     r19     ; ddddddee
        ror     r20     ; eeeeefff
        ror     r21     ; ffffgggg
        ror     r22     ; ggghhhhh
        ror     r23     ; hh000000

; Iter3
        lsr     r18     ; 0ccccccc
        ror     r19     ; ddddddde
        ror     r20     ; eeeeeeff
        ror     r21     ; fffffggg
        ror     r22     ; gggghhhh
        ror     r23     ; hhh00000

; Iter4
        lsr     r19     ; 0ddddddd
        ror     r20     ; eeeeeeef
        ror     r21     ; ffffffgg
        ror     r22     ; ggggghhh
        ror     r23     ; hhhh0000

; Iter5
        lsr     r20     ; 0eeeeeee
        ror     r21     ; fffffffg
        ror     r22     ; gggggghh
        ror     r23     ; hhhhh000

; Iter6
        lsr     r21     ; 0fffffff
        ror     r22     ; gggggggh
        ror     r23     ; hhhhhh00

; Iter7
        lsr     r22     ; 0ggggggg
        ror     r23     ; hhhhhhh0

; Iter8
        lsr     r23     ; 0hhhhhhh

        ret
;----------------------------------------------------------------------------------------------------------------

Warning: Grumpy Old Chuff. Reading this post may severely damage your mental health.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Aren't we drifting away from Johan's inquiry a little?

Chuck Baird

"I wish I were dumber so I could be more certain about my opinions. It looks fun." -- Scott Adams

http://www.cbaird.org

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Any comments please?

PDU?
Let's skip the "contest", Johans approach is more unusual.
And thus lead to interesting unusual answers.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Aren't we drifting away from Johan's inquiry a little?

Exactly the whole point was that this should NOT become a C versus Asm war. I went along with MBedder's suggestion because by writing the same program in the two variants (as I keep asking for in C compared to C++ threads BTW!) it might become evident what it is about C that Asm programmers find intimdating? But this was not to prove that Asm is tighter/faster than C - we all know and agree that.

By a huge irony (and no this is not sarcasm! ;-)) I've just been moaning in a C/C++ thread that "<<" syntax is "obscure" and yet (but for a very different reason) it would seem that C's propensity to use << (but in the bit shifting, not Io stream sense) as shown inthe code above is an intimidating barrier for Asm programmers.

When you tell them you can use:

LDI r16, (1<<URSEL) | (1 << USBS)
OUT UCSRC, r16

they have an attack of the colly-wobbles and so when faced with:

UCSRC = (1<<URSEL) | (1 << USBS);

they're presumably intimidated in the same way?

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

And how about a non fixed length 7 bit stream?

In either language I would probably would have unpacked the stream as I received it instead of in a chunk at the end.

Or setup the uart in 7 bit mode. Bit banged the stream to a pin and looped it back to the serial port ;)

To be serious I think this is akin to myself and ASM.
I can program in both but looking at assembly is more daunting and I resort back to C unless I have a time critical piece of code.
Why? I am just more familiar with C and other languages that are similar with curly braces and all.
I would suspect it is the same going from ASM to C.

If you have used ASM to start with, C is just unfamiliar and you feel more productive in ASM.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If so, they should just die trembling in horror when encounter something like this (no matter C or C++ or ASM):

      ldi     r19,0xFF & ('b'<<4)|('o'>>3)

:D :D

Warning: Grumpy Old Chuff. Reading this post may severely damage your mental health.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

1. The structure of code with brackets and a few words on each line.
2. Operators
3. Declaring variables and other stuff.

I cannot really agree with that list--unless the topic is changed to Assembler and Higher Level Languages.

1. Code structure--all block-oriented languages will have that type of structure. C isn't APL and the { } are arbitrary. But functionally no different than function/block syntax in PASCAL or VAX FORTRAN or a structured COBOL.

2. Operators--also generally the same as the other languages listed.
3. Variables--ditto.

Now, for 2. and 3. you can indeed get into multi-level casting and complex declarations. In practice I rarely do it. But it can be a stumbling block reading other "expert's" code. But I find the same thing when dabbling in C# on the PC and trying to use snippets from the experts.

=====================

Remember the the plus of using C on AVRs/micros is "it ain't the compiler's job to protect you from yourself". So you can do tricks to get the job done in an efficient manner. And shoot yourself in the foot also.

So the "C vs. ASM" battles I like to join are the "you can only do this in ASM" challenges. I guess I've switched around among so many different procedural languages over the years that syntax and nomenclature don't matter any more. For the ASM veterans, it is like moving around among x51 (and x44) and early x86 and Moto and then to AVR and others. It takes a bit but in the end it is the same core primitives used 90% of the time.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'll gladly give email interactive consulting for a 'while' (couple days? weeks? months?) to some asm programmer IF... you use the imagecraft compiler and something like my board with a mega32 with 16mhz xtal. Only one or two customers at a time please. And in return, I need the same consult on Android java. Its wierd.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, I'm not unknown to have hijacked a thread so as long as your comparisons are made without flames, and without trenches being dug I say it's all OK.

Still, what I was interested in was not those comparisons, but rather trying to understand the mechanisms behind the frustrations of people with long assembler background trying to get to grips with C. From what I recall I haven't seen much of "it produces horrendous code", but rather other misconceptions, confusions etc.

I am still interested in more answers to my "Name three..." question.

All this in the spirit of understanding what is hard, and why, so that we all can become better at what we do [sobbing alloed at this point :wink:].

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have gotten to help a few people start with embedded C by this point, and I came to C from Pascal and c51.
From Pascal, C seems incredibly terse and 'barren'; == vs = is hard, since = does the opposite of what it 'should' do. & vs. && is another problematic one, and common to Pascal and Asm people going to C: && is a really strange operation that reduces two integers to 1 or 0. It has no exact counterpart when coming from Pascal, and it has no obvious machine instruction in asm. C pointers are also odd: the dereferencing operator is on the wrong side of the identifier. Specifying pointers in C is similarly odd. Instead of having a pointer that points to a byte, you apparently have a byte that is pointed to by something.

One also underestimates the optimizer. If you look at real code (not single line examples), we write things in ways that suit us better, while at the same time keeping in touch with reality: We know that the optimizer will pull the loose code together to something good for us, as long as we don't put in operations that the underlying hardware won't do efficiently. If you read that without remembering that there's an optimizer involved, the code looks terribly inefficient, and illogical to someone who is used to looking at code that has already been through optimization. Manual optimization, but still optimization.

We are used to saying that the local variables live on the stack, and if you are an ASM programmer, you know that's not right. Most of the time they live in registers. And so it is with C with the optimizer on, but coming to C, to understand just how far a good optimizer will go, one has to see it. I highly recommend telling your C compiler to output asm source and then look at the truth.

Asm people are used to having control of implementation. In C, you have no control of implementation. The language specification explicitly states this. If you want a 1 clock delay between two operations, it takes no effort in asm. With C you cannot. So the language lacks something fundamental. Oh, you may succeed in getting it in the output today, but you can not specify it in the source, you are relying on a side effect, and the compiler is free to make that a 30-clock delay the next time you hit compile.

On the opposite side of the fence, pure C people are not used to having control of implementation. This leads to the belief that one should never have to control implementation. It usually works. So the day when they really need to control implementation, instead of writing those 20 lines of asm, they attempt to outsmart the compiler, rely on side effects, and sometimes succeed in writing code that, while it looks like C, will functionally break when recompiled.

/Kasper

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

wizhippo wrote:
And how about a non fixed length 7 bit stream?
No problem - just wrap the above function into a load-store wrapper:

;----------------------------------------------------------------------------------------------------------------
; Unpacks (BUFLEN*7/8) 7-bit packed bytes to BUFLEN unpacked bytes in RAM [buf].
;
; 63 code words (including unpack_inline function code),
; 90 cycles/4.5 uS @20MHZ per 8 output bytes,
; 2570 cycles/128.5 uS @20MHZ per 256 output bytes,
; 10250 cycles/512.5 uS @20MHZ per 1024 output bytes,
; 40970 cycles/2048.5 uS @20MHZ per 4096 output bytes
; (~10 cycles/0.5 uS @20MHZ per each output byte)
;
unpack_RAM:
        ldiw    r24,buflen/8            ; Initialize unpacked byte counter
        ldiw    X,buf+buflen*7/8        ; Initialize packed source pointer
        ldiw    Y,buf+buflen            ; Initialize unpacked destination pointer

unp_loop:
        ldi     r23,0   ; 
        ld      r22,-X  ; Load last 7 packed bytes from RAM
        ld      r21,-X  ;
        ld      r20,-X  ;
        ld      r19,-X  ;
        ld      r18,-X  ;
        ld      r17,-X  ;
        ld      r16,-X  ;

        rcall   unpack_inline

        st      -Y,r23  ; Save last 8 unpacked bytes to RAM
        st      -Y,r22  ;
        st      -Y,r21  ;
        st      -Y,r20  ;
        st      -Y,r19  ;
        st      -Y,r18  ;
        st      -Y,r17  ;
        st      -Y,r16  ;

        sbiw    r24,1   ; Repeat BUFLEN times
        brne    unp_loop

        ret
;----------------------------------------------------------------------------------------------------------------

Warning: Grumpy Old Chuff. Reading this post may severely damage your mental health.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello, folks 0

OK, just found this thread..... I was off doing some real "work" for a change :)

In my case, I am about equally competent or incompetent with assembler and c. For me, tool chain is a huge issue. My prior experience with c (about 15 years ago, or more) was with QuickC or something like that on a PC and a bit of IAR MSP430 c about 10 years ago. Assembler has all been 8051 and AVR asm2 (with a bit RCA CD1802 years before).

Currently, my dominant IDE use is with REalBasic - a nice xplat OO language by the way - where I don't have to worry about makefiles,optimizations, or any of that stuff, just write, debug, and build.

So, the whole idea of optimization kind of blows my mind. I can see a dialog with some buttons:

(*) optimize for speed
(*) optimize for size

I just don't see why there should be O0, O1, O2, Os, and whatever, or how any mere mortal can even choose!

My next biggest hang-up, if there is one, is dealing with casting and streams (and casting streams). Oh, plus the fact that I'm not totally comfortable with some pretty basic c-things, like unions and structs.

So, that is where I am coming from.

When I wrote, in that earlier thread:

Quote:
easier than what

It was more of a rhetorical question. When someone says "x is easier", my natural response is "by what measure against what benchmark".

I am NOT so concerned about control, but I AM concerned that I am able to understand the consequences of my choices (which, I guess, is a kind of "control"). With c, and particularly with 3rd party c "libraries", I don't get a warm fuzzy feeling. In dealing with small processors having limited resources, there is always the questions of "what does it take", and "how fast or slow does it run" and "how much RAM and flash". With assembler programs, I know, but I have to spend the time to create it. That's the rub, isn't it?

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

On the opposite side of the fence, pure C people are not used to having control of implementation. This leads to the belief that one should never have to control implementation. It usually works. So the day when they really need to control implementation, instead of writing those 20 lines of asm, they attempt to outsmart the compiler, rely on side effects, and sometimes succeed in writing code that, while it looks like C, will functionally break when recompiled.

That was a really interesting and enlightening thing to read. I guess I've been sneaking around this but never really managed to formulate it so good. The key parts is of-course "they attempt to outsmart the compiler, rely on side effects [...]"

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MBedder wrote:
The C and ASM are just two different tools serving the same purpose. The C can be compared to some power tool like an electric nut driver with a bit set, the ASM - to a precise hand toolset.

Whereas the electric nut driver can be more convenient in some cases such as screwing on or off many medium sized bolts at once, the properly collected, sharpened and adjusted hand toolset can be just indispensable in other cases.

Just a small and simple example - try to do this in C:

Unpack a contiguous 56-bit long, 7-bit per field bitstream to an 8-bit (1 byte) per field data array.

Bitstream as received: aaaaaaabbbbbbbcccccccdddddddeeeeeeefffffffggggggghhhhhhh (aaaaaaa..hhhhhhh = any bit sequences).
Input array = [aaaaaaab, bbbbbbcc, cccccddd, ddddeeee, eeefffff, ffgggggg, ghhhhhhh].
Output array = [0aaaaaaa, 0bbbbbbb, 0ccccccc, 0ddddddd, 0eeeeeee, 0fffffff, 0ggggggg, 0hhhhhhh].

After I see the properly working (in simulation) C code, I will supply my ASM implementation.


Here's a quick, non-tested try.
Probably both longer and slower than the ASM implementation, but guaranteed to be shorter (and probably easier) to read in source form:

void streamsplit(uint8_t *io_array)
{
	int i;
	long long shift_array = *(long long *) (io_array+1);
	for (i=7;i>=0;i--,shift_array>>=8)
		io_array[i] = shift_array & 0x7f;
}

/Jesper
http://www.yampp.com
The quick black AVR jumped over the lazy PIC.
What boots up, must come down.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

For me, tool chain is a huge issue.

OK... and a desire is:
Quote:
...a dialog with some buttons:

(*) optimize for speed
(*) optimize for size

Yet, you apparently chose a toolchain that has:
Quote:

O0, O1, O2, Os, and whatever, or how any mere mortal can even choose!

... versus one that has:

Quote:
The compiled program can be optimized for minimum size, respectively maximum execution speed, using the Optimize for|Size, respectively Optimize for|Speed, settings.
:twisted:

Quote:

My next biggest hang-up, if there is one, is dealing with casting and streams (and casting streams). Oh, plus the fact that I'm not totally comfortable with some pretty basic c-things, like unions and structs.

It can get crazy, indeed. The main point I'll make is that >>the mindset is the same as if you were writing in ASM and lying about the data types, lengths, layout, etc.<<

There is a current thread about simulating a shift register: https://www.avrfreaks.net/index.p...

I output the low bit of a 16-bit value one at a time, and then shift it down preparing for the next.

   DATA = (frog & 1) ? 1 : 0;
   frog >>= 1; 

where frog is an unsigned 16-bit value.

Now, the shift needs to be all 16 bits. But in ASM to do the (frog & 1) we say to ourself: "Self, I've got a 16-bit value in a register pair. I need to know if the low bit is set. I'm just going to peek at the low bit of the low register...".

The rules of C (and build options) might say that 1 is a 16-bit constant and a less than optimal (to the eye of the ASM guru) might be generated. This exact same mind can say "I know best; it's my app; play 8-bit games" and write

   DATA = ((unsigned char)frog & 1) ? 1 : 0; 

It is exactly the same mindset.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You don't need the "? 1:0" part ;) The "& 1" already guarantees the value is either 0 or 1.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

You don't need the "? 1:0" part Wink The "& 1" already guarantees the value is either 0 or 1.

Go to the thread linked above. that was "pointed out" to me. I challenged whether you will get as close to optimum (and it is an ugly AVR sequence) to copy that bit to I/O versus the conditional set.

If you show me a better generated code sequence, I'll be happy to see it. Grateful. Attribution in my code. Virtual beer.

(It does depend a bit on the "compiler context" and what happens to be register-based. Also, my initial version had MSB first, so try with a mask of 128 for 8 bit and 256 for 9 bit.)

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

From a C viewpoint, which is the language used to write the code, the statements ARE equivalent.

There will almost always be "better" ways to do things if you start close-reading the generated ASM and manipulating the original C to generate as efficient or fast code as possible.
But if this is an issue, then why not write in assembler directly?
As soon as a new compiler release is out, the hand-trimmed code may be totally bloated up.

/Jesper
http://www.yampp.com
The quick black AVR jumped over the lazy PIC.
What boots up, must come down.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jesper wrote:

Probably both longer and slower than the ASM implementation, but guaranteed to be shorter (and probably easier) to read in source form

Yes, just 14 times longer (216 words function code only vs 15 words) and 46 times slower (3895 cycles/195 uS vs 84 cycles/4.2 uS). Just a little, little bit - perhaps all for the readability sake, because 6 C lines vs 14 ASM lines is definitely much, much shorter :D :D

Warning: Grumpy Old Chuff. Reading this post may severely damage your mental health.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MBedder wrote:
jesper wrote:

Probably both longer and slower than the ASM implementation, but guaranteed to be shorter (and probably easier) to read in source form

Yes, just 14 times longer (216 words function code only vs 15 words) and 46 times slower (3895 cycles/195 uS vs 84 cycles/4.2 uS). Just a little, little bit - perhaps all for the readability sake, because 6 C lines vs 14 ASM lines is definitely much, much shorter :D :D

Within a project with 600 lines of c code is easier to under stand then 1400 lines of assembly.

Also within a project that has multiple people involved C normally is easier to read and understand faster then the assembly is. That is C to some extent self documents. Assembly tends to needs the comments.

I also want to point out it depends on a persons skill set. A C programmer as mentioned before does not normally have to have the same deep hardware and binary knowledge(such as how to add divide and other manipulations and assembly voodoo that C hides, I know I don't) that an assembly programmer has.

Back to the OP, if I knew assembly like others here in the forum, and did only embedded design on small devices with less then 16K code space I think I would too have problems using C. I would always have the mental block that I could do it more efficiently in asm and have that fine grained control.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MBedder wrote:
jesper wrote:

Probably both longer and slower than the ASM implementation, but guaranteed to be shorter (and probably easier) to read in source form

Yes, just 14 times longer (216 words function code only vs 15 words) and 46 times slower (3895 cycles/195 uS vs 84 cycles/4.2 uS). Just a little, little bit - perhaps all for the readability sake, because 6 C lines vs 14 ASM lines is definitely much, much shorter :D :D


I have no comments at all, not really needed - it should still be pretty obvious how it work.
I've been looking at your code for quite a while, and I'm still having a hard time figuring it out. Even with the comments.
I don't know how long you thought over your implementation solution. Mine took less than 2 minutes to figure out, and write.
And, as neither speed or size was a requirement, it solved the problem.

/Jesper
http://www.yampp.com
The quick black AVR jumped over the lazy PIC.
What boots up, must come down.

Pages