XC8: .asm to C ( i.e. Lowering One's Expectations)

Thread Starter

joeyd999

Joined Jun 6, 2011
6,334
I see, so you have no actual example of C code we can look at that that when compiled using the compiler you are working with, runs ten times slower than a purportedly equivalent algorithm coded in assembler, very well, that answers that question, you have no evidence to share.
What's with the freakin' attitude? Just ignore the thread and it won't bother you. I won't reply to your queries any further. Thanks.
 

ApacheKid

Joined Jan 12, 2015
1,762
What's with the freakin' attitude? Just ignore the thread and it won't bother you. I won't reply to your queries any further. Thanks.
I don't understand your question. The record shows that you made the following claim:

Yup. And I now understand why many believe these devices are so underpowered: C cuts the native performance by at least a factor of 10 in all of code size, execution speed, and power consumption.
It is - it seems - a claim you cannot support with facts and evidence, it is therefore anecdotal. In a forum where science and engineering are discussed I make no apologies for asking for evidence of such claims.
 

Thread Starter

joeyd999

Joined Jun 6, 2011
6,334
Finally, my project -- at this moment -- stands at 12,294 bytes optimized, 10052 bytes at O level 1, and 8725 bytes at O level 2. This for functionality that I can encode in about 1K bytes in .asm.

I know where most of these extra bytes are coming from -- and I don't have time to explain now (gotta get my kid to the doc) -- but I will explain in my next post.
For those who care, I will complete my thought above. For those who don't -- or who may find these posts overly burdensome -- there is a handy ignore button available under my avatar. Use it, please.

66% (5776 of the 8729 level 2 optimized bytes) of the code above is being consumed by the inclusion of sprintf for formatted conversion of signed and unsigned int16s, 24s, and 32s to ASCII.

XC8 does not have itoa(), ltoa(), ultoa() or any other conversion routines in its libraries, leaving only sprintf or home-grown code.

Obviously, I will have to write my own conversion/formatting code -- similar to that which I have already done in .asm.

Removing those 5776 bytes from the equation, I now have C code that generates about 3K of code for something I can do in .asm in 1K. About a 3:1 bloat in the code size with a similar hit in execution speed performance.

Usually, my projects utilize anywhere from 60 to 90% of all available instruction cycles at a chosen clock speed. It is patently obvious that to get similar code performance in C I will need to increase my clock speeds (and power consumption) by at least a factor of 4, or change architecture (there is nothing faster than a 64Mhz PIC18F).
 

WBahn

Joined Mar 31, 2012
32,925
For those who care, I will complete my thought above. For those who don't -- or who may find these posts overly burdensome -- there is a handy ignore button available under my avatar. Use it, please.

66% (5776 of the 8729 level 2 optimized bytes) of the code above is being consumed by the inclusion of sprintf for formatted conversion of signed and unsigned int16s, 24s, and 32s to ASCII.

XC8 does not have itoa(), ltoa(), ultoa() or any other conversion routines in its libraries, leaving only sprintf or home-grown code.

Obviously, I will have to write my own conversion/formatting code -- similar to that which I have already done in .asm.

Removing those 5776 bytes from the equation, I now have C code that generates about 3K of code for something I can do in .asm in 1K. About a 3:1 bloat in the code size with a similar hit in execution speed performance.

Usually, my projects utilize anywhere from 60 to 90% of all available instruction cycles at a chosen clock speed. It is patently obvious that to get similar code performance in C I will need to increase my clock speeds (and power consumption) by at least a factor of 4, or change architecture (there is nothing faster than a 64Mhz PIC18F).
The printf() function and its variants are notorious for eating up resources in embedded code. This is understandable since the code has to be able to handle any type conversion thrown at it at run time. I agree that it would make sense for a compiler that is targeting resource-limited platforms to provide the narrower conversion functions, but those shouldn't be too hard to roll your own, if necessary. That the compiler doesn't offer them is, perhaps, an indication that the compiler implementers were primarily interested in getting a compiler that met minimal functional requirements, which might also imply that their code generation is on a comparable level.
 

Thread Starter

joeyd999

Joined Jun 6, 2011
6,334
That the compiler doesn't offer them is, perhaps, an indication that the compiler implementers were primarily interested in getting a compiler that met minimal functional requirements, which might also imply that their code generation is on a comparable level.
My understanding is they were shooting for strict C99 compatibility. From my POV, that's a stupid goal. But, the executives at MC must have made a business case for it (along with the exclusion of .asm).
 

Thread Starter

joeyd999

Joined Jun 6, 2011
6,334
...but those shouldn't be too hard to roll your own, if necessary.
Which I will. But I provided an instructive example above with regard to binary to BCD conversion.

This can be done efficiently in .asm because I have a DAW (decimal adjust accumulator) instruction available to me. This is not exposed in C (to the best of my knowledge), thus an instruction cycle intensive inner loop must be created in order to simulate the equivalent.

I am finding all sorts of case where C is preventing me from using many kinds of resources that I have come to rely on over 30 years in order to produce the tightest, fastest code possible (which is of primary importance to me and the things that I do).
 

ApacheKid

Joined Jan 12, 2015
1,762
This is another example of the kinds of things that I dislike about C. There are umpteen versions of the ANSI standard now and many variants on a per vendor basis, then we have a host of "pragma" and extensions and so on.

The "sprintf" code is big, a huge amount of functionality, any language intended for use in programming MCUs really should make it easy to avoid large libraries being needed. The curious thing here is that sprintf probably relies on itoa, ltoa and so on, these are the kinds of functions one would use if writing sprintf!

Several languages (not C) include automatic conversions between many data types, for the very reason that this is a recurring, common requirement, but not C and of course C does not have a string data type anyway.

PL/I - a language I reference often (for a variety of reasons) implements many conversion implicitly, the compiler knows the rules for converting native types (they are part of the language standard) and invisibly inserts conversion operators during the code generation phase.

e.g. (emphasis mine)

Conversion Between Data Types Data names and expressions of unlike data type can be used in assignment statements. For example, if CODE is declared with the attribute CHARACTER ( 10) and MASK with an attribute BIT (10), the following assignment statement:

CODE == MASK;

will create, as a data item for CODE; a string of ten characters that contains only the characters 1 and O. The 1 bits in MASK become the 1 characters in CODE, and the 0 bits in MASK become the 0 characters in CODE. If the character length specified for CODE exceeds the bit length specified for MASK, the data item created for CODE is extended on the right-hand side with blank characters.

It's not restricted to simple assignments either, any right hand expression involving disparate types will incorporate automatic conversions of operands as needed. This is what programming languages should do, help the programmer not act as some obstacle course!

Found here.
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
I've been following @joeyd999 's journey into XC8 with morbid fascination - I have been down the same exact road with the same pain and depressing results as he relates here. We're both experienced PIC assembly programmers and the code XC8 generates is laughable by comparison, even in the purchased optimizations. It's true that few compilers will generate code to rival a good assembly effort (Keil 8051-class notwithstanding) and it's true that the PIC architecture presents challenges not found on other machines but XC8 is just a mess IMHO. I can vouch for all the issues Joey has related and more - keep looking, pard'ner. PICC-18 did a better job and you could tune C constructs for better code generation. I haven't seen much of that in XC8. I could go on but again, Joey has already said it.

The loss of MPASM is huge. I too have extensive macro libraries for all the 8bit families that don't work under pic-as.

FWIW - one thing nice about XC8 is that they did break printf et. al. into smaller routines. It links in only what is necessary to do what the source specifies. It's still big but not as bad as before.
I was surprised at Joey's assertion that stdlib.h functions like itoa are missing. If so, that is new. Earlier versions had those. They're in the XC8 Legacy Compiler Manual last updated in 2020. Perhaps they're still there but not documented.. the library documented in the new manual is pretty thin.
I agree that C99 compatibility on PIC is pointless on an 8bit Harvard microcontroller if it screws up everything else.
I am pretty sure that the time I've spent wrangling several generations of XC8 could have been better spent in just doing it in assembler, new PICs notwithstanding.

Joey, you have my sympathies here. I'm retired and unlikely to have to deal with the deprecation of the tools I've grown to depend on over decades but I have felt the frustration and dread of losing them. Good luck sorting it out.
 

Thread Starter

joeyd999

Joined Jun 6, 2011
6,334
We're both experienced PIC assembly programmers...
What I hate is the knee-jerk reaction regarding my desire to work in .asm. I am stupid and C is so much better, donchya know?

And portable.

I don't think the software guys really understand what that word means.

The funny thing is that these guys have absolutely no idea what one of these little buggers is really capable of when the hardware and instruction set is fully exploited.
 

ApacheKid

Joined Jan 12, 2015
1,762
What I hate is the knee-jerk reaction regarding my desire to work in .asm. I am stupid and C is so much better, donchya know?

And portable.

I don't think the software guys really understand what that word means.

The funny thing is that these guys have absolutely no idea what one of these little buggers is really capable of when the hardware and instruction set is fully exploited.
It's not I that should know but their compiler engineers, it's odd that in all this time and with all this commitment to the company's processors you haven't reached out and told them that their compilers are abysmal. It sounds like they know how to make processor chips but know little about compilers and code generation, so it's their software guys you should be arguing with not software engineers in this forum.

Here let me help you, reach out to Mark Pease, he's the manager of compiler development at Microchip, raise your concerns and observations with him rather than complaining, where there's a will, there's a way, tempus fugit.
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
portable. I don't think the software guys really understand what that word means.
True story: Back in the OTP days MPASM would change case-sensitivity for macro names from version to version. If macro 'Foo' was invoked 'foo' in one version it expanded. On the next version it didn't expand but did not issue an error/warning. It took the macro name as a label that did not start in column 1 - still not a problem according to the assembler. I programmed a test article which promptly failed - before programming 700 for production. When we figured out what was going on, I reported the issue and talked to the head of the assembler development team at uCHIP explaining why that was a bad thing. She did not think it was a valid issue and I kept what she said in mind for years following as a warning to self:
"We think that if two versions of MPASM assemble the same source with no errors, then it meets spec." (!). different object/,HEX files are.. well... hmm..
Eventually they added the 'Label does not begin in column 1' warning for which our build scripts searched the list file but that issue continues to this day because, as I was also told, 'we agree labels should start in col. 1 but there is some code out there which would have to be updated'. This was the early '90s.. That's the mindset. We say its portable, compatible etc. If not, It's your problem.
... and then there's the endless errata but time to get back to that time saving compiler, bud.
 

Thread Starter

joeyd999

Joined Jun 6, 2011
6,334
True story: Back in the OTP days MPASM would change case-sensitivity for macro names from version to version. If macro 'Foo' was invoked 'foo' in one version it expanded. On the next version it didn't expand but did not issue an error/warning. It took the macro name as a label that did not start in column 1 - still not a problem according to the assembler. I programmed a test article which promptly failed - before programming 700 for production. When we figured out what was going on, I reported the issue and talked to the head of the assembler development team at uCHIP explaining why that was a bad thing. She did not think it was a valid issue and I kept what she said in mind for years following as a warning to self:
"We think that if two versions of MPASM assemble the same source with no errors, then it meets spec." (!). different object/,HEX files are.. well... hmm..
Eventually they added the 'Label does not begin in column 1' warning for which our build scripts searched the list file but that issue continues to this day because, as I was also told, 'we agree labels should start in col. 1 but there is some code out there which would have to be updated'. This was the early '90s.. That's the mindset. It's your problem.
... and then there's the endless errata but time to get back to that time saving compiler, bud.
From the beginning of time, .asm was intended to be case insensitive. I've always kept the case-sensitive assembler switch glued in the off position -- from the first time such a switch existed.
 

WBahn

Joined Mar 31, 2012
32,925
Which I will. But I provided an instructive example above with regard to binary to BCD conversion.

This can be done efficiently in .asm because I have a DAW (decimal adjust accumulator) instruction available to me. This is not exposed in C (to the best of my knowledge), thus an instruction cycle intensive inner loop must be created in order to simulate the equivalent.

I am finding all sorts of case where C is preventing me from using many kinds of resources that I have come to rely on over 30 years in order to produce the tightest, fastest code possible (which is of primary importance to me and the things that I do).
I don't find that surprising and it is, if anything, even worse with other high level languages. At least in C (most compilers), you can embed assembly code snippets.

One thing that C lacks (as do most, but not all, other HL languages) is a bit rotate command even though most processors have that instruction. I have had many times that I have needed that. Some compilers are good enough to, sometimes, recognize the pattern of code that does this and implement it as a rotate in the object code.
 

ApacheKid

Joined Jan 12, 2015
1,762
I don't find that surprising and it is, if anything, even worse with other high level languages. At least in C (most compilers), you can embed assembly code snippets.

One thing that C lacks (as do most, but not all, other HL languages) is a bit rotate command even though most processors have that instruction. I have had many times that I have needed that. Some compilers are good enough to, sometimes, recognize the pattern of code that does this and implement it as a rotate in the object code.
I was reading yesterday and had no idea until then, that many processors these days now include a "popcount" instruction, doing that in the hardware with an instruction makes a great deal of sense.
 

Thread Starter

joeyd999

Joined Jun 6, 2011
6,334
I don't find that surprising and it is, if anything, even worse with other high level languages. At least in C (most compilers), you can embed assembly code snippets.

One thing that C lacks (as do most, but not all, other HL languages) is a bit rotate command even though most processors have that instruction. I have had many times that I have needed that. Some compilers are good enough to, sometimes, recognize the pattern of code that does this and implement it as a rotate in the object code.
Just being able to recall the status of a previous mathematical operation would be invaluable. I implement such functionality in my .asm float library.
 
Top