You're not debating. Your throwing empty lines, such as 'that doesn't prove anything' or you want to compare byte counts which is pointless because nobody knows any details.
Coding in C is much more practical than ASM. It will produce a better product on practically all occasions. A few mean and lean portions of code can be done in C as well.
But you prefer listening to your own self ;) I can imagine that Ulf can live with that. And so can I. Keep coding in ASM, you deserve it.
Thanks, Frank.
(remove 'q' and '.invalid' when replying by email)
Didn't find your answer? Ask the community — no account required.
I'm trying to decide on which to use for a project as the main default that...
W
Walter Banks
Good point. Precise timing is the only case where current C compilers cannot compete with asm. There is no mechanism in the language to specify that the elapsed time between two points in code should always be a specific amount of time. It is also not an easy thing to implement in a compiler. Any idea's anyone?
Current compilers (including ours) provide analysis tools for timing. They can provide timing information for each generated instruction and compilers that support McCabe structure analysis will have information about the code at each decision point in the code.
Both of these help but they are analysis after code is written rather than asynchronous precise timing tools.
w..
R
Robert Adsett
A nice piece of work, but I don't think he quite showed that. There are a few things that he didn't show that would appear to require at the least extra intrinsics (and thus be non-C). Things like using the condition flags for return values, or directly manipulating registers (like SP).
He did cover most of the ground though and I plan on keep a pointer to his document around.
Assembly is still useful to deal with the small number of cases left, but possibly (probably?) confined to small functional areas.
Robert
R
Robert Adsett
compete with asm. There is no mechanism in the language to specify that the elapsed time between two points in code should always be a specific amount of time. It is also not an
I like the earlier suggestion of a WaitUntilCycles(...) function. I use something similar for coarser timing reading off of timers.
Robert
W
Walter Banks
Robert,
Your point is well taken.
In the actual test suite for the RS08 we did cover everything that you mentioned. The test suite and the goal was to code everything in asm in C and this is what we did. The test suite (and the C compiler) depends on intrinsics for nop,stop,wait and bgnd. ISO 18037 allows the processor registers to be directly accessed. (AC and CC.C in the examples posted)
As an exercise to further my point with some customers (some months ago) I created a RS08 macro assembler that used the C snippets as the code generation and compiled the results. This hybrid assembler then ran the RS08 macro assembler tests and all the available RS08 reference designs that were written in asm.
The main disadvantage of magnetic media is that they are human unfriendly, compared to a good paper tape.
Reaching for assembly as a kneejerk is as bad as - probably worse than
- reaching for a C compiler as a kneejerk. There is a time and a place. For [knee]jerks too.
J
Joerg
Hello Ulf,
That would be a really nice feature. Much of my work is in really noise sensitive areas such as Doppler. Slipping one clock cycle can create so much phase noise that you'd have to redesign, even if it were only once in a while. Another example is the measurement of inductor current in a power conversion circuit. There will always have to be some code running to do other things yet a slip of a few clock cycles between measurement and reaction can cause instability or noise. Probably this could be done in C but many of us (certainly me) aren't used to it.
Regards, Joerg
http://www.analogconsultants.com
D
Didi
You will have to wait for longer than your lifetime to see me do a kneejerk. The way I program makes my code 10+ times more efficient than what is done in C, and I have invariably been a lot faster than anyone trying to measure up with me. If you want to go beyond general talk and use examples to compare, this probably can be done. But this sort of talk is just for birthday parties, engineering takes more tha that.
Without exception, anybody who claims assembly language is universally a better choice than C is not factoring in all the costs of either alternative.
D
Didi
I do not claim this. For one time utilities and stuff C and many other hll-s can be the better option. It can be the only option if the assembler for a given architechture is a nightmare. It can be the better option if a given architecture is a mess so it has to be hidden - like x86, which is the main reason why C is popular today. I work with architectures I can accept (and I have paid my price for opting not to accept what has been attempted to be driven down my throat), have used assembler for many years, the VPA I use now is more a compiler than an assembler, but retains the "alphabetic" vs."hieroglyphic" nature. Again, without concrete examples this is just birthday party talk.
No, this discussion is simply talking around and around the edge of a fundamentally indefensible and extremely silly point of view.
W
Wilco Dijkstra
For libraries people do indeed use a small subset as embedded programs don't need everything that is provided (eg. file IO, math functions).
But what subset of C are you referring to? C is already smaller and simpler than most other popular languages, and you can't leave out much. The only big thing that you could avoid using is the preprocessor, but that has no effect on program size/speed. I don't see people avoiding control statements, variables, expressions, structures, functions or any other high level features. So I don't believe that the advantage of C is diminished at all in the embedded world.
Wilco
W
Wilco Dijkstra
OK, if you post the assembler code, I'll post the C version.
Wilco
J
Jim Granville
The challenge here is handling branch variants, and some uC variants also have opcodes that vary with taken/not taken. [so the compiler now needs speed files by variant..]
Still, you could tag a code block, and ask for 'equal time padding', so the compiler would (try to) ensure all paths (?) were the same, up till the final patch. Then you are left with interrupt jitter effects, and if your core is large enough to have a cache...
-jg
W
Walter Banks
The last time I seriously looked at this from a compiler implementation perspective it basically came down to branches to a lower address, everything else was basically a directed graph problem. Branches to a lower address (conditional or not) were timing deterministic at run time.
The jitter issue took on new meaning a few months ago when I had a conversation on C vs asm with a old friend who has designed several of the current commonly used instructions sets. "Walter do this in C!" He achieved sub instruction resolution by knowing which execution cycle the instruction was referencing either data or an I/O pin and carefully selecting instructions. (similar to the Microchip PIC skip I posted yesterday).
I like Ulf's suggestion in general because it would improve the overall utilization of high volume parts. In the short term it likely can be achieved automatically as long as the timing could be determined at compile time. Timing tables are pretty much standard equipment in compilers these days and most know about rules for execution (most branches that are not taken are one cycle shorter)
Jim points out the effects of caches in the newer processors where run time execution history now affects straight line code execution timing. Some of the 8051's are now caching branches in unusual ways that make them unpredictable at compile time.
The point that Jim didn't say was that makes constant time in any implementation language more difficult.
w..
W
Wilco Dijkstra
Not necessarily true in the embedded world.
Everybody agrees it is exactly the opposite, assembler is typically very unfriendly, while C is much easier to read and understand. As a small example, consider your VPA vs C:
.file "x3.c" .text .align 2 .global f .type f, %function f: @ args = 0, pretend = 0, frame = 0 @ frame_needed = 0, uses_anonymous_args = 0 @ link register save eliminated. mov r3, r0, asl #16 mov r2, r3, lsr #16 add ip, r2, r3, lsr #18 mov r0, ip, asl #16 add r1, r2, r0, lsr #18 mov r3, r1, asl #16 add ip, r2, r3, lsr #20 mov r0, ip, asl #16 add r1, r2, r0, lsr #18 mov r3, r1, asl #16 sub ip, r2, r3, lsr #18 mov r0, ip, asl #16 add r1, r2, r0, lsr #19 mov r3, r1, asl #16 mov r0, r3, lsr #17 @ lr needed for prologue mov pc, lr .size f, .-f .ident "GCC: (GNU) 3.4.3"
The avr needs about double the 30 instructions, but everything has to be handled 8 bit at the time.
Even though the ARM is 32bit, in this case it should be similar to a
16 bit MCU.
Regads Anton Erasmus
J
Jim Granville
compete with asm. There is no mechanism in the language to specify that the elapsed time between two points in code should always be a specific amount of time. It is also not an
can provide timing information for each generated instruction and compilers that support McCabe structure analysis will have information about the code at each decision point in
asynchronous precise timing tools.
We reported the size of each procedure - as that was very easy to do, and it helps when comparing different algorithms.
Because this problem tends to be very localised, and the code tends to be low level, and stable, you could just report the timing trees to a label, in the listing.
Something like [20,12,14,16,19] [Min:12 Max 20]
then, users would be able to manually 'pad' the slower paths, to get equal times. [and paste that into the source, as a warning marker :) ]
You would also need a means to tag a line for 'show timestamp', as sometimes the critical path only applies up to a (eg) Pin sample point, and thereafter, the tail times do not matter.
Where branch jitter is an issue, you could add a simple directive to pad with jitter removal no-ops - tho maybe novices might think that was smarter than it was, and thus be a dangerous tool....
The compiler would need an editable opcode time table.
-jg
W
Wilco Dijkstra
Intrinsics are standard C, that's why they exist. Most compilers treat various library functions as intrinsics (eg. memcpy, memset, abs) and adding extra library functions that happen to map to a single instruction is perfectly legal. And unlike inline assembler they are portable too.
Some compilers already detect uses of the carry flag, eg. use an add with carry in x = y + z; a = b + c; if (x < y) a++;
Yes, the areas where assembler is the only option are pretty limited. I prefer using assembler only in the 1% where I need absolute optimal performance and use C for the rest.
Wilco
M
Mike Silva
It sounds as if you are comparing experienced, knowledgeable embedded assembler programmers with C programmers who don't have a clue about using C in embedded systems. A better comparison, surely, would be to compare to an experienced, knowledgeable embedded C programmer -- the kind who has a very good idea of the machine code that will result from every line of his C source.
Join the Discussion
Have something to add? Share your thoughts — no account required.
Didn't find your answer?
Ask the community — no account required
Report Content
You are reporting this content to the moderators. They will look at it
ASAP.