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

Thread Starter

joeyd999

Joined Jun 6, 2011
6,330
Well if it works, its valuable! It's an interesting exercise too to try and define precisely what is meant by "truly independent of each other" I guess it means that the execution path of each of them is never ever influenced by the execution of the others. That will likely extend to any hardware that they might share.

Having them totally "unaware" of each other is indeed a very good design point.
See this post.
 

Thread Starter

joeyd999

Joined Jun 6, 2011
6,330
I take my hat off to you, 14,000 lines of assembler is indeed a huge amount of code, you clearly have a deep understanding of your platform!
It's easy when the modules are pluggable. 3 lines of code pull in another couple of thousand.
 

Thread Starter

joeyd999

Joined Jun 6, 2011
6,330
BTW, @nsaspook, I'm trying to reproduce my framework in C. Still working on the optimizations, but so for the resultant object code is at least 5x larger than the equivalent asm.

I'm going insane trying to figure the exact sequence of C code I need to result in my desired .asm output (functionality notwithstanding).

Someone here, I don't remember who, called this method of coding "C--". Excellent term.

The fact that I have no FSRs available to me, nor the btg instruction, is killing me.
 

nsaspook

Joined Aug 27, 2009
16,333
BTW, @nsaspook, I'm trying to reproduce my framework in C. Still working on the optimizations, but so for the resultant object code is at least 5x larger than the equivalent asm.

I'm going insane trying to figure the exact sequence of C code I need to result in my desired .asm output (functionality notwithstanding).

Someone here, I don't remember who, called this method of coding "C--". Excellent term.

The fact that I have no FSRs available to me, nor the btg instruction, is killing me.
I don't think that will change much as you're an expert with asm, the compiler is not that smart. If you have the 'free' version be sure to use level 2 for optimization. The C abstract machine is sometimes not a good fit for 8-bit architectures. C is built on pointers and the assumption that everything has an address that can be manipulated at low cost. XC8 also auto promotes to 16-bit integers to be ANSI compatible.
https://www.microchip.com/forums/FindPost/808003
 

ApacheKid

Joined Jan 12, 2015
1,762
BTW, @nsaspook, I'm trying to reproduce my framework in C. Still working on the optimizations, but so for the resultant object code is at least 5x larger than the equivalent asm.

I'm going insane trying to figure the exact sequence of C code I need to result in my desired .asm output (functionality notwithstanding).

Someone here, I don't remember who, called this method of coding "C--". Excellent term.

The fact that I have no FSRs available to me, nor the btg instruction, is killing me.
You say about 5 times the size? that's code size I imagine. Why is that though? is it bad C code to start with or something like symbol tables etc?

C is far from my favorite programming language, but for the most part the code generated should be as good as a decent assembler programmer would write and is sometimes more compact.

It would be interesting to see - say - the comparison for some small, basic module.

In any decent compiler the generated code goes through another phase that identifies needless register and memory reads and writes.

It can recognize that some code that writes R12 to an address and then loads from that address into R12, can (likely) be removed, stripped out, that kind of machine level optimization is standard in any decent language implementation.

Of course with a knowledge of more than the code reveals, a human programmer can produce tight assembler, if we know things the compiler can never know, we can include that in our final code, but generally much of that can be captured in a decent C design.

I love assembler but would never seriously write anything large in it, critical bits yes, but a large application I doubt. I wrote my first program on one of these at around 1977:

1668038016851.png

Then a year or so later got my first real computer:

1668038078628.png

The Acorn System 1 (father company of what eventually became ARM Holdings) A 6502 CPU at 1 MHz with "firmware" (monitor they called it) in a 256 Byte ROM and a huge 1K of static RAM. I recall saving up for a while so I could buy an INS8154 IO chip for which there was a temptingly empty socket, then I joined the big boys!

Back then an assembler was an upgrade, far beyond my means!
 
Last edited:

Thread Starter

joeyd999

Joined Jun 6, 2011
6,330
I don't think that will change much as you're an expert with asm, the compiler is not that smart. If you have the 'free' version be sure to use level 2 for optimization. The C abstract machine is sometimes not a good fit for 8-bit architectures. C is built on pointers and the assumption that everything has an address that can be manipulated at low cost. XC8 also auto promotes to 16-bit integers to be ANSI compatible.
https://www.microchip.com/forums/FindPost/808003
Just out of curiosity, what am I to do when I need > 32 bit floats? And don't object to the use of floats. I know when to use them, when not to, and the cost of the choice either way.
 

Thread Starter

joeyd999

Joined Jun 6, 2011
6,330
Right. So, when I ultimately need to compute a 2nd order polynomial regression with *very* small residuals from *very* large input values, what are my options?

Funnily enough, this is elementary in .asm. I just string on extra bits where I need them.
 

nsaspook

Joined Aug 27, 2009
16,333
Right. So, when I ultimately need to compute a 2nd order polynomial regression with *very* small residuals from *very* large input values, what are my options?

Funnily enough, this is elementary in .asm. I just string on extra bits where I need them.
Pray or use a C call compatible asm library.
 

Thread Starter

joeyd999

Joined Jun 6, 2011
6,330
I've discovered that this:

C:
typedef union
{
    uint_fast8_t bytev;
    struct
    {
        unsigned b0:1;
        unsigned b1:1;
        unsigned b2:1;
        unsigned b3:1;
        unsigned b4:1;
        unsigned b5:1;
        unsigned b6:1;
        unsigned b7:1;
    } bitv;
} ct_bitmap8;

ct_bitmap8 lcd_swap_flags;

#define lcd_swap1_f     lcd_swap_flags.bitv.b0  //swapping line 1
#define lcd_swap2_f     lcd_swap_flags.bitv.b2  //swapping line 2
#define lcd_dalt1_f     lcd_swap_flags.bitv.b1  //alternate line 1
#define lcd_dalt2_f     lcd_swap_flags.bitv.b3  //alternate line 2
#define lcd_fswap_f     lcd_swap_flags.bitv.b4  //fast swap
#define lcd_tswap_f     lcd_swap_flags.bitv.b5  //temporary swap
produces far more compact code than this:

C:
_Bool lcd_swap1_f;      //swapping line 1
_Bool lcd_swap2_f;      //swapping line 2
_Bool lcd_dalt1_f;      //alternate line 1
_Bool lcd_dalt2_f;      //alternate line 2
_Bool lcd_fswap_f;      //fast swap
_Bool lcd_tswap_f;      //temporary swap
Each _Bool is treated as an 8 bit byte, and logical operations require multiple instructions on that byte.

With the explicitly packed flags, OTOH, the compiler generates the bcf, bsf, btg, btfsc, and btfss instructions as desired.
 

nsaspook

Joined Aug 27, 2009
16,333
I've discovered that this:

C:
typedef union
{
    uint_fast8_t bytev;
    struct
    {
        unsigned b0:1;
        unsigned b1:1;
        unsigned b2:1;
        unsigned b3:1;
        unsigned b4:1;
        unsigned b5:1;
        unsigned b6:1;
        unsigned b7:1;
    } bitv;
} ct_bitmap8;

ct_bitmap8 lcd_swap_flags;

#define lcd_swap1_f     lcd_swap_flags.bitv.b0  //swapping line 1
#define lcd_swap2_f     lcd_swap_flags.bitv.b2  //swapping line 2
#define lcd_dalt1_f     lcd_swap_flags.bitv.b1  //alternate line 1
#define lcd_dalt2_f     lcd_swap_flags.bitv.b3  //alternate line 2
#define lcd_fswap_f     lcd_swap_flags.bitv.b4  //fast swap
#define lcd_tswap_f     lcd_swap_flags.bitv.b5  //temporary swap
produces far more compact code than this:

C:
_Bool lcd_swap1_f;      //swapping line 1
_Bool lcd_swap2_f;      //swapping line 2
_Bool lcd_dalt1_f;      //alternate line 1
_Bool lcd_dalt2_f;      //alternate line 2
_Bool lcd_fswap_f;      //fast swap
_Bool lcd_tswap_f;      //temporary swap
Each _Bool is treated as an 8 bit byte, and logical operations require multiple instructions on that byte.

With the explicitly packed flags, OTOH, the compiler generates the bcf, bsf, btg, btfsc, and btfss instructions as desired.
Yes, that's why the BIT type is not needed for C bit fiddling even if some think it's a horrible deficiency not to have one. C has the capability to efficiently bit manipulate if you tell it that's what you want.
 
Last edited:

nsaspook

Joined Aug 27, 2009
16,333
Ironic: more C == less .asm.
It's a lump of clay (the basic C abstract machine) the expert molds into a masterpiece with small movements (specific source code instructions) of the hand on the turning table, converting that abstraction into the physical machine we need.
 
Last edited:

ApacheKid

Joined Jan 12, 2015
1,762
This is another of those "implementation dependent" features it seems. The fact that double can be 4 bytes on one compiler yet 8 bytes on some other - for the same language - is the kind of thing that I was alluding to in my criticisms of C recently.
 
Last edited:

Thread Starter

joeyd999

Joined Jun 6, 2011
6,330
It's a lump of clay (the basic C abstract machine) the expert molds into a masterpiece with small movements (specific source code instructions) of the hand on the turning table, converting that abstraction into the physical machine we need.
Whereas I'd liken .asm to a block of marble...
 

nsaspook

Joined Aug 27, 2009
16,333
This is another of those "implementation dependent" features it seem. The fact that double can be 4 bytes on one compiler yet 8 bytes on some other - for the same language - is the kind of thing that I was alluding to in my criticisms of C recently.
It's a very practical "implementation dependent" feature for 8-bit computers with no hardware FP. To dogmatically specific uniformity works in the software domain but physical machines require WISE choices for practical applications.
 

ApacheKid

Joined Jan 12, 2015
1,762
Yes, that's why the BIT type is not needed for C bit fiddling even if some think it's a horrible deficiency not to have one. C has the capability to efficiently bit manipulate if you tell it that's what you want.
That's all well and good, but having a type "bit" type that means the same thing in both cases, leads to equivalent generated code in both cases, would be good language design. I accept that C can do many things when these idiosyncrasies are understood, I just disapprove of them being idiosyncratic.

I mean if "unsigned <identifier> : <integer>" really means bit why can't one declare a local variable as that type? The "bit" notation is only allowed inside a struct!
 
Top